.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | Are you using a large modpack? Do you also experience insanely high launch times when using it?
Then my mod "Lightspeed" might be just what you are looking for.
3 |
4 | 🥳Thank you for 1000 Downloads - That's incredible for this short amount of time. More optimizations will come soon :)
5 | 📢 Offer: If you are still facing high launch times I encourage you to post a link to your modpack - I will then analyze it and provide further optimizations.
6 | 📰 News: In near future I'll test this mod with the most downloaded modpacks on curseforge in order to ensure overall compatibility and performance.
7 | 👀 Request: If you notice any issues please report them (on GitHub) - no improvement is worth having any crashes or incompatibility.
8 |
9 | 💡About
10 | Lightspeed is a launch optimization mod, that aims to significantly reduce minecrafts launch time when using (heavy) modpacks.
At the moment Lightspeed decreases minecraft's launch time by approx. 48% - 62%
11 | This mod is still work in progress and all optimizations will be added bit by bit to ensure a stable and slowly getting better experience.
12 | To let you track the launch time improvement for every update Lightspeed displays the launch time at the title screen (look at the Images tab).
13 |
14 | 📜 Motivation
15 | I'm using a large modpack myself that includes 273 mods (Minecraft 1.18.2). Minecraft takes half an eternity to start - even though I have a solid pc setup.
16 | An up-to-date computer takes 7 minutes, a setup of 2015 approx. 15 min and a notebook of 2018 even needs more than 20 min to launch minecraft.
17 | That's not really good.
18 |
19 | 🔭 Roadmap
20 | At the moment Lightspeed decreases minecraft's launch time by approx. 48% - 62%. Every future update aims to improve it at least by 10%.
My final goal is that Lightspeed make your launch 3 to 4 times faster than without using it.
Meaning an unoptimized launch of 7 minutes should be reduced to 2 minutes, 15 minutes to 4 minutes and so on.
If you like this mod, I would be happy if you post a comment with your initial launch time and the time achieved by using Lightspeed.
21 |
22 | 🧭Maxims (Guiding principles)
23 | To ensure that my goal (improved loading times for everyone) is actually achieved, Lightspeed follows or should follow a few guiding principles:
24 |
25 | - Efficiency over multithreading: Not everyone has a gaming cpu with 12, 16 or even 20 cores. Therefore, Lightspeed relies on caches and other measures to minimize operations wherever possible.
26 | - Minimally invasive: Even though Lightspeed is changing existing source code, it's not an completely overhaul or rearrangement of it. Every adjustment takes place with utmost care.
27 | - (Ideally) no incompatibilities: It's my goal that Lightspeed is and will be compatible with almost all mods out there - if you experience any crashes, weird behaviours or other issues please create an issue on GitHub.
28 |
29 |
30 | ⚗️How it works
31 | Minecraft and Forge are using some inefficient or redundant ways to load, hold and process data. I found some of these.
32 | I implemented an alternative algorithm per inefficiency and then observed the startup again to verify that the change resulted in the expected improvement.
33 | Lightspeed's optimizations will mainly focus on:
34 |
35 | - reducing file system operations (especially read access)
36 | - parallelizing suitable processes
37 | - caching computed results and data
38 | - improved data structures
39 |
40 |
41 | 🖥️ Test-Setup & Compatibilities
42 | The following section contains all mods that I'm using in my modpack. Which means that all of these mods should be compatible with Lightspeed.
43 |
44 |
AbsentByDesign AdditionalAdditions AdditionalLanterns AdditionalLights Alcocraft Alexsmobs AmbientAdditions AmbientSounds Appetite AppleSkin AppollosAdditionalStructures Aquaculture Architects Architectury Artifacts AutoRegLib AwesomeDungeonEnd AwesomeDungeonNether AwesomeDungeonOcean Awesomedungeon BadMobs Balm Beautify Bettas BetterAdvancements BetterAnimalsPlus BetterBiomeBlend BetterFpsDist BetterModsButton BeyondEarth BiomesO'Plenty BlockCarpentry BlueSkies Bookshelf BotanyPots BottleYourXp BottledAir Breezy BuildersAddition BuildersDelight Camera Canary Chipped Chiseled Citadel ClothConfig CofhCore ColdsStructures Collective CombatRoll Configured ConnectedTexturesMod CookingForBlockheads CornDelight Create CreativeCore CreaturesAndBeasts CrittersAndCompanions Croptopia CulturalDelights Curios DecorationDelightMod DecorativeBlocks DeeperInTheCaves Delightful Diet DimDungeons DisplayCase DoggyTalents DomesticationInnovation DomumOrnamentum DrawerFps Duckies DungeonCrawl DungeonsArise DynamicSurroundings Ecologics EntityCollisionFpsFix EntityCulling ExlineFurniture ExoticBirds Expandability ExpandedCaves ExtendedLights FallingLeaves FantasyFurniture FarmersDelight FastLeafDecay FastWorkbench FeatureNbtDeadlockBeGone FerriteCore FinsAndTails FixMySpawnR Floralis Flowery FloweryCore Flywheel FoodEnhancements ForgottenBiomes FramedBlocks Furnish Geckolib Gemsnjewels GoProne Goodall GrapplingHookMod Gravestone GuardVillagers GuiClock HappyHolidays Hedgehog HopoBetterUnderwaterRuins Hyle ImmersiveEngineering ImmversiveFX InControl Incendium IndustrialForegoing InfinityButtons IntegratedStructuresAndDungeons Jade Jeed Jei JeiIntegration JourneyMap Kiwi KnightQuest Koremods KotlinForForge Krypton LazyDfu LibraryFerret LightMeals Lightspeed MacawsBridges MacawsBridgesBOP MacawsDoors MacawsFences MacawsFencesBOP MacawsFurniture MacawsLights MacawsPaths MacawsRoofs MacawsRoofsBOP MacawsTrapdoors MacawsWindows Mantle ManyIdeasCore ManyIdeasDoors Mapperbase McjtyLib MmLib ModernXl MonkeMadness MoogsVoyagerStructures MoreBeautifulPlates MoreStorageDrawers MoreVillagers MouseTweaks MrCrayfish'sFurniture Multibeds NamelessTrinkets Naturalist NaturesCompass Nekoration Nightlights NockEnoughArrows NotJustSandwich Notes Observable ObsidianBoat OhTheBiomesYou'llGo Optifine OutOfSight Pam'sHarvestcraftCrops Pam'sHarvestcraftFoodCore Pam'sHarvestcraftFoodExtended Pam'sHarvestcraftTrees Paraglider Patchouli Phireworks PickUpNotifier Placebo PlayerAnimator PresenceFootsteps PrettyBeaches PrimalReservation ProjectVibrantJourneys PuzzlesLib Pyrotastic Quark QuickPlant Reblured Rechiseled RecipesLibrary RefinedStorage Relics Reliquary RepurposedStructures RexsAdditionalStructures RfToolsBase RoughTweaks Searchlight SecretRooms SecurityCraft Selene ShetiphianCore Shrines Signpost SimpleDivingGear SimplyHouses SimplyLight Sit SmarterFarmers SmoothChunk SnowRealMagic SnowUnderTrees SnowySpirit SophisticatedBackpacks SophisticatedCore SophisticatedStorage SoundPhysics SpiceOfLife SpyglassImprovements Starlight StorageDrawers Structory StructureGel StylishEffects SuperMartijn642ConfigLib SuperMartijn642CoreLib Supplementaries SushiGoCrafting SushiMod TerraBlender Terralith TheAbyss2 TheVeggieWay ThermalCultivation ThermalExpansion ThermalFoundation ThermalInnovation ThermalIntegration ThermalLocomotion Titanium ToughAsNails TownsAndTowers Trapcraft UTeamCore UnionLib Unstructured UntamedWilds UnusualDrill UnusualEnd UsefulBackpacks VanillaDegus Villagernames Waddles Waystones WildBackport Wilds XercaMod Xnet XtraArrows YungsApi YungsBetterDesertTemples YungsBetterDungeons YungsBetterMineshafts YungsBetterStrongholds YungsBetterWitchHuts mOREs
45 |
46 |
47 | ❗Important Notes
48 |
49 | - The optimizations will only show an effect if you are using several or a lot of mods.
50 | Some future optimizations may directly tweak other mods. In favor of overall compatibility mod-specific optimizations will only change the code of minecraft instead of the actual mod code.
51 | - It will probably not be possible to reduce the launch time down or near to vanilla level (about 40 seconds), because in spite of optimizations there is more to do than not using any mods - But I will try my best to retract that statement at some point.
52 |
53 |
54 | 📝FAQ
55 |
56 |
Q: Can I use Lightspeed in my modpack?
57 |
A: Yes - Feel free to include Lightspeed into your modpack - Remember to give credit and don't claim Lightspeed as your own creation.
58 |
59 |
Q: Which Minecraft versions are supported?
60 |
A: Lightspeed is currently available for 1.18.2. Other version will hopefully come soon - feel free to request a specific version.
61 |
62 |
Q: Are there any known incompatibilities with other mods?
63 |
A: Not yet - most mods should be compatible with Lightspeed. If you are facing any problems when using Lightspeed please create an issue on GitHub.
64 |
65 |
Q: I'm still facing high launch times. Why?
66 |
A: This mod is still work in progress - look at the Roadmap section for more info. Maybe some mods you are using contain inefficient algorithms. Feel free to create an issue on GitHub with your mod list. I will try to profile and to improve it. Another reason might be your maximum memory allocation (via -XMX) - if this value is too low, minecraft will try to free memory more often and this will hurt the launch time.
67 |
68 |
69 | 🌎 Links
70 | Report issues and request features
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | maven { url = 'https://repo.spongepowered.org/maven' }
4 | }
5 |
6 | dependencies {
7 | classpath 'org.spongepowered:mixingradle:0.7.+'
8 | }
9 | }
10 |
11 | plugins {
12 | id 'net.minecraftforge.gradle' version '5.1.+'
13 | }
14 |
15 | apply plugin: 'org.spongepowered.mixin'
16 |
17 | group = 'ccr4ft3r'
18 | version = "${mc_version}-${mod_version}"
19 |
20 | java {
21 | archivesBaseName = 'lightspeed'
22 | toolchain.languageVersion = JavaLanguageVersion.of(17)
23 | }
24 |
25 | minecraft {
26 | // The mappings can be changed at any time and must be in the following format.
27 | // Channel: Version:
28 | // official MCVersion Official field/method names from Mojang mapping files
29 | // parchment YYYY.MM.DD-MCVersion Open community-sourced parameter names and javadocs layered on top of official
30 | //
31 | // You must be aware of the Mojang license when using the 'official' or 'parchment' mappings.
32 | // See more information here: https://github.com/MinecraftForge/MCPConfig/blob/master/Mojang.md
33 | //
34 | // Parchment is an unofficial project maintained by ParchmentMC, separate from MinecraftForge
35 | // Additional setup is needed to use their mappings: https://github.com/ParchmentMC/Parchment/wiki/Getting-Started
36 | //
37 | // Use non-default mappings at your own risk. They may not always work.
38 | // Simply re-run your setup task after changing the mappings to update your workspace.
39 | mappings channel: 'official', version: '1.18.2'
40 |
41 | // Default run configurations.
42 | // These can be tweaked, removed, or duplicated as needed.
43 | runs {
44 | client {
45 | workingDirectory project.file('run')
46 |
47 | // Recommended logging data for a userdev environment
48 | // The markers can be added/remove as needed separated by commas.
49 | // "SCAN": For mods scan.
50 | // "REGISTRIES": For firing of registry events.
51 | // "REGISTRYDUMP": For getting the contents of all registries.
52 | property 'forge.logging.markers', 'REGISTRIES'
53 |
54 |
55 | // Recommended logging level for the console
56 | // You can set various levels here.
57 | // Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels
58 | property 'forge.logging.console.level', 'debug'
59 |
60 | // Comma-separated list of namespaces to load gametests from. Empty = all namespaces.
61 | property 'forge.enabledGameTestNamespaces', 'lightspeed'
62 |
63 | mods {
64 | lightspeed {
65 | source sourceSets.main
66 | }
67 | }
68 | }
69 |
70 | server {
71 | workingDirectory project.file('run')
72 |
73 | property 'forge.logging.markers', 'REGISTRIES'
74 |
75 | property 'forge.logging.console.level', 'debug'
76 |
77 | property 'forge.enabledGameTestNamespaces', 'lightspeed'
78 |
79 | mods {
80 | lightspeed {
81 | source sourceSets.main
82 | }
83 | }
84 | }
85 |
86 | // This run config launches GameTestServer and runs all registered gametests, then exits.
87 | // By default, the server will crash when no gametests are provided.
88 | // The gametest system is also enabled by default for other run configs under the /test command.
89 | gameTestServer {
90 | workingDirectory project.file('run')
91 |
92 | property 'forge.logging.markers', 'REGISTRIES'
93 |
94 | property 'forge.logging.console.level', 'debug'
95 |
96 | property 'forge.enabledGameTestNamespaces', 'lightspeed'
97 |
98 | mods {
99 | lightspeed {
100 | source sourceSets.main
101 | }
102 | }
103 | }
104 |
105 | data {
106 | workingDirectory project.file('run')
107 |
108 | property 'forge.logging.markers', 'REGISTRIES'
109 |
110 | property 'forge.logging.console.level', 'debug'
111 |
112 | // Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources.
113 | args '--mod', 'lightspeed', '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/')
114 |
115 | mods {
116 | lightspeed {
117 | source sourceSets.main
118 | }
119 | }
120 | }
121 | }
122 | }
123 |
124 | // Include resources generated by data generators.
125 | sourceSets.main.resources { srcDir 'src/generated/resources' }
126 |
127 | repositories {
128 | // Put repositories for dependencies here
129 | // ForgeGradle automatically adds the Forge maven and Maven Central for you
130 |
131 | // If you have mod jar dependencies in ./libs, you can declare them as a repository like so:
132 | // flatDir {
133 | // dir 'libs'
134 | // }
135 | maven {
136 | url "https://www.cursemaven.com"
137 | content {
138 | includeGroup "curse.maven"
139 | }
140 | }
141 | }
142 |
143 | dependencies {
144 | // Specify the version of Minecraft to use. If this is any group other than 'net.minecraft' it is assumed
145 | // that the dep is a ForgeGradle 'patcher' dependency, and its patches will be applied.
146 | // The userdev artifact is a special name and will get all sorts of transformations applied to it.
147 | minecraft "net.minecraftforge:forge:${mc_version}-${forge_version}"
148 | annotationProcessor 'org.spongepowered:mixin:0.8.5:processor'
149 |
150 | // Real mod deobf dependency examples - these get remapped to your current mappings
151 | // compileOnly fg.deobf("mezz.jei:jei-${mc_version}:${jei_version}:api") // Adds JEI API as a compile dependency
152 | // runtimeOnly fg.deobf("mezz.jei:jei-${mc_version}:${jei_version}") // Adds the full JEI mod as a runtime dependency
153 | // implementation fg.deobf("com.tterrag.registrate:Registrate:MC${mc_version}-${registrate_version}") // Adds registrate as a dependency
154 |
155 | // Examples using mod jars from ./libs
156 | // implementation fg.deobf("blank:coolmod-${mc_version}:${coolmod_version}")
157 |
158 | // For more info...
159 | // http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
160 | // http://www.gradle.org/docs/current/userguide/dependency_management.html
161 | }
162 |
163 | mixin {
164 | add sourceSets.main, "lightspeed.refmap.json"
165 | config "lightspeed.mixins.json"
166 | }
167 |
168 | // Example for how to get properties into the manifest for reading at runtime.
169 | jar {
170 | manifest {
171 | attributes([
172 | "Specification-Title" : "lightspeed",
173 | "Specification-Vendor" : "CCr4ft3r",
174 | "Specification-Version" : "1", // We are version 1 of ourselves
175 | "Implementation-Title" : project.name,
176 | "Implementation-Version" : project.jar.archiveVersion,
177 | "Implementation-Vendor" : "CCr4ft3r",
178 | "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")
179 | ])
180 | }
181 | }
182 |
183 | jar.finalizedBy('reobfJar')
184 |
185 | tasks.withType(JavaCompile).configureEach {
186 | options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation
187 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx3G
2 | org.gradle.daemon=false
3 |
4 | mc_version=1.18.2
5 | forge_version=40.1.73
6 | mod_version=1.1.0
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CCr4ft3r/lightspeed/d9106bd9ddeaa7fab52a04cff6280ad4e19e30e7/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015-2021 the original authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | #
21 | # Gradle start up script for POSIX generated by Gradle.
22 | #
23 | # Important for running:
24 | #
25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
26 | # noncompliant, but you have some other compliant shell such as ksh or
27 | # bash, then to run this script, type that shell name before the whole
28 | # command line, like:
29 | #
30 | # ksh Gradle
31 | #
32 | # Busybox and similar reduced shells will NOT work, because this script
33 | # requires all of these POSIX shell features:
34 | # * functions;
35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
37 | # * compound commands having a testable exit status, especially «case»;
38 | # * various built-in commands including «command», «set», and «ulimit».
39 | #
40 | # Important for patching:
41 | #
42 | # (2) This script targets any POSIX shell, so it avoids extensions provided
43 | # by Bash, Ksh, etc; in particular arrays are avoided.
44 | #
45 | # The "traditional" practice of packing multiple parameters into a
46 | # space-separated string is a well documented source of bugs and security
47 | # problems, so this is (mostly) avoided, by progressively accumulating
48 | # options in "$@", and eventually passing that to Java.
49 | #
50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
52 | # see the in-line comments for details.
53 | #
54 | # There are tweaks for specific operating systems such as AIX, CygWin,
55 | # Darwin, MinGW, and NonStop.
56 | #
57 | # (3) This script is generated from the Groovy template
58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
59 | # within the Gradle project.
60 | #
61 | # You can find Gradle at https://github.com/gradle/gradle/.
62 | #
63 | ##############################################################################
64 |
65 | # Attempt to set APP_HOME
66 |
67 | # Resolve links: $0 may be a link
68 | app_path=$0
69 |
70 | # Need this for daisy-chained symlinks.
71 | while
72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
73 | [ -h "$app_path" ]
74 | do
75 | ls=$( ls -ld "$app_path" )
76 | link=${ls#*' -> '}
77 | case $link in #(
78 | /*) app_path=$link ;; #(
79 | *) app_path=$APP_HOME$link ;;
80 | esac
81 | done
82 |
83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
84 |
85 | APP_NAME="Gradle"
86 | APP_BASE_NAME=${0##*/}
87 |
88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
90 |
91 | # Use the maximum available, or set MAX_FD != -1 to use that value.
92 | MAX_FD=maximum
93 |
94 | warn () {
95 | echo "$*"
96 | } >&2
97 |
98 | die () {
99 | echo
100 | echo "$*"
101 | echo
102 | exit 1
103 | } >&2
104 |
105 | # OS specific support (must be 'true' or 'false').
106 | cygwin=false
107 | msys=false
108 | darwin=false
109 | nonstop=false
110 | case "$( uname )" in #(
111 | CYGWIN* ) cygwin=true ;; #(
112 | Darwin* ) darwin=true ;; #(
113 | MSYS* | MINGW* ) msys=true ;; #(
114 | NONSTOP* ) nonstop=true ;;
115 | esac
116 |
117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
118 |
119 |
120 | # Determine the Java command to use to start the JVM.
121 | if [ -n "$JAVA_HOME" ] ; then
122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
123 | # IBM's JDK on AIX uses strange locations for the executables
124 | JAVACMD=$JAVA_HOME/jre/sh/java
125 | else
126 | JAVACMD=$JAVA_HOME/bin/java
127 | fi
128 | if [ ! -x "$JAVACMD" ] ; then
129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
130 |
131 | Please set the JAVA_HOME variable in your environment to match the
132 | location of your Java installation."
133 | fi
134 | else
135 | JAVACMD=java
136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
137 |
138 | Please set the JAVA_HOME variable in your environment to match the
139 | location of your Java installation."
140 | fi
141 |
142 | # Increase the maximum file descriptors if we can.
143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
144 | case $MAX_FD in #(
145 | max*)
146 | MAX_FD=$( ulimit -H -n ) ||
147 | warn "Could not query maximum file descriptor limit"
148 | esac
149 | case $MAX_FD in #(
150 | '' | soft) :;; #(
151 | *)
152 | ulimit -n "$MAX_FD" ||
153 | warn "Could not set maximum file descriptor limit to $MAX_FD"
154 | esac
155 | fi
156 |
157 | # Collect all arguments for the java command, stacking in reverse order:
158 | # * args from the command line
159 | # * the main class name
160 | # * -classpath
161 | # * -D...appname settings
162 | # * --module-path (only if needed)
163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
164 |
165 | # For Cygwin or MSYS, switch paths to Windows format before running java
166 | if "$cygwin" || "$msys" ; then
167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
169 |
170 | JAVACMD=$( cygpath --unix "$JAVACMD" )
171 |
172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
173 | for arg do
174 | if
175 | case $arg in #(
176 | -*) false ;; # don't mess with options #(
177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
178 | [ -e "$t" ] ;; #(
179 | *) false ;;
180 | esac
181 | then
182 | arg=$( cygpath --path --ignore --mixed "$arg" )
183 | fi
184 | # Roll the args list around exactly as many times as the number of
185 | # args, so each arg winds up back in the position where it started, but
186 | # possibly modified.
187 | #
188 | # NB: a `for` loop captures its iteration list before it begins, so
189 | # changing the positional parameters here affects neither the number of
190 | # iterations, nor the values presented in `arg`.
191 | shift # remove old arg
192 | set -- "$@" "$arg" # push replacement arg
193 | done
194 | fi
195 |
196 | # Collect all arguments for the java command;
197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
198 | # shell script including quotes and variable substitutions, so put them in
199 | # double quotes to make sure that they get re-expanded; and
200 | # * put everything else in single quotes, so that it's not re-expanded.
201 |
202 | set -- \
203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
204 | -classpath "$CLASSPATH" \
205 | org.gradle.wrapper.GradleWrapperMain \
206 | "$@"
207 |
208 | # Use "xargs" to parse quoted args.
209 | #
210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
211 | #
212 | # In Bash we could simply go:
213 | #
214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
215 | # set -- "${ARGS[@]}" "$@"
216 | #
217 | # but POSIX shell has neither arrays nor command substitution, so instead we
218 | # post-process each arg (as a line of input to sed) to backslash-escape any
219 | # character that might be a shell metacharacter, then use eval to reverse
220 | # that process (while maintaining the separation between arguments), and wrap
221 | # the whole thing up as a single "set" statement.
222 | #
223 | # This will of course break if any of these variables contains a newline or
224 | # an unmatched quote.
225 | #
226 |
227 | eval "set -- $(
228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
229 | xargs -n1 |
230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
231 | tr '\n' ' '
232 | )" '"$@"'
233 |
234 | exec "$JAVACMD" "$@"
235 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | maven { url = 'https://maven.minecraftforge.net/' }
5 | }
6 | }
7 |
8 | rootProject.name = 'lightspeed'
9 |
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/Main.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed;
2 |
3 | import com.ccr4ft3r.lightspeed.cache.GlobalCache;
4 | import com.ccr4ft3r.lightspeed.util.CompatUtil;
5 | import net.minecraftforge.fml.ModList;
6 | import net.minecraftforge.fml.common.Mod;
7 | import net.minecraftforge.resource.ResourceCacheManager;
8 |
9 | @Mod(ModConstants.MOD_ID)
10 | public class Main {
11 |
12 | public Main() {
13 | updateCacheFlags();
14 | }
15 |
16 | private void updateCacheFlags() {
17 | if (ModList.get().isLoaded(ModConstants.SOPHISTICATED_STORAGE_ID) && ModList.get().isLoaded(ModConstants.JSON_THINGS_ID))
18 | GlobalCache.shouldCacheWalkedPaths = false;
19 | if (CompatUtil.existsClass("net.minecraftforge.resource.ResourceCacheManager")
20 | && ResourceCacheManager.shouldUseCache())
21 | GlobalCache.shouldCacheEmptyNamespaces = false;
22 | if (ModList.get().isLoaded(ModConstants.MULTIBLOCKED_ID))
23 | GlobalCache.shouldCacheMaterials = false;
24 | }
25 | }
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/ModConstants.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed;
2 |
3 | public class ModConstants {
4 |
5 | public static final String MOD_ID = "lightspeed";
6 | public static final String JSON_THINGS_ID = "jsonthings";
7 | public static final String SOPHISTICATED_STORAGE_ID = "sophisticatedstorage";
8 | public static final String MULTIBLOCKED_ID = "multiblocked";
9 | }
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/cache/GlobalCache.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed.cache;
2 |
3 | import com.ccr4ft3r.lightspeed.interfaces.ICache;
4 | import com.ccr4ft3r.lightspeed.util.CacheUtil;
5 | import com.google.common.collect.Maps;
6 | import com.google.common.collect.Sets;
7 | import com.mojang.bridge.game.PackType;
8 |
9 | import java.io.File;
10 | import java.util.List;
11 | import java.util.Map;
12 | import java.util.Set;
13 | import java.util.concurrent.ExecutorService;
14 | import java.util.concurrent.Executors;
15 |
16 | import static com.ccr4ft3r.lightspeed.util.CacheUtil.*;
17 |
18 | public class GlobalCache {
19 |
20 | public static Boolean isEnabled = true;
21 | public static Boolean shouldCacheWalkedPaths = true;
22 | public static Boolean shouldCacheEmptyNamespaces = true;
23 | public static Boolean shouldCacheMaterials = true;
24 | public static final Map> SPLITTED_STRINGS_BY_SEQUENCE = Maps.newConcurrentMap();
25 | public static final Map CANONICAL_PATH_PER_FILE = Maps.newConcurrentMap();
26 | private static final Set CACHES = Sets.newConcurrentHashSet();
27 | public static final Map> PERSISTED_EXISTENCES_BY_MOD = Maps.newConcurrentMap();
28 | public static final Map>> PERSISTED_NAMESPACES_BY_MOD = Maps.newConcurrentMap();
29 | public static final ExecutorService EXECUTOR = Executors.newSingleThreadExecutor();
30 |
31 | public static void add(ICache cache) {
32 | CACHES.add(cache);
33 | }
34 |
35 | @SuppressWarnings("ResultOfMethodCallIgnored")
36 | public static void disablePersistAndClear() {
37 | isEnabled = false;
38 | CacheUtil.getCacheFiles(HAS_RESOURCE_CACHE_DIR).forEach(File::delete);
39 | CacheUtil.getCacheFiles(NAMESPACE_CACHE_DIR).forEach(File::delete);
40 | CACHES.forEach(ICache::persistAndClearCache);
41 | SPLITTED_STRINGS_BY_SEQUENCE.clear();
42 | CANONICAL_PATH_PER_FILE.clear();
43 | CACHES.clear();
44 | PERSISTED_EXISTENCES_BY_MOD.clear();
45 | PERSISTED_NAMESPACES_BY_MOD.clear();
46 | }
47 | }
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/events/TitleScreenInjector.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed.events;
2 |
3 | import com.ccr4ft3r.lightspeed.ModConstants;
4 | import com.ccr4ft3r.lightspeed.cache.GlobalCache;
5 | import com.mojang.logging.LogUtils;
6 | import net.minecraft.client.gui.screens.TitleScreen;
7 | import net.minecraftforge.api.distmarker.Dist;
8 | import net.minecraftforge.client.event.ScreenEvent;
9 | import net.minecraftforge.eventbus.api.EventPriority;
10 | import net.minecraftforge.eventbus.api.SubscribeEvent;
11 | import net.minecraftforge.fml.common.Mod;
12 | import net.minecraftforge.internal.BrandingControl;
13 |
14 | import java.lang.management.ManagementFactory;
15 | import java.lang.reflect.Field;
16 | import java.lang.reflect.InvocationTargetException;
17 | import java.lang.reflect.Method;
18 | import java.util.ArrayList;
19 | import java.util.List;
20 |
21 | @Mod.EventBusSubscriber(modid = ModConstants.MOD_ID, value = Dist.CLIENT)
22 | public class TitleScreenInjector {
23 |
24 | private static boolean launchComplete = false;
25 |
26 | @SuppressWarnings({"InstantiationOfUtilityClass", "unchecked"})
27 | @SubscribeEvent(priority = EventPriority.LOWEST)
28 | public static void onScreenInit(ScreenEvent.InitScreenEvent.Post event) {
29 | if (!(event.getScreen() instanceof TitleScreen) || launchComplete)
30 | return;
31 | launchComplete = true;
32 | try {
33 | long secondsToStart = ManagementFactory.getRuntimeMXBean().getUptime() / 1000;
34 | LogUtils.getLogger().info("Lightspeed: Launch took {}s", secondsToStart);
35 | BrandingControl brandingControl = new BrandingControl();
36 |
37 | Field f = BrandingControl.class.getDeclaredField("brandings");
38 | f.setAccessible(true);
39 | Method computeBranding = BrandingControl.class.getDeclaredMethod("computeBranding");
40 | computeBranding.setAccessible(true);
41 | computeBranding.invoke(null);
42 |
43 | List brandings = new ArrayList<>((List) f.get(brandingControl));
44 | LogUtils.getLogger().info("ERRORR: " + brandings);
45 | if (brandings.size() > 1) {
46 | List newBrandings = new ArrayList<>(brandings);
47 | f.set(brandingControl, newBrandings);
48 | newBrandings.add("Lightspeed: Launch took " + secondsToStart + "s");
49 | }
50 | } catch (NoSuchFieldException | NoSuchMethodException | IllegalAccessException |
51 | InvocationTargetException e) {
52 | LogUtils.getLogger().error("Cannot add launch time to title screen", e);
53 | }
54 | GlobalCache.EXECUTOR.execute(GlobalCache::disablePersistAndClear);
55 | GlobalCache.EXECUTOR.shutdown();
56 | }
57 | }
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/interfaces/ICache.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed.interfaces;
2 |
3 | public interface ICache {
4 | void persistAndClearCache();
5 | }
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/interfaces/IPackResources.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed.interfaces;
2 |
3 | import java.util.Map;
4 |
5 | public interface IPackResources extends ICache {
6 |
7 | Map getExistenceByResource();
8 |
9 | void setExistenceByResource(Map existenceByResource);
10 | }
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/interfaces/IPathResourcePack.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed.interfaces;
2 |
3 | import net.minecraft.server.packs.PackResources;
4 | import net.minecraftforge.forgespi.locating.IModFile;
5 |
6 | public interface IPathResourcePack extends PackResources, IPackResources {
7 | void setModFile(IModFile modFile);
8 |
9 | }
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/mixin/MinecraftMainMixin.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed.mixin;
2 |
3 | import com.ccr4ft3r.lightspeed.cache.GlobalCache;
4 | import com.ccr4ft3r.lightspeed.util.CacheUtil;
5 | import net.minecraft.client.main.Main;
6 | import org.apache.commons.io.FilenameUtils;
7 | import org.spongepowered.asm.mixin.Mixin;
8 | import org.spongepowered.asm.mixin.injection.At;
9 | import org.spongepowered.asm.mixin.injection.Inject;
10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
11 |
12 | import java.io.File;
13 | import java.util.Map;
14 |
15 | import static com.ccr4ft3r.lightspeed.util.CacheUtil.*;
16 |
17 | @Mixin(Main.class)
18 | public class MinecraftMainMixin {
19 |
20 | @Inject(method = "main", at = @At(value = "INVOKE", target = "Lnet/minecraft/SharedConstants;tryDetectVersion()V", shift = At.Shift.AFTER))
21 | private static void mainTryDetecVersionInjected(String[] p_129642_, CallbackInfo ci) {
22 | GlobalCache.EXECUTOR.execute(() -> {
23 | loadPersistedCaches(HAS_RESOURCE_CACHE_DIR, GlobalCache.PERSISTED_EXISTENCES_BY_MOD);
24 | loadPersistedCaches(NAMESPACE_CACHE_DIR, GlobalCache.PERSISTED_NAMESPACES_BY_MOD);
25 | });
26 | }
27 |
28 | @SuppressWarnings("ResultOfMethodCallIgnored")
29 | private static void loadPersistedCaches(File dir, Map> targetMap) {
30 | dir.mkdirs();
31 | CacheUtil.getCacheFiles(dir).forEach(file -> {
32 | String id = FilenameUtils.getBaseName(file.getName());
33 | targetMap.put(id, CacheUtil.load(file));
34 | });
35 | }
36 | }
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/mixin/misc/KeyValueConditionMixin.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed.mixin.misc;
2 |
3 | import com.ccr4ft3r.lightspeed.cache.GlobalCache;
4 | import com.google.common.base.Splitter;
5 | import net.minecraft.client.renderer.block.model.multipart.KeyValueCondition;
6 | import org.spongepowered.asm.mixin.Mixin;
7 | import org.spongepowered.asm.mixin.injection.At;
8 | import org.spongepowered.asm.mixin.injection.Redirect;
9 |
10 | import java.util.List;
11 |
12 | import static com.ccr4ft3r.lightspeed.cache.GlobalCache.*;
13 |
14 | @Mixin(value = KeyValueCondition.class, priority = Integer.MAX_VALUE)
15 | public abstract class KeyValueConditionMixin {
16 |
17 | @Redirect(method = "getPredicate", at = @At(value = "INVOKE", target = "Lcom/google/common/base/Splitter;splitToList(Ljava/lang/CharSequence;)Ljava/util/List;"))
18 | public List getPredicateSplitToListRedirected(Splitter instance, CharSequence sequence) {
19 | if (!GlobalCache.isEnabled)
20 | return instance.splitToList(sequence);
21 | return SPLITTED_STRINGS_BY_SEQUENCE.computeIfAbsent(sequence, (k) -> instance.splitToList(sequence));
22 | }
23 | }
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/mixin/misc/MaterialMixin.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed.mixin.misc;
2 |
3 | import com.ccr4ft3r.lightspeed.cache.GlobalCache;
4 | import net.minecraft.client.resources.model.Material;
5 | import org.spongepowered.asm.mixin.Mixin;
6 | import org.spongepowered.asm.mixin.injection.At;
7 | import org.spongepowered.asm.mixin.injection.Inject;
8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
9 |
10 | @Mixin(Material.class)
11 | public abstract class MaterialMixin {
12 |
13 | private Integer hash;
14 |
15 | @Inject(method = "hashCode", at = @At("HEAD"), cancellable = true)
16 | public void hashCodeHeadInjected(CallbackInfoReturnable cir) {
17 | if (GlobalCache.isEnabled && hash != null)
18 | cir.setReturnValue(hash);
19 | }
20 |
21 | @Inject(method = "hashCode", at = @At("RETURN"))
22 | public void hashCodeReturnInjected(CallbackInfoReturnable cir) {
23 | if (GlobalCache.isEnabled && hash == null)
24 | hash = cir.getReturnValue();
25 | }
26 | }
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/mixin/misc/ResourceLocationMixin.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed.mixin.misc;
2 |
3 | import com.ccr4ft3r.lightspeed.cache.GlobalCache;
4 | import net.minecraft.resources.ResourceLocation;
5 | import org.spongepowered.asm.mixin.Mixin;
6 | import org.spongepowered.asm.mixin.injection.At;
7 | import org.spongepowered.asm.mixin.injection.Inject;
8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
9 |
10 | @Mixin(ResourceLocation.class)
11 | public abstract class ResourceLocationMixin {
12 |
13 | private Integer hash;
14 |
15 | @Inject(method = "hashCode", at = @At("HEAD"), cancellable = true)
16 | public void hashCodeHeadInjected(CallbackInfoReturnable cir) {
17 | if (GlobalCache.isEnabled && hash != null)
18 | cir.setReturnValue(hash);
19 | }
20 |
21 | @Inject(method = "hashCode", at = @At("RETURN"))
22 | public void hashCodeReturnInjected(CallbackInfoReturnable cir) {
23 | if (GlobalCache.isEnabled && hash == null)
24 | hash = cir.getReturnValue();
25 | }
26 | }
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/mixin/misc/ResourcePackLoaderMixin.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed.mixin.misc;
2 |
3 | import com.ccr4ft3r.lightspeed.cache.GlobalCache;
4 | import com.ccr4ft3r.lightspeed.interfaces.IPathResourcePack;
5 | import net.minecraftforge.forgespi.language.IModFileInfo;
6 | import net.minecraftforge.resource.PathResourcePack;
7 | import net.minecraftforge.resource.ResourcePackLoader;
8 | import org.spongepowered.asm.mixin.Mixin;
9 | import org.spongepowered.asm.mixin.injection.At;
10 | import org.spongepowered.asm.mixin.injection.Inject;
11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
12 |
13 | @Mixin(ResourcePackLoader.class)
14 | public abstract class ResourcePackLoaderMixin {
15 |
16 | @Inject(method = "createPackForMod", at = @At("HEAD"), remap = false, cancellable = true)
17 | private static void createPackForModHeadInjected(IModFileInfo mf, CallbackInfoReturnable cir) {
18 | if (!GlobalCache.isEnabled)
19 | return;
20 | PathResourcePack resourcePack = new PathResourcePack(mf.getFile().getFileName(), mf.getFile().getFilePath());
21 | ((IPathResourcePack) resourcePack).setModFile(mf.getFile());
22 | cir.setReturnValue(resourcePack);
23 | }
24 | }
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/mixin/misc/SelectorMixin.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed.mixin.misc;
2 |
3 | import com.ccr4ft3r.lightspeed.cache.GlobalCache;
4 | import com.ccr4ft3r.lightspeed.interfaces.ICache;
5 | import com.google.common.collect.MapMaker;
6 | import net.minecraft.client.renderer.block.model.MultiVariant;
7 | import net.minecraft.client.renderer.block.model.multipart.Condition;
8 | import net.minecraft.client.renderer.block.model.multipart.Selector;
9 | import net.minecraft.world.level.block.Block;
10 | import net.minecraft.world.level.block.state.BlockState;
11 | import net.minecraft.world.level.block.state.StateDefinition;
12 | import org.spongepowered.asm.mixin.Mixin;
13 | import org.spongepowered.asm.mixin.injection.At;
14 | import org.spongepowered.asm.mixin.injection.Inject;
15 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
16 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
17 |
18 | import java.util.Map;
19 | import java.util.function.Predicate;
20 |
21 | @Mixin(Selector.class)
22 | public class SelectorMixin implements ICache {
23 |
24 | private final Map, Predicate> predicatePerDefinition = new MapMaker().weakKeys().makeMap();
25 |
26 | @Inject(method = "", at = @At("RETURN"))
27 | public void initReturnInjected(Condition p_112018_, MultiVariant p_112019_, CallbackInfo ci) {
28 | if (GlobalCache.isEnabled)
29 | GlobalCache.add(this);
30 | }
31 |
32 | @Inject(method = "getPredicate", at = @At("HEAD"), cancellable = true)
33 | public void getPredicateHeadInjected(StateDefinition p_112022_, CallbackInfoReturnable> cir) {
34 | if (!GlobalCache.isEnabled)
35 | return;
36 | Predicate predicate = predicatePerDefinition.get(p_112022_);
37 | if (predicate != null)
38 | cir.setReturnValue(predicate);
39 | }
40 |
41 | @Inject(method = "getPredicate", at = @At("RETURN"))
42 | public void getPredicateReturnInjected(StateDefinition p_112022_, CallbackInfoReturnable> cir) {
43 | if (GlobalCache.isEnabled)
44 | predicatePerDefinition.put(p_112022_, cir.getReturnValue());
45 | }
46 |
47 | @Override
48 | public void persistAndClearCache() {
49 | predicatePerDefinition.clear();
50 | }
51 | }
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/mixin/misc/StateDefinitonMixin.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed.mixin.misc;
2 |
3 | import com.ccr4ft3r.lightspeed.cache.GlobalCache;
4 | import com.ccr4ft3r.lightspeed.interfaces.ICache;
5 | import net.minecraft.world.level.block.state.StateDefinition;
6 | import net.minecraft.world.level.block.state.properties.Property;
7 | import org.spongepowered.asm.mixin.Mixin;
8 | import org.spongepowered.asm.mixin.injection.At;
9 | import org.spongepowered.asm.mixin.injection.Inject;
10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
12 |
13 | import java.util.Map;
14 | import java.util.function.Function;
15 |
16 | @SuppressWarnings({"rawtypes", "unchecked"})
17 | @Mixin(StateDefinition.class)
18 | public class StateDefinitonMixin implements ICache {
19 |
20 | private Map> propsByName;
21 |
22 | @Inject(method = "", at = @At("RETURN"))
23 | public void initReturnInjected(Function p_61052_, Object p_61053_, StateDefinition.Factory p_61054_, Map p_61055_, CallbackInfo ci) {
24 | if (GlobalCache.isEnabled)
25 | GlobalCache.add(this);
26 | }
27 |
28 | @Inject(method = "", at = @At("RETURN"))
29 | private void initHeadInjected(Function p_61052_, Object p_61053_, StateDefinition.Factory p_61054_, Map p_61055_, CallbackInfo ci) {
30 | if (GlobalCache.isEnabled)
31 | propsByName = p_61055_;
32 | }
33 |
34 | @Inject(method = "getProperty", at = @At("HEAD"), cancellable = true)
35 | public void getPropertyHeadInjected(String p_61082_, CallbackInfoReturnable> cir) {
36 | if (GlobalCache.isEnabled)
37 | cir.setReturnValue(propsByName.get(p_61082_));
38 | }
39 |
40 | @Override
41 | public void persistAndClearCache() {
42 | propsByName.clear();
43 | }
44 | }
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/mixin/model/BlockModelMixin.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed.mixin.model;
2 |
3 | import com.ccr4ft3r.lightspeed.cache.GlobalCache;
4 | import com.mojang.datafixers.util.Pair;
5 | import net.minecraft.client.renderer.block.model.BlockModel;
6 | import net.minecraft.client.resources.model.Material;
7 | import net.minecraft.client.resources.model.UnbakedModel;
8 | import net.minecraft.resources.ResourceLocation;
9 | import org.spongepowered.asm.mixin.Mixin;
10 | import org.spongepowered.asm.mixin.injection.At;
11 | import org.spongepowered.asm.mixin.injection.Inject;
12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
13 |
14 | import java.util.Collection;
15 | import java.util.Set;
16 | import java.util.function.Function;
17 |
18 | @Mixin(BlockModel.class)
19 | public abstract class BlockModelMixin {
20 |
21 | private Collection materials;
22 |
23 | @Inject(method = "getMaterials", at = @At("HEAD"), cancellable = true)
24 | public void getMaterialsHeadInjected(Function p_111855_, Set> p_111856_, CallbackInfoReturnable> cir) {
25 | if (GlobalCache.isEnabled && materials != null && GlobalCache.shouldCacheMaterials)
26 | cir.setReturnValue(materials);
27 | }
28 |
29 | @Inject(method = "getMaterials", at = @At("RETURN"))
30 | public void getMaterialsReturnInjected(Function p_111855_, Set> p_111856_, CallbackInfoReturnable> cir) {
31 | if (GlobalCache.isEnabled && materials == null)
32 | materials = cir.getReturnValue();
33 | }
34 | }
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/mixin/model/ModelBakeryMixin.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed.mixin.model;
2 |
3 | import com.ccr4ft3r.lightspeed.cache.GlobalCache;
4 | import com.mojang.math.Transformation;
5 | import net.minecraft.client.renderer.texture.TextureAtlasSprite;
6 | import net.minecraft.client.resources.model.BakedModel;
7 | import net.minecraft.client.resources.model.Material;
8 | import net.minecraft.client.resources.model.ModelBakery;
9 | import net.minecraft.client.resources.model.ModelState;
10 | import net.minecraft.resources.ResourceLocation;
11 | import org.apache.commons.lang3.tuple.Triple;
12 | import org.spongepowered.asm.mixin.Final;
13 | import org.spongepowered.asm.mixin.Mixin;
14 | import org.spongepowered.asm.mixin.Shadow;
15 | import org.spongepowered.asm.mixin.injection.At;
16 | import org.spongepowered.asm.mixin.injection.Inject;
17 | import org.spongepowered.asm.mixin.injection.Redirect;
18 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
19 | import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
20 |
21 | import java.util.Map;
22 | import java.util.function.Function;
23 |
24 | @Mixin(ModelBakery.class)
25 | public abstract class ModelBakeryMixin {
26 |
27 | @Shadow
28 | @Final
29 | private Map, BakedModel> bakedCache;
30 |
31 | @Inject(method = "bake(Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/client/resources/model/ModelState;Ljava/util/function/Function;)Lnet/minecraft/client/resources/model/BakedModel;", at = @At(value = "INVOKE", target = "Ljava/util/Map;containsKey(Ljava/lang/Object;)Z", shift = At.Shift.BEFORE), cancellable = true, remap = false, locals = LocalCapture.CAPTURE_FAILSOFT)
32 | public void bakeContainsKeyInjected(ResourceLocation p_119350_, ModelState p_119351_, Function sprites, CallbackInfoReturnable cir, Triple triple) {
33 | if (!GlobalCache.isEnabled) {
34 | return;
35 | }
36 | BakedModel bakedModel = this.bakedCache.get(triple);
37 | if (bakedModel != null)
38 | cir.setReturnValue(bakedModel);
39 | }
40 |
41 | @SuppressWarnings("SuspiciousMethodCalls")
42 | @Redirect(method = "bake(Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/client/resources/model/ModelState;Ljava/util/function/Function;)Lnet/minecraft/client/resources/model/BakedModel;", at = @At(value = "INVOKE", target = "Ljava/util/Map;containsKey(Ljava/lang/Object;)Z"), remap = false)
43 | public boolean bakeContainsKeyRedirected(Map, BakedModel> instance, Object o) {
44 | if (!GlobalCache.isEnabled) {
45 | return instance.containsKey(o);
46 | }
47 | return false;
48 | }
49 | }
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/mixin/model/MultiPartMixin.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed.mixin.model;
2 |
3 | import com.ccr4ft3r.lightspeed.cache.GlobalCache;
4 | import com.mojang.datafixers.util.Pair;
5 | import net.minecraft.client.renderer.block.model.multipart.MultiPart;
6 | import net.minecraft.client.renderer.block.model.multipart.Selector;
7 | import net.minecraft.client.resources.model.Material;
8 | import net.minecraft.client.resources.model.UnbakedModel;
9 | import net.minecraft.resources.ResourceLocation;
10 | import org.spongepowered.asm.mixin.Mixin;
11 | import org.spongepowered.asm.mixin.injection.At;
12 | import org.spongepowered.asm.mixin.injection.Inject;
13 | import org.spongepowered.asm.mixin.injection.Redirect;
14 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
15 |
16 | import java.util.Collection;
17 | import java.util.Set;
18 | import java.util.function.Function;
19 | import java.util.stream.Stream;
20 |
21 | import static com.ccr4ft3r.lightspeed.util.UnbakedModelHelper.*;
22 |
23 | @Mixin(MultiPart.class)
24 | public abstract class MultiPartMixin implements UnbakedModel {
25 |
26 | private Collection materials;
27 | private Collection dependencies;
28 |
29 | @Redirect(method = "getMaterials", at = @At(value = "INVOKE", target = "Ljava/util/stream/Stream;flatMap(Ljava/util/function/Function;)Ljava/util/stream/Stream;"))
30 | public Stream getMaterialsFlatMapRedirected(Stream instance, Function super T, ? extends Stream extends R>> function, Function p_111976_, Set> p_111977_) {
31 | if (!GlobalCache.isEnabled)
32 | return instance.flatMap((p_111981_) -> p_111981_.getVariant().getMaterials(p_111976_, p_111977_).stream());
33 | return instance.flatMap(selector -> getMaterialsStream(selector.getVariant(), p_111976_, p_111977_));
34 | }
35 |
36 | @Inject(method = "getMaterials", at = @At("HEAD"), cancellable = true)
37 | public void getMaterialsHeadInjected(Function p_111855_, Set> p_111856_, CallbackInfoReturnable> cir) {
38 | if (GlobalCache.isEnabled && materials != null && GlobalCache.shouldCacheMaterials)
39 | cir.setReturnValue(materials);
40 | }
41 |
42 | @Inject(method = "getMaterials", at = @At("RETURN"))
43 | public void getMaterialsReturnInjected(Function p_111855_, Set> p_111856_, CallbackInfoReturnable> cir) {
44 | if (GlobalCache.isEnabled && materials == null)
45 | materials = cir.getReturnValue();
46 | }
47 |
48 | @Inject(method = "getDependencies", at = @At("HEAD"), cancellable = true)
49 | public void getDependenciesHeadInjected(CallbackInfoReturnable> cir) {
50 | if (GlobalCache.isEnabled && dependencies != null)
51 | cir.setReturnValue(dependencies);
52 | }
53 |
54 | @Inject(method = "getDependencies", at = @At("RETURN"))
55 | public void getDependenciesReturnInjected(CallbackInfoReturnable> cir) {
56 | if (GlobalCache.isEnabled && dependencies == null)
57 | dependencies = cir.getReturnValue();
58 | }
59 | }
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/mixin/model/MultivariantMixin.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed.mixin.model;
2 |
3 | import com.ccr4ft3r.lightspeed.cache.GlobalCache;
4 | import com.ccr4ft3r.lightspeed.util.WeightedBuilder;
5 | import com.mojang.datafixers.util.Pair;
6 | import net.minecraft.client.renderer.block.model.MultiVariant;
7 | import net.minecraft.client.renderer.block.model.Variant;
8 | import net.minecraft.client.renderer.texture.TextureAtlasSprite;
9 | import net.minecraft.client.resources.model.*;
10 | import net.minecraft.resources.ResourceLocation;
11 | import org.spongepowered.asm.mixin.Mixin;
12 | import org.spongepowered.asm.mixin.Shadow;
13 | import org.spongepowered.asm.mixin.injection.At;
14 | import org.spongepowered.asm.mixin.injection.Inject;
15 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
16 |
17 | import java.util.Collection;
18 | import java.util.List;
19 | import java.util.Set;
20 | import java.util.function.Function;
21 |
22 | @Mixin(MultiVariant.class)
23 | public abstract class MultivariantMixin implements UnbakedModel {
24 |
25 | @Shadow
26 | public abstract List getVariants();
27 |
28 | private Collection materials;
29 | private Collection dependencies;
30 |
31 | @Inject(method = "getMaterials", at = @At("HEAD"), cancellable = true)
32 | public void getMaterialsHeadInjected(Function p_111855_, Set> p_111856_, CallbackInfoReturnable> cir) {
33 | if (GlobalCache.isEnabled && materials != null && GlobalCache.shouldCacheMaterials)
34 | cir.setReturnValue(materials);
35 | }
36 |
37 | @Inject(method = "getMaterials", at = @At("RETURN"))
38 | public void getMaterialsReturnInjected(Function p_111855_, Set> p_111856_, CallbackInfoReturnable> cir) {
39 | if (GlobalCache.isEnabled && materials == null)
40 | materials = cir.getReturnValue();
41 | }
42 |
43 | @Inject(method = "getDependencies", at = @At("HEAD"), cancellable = true)
44 | public void getDependenciesHeadInjected(CallbackInfoReturnable> cir) {
45 | if (GlobalCache.isEnabled && dependencies != null)
46 | cir.setReturnValue(dependencies);
47 | }
48 |
49 | @Inject(method = "getDependencies", at = @At("RETURN"))
50 | public void getDependenciesReturnInjected(CallbackInfoReturnable> cir) {
51 | if (GlobalCache.isEnabled && dependencies == null)
52 | dependencies = cir.getReturnValue();
53 | }
54 |
55 | }
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/mixin/resources/AbstractPackResourcesMixin.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed.mixin.resources;
2 |
3 | import com.ccr4ft3r.lightspeed.cache.GlobalCache;
4 | import com.ccr4ft3r.lightspeed.interfaces.IPackResources;
5 | import com.google.common.collect.Maps;
6 | import net.minecraft.server.packs.AbstractPackResources;
7 | import net.minecraft.server.packs.FolderPackResources;
8 | import org.spongepowered.asm.mixin.Mixin;
9 | import org.spongepowered.asm.mixin.Shadow;
10 | import org.spongepowered.asm.mixin.injection.At;
11 | import org.spongepowered.asm.mixin.injection.Inject;
12 | import org.spongepowered.asm.mixin.injection.Redirect;
13 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
14 |
15 | import java.io.File;
16 | import java.util.Map;
17 |
18 | @Mixin(AbstractPackResources.class)
19 | public abstract class AbstractPackResourcesMixin implements IPackResources {
20 |
21 | @Shadow
22 | protected abstract boolean hasResource(String p_10229_);
23 |
24 | private Map existenceByResource = Maps.newConcurrentMap();
25 |
26 | @Inject(method = "", at = @At("RETURN"))
27 | public void initReturnInjected(File p_10207_, CallbackInfo ci) {
28 | if (GlobalCache.isEnabled)
29 | GlobalCache.add(this);
30 | }
31 |
32 | @Redirect(method = "hasResource(Lnet/minecraft/server/packs/PackType;Lnet/minecraft/resources/ResourceLocation;)Z",
33 | at = @At(value = "INVOKE", target = "Lnet/minecraft/server/packs/AbstractPackResources;hasResource(Ljava/lang/String;)Z"))
34 | public boolean hasResourceHasResourceRedirected(AbstractPackResources instance, String s) {
35 | if (!GlobalCache.isEnabled)
36 | return hasResource(s);
37 | Boolean exists = existenceByResource.get(s);
38 | if (exists == null || !exists && (IPackResources) this instanceof FolderPackResources) {
39 | existenceByResource.put(s, exists = hasResource(s));
40 | }
41 | return exists;
42 | }
43 |
44 | @Override
45 | public void persistAndClearCache() {
46 | existenceByResource.clear();
47 | }
48 |
49 | @Override
50 | public void setExistenceByResource(Map existenceByResource) {
51 | this.existenceByResource = existenceByResource;
52 | }
53 |
54 | @Override
55 | public Map getExistenceByResource() {
56 | return existenceByResource;
57 | }
58 | }
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/mixin/resources/DefaultClientPackResourcesMixin.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed.mixin.resources;
2 |
3 | import com.ccr4ft3r.lightspeed.cache.GlobalCache;
4 | import com.ccr4ft3r.lightspeed.interfaces.IPackResources;
5 | import com.ccr4ft3r.lightspeed.util.CacheUtil;
6 | import com.google.common.collect.Maps;
7 | import net.minecraft.client.Minecraft;
8 | import net.minecraft.client.resources.AssetIndex;
9 | import net.minecraft.client.resources.DefaultClientPackResources;
10 | import net.minecraft.resources.ResourceLocation;
11 | import net.minecraft.server.packs.PackType;
12 | import net.minecraft.server.packs.metadata.pack.PackMetadataSection;
13 | import org.spongepowered.asm.mixin.Mixin;
14 | import org.spongepowered.asm.mixin.injection.At;
15 | import org.spongepowered.asm.mixin.injection.Inject;
16 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
17 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
18 |
19 | import java.io.File;
20 | import java.util.Map;
21 |
22 | import static com.ccr4ft3r.lightspeed.cache.GlobalCache.*;
23 | import static com.ccr4ft3r.lightspeed.util.CacheUtil.*;
24 |
25 | @Mixin(DefaultClientPackResources.class)
26 | public abstract class DefaultClientPackResourcesMixin implements IPackResources {
27 |
28 | private Map existenceByClientResource = Maps.newConcurrentMap();
29 | private Map existenceByServerResource = Maps.newConcurrentMap();
30 |
31 | private String id;
32 |
33 | @Inject(method = "", at = @At("RETURN"))
34 | public void initReturnInjected(PackMetadataSection p_174827_, AssetIndex p_174828_, CallbackInfo ci) {
35 | if (!GlobalCache.isEnabled)
36 | return;
37 | GlobalCache.add(this);
38 | id = Minecraft.getInstance().getLaunchedVersion();
39 | existenceByClientResource = PERSISTED_EXISTENCES_BY_MOD.computeIfAbsent(
40 | id + "-client", i -> Maps.newConcurrentMap());
41 | existenceByServerResource = PERSISTED_EXISTENCES_BY_MOD.computeIfAbsent(
42 | id + "-server", i -> Maps.newConcurrentMap());
43 | }
44 |
45 | @Inject(method = "hasResource", at = @At("HEAD"), cancellable = true)
46 | public void hasResourceHeadInjected(PackType p_10355_, ResourceLocation p_10356_, CallbackInfoReturnable cir) {
47 | if (!GlobalCache.isEnabled)
48 | return;
49 | Boolean exists = exists(p_10355_, p_10356_.toString());
50 | if (exists != null)
51 | cir.setReturnValue(exists);
52 | }
53 |
54 | @Inject(method = "hasResource", at = @At("RETURN"))
55 | public void hasResourceReturnInjected(PackType p_10355_, ResourceLocation p_10356_, CallbackInfoReturnable cir) {
56 | if (!GlobalCache.isEnabled)
57 | return;
58 | cacheExists(p_10355_, p_10356_.toString(), cir.getReturnValue());
59 | }
60 |
61 | public Boolean exists(PackType packType, String resourceName) {
62 | if (packType == PackType.CLIENT_RESOURCES)
63 | return existenceByClientResource.get(resourceName);
64 | return existenceByServerResource.get(resourceName);
65 | }
66 |
67 | public void cacheExists(PackType packType, String resourceName, boolean exists) {
68 | if (packType == PackType.CLIENT_RESOURCES)
69 | existenceByClientResource.put(resourceName, exists);
70 | else existenceByServerResource.put(resourceName, exists);
71 | }
72 |
73 | @Override
74 | public void persistAndClearCache() {
75 | CacheUtil.persist(existenceByClientResource, new File(HAS_RESOURCE_CACHE_DIR.getPath(), id + "-client.ser"));
76 | CacheUtil.persist(existenceByServerResource, new File(HAS_RESOURCE_CACHE_DIR.getPath(), id + "-server.ser"));
77 | existenceByClientResource.clear();
78 | existenceByServerResource.clear();
79 | }
80 | }
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/mixin/resources/DelegatingResourcePackMixin.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed.mixin.resources;
2 |
3 | import com.ccr4ft3r.lightspeed.cache.GlobalCache;
4 | import net.minecraft.resources.ResourceLocation;
5 | import net.minecraft.server.packs.PackResources;
6 | import net.minecraft.server.packs.PackType;
7 | import net.minecraftforge.resource.DelegatingResourcePack;
8 | import org.spongepowered.asm.mixin.Mixin;
9 | import org.spongepowered.asm.mixin.Shadow;
10 | import org.spongepowered.asm.mixin.injection.At;
11 | import org.spongepowered.asm.mixin.injection.Inject;
12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
13 |
14 | import java.util.List;
15 |
16 | @Mixin(DelegatingResourcePack.class)
17 | public abstract class DelegatingResourcePackMixin {
18 |
19 | @Shadow
20 | protected abstract List getCandidatePacks(PackType type, ResourceLocation location);
21 |
22 | @Inject(method = "hasResource(Lnet/minecraft/server/packs/PackType;Lnet/minecraft/resources/ResourceLocation;)Z", at = @At(value = "HEAD"), cancellable = true)
23 | public void hasResourceHeadInjected(PackType type, ResourceLocation location, CallbackInfoReturnable cir) {
24 | if (!GlobalCache.isEnabled)
25 | return;
26 | cir.setReturnValue(getCandidatePacks(type, location).parallelStream().anyMatch(p -> p.hasResource(type, location)));
27 | }
28 | }
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/mixin/resources/FilePackResourcesMixin.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed.mixin.resources;
2 |
3 | import com.ccr4ft3r.lightspeed.cache.GlobalCache;
4 | import com.ccr4ft3r.lightspeed.interfaces.IPackResources;
5 | import com.google.common.collect.Maps;
6 | import net.minecraft.resources.ResourceLocation;
7 | import net.minecraft.server.packs.FilePackResources;
8 | import net.minecraft.server.packs.PackType;
9 | import org.spongepowered.asm.mixin.Mixin;
10 | import org.spongepowered.asm.mixin.injection.At;
11 | import org.spongepowered.asm.mixin.injection.Inject;
12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
13 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
14 | import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
15 |
16 | import java.io.File;
17 | import java.util.Collection;
18 | import java.util.List;
19 | import java.util.Map;
20 | import java.util.Objects;
21 | import java.util.function.Predicate;
22 | import java.util.stream.Collectors;
23 | import java.util.zip.ZipEntry;
24 | import java.util.zip.ZipFile;
25 |
26 | @Mixin(FilePackResources.class)
27 | public abstract class FilePackResourcesMixin implements IPackResources {
28 |
29 | private final Map> entriesByPackType = Maps.newConcurrentMap();
30 |
31 | @Inject(method = "", at = @At("RETURN"))
32 | public void initReturnInjected(File p_10236_, CallbackInfo ci) {
33 | if (GlobalCache.isEnabled)
34 | GlobalCache.add(this);
35 | }
36 |
37 | @Inject(method = "getResources", at = @At(value = "INVOKE", target = "Ljava/util/zip/ZipFile;entries()Ljava/util/Enumeration;", shift = At.Shift.BEFORE), cancellable = true, locals = LocalCapture.CAPTURE_FAILSOFT)
38 | public void getResourcesHeadInjected(PackType packType, String pathIn, String pathIn2, int maxDepth, Predicate filter, CallbackInfoReturnable> cir, ZipFile zip) {
39 | if (!GlobalCache.isEnabled)
40 | return;
41 | String base = packType.getDirectory() + "/" + pathIn + "/";
42 | String path = base + pathIn2 + "/";
43 | List entries;
44 | if ((entries = entriesByPackType.get(packType)) == null) {
45 | entries = zip.stream().filter(e -> !e.isDirectory()).filter(
46 | e -> !e.getName().endsWith(".mcmeta")
47 | ).collect(Collectors.toList());
48 | entriesByPackType.put(packType, entries);
49 | }
50 | cir.setReturnValue(entries.stream().filter(e -> e.getName().startsWith(path)).map(e -> {
51 | String locPath = e.getName().substring(base.length());
52 | String[] splitted = locPath.split("/");
53 | if (splitted.length >= maxDepth + 1 && filter.test(splitted[splitted.length - 1])) {
54 | return new ResourceLocation(pathIn, locPath);
55 | }
56 | return null;
57 | }).filter(Objects::nonNull).collect(Collectors.toList()));
58 | }
59 |
60 | @Override
61 | public void persistAndClearCache() {
62 | entriesByPackType.clear();
63 | }
64 | }
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/mixin/resources/FolderPackResourcesMixin.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed.mixin.resources;
2 |
3 | import com.ccr4ft3r.lightspeed.cache.GlobalCache;
4 | import net.minecraft.server.packs.FolderPackResources;
5 | import org.spongepowered.asm.mixin.Mixin;
6 | import org.spongepowered.asm.mixin.injection.At;
7 | import org.spongepowered.asm.mixin.injection.Redirect;
8 |
9 | import java.io.File;
10 | import java.io.IOException;
11 |
12 | import static com.ccr4ft3r.lightspeed.cache.GlobalCache.*;
13 |
14 | @Mixin(FolderPackResources.class)
15 | public abstract class FolderPackResourcesMixin {
16 |
17 | @Redirect(method = "validatePath", at = @At(value = "INVOKE", target = "Ljava/io/File;getCanonicalPath()Ljava/lang/String;"))
18 | private static String validatePathGetCanonicalPathRedirected(File instance) throws IOException {
19 | if (!GlobalCache.isEnabled)
20 | return instance.getCanonicalPath();
21 | String canoncialPath = CANONICAL_PATH_PER_FILE.get(instance.getPath());
22 | if (canoncialPath == null) {
23 | CANONICAL_PATH_PER_FILE.put(instance.getPath(), canoncialPath = instance.getCanonicalPath());
24 | }
25 | return canoncialPath;
26 | }
27 | }
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/mixin/resources/PathResourcePackMixin.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed.mixin.resources;
2 |
3 | import com.ccr4ft3r.lightspeed.cache.GlobalCache;
4 | import com.ccr4ft3r.lightspeed.interfaces.IPackResources;
5 | import com.ccr4ft3r.lightspeed.interfaces.IPathResourcePack;
6 | import com.ccr4ft3r.lightspeed.util.CacheUtil;
7 | import com.google.common.collect.Maps;
8 | import net.minecraft.resources.ResourceLocation;
9 | import net.minecraft.server.packs.PackType;
10 | import net.minecraftforge.forgespi.locating.IModFile;
11 | import net.minecraftforge.resource.PathResourcePack;
12 | import org.apache.commons.io.FilenameUtils;
13 | import org.spongepowered.asm.mixin.Mixin;
14 | import org.spongepowered.asm.mixin.injection.At;
15 | import org.spongepowered.asm.mixin.injection.Inject;
16 | import org.spongepowered.asm.mixin.injection.Redirect;
17 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
18 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
19 | import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
20 |
21 | import java.io.File;
22 | import java.io.IOException;
23 | import java.nio.file.FileSystem;
24 | import java.nio.file.FileVisitOption;
25 | import java.nio.file.Files;
26 | import java.nio.file.Path;
27 | import java.util.*;
28 | import java.util.function.Predicate;
29 | import java.util.stream.Collectors;
30 | import java.util.stream.Stream;
31 |
32 | import static com.ccr4ft3r.lightspeed.util.CacheUtil.*;
33 |
34 | @Mixin(value = PathResourcePack.class)
35 | public abstract class PathResourcePackMixin implements IPathResourcePack, IPackResources {
36 |
37 | private final Map resolvedPathByResource = Maps.newConcurrentMap();
38 | private final Map> namespacesByPackType = Maps.newConcurrentMap();
39 | private final Map inputPathByPath = Maps.newConcurrentMap();
40 | private final Map>> filePathsByRootByPackType = initPathsMap();
41 | private IModFile modFile;
42 | private String id;
43 |
44 | @Inject(method = "", at = @At("RETURN"))
45 | public void initReturnInjected(String packName, Path source, CallbackInfo ci) {
46 | if (GlobalCache.isEnabled)
47 | GlobalCache.add(this);
48 | }
49 |
50 | private static Map>> initPathsMap() {
51 | Map>> map = Maps.newConcurrentMap();
52 | for (PackType packType : PackType.values()) {
53 | map.put(packType, Maps.newConcurrentMap());
54 | }
55 | return map;
56 | }
57 |
58 | @Inject(method = "resolve", at = @At("HEAD"), cancellable = true, remap = false)
59 | public void resolveHeadInjected(String[] paths, CallbackInfoReturnable cir) {
60 | if (modFile == null) {
61 | if (!GlobalCache.isEnabled)
62 | return;
63 | Path resolved = getResolvedPath(paths);
64 | if (resolved != null)
65 | cir.setReturnValue(resolved);
66 | return;
67 | }
68 | if (!GlobalCache.isEnabled) {
69 | cir.setReturnValue(modFile.findResource(paths));
70 | return;
71 | }
72 | Path path = getResolvedPath(paths);
73 | if (path == null)
74 | resolvedPathByResource.put(Arrays.toString(paths), path = modFile.findResource(paths));
75 |
76 | cir.setReturnValue(path);
77 | }
78 |
79 | @Inject(method = "resolve", at = @At("RETURN"), remap = false)
80 | public void resolveReturnInjected(String[] paths, CallbackInfoReturnable cir) {
81 | if (!GlobalCache.isEnabled || modFile != null)
82 | return;
83 | resolvedPathByResource.put(Arrays.toString(paths), cir.getReturnValue());
84 | }
85 |
86 | @Inject(method = "getNamespaces", at = @At("HEAD"), cancellable = true)
87 | public void getNamespacesHeadInjected(PackType type, CallbackInfoReturnable> cir) {
88 | if (!GlobalCache.isEnabled)
89 | return;
90 | Set namespaces = getCachedNamespaces(type);
91 | if (namespaces != null)
92 | cir.setReturnValue(namespaces);
93 | }
94 |
95 | @Inject(method = "getNamespaces", at = @At("RETURN"))
96 | public void getNamespacesReturnInjected(PackType type, CallbackInfoReturnable> cir) {
97 | if (!GlobalCache.isEnabled)
98 | return;
99 | if (GlobalCache.shouldCacheEmptyNamespaces || cir.getReturnValue() != null && !cir.getReturnValue().isEmpty())
100 | cacheNamespaces(type, cir.getReturnValue());
101 | }
102 |
103 | @Inject(method = "hasResource(Ljava/lang/String;)Z", at = @At("HEAD"), cancellable = true)
104 | public void hasResourceHeadInjected(String name, CallbackInfoReturnable cir) {
105 | if (!GlobalCache.isEnabled)
106 | return;
107 | Boolean exists = exists(name);
108 | if (exists != null)
109 | cir.setReturnValue(exists);
110 | }
111 |
112 | @Inject(method = "hasResource(Ljava/lang/String;)Z", at = @At("RETURN"))
113 | public void hasResourceReturnInjected(String name, CallbackInfoReturnable cir) {
114 | if (!GlobalCache.isEnabled)
115 | return;
116 | cacheExists(name, cir.getReturnValue());
117 | }
118 |
119 | @Inject(method = "getResources", at = @At(value = "INVOKE", target = "Ljava/nio/file/Path;getFileSystem()Ljava/nio/file/FileSystem;"), locals = LocalCapture.CAPTURE_FAILSOFT, cancellable = true)
120 | public synchronized void getResourcesInjected(PackType type, String resourceNamespace, String pathIn, int maxDepth, Predicate filter, CallbackInfoReturnable> cir, Path root) {
121 | if (!GlobalCache.isEnabled)
122 | return;
123 | String resource = root.toString();
124 | Boolean exists = exists(resource);
125 | if (exists == null) {
126 | cacheExists(resource, exists = Files.exists(root));
127 | }
128 | if (!exists)
129 | cir.setReturnValue(Collections.emptyList());
130 | }
131 |
132 | @Redirect(method = "getResources", at = @At(value = "INVOKE", target = "Ljava/nio/file/Files;walk(Ljava/nio/file/Path;[Ljava/nio/file/FileVisitOption;)Ljava/util/stream/Stream;"))
133 | public synchronized Stream getResourcesWalkInjected(Path start, FileVisitOption[] options, PackType type, String resourceNamespace) throws IOException {
134 | if (!GlobalCache.isEnabled || !GlobalCache.shouldCacheWalkedPaths)
135 | return Files.walk(start);
136 | List paths = getFilePaths(type, resourceNamespace);
137 | if (paths == null) {
138 | try (Stream pathStream = Files.walk(start)) {
139 | paths = pathStream.collect(Collectors.toList());
140 | } finally {
141 | cacheFilePaths(type, resourceNamespace, paths == null ? Collections.emptyList() : paths);
142 | }
143 | }
144 | return paths.parallelStream();
145 | }
146 |
147 | @Redirect(method = "getResources", at = @At(value = "INVOKE", target = "Ljava/nio/file/FileSystem;getPath(Ljava/lang/String;[Ljava/lang/String;)Ljava/nio/file/Path;"))
148 | public Path getResourcesGetPathRedirected(FileSystem instance, String s, String[] strings) {
149 | if (!GlobalCache.isEnabled)
150 | return instance.getPath(s);
151 | Path inputPath = inputPathByPath.get(s);
152 | if (inputPath == null) {
153 | inputPathByPath.put(s, inputPath = instance.getPath(s));
154 | }
155 | return inputPath;
156 | }
157 |
158 | @Override
159 | public void persistAndClearCache() {
160 | if (modFile != null) {
161 | CacheUtil.persist(getExistenceByResource(), new File(HAS_RESOURCE_CACHE_DIR.getPath(), id + ".ser"));
162 | CacheUtil.persist(namespacesByPackType, new File(NAMESPACE_CACHE_DIR.getPath(), id + ".ser"));
163 | }
164 | getExistenceByResource().clear();
165 | resolvedPathByResource.clear();
166 | namespacesByPackType.clear();
167 | filePathsByRootByPackType.clear();
168 | }
169 |
170 | @Override
171 | public void setModFile(IModFile modFile) {
172 | this.modFile = modFile;
173 | this.id = modFile.getModFileInfo().moduleName() + modFile.getModFileInfo().versionString()
174 | + "-" + FilenameUtils.getBaseName(modFile.getFilePath().toString()).replaceAll("[^a-zA-Z0-9.-]", "");
175 | setExistenceByResource(GlobalCache.PERSISTED_EXISTENCES_BY_MOD.computeIfAbsent(
176 | id, i -> Maps.newConcurrentMap()));
177 | }
178 |
179 | public Path getResolvedPath(String... paths) {
180 | return resolvedPathByResource.get(Arrays.toString(paths));
181 | }
182 |
183 | public Boolean exists(String resourceName) {
184 | return getExistenceByResource().get(resourceName);
185 | }
186 |
187 | public void cacheExists(String resourceName, boolean exists) {
188 | getExistenceByResource().put(resourceName, exists);
189 | }
190 |
191 | public void cacheFilePaths(PackType packType, String resourceNamespace, List filePaths) {
192 | getFilePathsMap(packType).putIfAbsent(resourceNamespace, filePaths);
193 | }
194 |
195 | public List getFilePaths(PackType packType, String resourceNamespace) {
196 | return getFilePathsMap(packType).get(resourceNamespace);
197 | }
198 |
199 | private Map> getFilePathsMap(PackType packType) {
200 | return filePathsByRootByPackType.get(packType);
201 | }
202 |
203 | public void cacheNamespaces(PackType packType, Set namespaces) {
204 | namespacesByPackType.put(packType, namespaces);
205 | }
206 |
207 | public Set getCachedNamespaces(PackType packType) {
208 | return namespacesByPackType.get(packType);
209 | }
210 | }
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/mixin/resources/VanillaPackResourcesMixin.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed.mixin.resources;
2 |
3 | import com.ccr4ft3r.lightspeed.cache.GlobalCache;
4 | import com.ccr4ft3r.lightspeed.interfaces.IPackResources;
5 | import com.google.common.collect.Maps;
6 | import net.minecraft.resources.ResourceLocation;
7 | import net.minecraft.server.packs.PackType;
8 | import net.minecraft.server.packs.metadata.pack.PackMetadataSection;
9 | import org.spongepowered.asm.mixin.Mixin;
10 | import org.spongepowered.asm.mixin.injection.At;
11 | import org.spongepowered.asm.mixin.injection.Inject;
12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
13 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
14 |
15 | import java.util.Map;
16 |
17 | @Mixin(net.minecraft.server.packs.VanillaPackResources.class)
18 | public abstract class VanillaPackResourcesMixin implements IPackResources {
19 |
20 | private final Map existencePerClientResource = Maps.newConcurrentMap();
21 | private final Map existencePerServerResource = Maps.newConcurrentMap();
22 |
23 | @Inject(method = "", at = @At("RETURN"))
24 | public void initHeadInjected(PackMetadataSection p_143761_, String[] p_143762_, CallbackInfo ci) {
25 | if (GlobalCache.isEnabled)
26 | GlobalCache.add(this);
27 | }
28 |
29 | @Inject(method = "hasResource", at = @At("HEAD"), cancellable = true)
30 | public void hasResourceHeadInjected(PackType p_10355_, ResourceLocation p_10356_, CallbackInfoReturnable cir) {
31 | if (!GlobalCache.isEnabled)
32 | return;
33 | Boolean exists = exists(p_10355_, p_10356_.toString());
34 | if (exists != null)
35 | cir.setReturnValue(exists);
36 | }
37 |
38 | @Inject(method = "hasResource", at = @At("RETURN"))
39 | public void hasResourceReturnInjected(PackType p_10355_, ResourceLocation p_10356_, CallbackInfoReturnable cir) {
40 | if (!GlobalCache.isEnabled)
41 | return;
42 | cacheExists(p_10355_, p_10356_.toString(), cir.getReturnValue());
43 | }
44 |
45 | public Boolean exists(PackType packType, String resourceName) {
46 | if (packType == PackType.CLIENT_RESOURCES)
47 | return existencePerClientResource.get(resourceName);
48 | return existencePerServerResource.get(resourceName);
49 | }
50 |
51 | public void cacheExists(PackType packType, String resourceName, boolean exists) {
52 | if (packType == PackType.CLIENT_RESOURCES)
53 | existencePerClientResource.put(resourceName, exists);
54 | else existencePerServerResource.put(resourceName, exists);
55 | }
56 |
57 | @Override
58 | public void persistAndClearCache() {
59 | existencePerClientResource.clear();
60 | existencePerServerResource.clear();
61 | getExistenceByResource().clear();
62 | }
63 | }
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/util/CacheUtil.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed.util;
2 |
3 | import com.google.common.collect.Maps;
4 | import com.mojang.logging.LogUtils;
5 | import net.minecraft.SharedConstants;
6 | import net.minecraftforge.fml.loading.FMLPaths;
7 |
8 | import java.io.*;
9 | import java.nio.file.Paths;
10 | import java.util.Arrays;
11 | import java.util.Map;
12 | import java.util.concurrent.ConcurrentHashMap;
13 | import java.util.stream.Stream;
14 |
15 | public class CacheUtil {
16 |
17 | public static final File CACHE_DIR = Paths.get(FMLPaths.GAMEDIR.get().toString(), "lightspeed-cache",
18 | SharedConstants.getCurrentVersion().getId()).toFile();
19 | public static final File HAS_RESOURCE_CACHE_DIR = new File(CACHE_DIR, "hasResource");
20 | public static final File NAMESPACE_CACHE_DIR = new File(CACHE_DIR, "namespaces");
21 |
22 | public static Stream getCacheFiles(File dir) {
23 | File[] caches = dir.listFiles((dir1, name) -> name.toLowerCase().endsWith(".ser"));
24 | if (caches == null)
25 | return Stream.empty();
26 | return Arrays.stream(caches)
27 | .filter(file -> !file.isDirectory());
28 | }
29 |
30 | public static void persist(Map, ?> toPersist, File file) {
31 | try {
32 | FileOutputStream fos = new FileOutputStream(file);
33 | ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(fos));
34 | oos.writeObject(toPersist);
35 | oos.flush();
36 | oos.close();
37 | fos.close();
38 | } catch (Exception e) {
39 | LogUtils.getLogger().error("Cannot create cache file: {}", file, e);
40 | }
41 | }
42 |
43 | @SuppressWarnings("unchecked")
44 | public static Map load(File file) {
45 | try {
46 | FileInputStream fis = new FileInputStream(file);
47 | ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(fis));
48 | ConcurrentHashMap loaded = (ConcurrentHashMap) ois.readObject();
49 | ois.close();
50 | fis.close();
51 | return loaded;
52 | } catch (Exception e) {
53 | LogUtils.getLogger().error("Cannot load cache file: {}", file.getName(), e);
54 | }
55 | return Maps.newConcurrentMap();
56 | }
57 | }
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/util/CompatUtil.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed.util;
2 |
3 | public class CompatUtil {
4 |
5 | public static boolean existsClass(String className) {
6 | try {
7 | Class.forName(className);
8 | return true;
9 | } catch (ClassNotFoundException e) {
10 | return false;
11 | }
12 | }
13 |
14 | }
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/util/UnbakedModelHelper.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed.util;
2 |
3 | import com.mojang.datafixers.util.Pair;
4 | import net.minecraft.client.renderer.block.model.MultiVariant;
5 | import net.minecraft.client.renderer.block.model.Variant;
6 | import net.minecraft.client.renderer.block.model.multipart.MultiPart;
7 | import net.minecraft.client.resources.model.Material;
8 | import net.minecraft.client.resources.model.UnbakedModel;
9 | import net.minecraft.resources.ResourceLocation;
10 |
11 | import java.util.Set;
12 | import java.util.function.Function;
13 | import java.util.stream.Stream;
14 |
15 | public class UnbakedModelHelper {
16 |
17 | public static Stream getMaterialsStream(MultiPart multiPart, Function p_111976_, Set> p_111977_) {
18 | return multiPart.getSelectors().stream().flatMap((p_111981_) -> getMaterialsStream(p_111981_.getVariant(), p_111976_, p_111977_));
19 | }
20 |
21 | public static Stream getMaterialsStream(MultiVariant multiVariant, Function p_111855_, Set> p_111856_) {
22 | return multiVariant.getVariants().stream().map(Variant::getModelLocation).distinct().flatMap((p_111860_) -> {
23 | UnbakedModel unbakedModel = p_111855_.apply(p_111860_);
24 | if (unbakedModel instanceof MultiPart multiPart)
25 | return getMaterialsStream(multiPart, p_111855_, p_111856_);
26 | if (unbakedModel instanceof MultiVariant multiVariant1)
27 | return getMaterialsStream(multiVariant1, p_111855_, p_111856_);
28 | return unbakedModel.getMaterials(p_111855_, p_111856_).stream();
29 | });
30 | }
31 | }
--------------------------------------------------------------------------------
/src/main/java/com/ccr4ft3r/lightspeed/util/WeightedBuilder.java:
--------------------------------------------------------------------------------
1 | package com.ccr4ft3r.lightspeed.util;
2 |
3 | import com.google.common.collect.Sets;
4 | import net.minecraft.client.resources.model.BakedModel;
5 | import net.minecraft.client.resources.model.WeightedBakedModel;
6 | import net.minecraft.util.random.WeightedEntry;
7 |
8 | import javax.annotation.Nullable;
9 | import java.util.ArrayList;
10 | import java.util.Set;
11 |
12 | public class WeightedBuilder {
13 |
14 | private final Set> list = Sets.newConcurrentHashSet();
15 |
16 | public void add(@Nullable BakedModel p_119560_, int p_119561_) {
17 | if (p_119560_ != null)
18 | list.add(WeightedEntry.wrap(p_119560_, p_119561_));
19 | }
20 |
21 | @Nullable
22 | public BakedModel build() {
23 | if (list.isEmpty()) {
24 | return null;
25 | } else {
26 | return list.size() == 1 ? list.iterator().next().getData() : new WeightedBakedModel(new ArrayList<>(list));
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/src/main/resources/META-INF/mods.toml:
--------------------------------------------------------------------------------
1 | # This is an example mods.toml file. It contains the data relating to the loading mods.
2 | # There are several mandatory fields (#mandatory), and many more that are optional (#optional).
3 | # The overall format is standard TOML format, v0.5.0.
4 | # Note that there are a couple of TOML lists in this file.
5 | # Find more information on toml format here: https://github.com/toml-lang/toml
6 | # The name of the mod loader type to load - for regular FML @Mod mods it should be javafml
7 | modLoader = "javafml" #mandatory
8 | # A version range to match for said mod loader - for regular FML @Mod it will be the forge version
9 | loaderVersion = "[40,)" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions.
10 | # The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties.
11 | # Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here.
12 | license = "All Rights Reserved"
13 | # A URL to refer people to when problems occur with this mod
14 | #issueTrackerURL="http://my.issue.tracker/" #optional
15 | # A list of mods - how many allowed here is determined by the individual mod loader
16 | [[mods]] #mandatory
17 | # The modid of the mod
18 | modId = "lightspeed" #mandatory
19 | # The version number of the mod - there's a few well known ${} variables useable here or just hardcode it
20 | # ${file.jarVersion} will substitute the value of the Implementation-Version as read from the mod's JAR file metadata
21 | # see the associated build.gradle script for how to populate this completely automatically during a build
22 | version = "${file.jarVersion}" #mandatory
23 | # A display name for the mod
24 | displayName = "Lightspeed" #mandatory
25 | # A URL to query for updates for this mod. See the JSON update specification
26 | #updateJSONURL="http://myurl.me/" #optional
27 | # A URL for the "homepage" for this mod, displayed in the mod UI
28 | #displayURL="http://example.com/" #optional
29 | # A file name (in the root of the mod JAR) containing a logo for display
30 | #logoFile="lightspeed.png" #optional
31 | # A text field displayed in the mod UI
32 | #credits="Thanks for this example mod goes to Java" #optional
33 | # A text field displayed in the mod UI
34 | authors = "CCr4ft3r" #optional
35 | # The description text for the mod (multi line!) (#mandatory)
36 | description = '''
37 | Buys you time by loading heavy modpacks significantly faster
38 | '''
39 | # A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional.
40 | [[dependencies.lightspeed]] #optional
41 | # the modid of the dependency
42 | modId = "forge" #mandatory
43 | # Does this dependency have to exist - if not, ordering below must be specified
44 | mandatory = true #mandatory
45 | # The version range of the dependency
46 | versionRange = "[40,)" #mandatory
47 | # An ordering relationship for the dependency - BEFORE or AFTER required if the relationship is not mandatory
48 | ordering = "NONE"
49 | # Side this dependency is applied on - BOTH, CLIENT or SERVER
50 | side = "BOTH"
51 | # Here's another dependency
52 | [[dependencies.lightspeed]]
53 | modId = "minecraft"
54 | mandatory = true
55 | # This version range declares a minimum of the current minecraft version up to but not including the next major version
56 | versionRange = "[1.18.2,1.19)"
57 | ordering = "NONE"
58 | side = "BOTH"
--------------------------------------------------------------------------------
/src/main/resources/lightspeed.mixins.json:
--------------------------------------------------------------------------------
1 | {
2 | "required": true,
3 | "package": "com.ccr4ft3r.lightspeed.mixin",
4 | "compatibilityLevel": "JAVA_17",
5 | "refmap": "lightspeed.refmap.json",
6 | "client": [
7 | "MinecraftMainMixin",
8 | "misc.KeyValueConditionMixin",
9 | "misc.MaterialMixin",
10 | "misc.SelectorMixin",
11 | "model.BlockModelMixin",
12 | "model.MultiPartMixin",
13 | "model.MultivariantMixin",
14 | "resources.DefaultClientPackResourcesMixin"
15 | ],
16 | "mixins": [
17 | "misc.ResourceLocationMixin",
18 | "misc.ResourcePackLoaderMixin",
19 | "misc.StateDefinitonMixin",
20 | "model.ModelBakeryMixin",
21 | "resources.AbstractPackResourcesMixin",
22 | "resources.DelegatingResourcePackMixin",
23 | "resources.FilePackResourcesMixin",
24 | "resources.FolderPackResourcesMixin",
25 | "resources.PathResourcePackMixin",
26 | "resources.VanillaPackResourcesMixin"
27 | ],
28 | "minVersion": "0.8"
29 | }
--------------------------------------------------------------------------------
/src/main/resources/pack.mcmeta:
--------------------------------------------------------------------------------
1 | {
2 | "pack": {
3 | "description": "lightspeed resources",
4 | "pack_format": 8,
5 | "forge:resource_pack_format": 8,
6 | "forge:data_pack_format": 9
7 | }
8 | }
--------------------------------------------------------------------------------