diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index d363f462..00000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,12 +0,0 @@ -# These are supported funding model platforms - -github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] -patreon: # Replace with a single Patreon username -open_collective: # Replace with a single Open Collective username -ko_fi: notequalalpha # Replace with a single Ko-fi username -tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel -community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: # Replace with a single Liberapay username -issuehunt: # Replace with a single IssueHunt username -otechie: # Replace with a single Otechie username -custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.github/ISSUE_TEMPLATE/LAUNCH_ISSUE.yaml b/.github/ISSUE_TEMPLATE/LAUNCH_ISSUE.yaml deleted file mode 100644 index 27dc5383..00000000 --- a/.github/ISSUE_TEMPLATE/LAUNCH_ISSUE.yaml +++ /dev/null @@ -1,46 +0,0 @@ -name: Launching Issue -description: Create an issue about your game failing to load/cache -title: "[LAUNCH]: " -labels: ["type: bug", "status: idle"] -body: - - type: markdown - attributes: - value: | - Thank you for reporting an issue about DashLoader, we care a lot about our mod and enjoy fixing every bug. - - type: input - id: version - attributes: - label: Version - description: What version of DashLoader are you running? - placeholder: 5.0.0-alpha.3 - validations: - required: true - - type: input - id: mc-version - attributes: - label: Minecraft Version - description: What Minecraft version are you using? - placeholder: 1.19.3 - validations: - required: true - - type: markdown - attributes: - value: | - Please provide **THE ENTIRE LOG** as the crashlogs don't contain much information about DashLoader. - Use a website like https://mclo.gs/ to upload logs. - Preferably we want a log for when you create the cache (The popup at the top left is present) and another log for when DashLoader loads the cache. - - type: input - id: logs - attributes: - label: Entire Logs - description: Link to the logs. - placeholder: https://mclo.gs/5K0ChKa - validations: - required: true - - type: textarea - id: extra - attributes: - label: Additional Notes - description: Anything else you want to add? - validations: - required: false diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 3dc2d914..00000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: '' -assignees: '' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Context (please complete the following information):** - - DashLoader Version [e.g. 3.0-rc14] - - Minecraft Version [e.g. 1.18.1] - -**Additional context** -Add any other context about the problem here. diff --git a/build.gradle b/build.gradle index ae74c8bd..8d77b323 100644 --- a/build.gradle +++ b/build.gradle @@ -1,154 +1,70 @@ plugins { - // Publishing - id 'com.matthewprenger.cursegradle' version '1.4.0' - id "com.modrinth.minotaur" version "2.+" - - id 'fabric-loom' version '0.12-SNAPSHOT' - id 'maven-publish' + id 'dev.architectury.loom' version '1.10-SNAPSHOT' apply false + id 'architectury-plugin' version '3.4-SNAPSHOT' + id 'com.github.johnrengelman.shadow' version '8.1.1' apply false } -sourceCompatibility = JavaVersion.VERSION_17 -targetCompatibility = JavaVersion.VERSION_17 - -archivesBaseName = project.archives_base_name -version = project.mod_version -group = project.maven_group - -repositories { - mavenCentral(); - mavenLocal() - maven { - name "Sonatype Snapshots" - url "https://s01.oss.sonatype.org/content/repositories/snapshots/" - } - maven { - url 'https://jitpack.io' - } - maven { - url 'https://notalpha.dev/maven/releases' - } +architectury { + minecraft = project.minecraft_version } -loom { - accessWidenerPath = file("src/main/resources/dashloader.accesswidener") +allprojects { + group = rootProject.maven_group + version = rootProject.mod_version } -dependencies { - // To change the versions see the gradle.properties file - minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" - modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" - - // TODO jákob if you need modmenu uncomment this and in gradle.properties - !alpha - // modImplementation "com.terraformersmc:modmenu:$project.modmenu_version" - - implementation "dev.notalpha:Hyphen:0.4.0-rc.5" - include "dev.notalpha:Hyphen:0.4.0-rc.5" - - implementation "dev.notalpha:Taski:2.1.0" - include "dev.notalpha:Taski:2.1.0" +subprojects { + apply plugin: 'dev.architectury.loom' + apply plugin: 'architectury-plugin' + apply plugin: 'maven-publish' - implementation 'com.github.luben:zstd-jni:1.5.2-2' - include 'com.github.luben:zstd-jni:1.5.2-2' - - modCompileOnly fabricApi.module("fabric-renderer-indigo", "0.69.1+1.19.3"); -} - -test { - useJUnitPlatform() - testLogging { - events "passed", "skipped", "failed" + base { + // Set up a suffixed format for the mod jar names, e.g. `example-fabric`. + archivesName = "$rootProject.archives_name-$project.name" } -} - -processResources { - inputs.property "version", project.version - filesMatching("fabric.mod.json") { - expand "version": project.version + repositories { + // Add repositories to retrieve artifacts from in here. + // You should only use this when depending on other mods because + // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. + // See https://docs.gradle.org/current/userguide/declaring_repositories.html + // for more information about repositories. } -} - -tasks.withType(JavaCompile).configureEach { - // ensure that the encoding is set to UTF-8, no matter what the system default is - // this fixes some edge cases with special characters not displaying correctly - // see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html - // If Javadoc is generated, this must be specified in that task too. - it.options.encoding = "UTF-8" - - // Minecraft 1.17 (21w19a) upwards uses Java 16. - it.options.release = 17 -} - -java { - //include sources in maven publish - withSourcesJar() -} -jar { - from("LICENSE") { - rename { "${it}_${project.archivesBaseName}" } + dependencies { + minecraft "net.minecraft:minecraft:$rootProject.minecraft_version" + mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" } -} -// Publishing -modrinth { - token = project.hasProperty("modrinthApiKey") ? project.modrinthApiKey : "" - projectId = 'ZfQ3kTvR' - changelog = file("changelog.md").getText(); - versionNumber = project.version - versionName = "$project.version".split("\\+")[0] + " for $project.minecraft_version" - uploadFile = remapJar - versionType = "alpha" - gameVersions = ['1.19.3'] - loaders = ['fabric', 'quilt'] -} + java { + // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task + // if it is present. + // If you remove this line, sources will not be generated. + withSourcesJar() -curseforge { - apiKey = project.hasProperty("curseForgeApiKey") ? project.curseForgeApiKey : "" - project { - id = '472772' - changelogType = "markdown" - changelog = file("changelog.md"); - releaseType = 'alpha' - - addGameVersion "1.19.3" - addGameVersion "Fabric" - addGameVersion "Quilt" - addGameVersion "Java 17" - - mainArtifact(remapJar) { - displayName = "$project.version".split("\\+")[0] + " for $project.minecraft_version" - } - } - options { - forgeGradleIntegration = false + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } -} - -tasks.register("publishMod") { - dependsOn 'modrinth' - dependsOn 'curseforge' -} -tasks.register("getVersion") { - print("$project.version") -} + tasks.withType(JavaCompile).configureEach { + it.options.release = 17 + } -publishing { - repositories { - maven { - name = "notalpha" - url = "https://notalpha.dev/maven/releases" - credentials(PasswordCredentials) - authentication { - basic(BasicAuthentication) + // Configure Maven publishing. + publishing { + publications { + mavenJava(MavenPublication) { + artifactId = base.archivesName.get() + from components.java } } - } - publications { - maven(MavenPublication) { - from components.java + + // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. + repositories { + // Add repositories to publish to here. + // Notice: This block does NOT have the same function as the block in the top level. + // The repositories here will be used for publishing your artifact, not for + // retrieving dependencies. } } -} \ No newline at end of file +} diff --git a/common/build.gradle b/common/build.gradle new file mode 100644 index 00000000..713ca35f --- /dev/null +++ b/common/build.gradle @@ -0,0 +1,44 @@ +architectury { + common rootProject.enabled_platforms.split(',') +} + +repositories { + mavenCentral() + mavenLocal() + maven { + name "Sonatype Snapshots" + url "https://s01.oss.sonatype.org/content/repositories/snapshots/" + } + maven { + url 'https://jitpack.io' + } + maven { + url "https://notalpha.dev/maven/releases" + } +} + +dependencies { + // We depend on Fabric Loader here to use the Fabric @Environment annotations, + // which get remapped to the correct annotations on each platform. + // Do NOT use other classes from Fabric Loader. + modImplementation "net.fabricmc:fabric-loader:$rootProject.fabric_loader_version" + + modImplementation "dev.architectury:architectury:$rootProject.architectury_api_version" + + implementation "dev.quantumfusion:Hyphen:0.4.0-rc.3" + include "dev.quantumfusion:Hyphen:0.4.0-rc.3" + + implementation "dev.notalpha:Taski:2.1.0" + include "dev.notalpha:Taski:2.1.0" + + implementation 'com.github.luben:zstd-jni:1.5.2-2' + include 'com.github.luben:zstd-jni:1.5.2-2' + + implementation 'com.github.luben:zstd-jni:1.5.2-2' + + modCompileOnly "net.fabricmc.fabric-api:fabric-renderer-indigo:1.5.2+2034447c28" +} + +loom { + accessWidenerPath = file("src/main/resources/dashloader.accesswidener") +} diff --git a/common/src/main/java/cn/ksmcbrigade/dashloader/Dashloader.java b/common/src/main/java/cn/ksmcbrigade/dashloader/Dashloader.java new file mode 100644 index 00000000..44cc623c --- /dev/null +++ b/common/src/main/java/cn/ksmcbrigade/dashloader/Dashloader.java @@ -0,0 +1,12 @@ +package cn.ksmcbrigade.dashloader; + +import dev.notalpha.dashloader.client.DashLoaderClient; + +public final class Dashloader { + public static final String MOD_ID = "dashloader"; + + public static void init() { + System.out.println("DashLoaderForge loading..."); + System.out.println("DashLoader need reload: "+DashLoaderClient.NEEDS_RELOAD); + } +} diff --git a/src/main/java/dev/notalpha/dashloader/CacheFactory.java b/common/src/main/java/dev/notalpha/dashloader/CacheFactoryImpl.java similarity index 54% rename from src/main/java/dev/notalpha/dashloader/CacheFactory.java rename to common/src/main/java/dev/notalpha/dashloader/CacheFactoryImpl.java index 869a2145..2b83261a 100644 --- a/src/main/java/dev/notalpha/dashloader/CacheFactory.java +++ b/common/src/main/java/dev/notalpha/dashloader/CacheFactoryImpl.java @@ -1,10 +1,11 @@ package dev.notalpha.dashloader; +import dev.notalpha.dashloader.api.DashModule; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryWriter; -import dev.notalpha.dashloader.api.cache.DashCacheFactory; -import dev.notalpha.dashloader.api.cache.DashModule; import dev.notalpha.dashloader.registry.MissingHandler; +import dev.notalpha.dashloader.api.cache.Cache; +import dev.notalpha.dashloader.api.cache.CacheFactory; +import dev.notalpha.dashloader.api.registry.RegistryWriter; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -14,20 +15,21 @@ import java.util.List; import java.util.function.BiFunction; -public class CacheFactory implements DashCacheFactory { - private static final Logger LOGGER = LogManager.getLogger("CacherFactory"); +public class CacheFactoryImpl implements CacheFactory { + private static final Logger LOGGER = LogManager.getLogger("CacheFactory"); private final List> dashObjects; private final List> modules; private final List> missingHandlers; private boolean failed = false; - public CacheFactory() { + public CacheFactoryImpl() { this.dashObjects = new ArrayList<>(); this.modules = new ArrayList<>(); this.missingHandlers = new ArrayList<>(); } - public void addDashObject(Class> dashClass) { + @Override + public void addDashObject(Class> dashClass) { final Class[] interfaces = dashClass.getInterfaces(); if (interfaces.length == 0) { LOGGER.error("No DashObject interface found. Class: {}", dashClass.getSimpleName()); @@ -37,15 +39,17 @@ public void addDashObject(Class> dashClass) { this.dashObjects.add(new DashObjectClass<>(dashClass)); } - public void addModule(DashModule handler) { - this.modules.add(handler); + @Override + public void addModule(DashModule module) { + this.modules.add(module); } @Override - public void addMissingHandler(Class parentClass, BiFunction> func) { - this.missingHandlers.add(new MissingHandler<>(parentClass, func)); + public void addMissingHandler(Class rClass, BiFunction> func) { + this.missingHandlers.add(new MissingHandler<>(rClass, func)); } + @Override public Cache build(Path cacheDir) { if (this.failed) { throw new RuntimeException("Failed to initialize the API"); @@ -54,14 +58,20 @@ public Cache build(Path cacheDir) { // Set dashobject ids this.dashObjects.sort(Comparator.comparing(o -> o.getDashClass().getName())); this.modules.sort(Comparator.comparing(o -> o.getDataClass().getName())); - this.missingHandlers.sort(Comparator.comparing(o -> o.parentClass.getName())); - List> objects = this.dashObjects; - for (int i = 0; i < objects.size(); i++) { - DashObjectClass dashObject = objects.get(i); - dashObject.dashObjectId = i; + + int id = 0; + Class lastClass = null; + for (DashObjectClass dashObject : this.dashObjects) { + if (dashObject.getDashClass() == lastClass) { + DashLoader.LOG.warn("Duplicate DashObject found: {}", dashObject.getDashClass()); + continue; + } + lastClass = dashObject.getDashClass(); + dashObject.dashObjectId = id; + id += 1; } - return new Cache(cacheDir.resolve(DashLoader.MOD_HASH + "/"), modules, dashObjects, missingHandlers); + return new CacheImpl(cacheDir.resolve(DashLoader.MOD_HASH + "/"), modules, dashObjects, this.missingHandlers); } } \ No newline at end of file diff --git a/src/main/java/dev/notalpha/dashloader/Cache.java b/common/src/main/java/dev/notalpha/dashloader/CacheImpl.java similarity index 85% rename from src/main/java/dev/notalpha/dashloader/Cache.java rename to common/src/main/java/dev/notalpha/dashloader/CacheImpl.java index 82ccfec9..50e6fa33 100644 --- a/src/main/java/dev/notalpha/dashloader/Cache.java +++ b/common/src/main/java/dev/notalpha/dashloader/CacheImpl.java @@ -1,16 +1,16 @@ package dev.notalpha.dashloader; +import dev.notalpha.dashloader.api.DashModule; +import dev.notalpha.dashloader.registry.MissingHandler; +import dev.notalpha.dashloader.api.cache.Cache; import dev.notalpha.dashloader.api.cache.CacheStatus; -import dev.notalpha.dashloader.api.cache.DashCache; -import dev.notalpha.dashloader.api.cache.DashModule; import dev.notalpha.dashloader.config.ConfigHandler; import dev.notalpha.dashloader.io.MappingSerializer; import dev.notalpha.dashloader.io.RegistrySerializer; import dev.notalpha.dashloader.io.data.CacheInfo; import dev.notalpha.dashloader.misc.ProfilerUtil; -import dev.notalpha.dashloader.registry.MissingHandler; -import dev.notalpha.dashloader.registry.RegistryFactory; import dev.notalpha.dashloader.registry.RegistryReaderImpl; +import dev.notalpha.dashloader.registry.RegistryWriterImpl; import dev.notalpha.dashloader.registry.data.StageData; import dev.notalpha.taski.builtin.StepTask; import org.apache.commons.io.FileUtils; @@ -26,7 +26,7 @@ import java.util.function.Consumer; import java.util.stream.Stream; -public final class Cache implements DashCache { +public final class CacheImpl implements Cache { private static final String METADATA_FILE_NAME = "metadata.bin"; private CacheStatus status; private String hash; @@ -41,7 +41,7 @@ public final class Cache implements DashCache { private final RegistrySerializer registrySerializer; private final MappingSerializer mappingsSerializer; - Cache(Path cacheDir, List> cacheHandlers, List> dashObjects, List> missingHandlers) { + CacheImpl(Path cacheDir, List> cacheHandlers, List> dashObjects, List> missingHandlers) { this.cacheDir = cacheDir; this.cacheHandlers = cacheHandlers; this.dashObjects = dashObjects; @@ -50,21 +50,23 @@ public final class Cache implements DashCache { this.mappingsSerializer = new MappingSerializer(cacheHandlers); } - public void start() { + public void load(String name) { + this.hash = name; + if (this.exists()) { this.setStatus(CacheStatus.LOAD); - this.load(); + this.loadCache(); } else { this.setStatus(CacheStatus.SAVE); } } public boolean save(@Nullable Consumer taskConsumer) { + if (status != CacheStatus.SAVE) { + throw new RuntimeException("Status is not SAVE"); + } DashLoader.LOG.info("Starting DashLoader Caching"); try { - if (status != CacheStatus.SAVE) { - throw new RuntimeException("Status is not SAVE"); - } Path ourDir = getDir(); @@ -119,7 +121,7 @@ public boolean save(@Nullable Consumer taskConsumer) { taskConsumer.accept(main); } - RegistryFactory factory = RegistryFactory.create(missingHandlers, dashObjects); + RegistryWriterImpl factory = RegistryWriterImpl.create(missingHandlers, dashObjects); // Mappings mappingsSerializer.save(ourDir, factory, cacheHandlers, main); @@ -142,13 +144,16 @@ public boolean save(@Nullable Consumer taskConsumer) { } catch (Throwable thr) { DashLoader.LOG.error("Failed caching", thr); this.setStatus(CacheStatus.SAVE); - this.clear(); + this.remove(); return false; } } - public void load() { - this.status = CacheStatus.LOAD; + private void loadCache() { + if (status != CacheStatus.LOAD) { + throw new RuntimeException("Status is not LOAD"); + } + long start = System.currentTimeMillis(); try { StepTask task = new StepTask("Loading DashCache", 3); @@ -163,14 +168,12 @@ public void load() { RegistryReaderImpl reader = new RegistryReaderImpl(info, stageData); // Exporting assets - task.run(() -> { - reader.export(task::setSubTask); - }); + task.run(() -> reader.export(task::setSubTask)); // Loading mappings if (!mappingsSerializer.load(cacheDir, reader, cacheHandlers)) { this.setStatus(CacheStatus.SAVE); - this.clear(); + this.remove(); return; } @@ -178,20 +181,15 @@ public void load() { } catch (Exception e) { DashLoader.LOG.error("Summoned CrashLoader in {}", ProfilerUtil.getTimeStringFromStart(start), e); this.setStatus(CacheStatus.SAVE); - this.clear(); + this.remove(); } } - public void setHash(String hash) { - DashLoader.LOG.info("Hash changed to " + hash); - this.hash = hash; - } - public boolean exists() { return Files.exists(this.getDir()); } - public void clear() { + public void remove() { try { FileUtils.deleteDirectory(this.getDir().toFile()); } catch (IOException e) { @@ -199,6 +197,11 @@ public void clear() { } } + @Override + public void reset() { + this.setStatus(CacheStatus.IDLE); + } + public Path getDir() { if (hash == null) { throw new RuntimeException("Cache hash has not been set."); @@ -207,15 +210,15 @@ public Path getDir() { } - public void setStatus(CacheStatus status) { + public CacheStatus getStatus() { + return status; + } + + private void setStatus(CacheStatus status) { if (this.status != status) { this.status = status; DashLoader.LOG.info("\u001B[46m\u001B[30m DashLoader Status change {}\n\u001B[0m", status); this.cacheHandlers.forEach(handler -> handler.reset(this)); } } - - public CacheStatus getStatus() { - return status; - } } diff --git a/src/main/java/dev/notalpha/dashloader/DashLoader.java b/common/src/main/java/dev/notalpha/dashloader/DashLoader.java similarity index 84% rename from src/main/java/dev/notalpha/dashloader/DashLoader.java rename to common/src/main/java/dev/notalpha/dashloader/DashLoader.java index bb0fc536..6c8e64f7 100644 --- a/src/main/java/dev/notalpha/dashloader/DashLoader.java +++ b/common/src/main/java/dev/notalpha/dashloader/DashLoader.java @@ -13,13 +13,8 @@ import java.util.Comparator; -public class DashLoader { - private static final String VERSION = FabricLoader.getInstance() - .getModContainer("dashloader") - .orElseThrow(() -> new IllegalStateException("DashLoader not found... apparently! WTF?")) - .getMetadata() - .getVersion() - .getFriendlyString(); +public final class DashLoader { + private static final String VERSION ="5.0.0-beta.3+1.20.0"; public static final Logger LOG = LogManager.getLogger("DashLoader"); public static final Serializer METADATA_SERIALIZER = new Serializer<>(CacheInfo.class); public static final String MOD_HASH; diff --git a/src/main/java/dev/notalpha/dashloader/DashObjectClass.java b/common/src/main/java/dev/notalpha/dashloader/DashObjectClass.java similarity index 79% rename from src/main/java/dev/notalpha/dashloader/DashObjectClass.java rename to common/src/main/java/dev/notalpha/dashloader/DashObjectClass.java index e194a8c2..d9f57bbf 100644 --- a/src/main/java/dev/notalpha/dashloader/DashObjectClass.java +++ b/common/src/main/java/dev/notalpha/dashloader/DashObjectClass.java @@ -1,6 +1,7 @@ package dev.notalpha.dashloader; import dev.notalpha.dashloader.api.DashObject; +import dev.quantumfusion.hyphen.util.ScanUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -15,7 +16,7 @@ * @param Raw * @param Dashable */ -public final class DashObjectClass> { +public final class DashObjectClass> { private final Class dashClass; @Nullable private Class targetClass; @@ -40,17 +41,16 @@ public Class getTargetClass() { } boolean foundDashObject = false; - Class[] interfaces = this.dashClass.getInterfaces(); - for (int i = 0; i < interfaces.length; i++) { - if (interfaces[i] == DashObject.class) { + for (Type genericInterface : genericInterfaces) { + if (ScanUtil.getClassFrom(genericInterface) == DashObject.class) { foundDashObject = true; - var genericInterface = genericInterfaces[i]; if (genericInterface instanceof ParameterizedType targetClass) { - if (targetClass.getActualTypeArguments()[0] instanceof Class targetClas) { - this.targetClass = (Class) targetClas; - } else { + Type[] actualTypeArguments = targetClass.getActualTypeArguments(); + Class classFrom = ScanUtil.getClassFrom(actualTypeArguments[0]); + if (classFrom == null) { throw new RuntimeException(this.dashClass + " has a non resolvable DashObject parameter"); } + this.targetClass = (Class) classFrom; } else { throw new RuntimeException(this.dashClass + " implements raw DashObject"); } diff --git a/src/main/java/dev/notalpha/dashloader/api/cache/CachingData.java b/common/src/main/java/dev/notalpha/dashloader/api/CachingData.java similarity index 70% rename from src/main/java/dev/notalpha/dashloader/api/cache/CachingData.java rename to common/src/main/java/dev/notalpha/dashloader/api/CachingData.java index 35e4f279..44324625 100644 --- a/src/main/java/dev/notalpha/dashloader/api/cache/CachingData.java +++ b/common/src/main/java/dev/notalpha/dashloader/api/CachingData.java @@ -1,5 +1,7 @@ -package dev.notalpha.dashloader.api.cache; +package dev.notalpha.dashloader.api; +import dev.notalpha.dashloader.api.cache.Cache; +import dev.notalpha.dashloader.api.cache.CacheStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -9,7 +11,7 @@ public class CachingData { @Nullable private D data; - private DashCache cache; + private Cache cacheManager; @Nullable private CacheStatus dataStatus; @@ -43,9 +45,9 @@ public void visit(CacheStatus status, Consumer consumer) { return null; } - public void reset(DashCache cache, @NotNull D data) { - this.cache = cache; - set(cache.getStatus(), data); + public void reset(Cache cacheManager, @NotNull D data) { + this.cacheManager = cacheManager; + set(cacheManager.getStatus(), data); } /** @@ -58,11 +60,11 @@ public void set(CacheStatus status, @NotNull D data) { return; } - if (cache == null) { + if (cacheManager == null) { throw new RuntimeException("cacheManager is null. This OptionData has never been reset in its handler."); } - CacheStatus currentStatus = cache.getStatus(); + CacheStatus currentStatus = cacheManager.getStatus(); if (status == currentStatus) { this.dataStatus = status; this.data = data; @@ -70,6 +72,6 @@ public void set(CacheStatus status, @NotNull D data) { } public boolean active(CacheStatus status) { - return status == this.dataStatus && status == cache.getStatus() && this.data != null && (onlyOn == null || onlyOn == status); + return status == this.dataStatus && status == cacheManager.getStatus() && this.data != null && (onlyOn == null || onlyOn == status); } } diff --git a/common/src/main/java/dev/notalpha/dashloader/api/DashEntrypoint.java b/common/src/main/java/dev/notalpha/dashloader/api/DashEntrypoint.java new file mode 100644 index 00000000..7aba27ac --- /dev/null +++ b/common/src/main/java/dev/notalpha/dashloader/api/DashEntrypoint.java @@ -0,0 +1,18 @@ +package dev.notalpha.dashloader.api; + + +import dev.notalpha.dashloader.api.cache.CacheFactory; + +import java.util.List; + +/** + * The DashEntrypoint allows operations on the DashLoader Minecraft cache, like adding support to external DashObjects, Modules or MissingHandlers. + */ +public interface DashEntrypoint { + /** + * Runs on DashLoader initialization. This is quite early compared to the cache. + * + * @param factory Factory to register your DashObjects/Modules to. + */ + void onDashLoaderInit(CacheFactory factory); +} diff --git a/common/src/main/java/dev/notalpha/dashloader/api/DashModule.java b/common/src/main/java/dev/notalpha/dashloader/api/DashModule.java new file mode 100644 index 00000000..62cbe660 --- /dev/null +++ b/common/src/main/java/dev/notalpha/dashloader/api/DashModule.java @@ -0,0 +1,68 @@ +package dev.notalpha.dashloader.api; + +import dev.notalpha.dashloader.api.cache.Cache; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.taski.builtin.StepTask; + +/** + * A DashModule is a manager of data in a Cache. + * It's responsible for providing and consuming objects from/to the registry and saving the resulting id's and/or other data into the data class. + *

+ * These may conditionally be disabled by {@link DashModule#isActive()}. + * + * @param The Data class which will be saved + */ +public interface DashModule { + /** + * This runs when the module gets reset by dashloader. + * This is used to reset CachingData instances to their correct state. + * + * @param cache The cache object which is resetting. + */ + void reset(Cache cache); + + /** + * Runs when DashLoader is creating a save. + * This should fill the RegistryFactory with objects that it wants available on next load. + * + * @param writer RegistryWriter to provide objects to. + * @param task Task to track progress of the saving. + * @return The DataObject which will be saved for next load. + */ + D save(RegistryWriter writer, StepTask task); + + /** + * Runs when DashLoader is loading back a save. + * This should read back the objects from the RegistryReading with the ids commonly saved in the DataObject. + * + * @param data DataObject which got saved in {@link DashModule#save(RegistryWriter, StepTask)} + * @param reader RegistryReader which contains objects which got cached. + * @param task Task to track progress of the loading. + */ + void load(D data, RegistryReader reader, StepTask task); + + /** + * Gets the DataClass which the module uses to save data for the cache load. + */ + Class getDataClass(); + + /** + * Returns if the module is currently active. + *

+ * When saving, if the module is active it will run the save method and then save the data object to the cache. + *

+ * When loading back the cache. If the cache did not have the module in the same state as now, it will force a recache. + */ + default boolean isActive() { + return true; + } + + /** + * The weight of the module in the progress task. + * The bigger the value the more space the module will use in the progress. + */ + default float taskWeight() { + return 100; + } +} diff --git a/common/src/main/java/dev/notalpha/dashloader/api/DashObject.java b/common/src/main/java/dev/notalpha/dashloader/api/DashObject.java new file mode 100644 index 00000000..bc835637 --- /dev/null +++ b/common/src/main/java/dev/notalpha/dashloader/api/DashObject.java @@ -0,0 +1,38 @@ +package dev.notalpha.dashloader.api; + +import dev.notalpha.dashloader.api.registry.RegistryReader; + +/** + * A DashObject is responsible for making normal objects serializable + * by mapping them to a more serializable format and deduplicating inner objects through the registry. + * + * @param The target object which it's adding support to. + */ +@SuppressWarnings("unused") +public interface DashObject { + /** + * Runs before export on the main thread. + * + * @see DashObject#export(RegistryReader) + */ + @SuppressWarnings("unused") + default void preExport(RegistryReader reader) { + } + + /** + * The export method converts the DashObject into the original counterpart which was provided on save. + *

+ * Note: This runs in parallel meaning that it does not run on the Main thread. If you need to load things on the main thread use {@link DashObject#postExport(RegistryReader)} + */ + @SuppressWarnings("unused") + O export(RegistryReader reader); + + /** + * Runs after export on the main thread. + * + * @see DashObject#export(RegistryReader) + */ + @SuppressWarnings("unused") + default void postExport(RegistryReader reader) { + } +} diff --git a/common/src/main/java/dev/notalpha/dashloader/api/cache/Cache.java b/common/src/main/java/dev/notalpha/dashloader/api/cache/Cache.java new file mode 100644 index 00000000..71253f50 --- /dev/null +++ b/common/src/main/java/dev/notalpha/dashloader/api/cache/Cache.java @@ -0,0 +1,52 @@ +package dev.notalpha.dashloader.api.cache; + +import dev.notalpha.taski.builtin.StepTask; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; +import java.util.function.Consumer; + +/** + * The Cache is responsible for managing, saving and loading caches from its assigned directory. + * + * @see CacheFactory + */ +public interface Cache { + /** + * Attempt to load the DashLoader cache with the current name if it exists, + * else it will set the cache into SAVE status and reset managers to be ready for caching. + * + * @param name The cache name which will be used. + */ + void load(String name); + + /** + * Create and save a cache from the modules which are currently enabled. + * + * @param taskConsumer An optional task function which allows you to track the progress. + * @return If the cache creation was successful + */ + boolean save(@Nullable Consumer taskConsumer); + + /** + * Resets the cache into an IDLE state where it resets the cache storages to save memory. + */ + void reset(); + + /** + * Remove the existing cache if it exists. + */ + void remove(); + + /** + * Gets the current status or state of the Cache. + */ + CacheStatus getStatus(); + + /** + * Gets the current directory of the cache. + * + * @return Path to the cache directory which contains the data. + */ + Path getDir(); +} diff --git a/common/src/main/java/dev/notalpha/dashloader/api/cache/CacheFactory.java b/common/src/main/java/dev/notalpha/dashloader/api/cache/CacheFactory.java new file mode 100644 index 00000000..14628d2c --- /dev/null +++ b/common/src/main/java/dev/notalpha/dashloader/api/cache/CacheFactory.java @@ -0,0 +1,54 @@ +package dev.notalpha.dashloader.api.cache; + +import dev.notalpha.dashloader.CacheFactoryImpl; +import dev.notalpha.dashloader.api.DashModule; +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryWriter; + +import java.nio.file.Path; +import java.util.function.BiFunction; + +/** + * The CacheFactory is used to construct a {@link Cache} + */ +public interface CacheFactory { + /** + * Creates a new Factory + * + * @return CacheFactory + */ + static CacheFactory create() { + return new CacheFactoryImpl(); + } + + /** + * Adds a DashObject to the Cache, this will allow the Cache to cache the DashObject's target. + * + * @param dashClass The class + */ + void addDashObject(Class> dashClass); + + /** + * Adds a module to the Cache. Please note only enabled Modules will actually be cached. + */ + void addModule(DashModule module); + + /** + * Adds a missing handler to the Cache, a missing handler is used when an Object does not have a DashObject directly bound to it. + * The registry will go through every missing handler until it finds one which does not return {@code null}. + * @param rClass The class which the object needs to implement. + * If you want to go through any object you can insert {@code Object.class} because every java object inherits this. + * @param func The consumer function for an object which fits the {@code rClass}. + * If this function returns a non-null value, it will use that DashObject for serialization of that object. + * @param The super class of the objects being missed. + */ + void addMissingHandler(Class rClass, BiFunction> func); + + /** + * Builds the cache object. + * + * @param path The directory which contains the caches. + * @return A DashLoader cache object. + */ + Cache build(Path path); +} diff --git a/common/src/main/java/dev/notalpha/dashloader/api/cache/CacheStatus.java b/common/src/main/java/dev/notalpha/dashloader/api/cache/CacheStatus.java new file mode 100644 index 00000000..02c7b5d6 --- /dev/null +++ b/common/src/main/java/dev/notalpha/dashloader/api/cache/CacheStatus.java @@ -0,0 +1,19 @@ +package dev.notalpha.dashloader.api.cache; + +/** + * Status/State values for a given Cache. + */ +public enum CacheStatus { + /** + * The cache is in an IDLE state where there are no temporary resources in memory. + */ + IDLE, + /** + * The Cache is loading back an existing cache from a file. + */ + LOAD, + /** + * The Cache is trying to create/save a cache. + */ + SAVE, +} diff --git a/src/main/java/dev/notalpha/dashloader/api/collection/IntIntList.java b/common/src/main/java/dev/notalpha/dashloader/api/collection/IntIntList.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/api/collection/IntIntList.java rename to common/src/main/java/dev/notalpha/dashloader/api/collection/IntIntList.java diff --git a/src/main/java/dev/notalpha/dashloader/api/collection/IntObjectList.java b/common/src/main/java/dev/notalpha/dashloader/api/collection/IntObjectList.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/api/collection/IntObjectList.java rename to common/src/main/java/dev/notalpha/dashloader/api/collection/IntObjectList.java diff --git a/src/main/java/dev/notalpha/dashloader/api/collection/ObjectIntList.java b/common/src/main/java/dev/notalpha/dashloader/api/collection/ObjectIntList.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/api/collection/ObjectIntList.java rename to common/src/main/java/dev/notalpha/dashloader/api/collection/ObjectIntList.java diff --git a/src/main/java/dev/notalpha/dashloader/api/collection/ObjectObjectList.java b/common/src/main/java/dev/notalpha/dashloader/api/collection/ObjectObjectList.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/api/collection/ObjectObjectList.java rename to common/src/main/java/dev/notalpha/dashloader/api/collection/ObjectObjectList.java diff --git a/src/main/java/dev/notalpha/dashloader/registry/RegistryAddException.java b/common/src/main/java/dev/notalpha/dashloader/api/registry/RegistryAddException.java similarity index 89% rename from src/main/java/dev/notalpha/dashloader/registry/RegistryAddException.java rename to common/src/main/java/dev/notalpha/dashloader/api/registry/RegistryAddException.java index 8521a268..30fc972f 100644 --- a/src/main/java/dev/notalpha/dashloader/registry/RegistryAddException.java +++ b/common/src/main/java/dev/notalpha/dashloader/api/registry/RegistryAddException.java @@ -1,4 +1,4 @@ -package dev.notalpha.dashloader.registry; +package dev.notalpha.dashloader.api.registry; public class RegistryAddException extends RuntimeException { public final Class targetClass; diff --git a/common/src/main/java/dev/notalpha/dashloader/api/registry/RegistryReader.java b/common/src/main/java/dev/notalpha/dashloader/api/registry/RegistryReader.java new file mode 100644 index 00000000..d114f330 --- /dev/null +++ b/common/src/main/java/dev/notalpha/dashloader/api/registry/RegistryReader.java @@ -0,0 +1,18 @@ +package dev.notalpha.dashloader.api.registry; + +/** + * The RegistryReader is used to read objects from the cache's registry. + * + * @see RegistryWriter + */ +public interface RegistryReader { + /** + * Gets an object from the Cache. + * + * @param pointer The registry pointer to the object. + * @param Target object class. + * @return The object that got cached. + * @see RegistryWriter#add(Object) + */ + R get(final int pointer); +} diff --git a/common/src/main/java/dev/notalpha/dashloader/api/registry/RegistryUtil.java b/common/src/main/java/dev/notalpha/dashloader/api/registry/RegistryUtil.java new file mode 100644 index 00000000..6f4aa41f --- /dev/null +++ b/common/src/main/java/dev/notalpha/dashloader/api/registry/RegistryUtil.java @@ -0,0 +1,43 @@ +package dev.notalpha.dashloader.api.registry; + +/** + * Contains utilities for handling RegistryIds + */ +public final class RegistryUtil { + /** + * Creates a new registry id. + * + * @param objectPos The chunk object position. + * @param chunkPos The index to the chunk the object is in. + * @return Registry ID + */ + public static int createId(int objectPos, byte chunkPos) { + if (chunkPos > 0b111111) { + throw new IllegalStateException("Chunk pos is too big. " + chunkPos + " > " + 0x3f); + } + if (objectPos > 0x3ffffff) { + throw new IllegalStateException("Object pos is too big. " + objectPos + " > " + 0x3ffffff); + } + return objectPos << 6 | (chunkPos & 0x3f); + } + + /** + * Gets the chunk id portion of the Registry ID + * + * @param id Registry ID + * @return Chunk index. + */ + public static byte getChunkId(int id) { + return (byte) (id & 0x3f); + } + + /** + * Gets the object id portion of the Registry ID + * + * @param id Registry ID + * @return The index of the object in the chunk. + */ + public static int getObjectId(int id) { + return id >>> 6; + } +} diff --git a/common/src/main/java/dev/notalpha/dashloader/api/registry/RegistryWriter.java b/common/src/main/java/dev/notalpha/dashloader/api/registry/RegistryWriter.java new file mode 100644 index 00000000..8b93f32e --- /dev/null +++ b/common/src/main/java/dev/notalpha/dashloader/api/registry/RegistryWriter.java @@ -0,0 +1,19 @@ +package dev.notalpha.dashloader.api.registry; + +/** + * A RegistryWriter is provided to DashObjects and Modules on save minecraft objects to the cache by converting them into DashObjects. + * On cache load, a RegistryReader is provided so you can read back the objects from the cache. + * + * @see RegistryReader + */ +public interface RegistryWriter { + /** + * Adds an object to the Cache, the object needs to have a DashObject backing it else it will fail. + * + * @param object The Object to add to the cache. + * @param The target class being cached. + * @return A registry id which points to the object. + * @see RegistryReader#get(int) + */ + int add(R object); +} diff --git a/src/main/java/dev/notalpha/dashloader/client/DashLoaderClient.java b/common/src/main/java/dev/notalpha/dashloader/client/DashLoaderClient.java similarity index 80% rename from src/main/java/dev/notalpha/dashloader/client/DashLoaderClient.java rename to common/src/main/java/dev/notalpha/dashloader/client/DashLoaderClient.java index 96e548ab..a05ee11f 100644 --- a/src/main/java/dev/notalpha/dashloader/client/DashLoaderClient.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/DashLoaderClient.java @@ -1,14 +1,14 @@ package dev.notalpha.dashloader.client; -import dev.notalpha.dashloader.Cache; -import dev.notalpha.dashloader.CacheFactory; import dev.notalpha.dashloader.api.DashEntrypoint; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.cache.DashCacheFactory; +import dev.notalpha.dashloader.api.cache.Cache; +import dev.notalpha.dashloader.api.cache.CacheFactory; import dev.notalpha.dashloader.client.blockstate.DashBlockState; import dev.notalpha.dashloader.client.font.*; import dev.notalpha.dashloader.client.identifier.DashIdentifier; import dev.notalpha.dashloader.client.identifier.DashModelIdentifier; +import dev.notalpha.dashloader.client.identifier.DashSpriteIdentifier; import dev.notalpha.dashloader.client.model.*; import dev.notalpha.dashloader.client.model.components.DashBakedQuad; import dev.notalpha.dashloader.client.model.components.DashBakedQuadCollection; @@ -19,66 +19,41 @@ import dev.notalpha.dashloader.client.splash.SplashModule; import dev.notalpha.dashloader.client.sprite.DashImage; import dev.notalpha.dashloader.client.sprite.DashSprite; -import dev.notalpha.dashloader.client.sprite.SpriteModule; -import net.fabricmc.loader.api.FabricLoader; +import dev.notalpha.dashloader.client.sprite.SpriteStitcherModule; import net.minecraft.client.render.model.json.AndMultipartModelSelector; import net.minecraft.client.render.model.json.MultipartModelSelector; import net.minecraft.client.render.model.json.OrMultipartModelSelector; import net.minecraft.client.render.model.json.SimpleMultipartModelSelector; +import net.minecraft.client.texture.Sprite; import net.minecraft.client.util.ModelIdentifier; import net.minecraft.util.Identifier; import java.nio.file.Path; -import java.util.List; public class DashLoaderClient implements DashEntrypoint { public static final Cache CACHE; public static boolean NEEDS_RELOAD = false; static { - CacheFactory cacheManagerFactory = new CacheFactory(); - List entryPoints = FabricLoader.getInstance().getEntrypoints("dashloader", DashEntrypoint.class); + CacheFactory cacheManagerFactory = CacheFactory.create(); + /*List entryPoints = FabricLoader.getInstance().getEntrypoints("dashloader", DashEntrypoint.class); for (DashEntrypoint entryPoint : entryPoints) { entryPoint.onDashLoaderInit(cacheManagerFactory); - } + }*/ + new DashLoaderClient().onDashLoaderInit(cacheManagerFactory); CACHE = cacheManagerFactory.build(Path.of("./dashloader-cache/client/")); + System.out.println("DashLoaderForge loaded."); } @Override - public void onDashLoaderInit(DashCacheFactory factory) { + public void onDashLoaderInit(CacheFactory factory) { factory.addModule(new FontModule()); factory.addModule(new ModelModule()); factory.addModule(new ShaderModule()); factory.addModule(new SplashModule()); - factory.addModule(new SpriteModule()); + factory.addModule(new SpriteStitcherModule()); - for (Class> aClass : new Class[]{ - DashIdentifier.class, - DashModelIdentifier.class, - DashBasicBakedModel.class, - DashBuiltinBakedModel.class, - DashMultipartBakedModel.class, - DashWeightedBakedModel.class, - DashBakedQuad.class, - DashBakedQuadCollection.class, - DashAndPredicate.class, - DashOrPredicate.class, - DashSimplePredicate.class, - DashStaticPredicate.class, - DashImage.class, - DashSprite.class, - DashBitmapFont.class, - DashBlankFont.class, - DashSpaceFont.class, - DashTrueTypeFont.class, - DashUnicodeFont.class, - DashBlockState.class, - DashVertexFormat.class, - DashShader.class - }) { - factory.addDashObject(aClass); - } factory.addMissingHandler( Identifier.class, (identifier, registryWriter) -> { @@ -89,6 +64,11 @@ public void onDashLoaderInit(DashCacheFactory factory) { } } ); + + factory.addMissingHandler( + Sprite.class, + DashSprite::new + ); factory.addMissingHandler( MultipartModelSelector.class, (selector, writer) -> { @@ -109,5 +89,34 @@ public void onDashLoaderInit(DashCacheFactory factory) { } } ); + + //noinspection unchecked + for (Class> aClass : new Class[]{ + DashIdentifier.class, + DashModelIdentifier.class, + DashBasicBakedModel.class, + DashBuiltinBakedModel.class, + DashMultipartBakedModel.class, + DashWeightedBakedModel.class, + DashBakedQuad.class, + DashBakedQuadCollection.class, + DashSpriteIdentifier.class, + DashAndPredicate.class, + DashOrPredicate.class, + DashSimplePredicate.class, + DashStaticPredicate.class, + DashImage.class, + DashSprite.class, + DashBitmapFont.class, + DashBlankFont.class, + DashSpaceFont.class, + DashTrueTypeFont.class, + DashUnihexFont.class, + DashBlockState.class, + DashVertexFormat.class, + DashShader.class + }) { + factory.addDashObject(aClass); + } } } diff --git a/common/src/main/java/dev/notalpha/dashloader/client/Dazy.java b/common/src/main/java/dev/notalpha/dashloader/client/Dazy.java new file mode 100644 index 00000000..fce79c4a --- /dev/null +++ b/common/src/main/java/dev/notalpha/dashloader/client/Dazy.java @@ -0,0 +1,23 @@ +package dev.notalpha.dashloader.client; + +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.SpriteIdentifier; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Function; + +// its lazy, but dash! Used for resolution of sprites. +public abstract class Dazy { + @Nullable + private transient V loaded; + + protected abstract V resolve(Function spriteLoader); + public V get(Function spriteLoader) { + if (loaded != null) { + return loaded; + } + + loaded = resolve(spriteLoader); + return loaded; + } +} diff --git a/src/main/java/dev/notalpha/dashloader/client/blockstate/DashBlockState.java b/common/src/main/java/dev/notalpha/dashloader/client/blockstate/DashBlockState.java similarity index 94% rename from src/main/java/dev/notalpha/dashloader/client/blockstate/DashBlockState.java rename to common/src/main/java/dev/notalpha/dashloader/client/blockstate/DashBlockState.java index 2c04b8c8..68d62fbd 100644 --- a/src/main/java/dev/notalpha/dashloader/client/blockstate/DashBlockState.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/blockstate/DashBlockState.java @@ -1,14 +1,14 @@ package dev.notalpha.dashloader.client.blockstate; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.api.RegistryWriter; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; import dev.notalpha.dashloader.mixin.accessor.ModelLoaderAccessor; import net.minecraft.block.BlockState; import net.minecraft.registry.Registries; import net.minecraft.util.Identifier; -public final class DashBlockState implements DashObject { +public final class DashBlockState implements DashObject { public static final Identifier ITEM_FRAME = new Identifier("dashloader:itemframewhy"); public final int owner; public final int pos; diff --git a/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFont.java b/common/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFont.java similarity index 67% rename from src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFont.java rename to common/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFont.java index fe1386e2..247f6541 100644 --- a/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFont.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFont.java @@ -1,16 +1,16 @@ package dev.notalpha.dashloader.client.font; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.api.RegistryWriter; import dev.notalpha.dashloader.api.collection.IntObjectList; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; import dev.notalpha.dashloader.mixin.accessor.BitmapFontAccessor; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import net.minecraft.client.font.BitmapFont; +import net.minecraft.client.font.GlyphContainer; import java.util.ArrayList; -public final class DashBitmapFont implements DashObject { +public final class DashBitmapFont implements DashObject { public final int image; public final IntObjectList glyphs; @@ -24,11 +24,14 @@ public DashBitmapFont(BitmapFont bitmapFont, RegistryWriter writer) { BitmapFontAccessor font = ((BitmapFontAccessor) bitmapFont); this.image = writer.add(font.getImage()); this.glyphs = new IntObjectList<>(new ArrayList<>()); - font.getGlyphs().forEach((integer, bitmapFontGlyph) -> this.glyphs.put(integer, new DashBitmapFontGlyph(bitmapFontGlyph, writer))); + font.getGlyphs().forEachGlyph((integer, bitmapFontGlyph) -> this.glyphs.put(integer, new DashBitmapFontGlyph(bitmapFontGlyph, writer))); } public BitmapFont export(RegistryReader reader) { - Int2ObjectOpenHashMap out = new Int2ObjectOpenHashMap<>(); + GlyphContainer out = new GlyphContainer<>( + BitmapFont.BitmapFontGlyph[]::new, + BitmapFont.BitmapFontGlyph[][]::new + ); this.glyphs.forEach((key, value) -> out.put(key, value.export(reader))); return BitmapFontAccessor.init(reader.get(this.image), out); } diff --git a/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFontGlyph.java b/common/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFontGlyph.java similarity index 92% rename from src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFontGlyph.java rename to common/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFontGlyph.java index 21e4be84..3aa4ee29 100644 --- a/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFontGlyph.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFontGlyph.java @@ -1,7 +1,7 @@ package dev.notalpha.dashloader.client.font; -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.api.RegistryWriter; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; import dev.notalpha.dashloader.mixin.accessor.BitmapFontGlyphAccessor; import net.minecraft.client.font.BitmapFont; diff --git a/src/main/java/dev/notalpha/dashloader/client/font/DashBlankFont.java b/common/src/main/java/dev/notalpha/dashloader/client/font/DashBlankFont.java similarity index 80% rename from src/main/java/dev/notalpha/dashloader/client/font/DashBlankFont.java rename to common/src/main/java/dev/notalpha/dashloader/client/font/DashBlankFont.java index d537e255..24414c1d 100644 --- a/src/main/java/dev/notalpha/dashloader/client/font/DashBlankFont.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/font/DashBlankFont.java @@ -1,10 +1,10 @@ package dev.notalpha.dashloader.client.font; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryReader; import net.minecraft.client.font.BlankFont; -public final class DashBlankFont implements DashObject { +public final class DashBlankFont implements DashObject { @Override public BlankFont export(RegistryReader exportHandler) { return new BlankFont(); diff --git a/src/main/java/dev/notalpha/dashloader/client/font/DashSpaceFont.java b/common/src/main/java/dev/notalpha/dashloader/client/font/DashSpaceFont.java similarity index 93% rename from src/main/java/dev/notalpha/dashloader/client/font/DashSpaceFont.java rename to common/src/main/java/dev/notalpha/dashloader/client/font/DashSpaceFont.java index bb2432ab..720dae61 100644 --- a/src/main/java/dev/notalpha/dashloader/client/font/DashSpaceFont.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/font/DashSpaceFont.java @@ -1,13 +1,13 @@ package dev.notalpha.dashloader.client.font; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryReader; import it.unimi.dsi.fastutil.ints.Int2FloatArrayMap; import it.unimi.dsi.fastutil.ints.IntSet; import net.minecraft.client.font.Glyph; import net.minecraft.client.font.SpaceFont; -public final class DashSpaceFont implements DashObject { +public final class DashSpaceFont implements DashObject { public final int[] ints; public final float[] floats; diff --git a/src/main/java/dev/notalpha/dashloader/client/font/DashTrueTypeFont.java b/common/src/main/java/dev/notalpha/dashloader/client/font/DashTrueTypeFont.java similarity index 97% rename from src/main/java/dev/notalpha/dashloader/client/font/DashTrueTypeFont.java rename to common/src/main/java/dev/notalpha/dashloader/client/font/DashTrueTypeFont.java index 5e9bbd28..97181696 100644 --- a/src/main/java/dev/notalpha/dashloader/client/font/DashTrueTypeFont.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/font/DashTrueTypeFont.java @@ -1,8 +1,8 @@ package dev.notalpha.dashloader.client.font; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryReader; import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.api.registry.RegistryReader; import dev.notalpha.dashloader.io.IOHelper; import dev.notalpha.dashloader.misc.UnsafeHelper; import dev.notalpha.dashloader.mixin.accessor.TrueTypeFontAccessor; @@ -21,7 +21,7 @@ import java.util.List; import java.util.Optional; -public final class DashTrueTypeFont implements DashObject { +public final class DashTrueTypeFont implements DashObject { public final byte[] ttfBuffer; public final float oversample; public final List excludedCharacters; diff --git a/common/src/main/java/dev/notalpha/dashloader/client/font/DashUnihexFont.java b/common/src/main/java/dev/notalpha/dashloader/client/font/DashUnihexFont.java new file mode 100644 index 00000000..3da2da0b --- /dev/null +++ b/common/src/main/java/dev/notalpha/dashloader/client/font/DashUnihexFont.java @@ -0,0 +1,54 @@ +package dev.notalpha.dashloader.client.font; + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.collection.IntObjectList; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.mixin.accessor.UnihexFontAccessor; +import net.minecraft.client.font.GlyphContainer; +import net.minecraft.client.font.UnihexFont; + +public final class DashUnihexFont implements DashObject { + + + public final IntObjectList glyphs; + + public DashUnihexFont(IntObjectList glyphs) { + this.glyphs = glyphs; + } + + public DashUnihexFont(UnihexFont rawFont, RegistryWriter writer) { + this.glyphs = new IntObjectList<>(); + var font = ((UnihexFontAccessor) rawFont); + var fontImages = font.getGlyphs(); + fontImages.forEachGlyph(this.glyphs::put); + } + + + public UnihexFont export(RegistryReader handler) { + GlyphContainer container = new GlyphContainer<>( + UnihexFont.UnicodeTextureGlyph[]::new, + UnihexFont.UnicodeTextureGlyph[][]::new + ); + this.glyphs.forEach(container::put); + return UnihexFontAccessor.create(container); + } + + public static class DashUnicodeTextureGlyph { + public final UnihexFont.BitmapGlyph contents; + public final int left; + public final int right; + + public DashUnicodeTextureGlyph(UnihexFont.BitmapGlyph contents, int left, int right) { + this.contents = contents; + this.left = left; + this.right = right; + } + + public DashUnicodeTextureGlyph(UnihexFont.UnicodeTextureGlyph glyph) { + this.contents = glyph.contents(); + this.left = glyph.left(); + this.right = glyph.right(); + } + } +} diff --git a/common/src/main/java/dev/notalpha/dashloader/client/font/FontModule.java b/common/src/main/java/dev/notalpha/dashloader/client/font/FontModule.java new file mode 100644 index 00000000..ef2dcd2f --- /dev/null +++ b/common/src/main/java/dev/notalpha/dashloader/client/font/FontModule.java @@ -0,0 +1,127 @@ +package dev.notalpha.dashloader.client.font; + +import dev.notalpha.dashloader.api.CachingData; +import dev.notalpha.dashloader.api.DashModule; +import dev.notalpha.dashloader.api.cache.Cache; +import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.api.collection.IntObjectList; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.config.ConfigHandler; +import dev.notalpha.dashloader.config.Option; +import dev.notalpha.taski.builtin.StepTask; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.client.font.Font; +import net.minecraft.client.font.FontManager; +import net.minecraft.util.Identifier; +import org.apache.commons.lang3.tuple.Pair; +import org.lwjgl.stb.STBTTFontinfo; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class FontModule implements DashModule { + public static final CachingData DATA = new CachingData<>(); + public static final CachingData> FONT_TO_IDENT = new CachingData<>(); + + @Override + public void reset(Cache cache) { + DATA.reset(cache, new ProviderIndex(new HashMap<>(), new ArrayList<>())); + FONT_TO_IDENT.reset(cache, new HashMap<>()); + } + + @Override + public Data save(RegistryWriter factory, StepTask task) { + ProviderIndex providerIndex = DATA.get(CacheStatus.SAVE); + assert providerIndex != null; + + + int taskSize = 0; + for (List value : providerIndex.providers.values()) { + taskSize += value.size(); + } + taskSize += providerIndex.allProviders.size(); + task.reset(taskSize); + + var providers = new IntObjectList>(); + providerIndex.providers.forEach((identifier, fonts) -> { + var values = new ArrayList(); + for (Font font : fonts) { + values.add(factory.add(font)); + task.next(); + } + providers.put(factory.add(identifier), values); + }); + + var allProviders = new ArrayList(); + for (Font allProvider : providerIndex.allProviders) { + allProviders.add(factory.add(allProvider)); + task.next(); + } + + return new Data(new DashProviderIndex(providers, allProviders)); + } + + @Override + public void load(Data data, RegistryReader reader, StepTask task) { + ProviderIndex index = new ProviderIndex(new HashMap<>(), new ArrayList<>()); + data.fontMap.providers.forEach((key, value) -> { + var fonts = new ArrayList(); + for (Integer i : value) { + fonts.add(reader.get(i)); + } + index.providers.put(reader.get(key), fonts); + }); + + data.fontMap.allProviders.forEach((value) -> { + index.allProviders.add(reader.get(value)); + }); + DATA.set(CacheStatus.LOAD, index); + } + + @Override + public Class getDataClass() { + return Data.class; + } + + @Override + public boolean isActive() { + return ConfigHandler.optionActive(Option.CACHE_FONT); + } + + public static final class Data { + public final DashProviderIndex fontMap; + + public Data(DashProviderIndex fontMap) { + this.fontMap = fontMap; + } + } + + public static final class DashProviderIndex { + public final IntObjectList> providers; + public final List allProviders; + + public DashProviderIndex(IntObjectList> providers, List allProviders) { + this.providers = providers; + this.allProviders = allProviders; + } + } + + public static final class ProviderIndex { + public final Map> providers; + public final List allProviders; + + + public ProviderIndex(Map> providers, List allProviders) { + this.providers = providers; + this.allProviders = allProviders; + } + } +} diff --git a/src/main/java/dev/notalpha/dashloader/client/identifier/DashIdentifier.java b/common/src/main/java/dev/notalpha/dashloader/client/identifier/DashIdentifier.java similarity index 93% rename from src/main/java/dev/notalpha/dashloader/client/identifier/DashIdentifier.java rename to common/src/main/java/dev/notalpha/dashloader/client/identifier/DashIdentifier.java index f1d6bcbd..6e194119 100644 --- a/src/main/java/dev/notalpha/dashloader/client/identifier/DashIdentifier.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/identifier/DashIdentifier.java @@ -1,11 +1,11 @@ package dev.notalpha.dashloader.client.identifier; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryReader; import dev.notalpha.dashloader.mixin.accessor.IdentifierAccessor; import net.minecraft.util.Identifier; -public final class DashIdentifier implements DashObject { +public final class DashIdentifier implements DashObject { public final String namespace; public final String path; diff --git a/src/main/java/dev/notalpha/dashloader/client/identifier/DashModelIdentifier.java b/common/src/main/java/dev/notalpha/dashloader/client/identifier/DashModelIdentifier.java similarity index 93% rename from src/main/java/dev/notalpha/dashloader/client/identifier/DashModelIdentifier.java rename to common/src/main/java/dev/notalpha/dashloader/client/identifier/DashModelIdentifier.java index f046d3e2..8eaaa499 100644 --- a/src/main/java/dev/notalpha/dashloader/client/identifier/DashModelIdentifier.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/identifier/DashModelIdentifier.java @@ -2,11 +2,11 @@ import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryReader; import dev.notalpha.dashloader.mixin.accessor.ModelIdentifierAccessor; import net.minecraft.client.util.ModelIdentifier; -public final class DashModelIdentifier implements DashObject { +public final class DashModelIdentifier implements DashObject { public final String namespace; public final String path; public final String variant; diff --git a/common/src/main/java/dev/notalpha/dashloader/client/identifier/DashSpriteIdentifier.java b/common/src/main/java/dev/notalpha/dashloader/client/identifier/DashSpriteIdentifier.java new file mode 100644 index 00000000..bdd32526 --- /dev/null +++ b/common/src/main/java/dev/notalpha/dashloader/client/identifier/DashSpriteIdentifier.java @@ -0,0 +1,27 @@ +package dev.notalpha.dashloader.client.identifier; + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import net.minecraft.client.util.SpriteIdentifier; +import net.minecraft.util.Identifier; + +public class DashSpriteIdentifier implements DashObject { + public final int atlas; + public final int texture; + + public DashSpriteIdentifier(int atlas, int texture) { + this.atlas = atlas; + this.texture = texture; + } + + public DashSpriteIdentifier(SpriteIdentifier identifier, RegistryWriter writer) { + this.atlas = writer.add(identifier.getAtlasId()); + this.texture = writer.add(identifier.getTextureId()); + } + + @Override + public SpriteIdentifier export(RegistryReader reader) { + return new SpriteIdentifier(reader.get(atlas), reader.get(texture)); + } +} diff --git a/src/main/java/dev/notalpha/dashloader/client/model/DashBasicBakedModel.java b/common/src/main/java/dev/notalpha/dashloader/client/model/DashBasicBakedModel.java similarity index 52% rename from src/main/java/dev/notalpha/dashloader/client/model/DashBasicBakedModel.java rename to common/src/main/java/dev/notalpha/dashloader/client/model/DashBasicBakedModel.java index 4c82acda..d62680de 100644 --- a/src/main/java/dev/notalpha/dashloader/client/model/DashBasicBakedModel.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/model/DashBasicBakedModel.java @@ -1,25 +1,33 @@ package dev.notalpha.dashloader.client.model; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.api.RegistryWriter; import dev.notalpha.dashloader.api.collection.ObjectObjectList; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.client.Dazy; import dev.notalpha.dashloader.client.model.components.BakedQuadCollection; +import dev.notalpha.dashloader.client.model.components.DashBakedQuadCollection; import dev.notalpha.dashloader.client.model.components.DashModelOverrideList; import dev.notalpha.dashloader.client.model.components.DashModelTransformation; +import dev.notalpha.dashloader.client.sprite.DashSprite; import dev.notalpha.dashloader.mixin.accessor.BasicBakedModelAccessor; -import dev.notalpha.hyphen.scan.annotations.DataNullable; +import dev.quantumfusion.hyphen.scan.annotations.DataNullable; import net.minecraft.client.render.model.BakedQuad; import net.minecraft.client.render.model.BasicBakedModel; +import net.minecraft.client.render.model.json.ModelOverrideList; +import net.minecraft.client.render.model.json.ModelTransformation; import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.SpriteIdentifier; import net.minecraft.util.math.Direction; import net.minecraft.util.math.random.Random; import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; +import java.util.function.Function; -public final class DashBasicBakedModel implements DashObject { +public final class DashBasicBakedModel implements DashObject { public final int quads; public final ObjectObjectList faceQuads; public final boolean usesAo; @@ -49,13 +57,13 @@ public DashBasicBakedModel(int quads, public DashBasicBakedModel(BasicBakedModel basicBakedModel, RegistryWriter writer) { BasicBakedModelAccessor access = ((BasicBakedModelAccessor) basicBakedModel); - basicBakedModel.getQuads(null, null, Random.create()); - this.quads = writer.add(new BakedQuadCollection(access.getQuads())); + Random random = Random.create(); + this.quads = writer.add(new BakedQuadCollection(basicBakedModel.getQuads(null, null, random))); this.faceQuads = new ObjectObjectList<>(); - access.getFaceQuads().forEach((direction, bakedQuads) -> { - this.faceQuads.put(direction, writer.add(new BakedQuadCollection(bakedQuads))); - }); + for (Direction value : Direction.values()) { + this.faceQuads.put(value, writer.add(new BakedQuadCollection(basicBakedModel.getQuads(null, value, random)))); + } this.itemPropertyOverrides = new DashModelOverrideList(access.getItemPropertyOverrides(), writer); this.usesAo = access.getUsesAo(); @@ -67,19 +75,26 @@ public DashBasicBakedModel(BasicBakedModel basicBakedModel, RegistryWriter write @Override - public BasicBakedModel export(final RegistryReader reader) { - final Sprite sprite = reader.get(this.spritePointer); - - BakedQuadCollection collection = reader.get(this.quads); - var quadsOut = collection.quads; + public DazyImpl export(final RegistryReader reader) { + final DashSprite.DazyImpl sprite = reader.get(this.spritePointer); + final DashBakedQuadCollection.DazyImpl quads = reader.get(this.quads); - var faceQuadsOut = new HashMap>(); + var faceQuads = new HashMap(); for (var entry : this.faceQuads.list()) { - BakedQuadCollection collectionEntry = reader.get(entry.value()); - faceQuadsOut.put(entry.key(), collectionEntry.quads); + DashBakedQuadCollection.DazyImpl collection = reader.get(entry.value()); + faceQuads.put(entry.key(), collection); } - return new BasicBakedModel(quadsOut, faceQuadsOut, this.usesAo, this.isSideLit, this.hasDepth, sprite, DashModelTransformation.exportOrDefault(this.transformation), this.itemPropertyOverrides.export(reader)); + return new DazyImpl( + quads, + faceQuads, + usesAo, + isSideLit, + hasDepth, + DashModelTransformation.exportOrDefault(this.transformation), + this.itemPropertyOverrides.export(reader), + sprite + ); } @Override @@ -112,4 +127,46 @@ public int hashCode() { result = 31 * result + spritePointer; return result; } + + public static class DazyImpl extends Dazy { + public final DashBakedQuadCollection.DazyImpl quads; + public final Map faceQuads; + public final boolean usesAo; + public final boolean isSideLit; + public final boolean hasDepth; + public final ModelTransformation transformation; + public final DashModelOverrideList.DazyImpl itemPropertyOverrides; + public final DashSprite.DazyImpl sprite; + + public DazyImpl(DashBakedQuadCollection.DazyImpl quads, + Map faceQuads, + boolean usesAo, + boolean isSideLit, + boolean hasDepth, + ModelTransformation transformation, + DashModelOverrideList.DazyImpl itemPropertyOverrides, + DashSprite.DazyImpl sprite) { + this.quads = quads; + this.faceQuads = faceQuads; + this.usesAo = usesAo; + this.isSideLit = isSideLit; + this.hasDepth = hasDepth; + this.transformation = transformation; + this.itemPropertyOverrides = itemPropertyOverrides; + this.sprite = sprite; + } + + @Override + protected BasicBakedModel resolve(Function spriteLoader) { + List quads = this.quads.get(spriteLoader); + var faceQuadsOut = new HashMap>(); + this.faceQuads.forEach((direction, dazy) -> { + faceQuadsOut.put(direction, dazy.get(spriteLoader)); + }); + + Sprite sprite = this.sprite.get(spriteLoader); + ModelOverrideList list = itemPropertyOverrides.get(spriteLoader); + return new BasicBakedModel(quads, faceQuadsOut, usesAo, isSideLit, hasDepth, sprite, transformation, list); + } + } } diff --git a/src/main/java/dev/notalpha/dashloader/client/model/DashBuiltinBakedModel.java b/common/src/main/java/dev/notalpha/dashloader/client/model/DashBuiltinBakedModel.java similarity index 58% rename from src/main/java/dev/notalpha/dashloader/client/model/DashBuiltinBakedModel.java rename to common/src/main/java/dev/notalpha/dashloader/client/model/DashBuiltinBakedModel.java index 0c450454..8efca594 100644 --- a/src/main/java/dev/notalpha/dashloader/client/model/DashBuiltinBakedModel.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/model/DashBuiltinBakedModel.java @@ -1,19 +1,24 @@ package dev.notalpha.dashloader.client.model; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.api.RegistryWriter; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.client.Dazy; import dev.notalpha.dashloader.client.model.components.DashModelOverrideList; import dev.notalpha.dashloader.client.model.components.DashModelTransformation; +import dev.notalpha.dashloader.client.sprite.DashSprite; import dev.notalpha.dashloader.mixin.accessor.BuiltinBakedModelAccessor; -import dev.notalpha.hyphen.scan.annotations.DataNullable; +import dev.quantumfusion.hyphen.scan.annotations.DataNullable; import net.minecraft.client.render.model.BuiltinBakedModel; +import net.minecraft.client.render.model.json.ModelOverrideList; import net.minecraft.client.render.model.json.ModelTransformation; import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.SpriteIdentifier; import java.util.Objects; +import java.util.function.Function; -public final class DashBuiltinBakedModel implements DashObject { +public final class DashBuiltinBakedModel implements DashObject { @DataNullable public final DashModelTransformation transformation; public final DashModelOverrideList itemPropertyOverrides; @@ -38,9 +43,10 @@ public DashBuiltinBakedModel(BuiltinBakedModel builtinBakedModel, RegistryWriter @Override - public BuiltinBakedModel export(RegistryReader reader) { - Sprite sprite = reader.get(this.spritePointer); - return new BuiltinBakedModel(DashModelTransformation.exportOrDefault(this.transformation), this.itemPropertyOverrides.export(reader), sprite, this.sideLit); + public DazyImpl export(RegistryReader reader) { + DashSprite.DazyImpl sprite = reader.get(this.spritePointer); + DashModelOverrideList.DazyImpl export = this.itemPropertyOverrides.export(reader); + return new DazyImpl(DashModelTransformation.exportOrDefault(this.transformation), export, sprite, this.sideLit); } @Override @@ -65,4 +71,25 @@ public int hashCode() { result = 31 * result + (sideLit ? 1 : 0); return result; } + + public static class DazyImpl extends Dazy { + public final ModelTransformation transformation; + public final DashModelOverrideList.DazyImpl itemPropertyOverrides; + public final DashSprite.DazyImpl sprite; + public final boolean sideLit; + + public DazyImpl(ModelTransformation transformation, DashModelOverrideList.DazyImpl itemPropertyOverrides, DashSprite.DazyImpl sprite, boolean sideLit) { + this.transformation = transformation; + this.itemPropertyOverrides = itemPropertyOverrides; + this.sprite = sprite; + this.sideLit = sideLit; + } + + @Override + protected BuiltinBakedModel resolve(Function spriteLoader) { + Sprite sprite = this.sprite.get(spriteLoader); + ModelOverrideList list = itemPropertyOverrides.get(spriteLoader); + return new BuiltinBakedModel(transformation, list, sprite, sideLit); + } + } } diff --git a/src/main/java/dev/notalpha/dashloader/client/model/DashMultipartBakedModel.java b/common/src/main/java/dev/notalpha/dashloader/client/model/DashMultipartBakedModel.java similarity index 61% rename from src/main/java/dev/notalpha/dashloader/client/model/DashMultipartBakedModel.java rename to common/src/main/java/dev/notalpha/dashloader/client/model/DashMultipartBakedModel.java index 4b4ee118..a05463de 100644 --- a/src/main/java/dev/notalpha/dashloader/client/model/DashMultipartBakedModel.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/model/DashMultipartBakedModel.java @@ -1,23 +1,27 @@ package dev.notalpha.dashloader.client.model; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.api.RegistryWriter; import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.client.Dazy; import dev.notalpha.dashloader.mixin.accessor.MultipartBakedModelAccessor; import net.minecraft.block.BlockState; import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.MultipartBakedModel; import net.minecraft.client.render.model.json.MultipartModelSelector; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.SpriteIdentifier; import net.minecraft.util.Identifier; import org.apache.commons.lang3.tuple.Pair; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.function.Function; import java.util.function.Predicate; -public class DashMultipartBakedModel implements DashObject { +public class DashMultipartBakedModel implements DashObject { public final List components; public DashMultipartBakedModel(List components) { @@ -45,21 +49,16 @@ public DashMultipartBakedModel(MultipartBakedModel model, RegistryWriter writer) } @Override - public MultipartBakedModel export(RegistryReader reader) { - List, BakedModel>> componentsOut = new ArrayList<>(this.components.size()); + public DazyImpl export(RegistryReader reader) { + List componentsOut = new ArrayList<>(this.components.size()); this.components.forEach(component -> { - BakedModel compModel = reader.get(component.model); + Dazy compModel = reader.get(component.model); Identifier compIdentifier = reader.get(component.identifier); MultipartModelSelector compSelector = reader.get(component.selector); Predicate predicate = compSelector.getPredicate(ModelModule.getStateManager(compIdentifier)); - componentsOut.add(Pair.of(predicate, compModel)); + componentsOut.add(new DazyImpl.Component(compModel, predicate)); }); - - MultipartBakedModel multipartBakedModel = new MultipartBakedModel(componentsOut); - MultipartBakedModelAccessor access = (MultipartBakedModelAccessor) multipartBakedModel; - // Fixes race condition which strangely does not happen in vanilla a ton? - access.setStateCache(Collections.synchronizedMap(access.getStateCache())); - return multipartBakedModel; + return new DazyImpl(componentsOut); } public static final class Component { @@ -109,5 +108,41 @@ public boolean equals(Object o) { public int hashCode() { return components.hashCode(); } + + public static class DazyImpl extends Dazy { + public final List components; + + public DazyImpl(List components) { + this.components = components; + } + + @Override + protected MultipartBakedModel resolve(Function spriteLoader) { + List, BakedModel>> componentsOut = new ArrayList<>(this.components.size()); + + for (Component component : components) { + var model = component.model.get(spriteLoader); + var selector = component.selector; + componentsOut.add(Pair.of(selector, model)); + } + + MultipartBakedModel multipartBakedModel = new MultipartBakedModel(componentsOut); + MultipartBakedModelAccessor access = (MultipartBakedModelAccessor) multipartBakedModel; + // Fixes race condition which strangely does not happen in vanilla a ton? + access.setStateCache(Collections.synchronizedMap(access.getStateCache())); + return multipartBakedModel; + } + + + public static class Component { + public final Dazy model; + public final Predicate selector; + + public Component(Dazy model, Predicate selector) { + this.model = model; + this.selector = selector; + } + } + } } diff --git a/src/main/java/dev/notalpha/dashloader/client/model/DashWeightedBakedModel.java b/common/src/main/java/dev/notalpha/dashloader/client/model/DashWeightedBakedModel.java similarity index 50% rename from src/main/java/dev/notalpha/dashloader/client/model/DashWeightedBakedModel.java rename to common/src/main/java/dev/notalpha/dashloader/client/model/DashWeightedBakedModel.java index ef40e3e4..49d759ab 100644 --- a/src/main/java/dev/notalpha/dashloader/client/model/DashWeightedBakedModel.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/model/DashWeightedBakedModel.java @@ -1,18 +1,22 @@ package dev.notalpha.dashloader.client.model; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.api.RegistryWriter; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.client.Dazy; import dev.notalpha.dashloader.client.model.components.DashWeightedModelEntry; import dev.notalpha.dashloader.mixin.accessor.WeightedBakedModelAccessor; import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.WeightedBakedModel; -import net.minecraft.util.collection.Weighted.Present; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.SpriteIdentifier; +import net.minecraft.util.collection.Weighted; import java.util.ArrayList; import java.util.List; +import java.util.function.Function; -public final class DashWeightedBakedModel implements DashObject { +public final class DashWeightedBakedModel implements DashObject { public final List models; public DashWeightedBakedModel(List models) { @@ -27,12 +31,12 @@ public DashWeightedBakedModel(WeightedBakedModel model, RegistryWriter writer) { } @Override - public WeightedBakedModel export(RegistryReader reader) { - var modelsOut = new ArrayList>(); + public DazyImpl export(RegistryReader reader) { + var modelsOut = new ArrayList(); for (DashWeightedModelEntry model : this.models) { modelsOut.add(model.export(reader)); } - return new WeightedBakedModel(modelsOut); + return new DazyImpl(modelsOut); } @Override @@ -49,4 +53,32 @@ public boolean equals(Object o) { public int hashCode() { return models.hashCode(); } + + public static class DazyImpl extends Dazy { + public final List entries; + + public DazyImpl(List entries) { + this.entries = entries; + } + + @Override + protected WeightedBakedModel resolve(Function spriteLoader) { + List> models = new ArrayList<>(); + for (Entry entry : this.entries) { + BakedModel model = entry.model.get(spriteLoader); + models.add(Weighted.of(model, entry.weight)); + } + return new WeightedBakedModel(models); + } + + public static class Entry { + public final int weight; + public final Dazy model; + + public Entry(int weight, Dazy model) { + this.weight = weight; + this.model = model; + } + } + } } diff --git a/src/main/java/dev/notalpha/dashloader/client/model/ModelModule.java b/common/src/main/java/dev/notalpha/dashloader/client/model/ModelModule.java similarity index 82% rename from src/main/java/dev/notalpha/dashloader/client/model/ModelModule.java rename to common/src/main/java/dev/notalpha/dashloader/client/model/ModelModule.java index b5ad45a6..bc6588ee 100644 --- a/src/main/java/dev/notalpha/dashloader/client/model/ModelModule.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/model/ModelModule.java @@ -1,18 +1,19 @@ package dev.notalpha.dashloader.client.model; import dev.notalpha.dashloader.DashLoader; -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.api.RegistryWriter; +import dev.notalpha.dashloader.api.CachingData; +import dev.notalpha.dashloader.api.DashModule; +import dev.notalpha.dashloader.api.cache.Cache; import dev.notalpha.dashloader.api.cache.CacheStatus; -import dev.notalpha.dashloader.api.cache.CachingData; -import dev.notalpha.dashloader.api.cache.DashCache; -import dev.notalpha.dashloader.api.cache.DashModule; import dev.notalpha.dashloader.api.collection.IntIntList; +import dev.notalpha.dashloader.api.registry.RegistryAddException; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.client.Dazy; import dev.notalpha.dashloader.client.model.fallback.UnbakedBakedModel; import dev.notalpha.dashloader.config.ConfigHandler; import dev.notalpha.dashloader.config.Option; import dev.notalpha.dashloader.mixin.accessor.ModelLoaderAccessor; -import dev.notalpha.dashloader.registry.RegistryAddException; import dev.notalpha.taski.builtin.StepTask; import net.minecraft.block.Block; import net.minecraft.block.BlockState; @@ -33,8 +34,9 @@ public class ModelModule implements DashModule { public static final CachingData> MODELS_LOAD = new CachingData<>(CacheStatus.LOAD); public static final CachingData> MISSING_READ = new CachingData<>(); public static final CachingData, StateManager>>> MULTIPART_PREDICATES = new CachingData<>(CacheStatus.SAVE); + @Override - public void reset(DashCache cache) { + public void reset(Cache cache) { MODELS_SAVE.reset(cache, new HashMap<>()); MODELS_LOAD.reset(cache, new HashMap<>()); MISSING_READ.reset(cache, new HashMap<>()); @@ -42,7 +44,7 @@ public void reset(DashCache cache) { } @Override - public Data save(RegistryWriter writer, StepTask task) { + public Data save(RegistryWriter factory, StepTask task) { var models = MODELS_SAVE.get(CacheStatus.SAVE); if (models == null) { @@ -55,8 +57,8 @@ public Data save(RegistryWriter writer, StepTask task) { task.doForEach(models, (identifier, bakedModel) -> { if (bakedModel != null) { try { - final int add = writer.add(bakedModel); - outModels.put(writer.add(identifier), add); + final int add = factory.add(bakedModel); + outModels.put(factory.add(identifier), add); out.add(identifier); } catch (RegistryAddException ignored) { // Fallback is checked later with the blockstates missing. @@ -70,7 +72,7 @@ public Data save(RegistryWriter writer, StepTask task) { block.getStateManager().getStates().forEach((blockState) -> { final ModelIdentifier modelId = BlockModels.getModelId(blockState); if (!out.contains(modelId)) { - missingModels.put(writer.add(blockState), writer.add(modelId)); + missingModels.put(factory.add(blockState), factory.add(modelId)); } }); } @@ -80,16 +82,16 @@ public Data save(RegistryWriter writer, StepTask task) { } @Override - public void load(Data mappings, RegistryReader reader, StepTask task) { - final HashMap out = new HashMap<>(mappings.models.list().size()); - mappings.models.forEach((key, value) -> { - BakedModel model = reader.get(value); + public void load(Data data, RegistryReader reader, StepTask task) { + final HashMap out = new HashMap<>(data.models.list().size()); + data.models.forEach((key, value) -> { + Dazy model = reader.get(value); Identifier identifier = reader.get(key); - out.put(identifier, new UnbakedBakedModel(model, identifier)); + out.put(identifier, new UnbakedBakedModel(model)); }); var missingModelsRead = new HashMap(); - mappings.missingModels.forEach((blockState, modelId) -> { + data.missingModels.forEach((blockState, modelId) -> { missingModelsRead.put(reader.get(blockState), reader.get(modelId)); }); diff --git a/src/main/java/dev/notalpha/dashloader/client/model/components/BakedQuadCollection.java b/common/src/main/java/dev/notalpha/dashloader/client/model/components/BakedQuadCollection.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/client/model/components/BakedQuadCollection.java rename to common/src/main/java/dev/notalpha/dashloader/client/model/components/BakedQuadCollection.java diff --git a/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuad.java b/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuad.java similarity index 55% rename from src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuad.java rename to common/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuad.java index 1d0c7f9b..97be8df4 100644 --- a/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuad.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuad.java @@ -1,14 +1,19 @@ package dev.notalpha.dashloader.client.model.components; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.api.RegistryWriter; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.client.Dazy; +import dev.notalpha.dashloader.client.sprite.DashSprite; import net.minecraft.client.render.model.BakedQuad; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.SpriteIdentifier; import net.minecraft.util.math.Direction; import java.util.Arrays; +import java.util.function.Function; -public final class DashBakedQuad implements DashObject { +public final class DashBakedQuad implements DashObject { public final int[] vertexData; public final int colorIndex; public final Direction face; @@ -28,8 +33,8 @@ public DashBakedQuad(BakedQuad bakedQuad, RegistryWriter writer) { this(bakedQuad.getVertexData(), bakedQuad.getColorIndex(), bakedQuad.getFace(), bakedQuad.hasShade(), writer.add(bakedQuad.getSprite())); } - public BakedQuad export(RegistryReader handler) { - return new BakedQuad(this.vertexData, this.colorIndex, this.face, handler.get(this.sprite), this.shade); + public DazyImpl export(RegistryReader handler) { + return new DazyImpl(this.vertexData, this.colorIndex, this.face, this.shade, handler.get(this.sprite)); } @Override @@ -55,4 +60,26 @@ public int hashCode() { result = 31 * result + sprite; return result; } + + public static class DazyImpl extends Dazy { + public final int[] vertexData; + public final int colorIndex; + public final Direction face; + public final boolean shade; + public final DashSprite.DazyImpl sprite; + + public DazyImpl(int[] vertexData, int colorIndex, Direction face, boolean shade, DashSprite.DazyImpl sprite) { + this.vertexData = vertexData; + this.colorIndex = colorIndex; + this.face = face; + this.shade = shade; + this.sprite = sprite; + } + + @Override + protected BakedQuad resolve(Function spriteLoader) { + Sprite sprite = this.sprite.get(spriteLoader); + return new BakedQuad(vertexData, colorIndex, face, sprite, shade); + } + } } diff --git a/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuadCollection.java b/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuadCollection.java similarity index 50% rename from src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuadCollection.java rename to common/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuadCollection.java index ee566fb4..9dd82cb8 100644 --- a/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuadCollection.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuadCollection.java @@ -1,14 +1,18 @@ package dev.notalpha.dashloader.client.model.components; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.api.RegistryWriter; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.client.Dazy; import net.minecraft.client.render.model.BakedQuad; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.SpriteIdentifier; import java.util.ArrayList; import java.util.List; +import java.util.function.Function; -public class DashBakedQuadCollection implements DashObject { +public class DashBakedQuadCollection implements DashObject { public final List quads; public DashBakedQuadCollection(List quads) { @@ -23,12 +27,12 @@ public DashBakedQuadCollection(BakedQuadCollection quads, RegistryWriter writer) } @Override - public BakedQuadCollection export(RegistryReader reader) { - var out = new ArrayList(this.quads.size()); + public DazyImpl export(RegistryReader reader) { + var out = new ArrayList(this.quads.size()); for (Integer quad : this.quads) { out.add(reader.get(quad)); } - return new BakedQuadCollection(out); + return new DazyImpl(out); } @Override @@ -45,4 +49,23 @@ public boolean equals(Object o) { public int hashCode() { return quads.hashCode(); } + + public static class DazyImpl extends Dazy> { + public final List quads; + + public DazyImpl(List quads) { + this.quads = quads; + } + + @Override + protected List resolve(Function spriteLoader) { + var out = new ArrayList(quads.size()); + quads.forEach( + dazyBakedQuad -> { + out.add(dazyBakedQuad.get(spriteLoader)); + } + ); + return out; + } + } } diff --git a/src/main/java/dev/notalpha/dashloader/client/model/components/DashMesh.java b/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashMesh.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/client/model/components/DashMesh.java rename to common/src/main/java/dev/notalpha/dashloader/client/model/components/DashMesh.java diff --git a/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideList.java b/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideList.java similarity index 60% rename from src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideList.java rename to common/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideList.java index bb34f91d..0e13f458 100644 --- a/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideList.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideList.java @@ -1,12 +1,16 @@ package dev.notalpha.dashloader.client.model.components; -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.api.RegistryWriter; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.client.Dazy; import dev.notalpha.dashloader.mixin.accessor.ModelOverrideListAccessor; import net.minecraft.client.render.model.json.ModelOverrideList; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.SpriteIdentifier; import net.minecraft.util.Identifier; import java.util.Arrays; +import java.util.function.Function; public final class DashModelOverrideList { public final DashModelOverrideListBakedOverride[] overrides; @@ -33,23 +37,18 @@ public DashModelOverrideList(ModelOverrideList modelOverrideList, RegistryWriter } } - public ModelOverrideList export(RegistryReader reader) { - var out = ModelOverrideListAccessor.newModelOverrideList(); - ModelOverrideListAccessor access = (ModelOverrideListAccessor) out; - + public DazyImpl export(RegistryReader reader) { var conditionTypesOut = new Identifier[this.conditionTypes.length]; for (int i = 0; i < this.conditionTypes.length; i++) { conditionTypesOut[i] = reader.get(this.conditionTypes[i]); } - var overridesOut = new ModelOverrideList.BakedOverride[this.overrides.length]; + var overridesOut = new DashModelOverrideListBakedOverride.DazyImpl[this.overrides.length]; for (int i = 0; i < this.overrides.length; i++) { overridesOut[i] = this.overrides[i].export(reader); } - access.setConditionTypes(conditionTypesOut); - access.setOverrides(overridesOut); - return out; + return new DazyImpl(overridesOut, conditionTypesOut); } @Override @@ -70,4 +69,28 @@ public int hashCode() { result = 31 * result + Arrays.hashCode(conditionTypes); return result; } + + public static class DazyImpl extends Dazy { + public final DashModelOverrideListBakedOverride.DazyImpl[] overrides; + public final Identifier[] conditionTypes; //identifiers + + public DazyImpl(DashModelOverrideListBakedOverride.DazyImpl[] overrides, Identifier[] conditionTypes) { + this.overrides = overrides; + this.conditionTypes = conditionTypes; + } + + @Override + protected ModelOverrideList resolve(Function spriteLoader) { + var out = ModelOverrideListAccessor.newModelOverrideList(); + ModelOverrideListAccessor access = (ModelOverrideListAccessor) out; + + var overridesOut = new ModelOverrideList.BakedOverride[this.overrides.length]; + for (int i = 0; i < this.overrides.length; i++) { + overridesOut[i] = this.overrides[i].get(spriteLoader); + } + access.setConditionTypes(conditionTypes); + access.setOverrides(overridesOut); + return out; + } + } } diff --git a/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListBakedOverride.java b/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListBakedOverride.java similarity index 64% rename from src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListBakedOverride.java rename to common/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListBakedOverride.java index 00137154..84b11e43 100644 --- a/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListBakedOverride.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListBakedOverride.java @@ -1,15 +1,19 @@ package dev.notalpha.dashloader.client.model.components; -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.api.RegistryWriter; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.client.Dazy; import dev.notalpha.dashloader.mixin.accessor.ModelOverrideListBakedOverrideAccessor; -import dev.notalpha.hyphen.scan.annotations.DataNullable; +import dev.quantumfusion.hyphen.scan.annotations.DataNullable; import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.json.ModelOverrideList; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.SpriteIdentifier; import org.jetbrains.annotations.Nullable; import java.util.Arrays; import java.util.Objects; +import java.util.function.Function; public final class DashModelOverrideListBakedOverride { public final DashModelOverrideListInlinedCondition[] conditions; @@ -32,13 +36,13 @@ public DashModelOverrideListBakedOverride(ModelOverrideList.BakedOverride overri } } - public ModelOverrideList.BakedOverride export(RegistryReader reader) { + public DazyImpl export(RegistryReader reader) { var conditionsOut = new ModelOverrideList.InlinedCondition[this.conditions.length]; for (int i = 0; i < this.conditions.length; i++) { conditionsOut[i] = this.conditions[i].export(); } - return ModelOverrideListBakedOverrideAccessor.newModelOverrideListBakedOverride(conditionsOut, this.model == null ? null : reader.get(this.model)); + return new DazyImpl(conditionsOut, this.model == null ? null : reader.get(this.model)); } @Override @@ -59,4 +63,22 @@ public int hashCode() { result = 31 * result + (model != null ? model.hashCode() : 0); return result; } + + + public static class DazyImpl extends Dazy { + public final ModelOverrideList.InlinedCondition[] conditions; + @Nullable + public final Dazy model; + + public DazyImpl(ModelOverrideList.InlinedCondition[] conditions, Dazy model) { + this.conditions = conditions; + this.model = model; + } + + @Override + protected ModelOverrideList.BakedOverride resolve(Function spriteLoader) { + BakedModel bakedModel = model == null ? null : model.get(spriteLoader); + return ModelOverrideListBakedOverrideAccessor.newModelOverrideListBakedOverride(conditions, bakedModel); + } + } } diff --git a/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListInlinedCondition.java b/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListInlinedCondition.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListInlinedCondition.java rename to common/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListInlinedCondition.java diff --git a/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelTransformation.java b/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelTransformation.java similarity index 96% rename from src/main/java/dev/notalpha/dashloader/client/model/components/DashModelTransformation.java rename to common/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelTransformation.java index cde1017c..21c9a51a 100644 --- a/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelTransformation.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelTransformation.java @@ -1,28 +1,21 @@ package dev.notalpha.dashloader.client.model.components; -import dev.notalpha.hyphen.scan.annotations.DataNullable; +import dev.quantumfusion.hyphen.scan.annotations.DataNullable; import net.minecraft.client.render.model.json.ModelTransformation; import net.minecraft.client.render.model.json.Transformation; import org.jetbrains.annotations.Nullable; import java.util.Objects; +@DataNullable public final class DashModelTransformation { - @DataNullable public final Transformation thirdPersonLeftHand; - @DataNullable public final Transformation thirdPersonRightHand; - @DataNullable public final Transformation firstPersonLeftHand; - @DataNullable public final Transformation firstPersonRightHand; - @DataNullable public final Transformation head; - @DataNullable public final Transformation gui; - @DataNullable public final Transformation ground; - @DataNullable public final Transformation fixed; public transient int nullTransformations = 0; diff --git a/src/main/java/dev/notalpha/dashloader/client/model/components/DashWeightedModelEntry.java b/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashWeightedModelEntry.java similarity index 68% rename from src/main/java/dev/notalpha/dashloader/client/model/components/DashWeightedModelEntry.java rename to common/src/main/java/dev/notalpha/dashloader/client/model/components/DashWeightedModelEntry.java index da2bec08..f7dcd5db 100644 --- a/src/main/java/dev/notalpha/dashloader/client/model/components/DashWeightedModelEntry.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashWeightedModelEntry.java @@ -1,10 +1,9 @@ package dev.notalpha.dashloader.client.model.components; -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.api.RegistryWriter; -import dev.notalpha.dashloader.mixin.accessor.WeightedBakedModelEntryAccessor; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.client.model.DashWeightedBakedModel; import net.minecraft.client.render.model.BakedModel; -import net.minecraft.util.collection.Weight; import net.minecraft.util.collection.Weighted; public final class DashWeightedModelEntry { @@ -21,9 +20,8 @@ public DashWeightedModelEntry(Weighted.Present entry, RegistryWriter } - public Weighted.Present export(RegistryReader handler) { - //noinspection unchecked - return WeightedBakedModelEntryAccessor.init(handler.get(this.model), Weight.of(this.weight)); + public DashWeightedBakedModel.DazyImpl.Entry export(RegistryReader handler) { + return new DashWeightedBakedModel.DazyImpl.Entry(this.weight, handler.get(this.model)); } @Override diff --git a/src/main/java/dev/notalpha/dashloader/client/model/fallback/UnbakedBakedModel.java b/common/src/main/java/dev/notalpha/dashloader/client/model/fallback/UnbakedBakedModel.java similarity index 74% rename from src/main/java/dev/notalpha/dashloader/client/model/fallback/UnbakedBakedModel.java rename to common/src/main/java/dev/notalpha/dashloader/client/model/fallback/UnbakedBakedModel.java index 04de939f..903a7876 100644 --- a/src/main/java/dev/notalpha/dashloader/client/model/fallback/UnbakedBakedModel.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/model/fallback/UnbakedBakedModel.java @@ -1,5 +1,6 @@ package dev.notalpha.dashloader.client.model.fallback; +import dev.notalpha.dashloader.client.Dazy; import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.Baker; import net.minecraft.client.render.model.ModelBakeSettings; @@ -18,12 +19,10 @@ /** * An unbaked model which holds a baked model, used for fallback to reuse cached models. */ -public class UnbakedBakedModel extends JsonUnbakedModel implements UnbakedModel { - private final BakedModel bakedModel; +public class UnbakedBakedModel implements UnbakedModel { + private final Dazy bakedModel; - public UnbakedBakedModel(BakedModel bakedModel, Identifier identifier) { - super(null, List.of(), Map.of(), bakedModel.useAmbientOcclusion(), GuiLight.ITEM, ModelTransformation.NONE, List.of()); - this.id = identifier.toString(); + public UnbakedBakedModel(Dazy bakedModel) { this.bakedModel = bakedModel; } @@ -38,6 +37,6 @@ public void setParents(Function modelLoader) { @Override public BakedModel bake(Baker baker, Function textureGetter, ModelBakeSettings rotationContainer, Identifier modelId) { - return this.bakedModel; + return this.bakedModel.get(textureGetter); } } diff --git a/src/main/java/dev/notalpha/dashloader/client/model/predicates/BooleanSelector.java b/common/src/main/java/dev/notalpha/dashloader/client/model/predicates/BooleanSelector.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/client/model/predicates/BooleanSelector.java rename to common/src/main/java/dev/notalpha/dashloader/client/model/predicates/BooleanSelector.java diff --git a/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashAndPredicate.java b/common/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashAndPredicate.java similarity index 91% rename from src/main/java/dev/notalpha/dashloader/client/model/predicates/DashAndPredicate.java rename to common/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashAndPredicate.java index 05797de3..45377653 100644 --- a/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashAndPredicate.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashAndPredicate.java @@ -1,8 +1,8 @@ package dev.notalpha.dashloader.client.model.predicates; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.api.RegistryWriter; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; import dev.notalpha.dashloader.mixin.accessor.AndMultipartModelSelectorAccessor; import net.minecraft.client.render.model.json.AndMultipartModelSelector; import net.minecraft.client.render.model.json.MultipartModelSelector; @@ -11,7 +11,7 @@ import java.util.Arrays; import java.util.List; -public final class DashAndPredicate implements DashObject { +public final class DashAndPredicate implements DashObject { public final int[] selectors; public DashAndPredicate(int[] selectors) { diff --git a/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashOrPredicate.java b/common/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashOrPredicate.java similarity index 91% rename from src/main/java/dev/notalpha/dashloader/client/model/predicates/DashOrPredicate.java rename to common/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashOrPredicate.java index f1f13920..9a208f5a 100644 --- a/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashOrPredicate.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashOrPredicate.java @@ -1,8 +1,8 @@ package dev.notalpha.dashloader.client.model.predicates; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.api.RegistryWriter; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; import dev.notalpha.dashloader.mixin.accessor.OrMultipartModelSelectorAccessor; import net.minecraft.client.render.model.json.MultipartModelSelector; import net.minecraft.client.render.model.json.OrMultipartModelSelector; @@ -12,7 +12,7 @@ import java.util.List; -public final class DashOrPredicate implements DashObject { +public final class DashOrPredicate implements DashObject { public final int[] selectors; public DashOrPredicate(int[] selectors) { diff --git a/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashSimplePredicate.java b/common/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashSimplePredicate.java similarity index 91% rename from src/main/java/dev/notalpha/dashloader/client/model/predicates/DashSimplePredicate.java rename to common/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashSimplePredicate.java index cf72e8d5..9395653b 100644 --- a/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashSimplePredicate.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashSimplePredicate.java @@ -1,12 +1,12 @@ package dev.notalpha.dashloader.client.model.predicates; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryReader; import dev.notalpha.dashloader.mixin.accessor.SimpleMultipartModelSelectorAccessor; import net.minecraft.client.render.model.json.SimpleMultipartModelSelector; -public final class DashSimplePredicate implements DashObject { +public final class DashSimplePredicate implements DashObject { public final String key; public final String valueString; diff --git a/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashStaticPredicate.java b/common/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashStaticPredicate.java similarity index 89% rename from src/main/java/dev/notalpha/dashloader/client/model/predicates/DashStaticPredicate.java rename to common/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashStaticPredicate.java index c5681d36..f4419be8 100644 --- a/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashStaticPredicate.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashStaticPredicate.java @@ -1,9 +1,9 @@ package dev.notalpha.dashloader.client.model.predicates; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryReader; -public final class DashStaticPredicate implements DashObject { +public final class DashStaticPredicate implements DashObject { public final boolean value; public DashStaticPredicate(boolean value) { diff --git a/src/main/java/dev/notalpha/dashloader/client/shader/DashGlBlendState.java b/common/src/main/java/dev/notalpha/dashloader/client/shader/DashGlBlendState.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/client/shader/DashGlBlendState.java rename to common/src/main/java/dev/notalpha/dashloader/client/shader/DashGlBlendState.java diff --git a/src/main/java/dev/notalpha/dashloader/client/shader/DashGlUniform.java b/common/src/main/java/dev/notalpha/dashloader/client/shader/DashGlUniform.java similarity index 95% rename from src/main/java/dev/notalpha/dashloader/client/shader/DashGlUniform.java rename to common/src/main/java/dev/notalpha/dashloader/client/shader/DashGlUniform.java index 6b3c2a35..d563c837 100644 --- a/src/main/java/dev/notalpha/dashloader/client/shader/DashGlUniform.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/shader/DashGlUniform.java @@ -2,7 +2,7 @@ import dev.notalpha.dashloader.io.IOHelper; import dev.notalpha.dashloader.mixin.accessor.GlUniformAccessor; -import dev.notalpha.hyphen.scan.annotations.DataNullable; +import dev.quantumfusion.hyphen.scan.annotations.DataNullable; import net.minecraft.client.gl.GlUniform; import net.minecraft.client.gl.ShaderProgram; @@ -33,7 +33,6 @@ public DashGlUniform(GlUniform glUniform, boolean loaded) { } - public GlUniform export(ShaderProgram shader) { GlUniform glUniform = new GlUniform(this.name, this.dataType, 0, shader); GlUniformAccessor access = (GlUniformAccessor) glUniform; diff --git a/src/main/java/dev/notalpha/dashloader/client/shader/DashShader.java b/common/src/main/java/dev/notalpha/dashloader/client/shader/DashShader.java similarity index 95% rename from src/main/java/dev/notalpha/dashloader/client/shader/DashShader.java rename to common/src/main/java/dev/notalpha/dashloader/client/shader/DashShader.java index 4abdb133..8aecd44f 100644 --- a/src/main/java/dev/notalpha/dashloader/client/shader/DashShader.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/shader/DashShader.java @@ -3,19 +3,19 @@ import com.google.common.collect.ImmutableList; import com.mojang.blaze3d.platform.GlStateManager; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.api.RegistryWriter; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; import dev.notalpha.dashloader.misc.UnsafeHelper; import dev.notalpha.dashloader.mixin.accessor.ShaderProgramAccessor; -import dev.notalpha.hyphen.scan.annotations.DataNullable; -import dev.notalpha.hyphen.scan.annotations.DataSubclasses; +import dev.quantumfusion.hyphen.scan.annotations.DataNullable; +import dev.quantumfusion.hyphen.scan.annotations.DataSubclasses; import net.minecraft.client.gl.GlProgramManager; import net.minecraft.client.gl.GlUniform; import net.minecraft.client.gl.ShaderProgram; import java.util.*; -public final class DashShader implements DashObject { +public final class DashShader implements DashObject { public final Map samplers; public final String name; public final DashGlBlendState blendState; diff --git a/src/main/java/dev/notalpha/dashloader/client/shader/DashShaderStage.java b/common/src/main/java/dev/notalpha/dashloader/client/shader/DashShaderStage.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/client/shader/DashShaderStage.java rename to common/src/main/java/dev/notalpha/dashloader/client/shader/DashShaderStage.java diff --git a/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormat.java b/common/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormat.java similarity index 94% rename from src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormat.java rename to common/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormat.java index 2655f910..f98a073c 100644 --- a/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormat.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormat.java @@ -2,9 +2,9 @@ import com.google.common.collect.ImmutableMap; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryReader; import dev.notalpha.dashloader.mixin.accessor.VertexFormatAccessor; -import dev.notalpha.hyphen.scan.annotations.DataNullable; +import dev.quantumfusion.hyphen.scan.annotations.DataNullable; import net.minecraft.client.render.VertexFormat; import net.minecraft.client.render.VertexFormatElement; import net.minecraft.client.render.VertexFormats; @@ -14,7 +14,7 @@ import java.util.List; import java.util.Map; -public class DashVertexFormat implements DashObject { +public class DashVertexFormat implements DashObject { public static final List BUILT_IN = new ArrayList<>(); static { diff --git a/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormatElement.java b/common/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormatElement.java similarity index 93% rename from src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormatElement.java rename to common/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormatElement.java index 0adf9bce..f37b0a4a 100644 --- a/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormatElement.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormatElement.java @@ -1,15 +1,15 @@ package dev.notalpha.dashloader.client.shader; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.hyphen.scan.annotations.DataNullable; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.quantumfusion.hyphen.scan.annotations.DataNullable; import net.minecraft.client.render.VertexFormatElement; import net.minecraft.client.render.VertexFormats; import java.util.ArrayList; import java.util.List; -public class DashVertexFormatElement implements DashObject { +public class DashVertexFormatElement implements DashObject { public static final List BUILT_IN = new ArrayList<>(); static { diff --git a/src/main/java/dev/notalpha/dashloader/client/shader/ShaderModule.java b/common/src/main/java/dev/notalpha/dashloader/client/shader/ShaderModule.java similarity index 67% rename from src/main/java/dev/notalpha/dashloader/client/shader/ShaderModule.java rename to common/src/main/java/dev/notalpha/dashloader/client/shader/ShaderModule.java index 350f8141..0136eddb 100644 --- a/src/main/java/dev/notalpha/dashloader/client/shader/ShaderModule.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/shader/ShaderModule.java @@ -1,12 +1,12 @@ package dev.notalpha.dashloader.client.shader; -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.api.RegistryWriter; +import dev.notalpha.dashloader.api.CachingData; +import dev.notalpha.dashloader.api.DashModule; +import dev.notalpha.dashloader.api.cache.Cache; import dev.notalpha.dashloader.api.cache.CacheStatus; -import dev.notalpha.dashloader.api.cache.CachingData; -import dev.notalpha.dashloader.api.cache.DashCache; -import dev.notalpha.dashloader.api.cache.DashModule; import dev.notalpha.dashloader.api.collection.ObjectIntList; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; import dev.notalpha.dashloader.config.ConfigHandler; import dev.notalpha.dashloader.config.Option; import dev.notalpha.taski.builtin.StepTask; @@ -24,30 +24,28 @@ public class ShaderModule implements DashModule { public static final CachingData>> WRITE_PROGRAM_SOURCES = new CachingData<>(CacheStatus.SAVE); @Override - public void reset(DashCache cacheManager) { - SHADERS.reset(cacheManager, new HashMap<>()); - WRITE_PROGRAM_SOURCES.reset(cacheManager, new Int2ObjectOpenHashMap<>()); + public void reset(Cache cache) { + SHADERS.reset(cache, new HashMap<>()); + WRITE_PROGRAM_SOURCES.reset(cache, new Int2ObjectOpenHashMap<>()); } @Override - public Data save(RegistryWriter writer, StepTask task) { + public Data save(RegistryWriter factory, StepTask task) { final Map minecraftData = SHADERS.get(CacheStatus.SAVE); if (minecraftData == null) { return null; } var shaders = new ObjectIntList(); - task.doForEach(minecraftData, (s, shader) -> { - shaders.put(s, writer.add(shader)); - }); + task.doForEach(minecraftData, (s, shader) -> shaders.put(s, factory.add(shader))); return new Data(shaders); } @Override - public void load(Data mappings, RegistryReader reader, StepTask task) { + public void load(Data data, RegistryReader reader, StepTask task) { HashMap out = new HashMap<>(); - mappings.shaders.forEach((key, value) -> out.put(key, reader.get(value))); + data.shaders.forEach((key, value) -> out.put(key, reader.get(value))); SHADERS.set(CacheStatus.LOAD, out); } diff --git a/src/main/java/dev/notalpha/dashloader/client/splash/SplashModule.java b/common/src/main/java/dev/notalpha/dashloader/client/splash/SplashModule.java similarity index 67% rename from src/main/java/dev/notalpha/dashloader/client/splash/SplashModule.java rename to common/src/main/java/dev/notalpha/dashloader/client/splash/SplashModule.java index 6535dd8a..c5da26e9 100644 --- a/src/main/java/dev/notalpha/dashloader/client/splash/SplashModule.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/splash/SplashModule.java @@ -1,11 +1,11 @@ package dev.notalpha.dashloader.client.splash; -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.api.RegistryWriter; +import dev.notalpha.dashloader.api.CachingData; +import dev.notalpha.dashloader.api.DashModule; +import dev.notalpha.dashloader.api.cache.Cache; import dev.notalpha.dashloader.api.cache.CacheStatus; -import dev.notalpha.dashloader.api.cache.CachingData; -import dev.notalpha.dashloader.api.cache.DashCache; -import dev.notalpha.dashloader.api.cache.DashModule; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; import dev.notalpha.dashloader.config.ConfigHandler; import dev.notalpha.dashloader.config.Option; import dev.notalpha.taski.builtin.StepTask; @@ -18,8 +18,8 @@ public class SplashModule implements DashModule { public static final CachingData> TEXTS = new CachingData<>(); @Override - public void reset(DashCache cacheManager) { - TEXTS.reset(cacheManager, new ArrayList<>()); + public void reset(Cache cache) { + TEXTS.reset(cache, new ArrayList<>()); } @Override @@ -28,8 +28,8 @@ public Data save(RegistryWriter writer, StepTask task) { } @Override - public void load(Data mappings, RegistryReader reader, StepTask task) { - TEXTS.set(CacheStatus.LOAD, mappings.splashList); + public void load(Data data, RegistryReader reader, StepTask task) { + TEXTS.set(CacheStatus.LOAD, data.splashList); } @Override diff --git a/src/main/java/dev/notalpha/dashloader/client/sprite/DashImage.java b/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashImage.java similarity index 92% rename from src/main/java/dev/notalpha/dashloader/client/sprite/DashImage.java rename to common/src/main/java/dev/notalpha/dashloader/client/sprite/DashImage.java index 517d3cec..7ad960c6 100644 --- a/src/main/java/dev/notalpha/dashloader/client/sprite/DashImage.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashImage.java @@ -1,7 +1,7 @@ package dev.notalpha.dashloader.client.sprite; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryReader; import dev.notalpha.dashloader.io.def.NativeImageData; import dev.notalpha.dashloader.mixin.accessor.NativeImageAccessor; import net.minecraft.client.texture.NativeImage; @@ -9,7 +9,7 @@ import java.nio.ByteBuffer; -public final class DashImage implements DashObject { +public final class DashImage implements DashObject { public final NativeImageData image; public final NativeImage.Format format; public final boolean useSTB; diff --git a/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashSprite.java b/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashSprite.java new file mode 100644 index 00000000..58ddbae6 --- /dev/null +++ b/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashSprite.java @@ -0,0 +1,54 @@ +package dev.notalpha.dashloader.client.sprite; + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.client.Dazy; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.SpriteIdentifier; + +import java.util.function.Function; + +public class DashSprite implements DashObject { + public final int id; + + public DashSprite(int id) { + this.id = id; + } + + public DashSprite(Sprite sprite, RegistryWriter writer) { + this.id = writer.add(new SpriteIdentifier(sprite.getAtlasId(), sprite.getContents().getId())); + } + + @Override + public DazyImpl export(final RegistryReader registry) { + return new DazyImpl(registry.get(id)); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DashSprite that = (DashSprite) o; + + return id == that.id; + } + + @Override + public int hashCode() { + return id; + } + + public static class DazyImpl extends Dazy { + public final SpriteIdentifier location; + + public DazyImpl(SpriteIdentifier location) { + this.location = location; + } + @Override + protected Sprite resolve(Function spriteLoader) { + return spriteLoader.apply(location); + } + } +} diff --git a/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimation.java b/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimation.java similarity index 96% rename from src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimation.java rename to common/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimation.java index aa165640..ec3ef01e 100644 --- a/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimation.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimation.java @@ -1,6 +1,6 @@ package dev.notalpha.dashloader.client.sprite; -import dev.notalpha.dashloader.api.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryReader; import dev.notalpha.dashloader.mixin.accessor.SpriteAnimationAccessor; import net.minecraft.client.texture.SpriteContents; diff --git a/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimationFrame.java b/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimationFrame.java similarity index 90% rename from src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimationFrame.java rename to common/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimationFrame.java index 4179b6e3..1216a9a7 100644 --- a/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimationFrame.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimationFrame.java @@ -1,11 +1,11 @@ package dev.notalpha.dashloader.client.sprite; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryReader; import dev.notalpha.dashloader.mixin.accessor.SpriteAnimationFrameAccessor; import net.minecraft.client.texture.SpriteContents; -public final class DashSpriteAnimationFrame implements DashObject { +public final class DashSpriteAnimationFrame implements DashObject { public final int index; public final int time; diff --git a/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteContents.java b/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteContents.java similarity index 92% rename from src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteContents.java rename to common/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteContents.java index db90db14..3ad5a9a7 100644 --- a/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteContents.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteContents.java @@ -1,10 +1,10 @@ package dev.notalpha.dashloader.client.sprite; -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.api.RegistryWriter; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; import dev.notalpha.dashloader.misc.UnsafeHelper; import dev.notalpha.dashloader.mixin.accessor.SpriteContentsAccessor; -import dev.notalpha.hyphen.scan.annotations.DataNullable; +import dev.quantumfusion.hyphen.scan.annotations.DataNullable; import net.minecraft.client.texture.NativeImage; import net.minecraft.client.texture.SpriteContents; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/dev/notalpha/dashloader/client/sprite/DashStitchResult.java b/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashStitchResult.java similarity index 91% rename from src/main/java/dev/notalpha/dashloader/client/sprite/DashStitchResult.java rename to common/src/main/java/dev/notalpha/dashloader/client/sprite/DashStitchResult.java index 02f15c1f..3a5034c1 100644 --- a/src/main/java/dev/notalpha/dashloader/client/sprite/DashStitchResult.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashStitchResult.java @@ -1,8 +1,8 @@ package dev.notalpha.dashloader.client.sprite; -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.api.RegistryWriter; import dev.notalpha.dashloader.api.collection.IntIntList; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; import dev.notalpha.taski.builtin.StepTask; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import net.minecraft.client.texture.Sprite; @@ -43,9 +43,7 @@ public DashStitchResult(SpriteLoader.StitchResult stitchResult, RegistryWriter w public SpriteLoader.StitchResult export(RegistryReader reader) { Map regions = new Object2ObjectOpenHashMap<>(); - this.regions.forEach((key, value) -> { - regions.put(reader.get(key), reader.get(value)); - }); + this.regions.forEach((key, value) -> regions.put(reader.get(key), reader.get(value))); return new SpriteLoader.StitchResult( this.width, diff --git a/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashTextureSlot.java b/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashTextureSlot.java new file mode 100644 index 00000000..bee1d428 --- /dev/null +++ b/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashTextureSlot.java @@ -0,0 +1,18 @@ +package dev.notalpha.dashloader.client.sprite; + +import net.minecraft.client.texture.TextureStitcher; + +public class DashTextureSlot { + public final int x; + public final int y; + public final int width; + public final int height; + public transient T contents; + + public DashTextureSlot(int x, int y, int width, int height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } +} diff --git a/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashTextureStitcher.java b/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashTextureStitcher.java new file mode 100644 index 00000000..9fe99f24 --- /dev/null +++ b/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashTextureStitcher.java @@ -0,0 +1,162 @@ +package dev.notalpha.dashloader.client.sprite; + +import dev.notalpha.dashloader.DashLoader; +import dev.notalpha.dashloader.api.collection.IntObjectList; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import net.minecraft.client.texture.TextureStitcher; +import net.minecraft.util.Identifier; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; + +public class DashTextureStitcher extends TextureStitcher { + @Nullable + private ExportedData data; + private int remainingSlots; + + public DashTextureStitcher(int maxWidth, int maxHeight, int mipLevel, @Nullable ExportedData data) { + super(maxWidth, maxHeight, mipLevel); + this.data = data; + this.remainingSlots = data == null ? 0 : data.slots.size(); + } + + @Override + public int getWidth() { + if (this.data == null) { + return super.getWidth(); + } + return data.width; + } + + @Override + public int getHeight() { + if (this.data == null) { + return super.getHeight(); + } + return data.height; + } + + @Override + public void add(T info) { + if (data == null) { + super.add(info); + return; + } + + // If it starts recaching, doRecache will re-add the entries to the list. + var id = info.getId(); + var slot = data.slots.get(id); + if (slot == null) { + DashLoader.LOG.warn("Sprite {} was not cached last time.", id); + + doFallback(); + // This was never added to the slot, so it would not get added to super. + this.add(info); + return; + } + + if (slot.contents != null) { + DashLoader.LOG.warn("Sprite {} was added twice??", id); + } + + remainingSlots -= 1; + slot.contents = info; + + if (slot.width != info.getWidth() || slot.height != info.getHeight()) { + DashLoader.LOG.warn("Sprite {} had changed dimensions since last launch, falling back.", id); + doFallback(); + return; + } + } + + public void doFallback() { + if (data != null) { + DashLoader.LOG.error("Using fallback on texture stitcher."); + var slots = data.slots; + data = null; + slots.forEach((identifier, tDashTextureSlot) -> { + if (tDashTextureSlot.contents != null) { + this.add(tDashTextureSlot.contents); + } + }); + } else { + DashLoader.LOG.error("Tried to fallback stitcher twice."); + } + } + + @Override + public void stitch() { + if (data != null && remainingSlots != 0) { + DashLoader.LOG.warn("Remaining slots did not match the cached amount, Falling back."); + data.slots.forEach((identifier, tDashTextureSlot) -> { + if (tDashTextureSlot.contents == null) { + DashLoader.LOG.error("Sprite {} was not requested", identifier); + } + }); + doFallback(); + } + + if (data == null) { + super.stitch(); + } + } + + @Override + public void getStitchedSprites(SpriteConsumer consumer) { + if (data == null) { + super.getStitchedSprites(consumer); + } else { + data.slots.forEach((identifier, dashTextureSlot) -> { + consumer.load(dashTextureSlot.contents, dashTextureSlot.x, dashTextureSlot.y); + }); + } + } + + public static class Data { + public final IntObjectList> slots; + public final int width; + public final int height; + + public Data(IntObjectList> slots, int width, int height) { + this.slots = slots; + this.width = width; + this.height = height; + } + + public Data(RegistryWriter factory, TextureStitcher stitcher) { + this.slots = new IntObjectList<>(); + stitcher.getStitchedSprites((info, x, y) -> { + this.slots.put(factory.add(info.getId()), new DashTextureSlot<>(x, y, info.getWidth(), info.getHeight())); + }); + this.width = stitcher.getWidth(); + this.height = stitcher.getHeight(); + } + + public ExportedData export(RegistryReader reader) { + var output = new HashMap>(); + this.slots.forEach((key, value) -> { + output.put(reader.get(key), value); + }); + + return new ExportedData<>( + output, + width, + height + ); + } + } + + public static class ExportedData { + public final Map> slots; + public final int width; + public final int height; + + public ExportedData(Map> slots, int width, int height) { + this.slots = slots; + this.width = width; + this.height = height; + } + } +} diff --git a/common/src/main/java/dev/notalpha/dashloader/client/sprite/SpriteStitcherModule.java b/common/src/main/java/dev/notalpha/dashloader/client/sprite/SpriteStitcherModule.java new file mode 100644 index 00000000..b9feebac --- /dev/null +++ b/common/src/main/java/dev/notalpha/dashloader/client/sprite/SpriteStitcherModule.java @@ -0,0 +1,111 @@ +package dev.notalpha.dashloader.client.sprite; + +import dev.notalpha.dashloader.DashLoader; +import dev.notalpha.dashloader.api.CachingData; +import dev.notalpha.dashloader.api.DashModule; +import dev.notalpha.dashloader.api.cache.Cache; +import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.api.collection.IntObjectList; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.config.ConfigHandler; +import dev.notalpha.dashloader.config.Option; +import dev.notalpha.taski.builtin.StepTask; +import net.minecraft.client.texture.TextureStitcher; +import net.minecraft.util.Identifier; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.*; + +public class SpriteStitcherModule implements DashModule { + //public final static CachingData> ATLASES = new CachingData<>(); + public final static CachingData>>> STITCHERS_SAVE = new CachingData<>(CacheStatus.SAVE); + public final static CachingData>> STITCHERS_LOAD = new CachingData<>(CacheStatus.LOAD); + //public final static CachingData> ATLAS_IDS = new CachingData<>(CacheStatus.SAVE); + + @Override + public void reset(Cache cache) { + // ATLASES.reset(cache, new HashMap<>()); + STITCHERS_SAVE.reset(cache, new ArrayList<>()); + STITCHERS_LOAD.reset(cache, new HashMap<>()); + //ATLAS_IDS.reset(cache, new HashMap<>()); + } + + @Override + public Data save(RegistryWriter writer, StepTask task) { + task.reset(2); + + var stitchers = new HashMap>(); + var duplicate = new HashSet(); + task.run(new StepTask("Caching Stitchers"), (stepTask) -> { + stepTask.doForEach(STITCHERS_SAVE.get(CacheStatus.SAVE), (pair) -> { + var identifier = pair.getLeft(); + var textureStitcher = pair.getRight(); + DashTextureStitcher.Data existing = stitchers.put(identifier, new DashTextureStitcher.Data<>(writer, textureStitcher)); + if (existing != null) { + duplicate.add(identifier); + } + }); + }); + duplicate.forEach(identifier -> { + DashLoader.LOG.warn("Duplicate stitcher {}", identifier); + stitchers.remove(identifier); + }); + + + var output = new IntObjectList>(); + + stitchers.forEach((identifier, data) -> { + output.put(writer.add(identifier), data); + }); + + //var results = new IntObjectList(); + //task.run(new StepTask("Caching Atlases"), (stepTask) -> { + // var map = ATLASES.get(CacheStatus.SAVE); + // stepTask.doForEach(map, (identifier, stitchResult) -> { + // StepTask atlases = new StepTask("atlas", stitchResult.regions().size()); + // task.setSubTask(atlases); + // results.put(factory.add(identifier), new DashStitchResult(stitchResult, factory, atlases)); + // }); + //}); + + return new Data(output); + } + + @Override + public void load(Data data, RegistryReader reader, StepTask task) { + //HashMap stitchResults = new HashMap<>(data.results.list().size()); + //data.results.forEach((identifier, stitchResult) -> { + // stitchResults.put(reader.get(identifier), stitchResult.export(reader)); + //}); +// + //ATLASES.set(CacheStatus.LOAD, stitchResults); + var map = new HashMap>(); + data.stitchers.forEach((key, value) -> { + map.put(reader.get(key), value.export(reader)); + }); + STITCHERS_LOAD.set(CacheStatus.LOAD, map); + } + + @Override + public Class getDataClass() { + return Data.class; + } + + @Override + public boolean isActive() { + return ConfigHandler.optionActive(Option.CACHE_SPRITES); + } + + public static final class Data { + // public final IntObjectList results; + public final IntObjectList> stitchers; + + public Data( + // IntObjectList results, + IntObjectList> stitchers) { + // this.results = results; + this.stitchers = stitchers; + } + } +} diff --git a/src/main/java/dev/notalpha/dashloader/client/ui/Color.java b/common/src/main/java/dev/notalpha/dashloader/client/ui/Color.java similarity index 85% rename from src/main/java/dev/notalpha/dashloader/client/ui/Color.java rename to common/src/main/java/dev/notalpha/dashloader/client/ui/Color.java index 09b3a945..82f86854 100644 --- a/src/main/java/dev/notalpha/dashloader/client/ui/Color.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/ui/Color.java @@ -16,15 +16,15 @@ public Color(int red, int green, int blue) { } public int red() { - return (rgba >> 24) & 0xFF; + return (rgba >>> 24) & 0xFF; } public int green() { - return (rgba >> 16) & 0xFF; + return (rgba >>> 16) & 0xFF; } public int blue() { - return (rgba >> 8) & 0xFF; + return (rgba >>> 8) & 0xFF; } public int alpha() { @@ -32,7 +32,7 @@ public int alpha() { } public int rgb() { - return rgba >> 8; + return rgba >>> 8; } public int rgba() { diff --git a/src/main/java/dev/notalpha/dashloader/client/ui/DashToast.java b/common/src/main/java/dev/notalpha/dashloader/client/ui/DashToast.java similarity index 88% rename from src/main/java/dev/notalpha/dashloader/client/ui/DashToast.java rename to common/src/main/java/dev/notalpha/dashloader/client/ui/DashToast.java index ab3ee673..9f6d92db 100644 --- a/src/main/java/dev/notalpha/dashloader/client/ui/DashToast.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/ui/DashToast.java @@ -3,6 +3,7 @@ import com.mojang.blaze3d.systems.RenderSystem; import dev.notalpha.dashloader.misc.HahaManager; import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.render.*; import net.minecraft.client.toast.Toast; import net.minecraft.client.toast.ToastManager; @@ -29,6 +30,7 @@ public class DashToast implements Toast { private final String fact = HahaManager.getFact(); private long oldTime = System.currentTimeMillis(); public final DashToastState state; + private static void drawVertex(Matrix4f m4f, BufferBuilder bb, float z, float x, float y, Color color) { bb.vertex(m4f, x, y, z).color(color.red(), color.green(), color.blue(), color.alpha()).next(); } @@ -51,7 +53,7 @@ public DashToast() { @Override - public Visibility draw(MatrixStack matrices, ToastManager manager, long startTime) { + public Visibility draw(DrawContext context, ToastManager manager, long startTime) { final int width = this.getWidth(); final int height = this.getHeight(); final int barY = height - PROGRESS_BAR_HEIGHT; @@ -84,10 +86,10 @@ public Visibility draw(MatrixStack matrices, ToastManager manager, long startTim // Setup scissor + MatrixStack matrices = context.getMatrices(); { - MatrixStack matrixStack = RenderSystem.getModelViewStack(); Vector4f vec = new Vector4f(0.0f, 0.0f, 0.0f, 1.0f); - vec.mul(matrixStack.peek().getPositionMatrix()); + vec.mul(matrices.peek().getPositionMatrix()); Window window = manager.getClient().getWindow(); double scale = window.getScaleFactor(); RenderSystem.enableScissor( @@ -98,7 +100,7 @@ public Visibility draw(MatrixStack matrices, ToastManager manager, long startTim } // Draw the ui - DrawerUtil.drawRect(matrices, 0, 0, width, height, DrawerUtil.BACKGROUND_COLOR); + DrawerUtil.drawRect(context, 0, 0, width, height, DrawerUtil.BACKGROUND_COLOR); // Draw the background lines. this.drawBatched(matrices, (matrix4f, bufferBuilder) -> { @@ -112,17 +114,17 @@ public Visibility draw(MatrixStack matrices, ToastManager manager, long startTim // Draw progress text String progressText = this.state.getProgressText(); int progressTextY = this.fact != null ? barY - PADDING : (barY / 2) + (textRenderer.fontHeight / 2); - DrawerUtil.drawText(matrices, textRenderer, PADDING, progressTextY, this.state.getText(), DrawerUtil.STATUS_COLOR); - DrawerUtil.drawText(matrices, textRenderer, (width - PADDING) - textRenderer.getWidth(progressText), progressTextY, progressText, DrawerUtil.STATUS_COLOR); + DrawerUtil.drawText(context, textRenderer, PADDING, progressTextY, this.state.getText(), DrawerUtil.STATUS_COLOR); + DrawerUtil.drawText(context, textRenderer, (width - PADDING) - textRenderer.getWidth(progressText), progressTextY, progressText, DrawerUtil.STATUS_COLOR); if (this.fact != null) { // Draw the fun fact - DrawerUtil.drawText(matrices, textRenderer, PADDING, textRenderer.fontHeight + PADDING, this.fact, DrawerUtil.FOREGROUND_COLOR); + DrawerUtil.drawText(context, textRenderer, PADDING, textRenderer.fontHeight + PADDING, this.fact, DrawerUtil.FOREGROUND_COLOR); } // Draw progress bar - DrawerUtil.drawRect(matrices, 0, barY, width, PROGRESS_BAR_HEIGHT, DrawerUtil.PROGRESS_TRACK); - DrawerUtil.drawRect(matrices, 0, barY, (int) (width * progress), PROGRESS_BAR_HEIGHT, progressColor); + DrawerUtil.drawRect(context, 0, barY, width, PROGRESS_BAR_HEIGHT, DrawerUtil.PROGRESS_TRACK); + DrawerUtil.drawRect(context, 0, barY, (int) (width * progress), PROGRESS_BAR_HEIGHT, progressColor); // Epic rtx graphics. aka i slapped some glow on the things. this.drawBatched(matrices, (matrix4f, bb) -> { @@ -148,14 +150,12 @@ public Visibility draw(MatrixStack matrices, ToastManager manager, long startTim private void drawBatched(MatrixStack ms, BiConsumer consumer) { BufferBuilder bufferBuilder = Tessellator.getInstance().getBuffer(); RenderSystem.enableBlend(); - RenderSystem.disableTexture(); RenderSystem.defaultBlendFunc(); RenderSystem.setShader(GameRenderer::getPositionColorProgram); bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR); Matrix4f matrix = ms.peek().getPositionMatrix(); consumer.accept(matrix, bufferBuilder); BufferRenderer.drawWithGlobalProgram(bufferBuilder.end()); - RenderSystem.enableTexture(); RenderSystem.disableBlend(); } diff --git a/src/main/java/dev/notalpha/dashloader/client/ui/DashToastState.java b/common/src/main/java/dev/notalpha/dashloader/client/ui/DashToastState.java similarity index 99% rename from src/main/java/dev/notalpha/dashloader/client/ui/DashToastState.java rename to common/src/main/java/dev/notalpha/dashloader/client/ui/DashToastState.java index 7a8db073..cb58d51a 100644 --- a/src/main/java/dev/notalpha/dashloader/client/ui/DashToastState.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/ui/DashToastState.java @@ -21,7 +21,7 @@ public final class DashToastState { public DashToastState() { - var langCode = MinecraftClient.getInstance().getLanguageManager().getLanguage().getCode(); + var langCode = MinecraftClient.getInstance().getLanguageManager().getLanguage(); DashLoader.LOG.info(langCode); var stream = this.getClass().getClassLoader().getResourceAsStream("dashloader/lang/" + langCode + ".json"); this.translations = new HashMap<>(); diff --git a/src/main/java/dev/notalpha/dashloader/client/ui/DashToastStatus.java b/common/src/main/java/dev/notalpha/dashloader/client/ui/DashToastStatus.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/client/ui/DashToastStatus.java rename to common/src/main/java/dev/notalpha/dashloader/client/ui/DashToastStatus.java diff --git a/src/main/java/dev/notalpha/dashloader/client/ui/DrawerUtil.java b/common/src/main/java/dev/notalpha/dashloader/client/ui/DrawerUtil.java similarity index 87% rename from src/main/java/dev/notalpha/dashloader/client/ui/DrawerUtil.java rename to common/src/main/java/dev/notalpha/dashloader/client/ui/DrawerUtil.java index 434c1df7..b70c810b 100644 --- a/src/main/java/dev/notalpha/dashloader/client/ui/DrawerUtil.java +++ b/common/src/main/java/dev/notalpha/dashloader/client/ui/DrawerUtil.java @@ -1,9 +1,8 @@ package dev.notalpha.dashloader.client.ui; import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.DrawableHelper; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.render.BufferBuilder; -import net.minecraft.client.util.math.MatrixStack; import net.minecraft.text.Text; import org.joml.Matrix4f; @@ -25,20 +24,20 @@ public class DrawerUtil { }; - - public static void drawRect(MatrixStack matrixStack, int x, int y, int width, int height, Color color) { + public static void drawRect(DrawContext context, int x, int y, int width, int height, Color color) { final int x2 = width + x; final int y2 = height + y; - DrawableHelper.fill(matrixStack, x, y, x2, y2, convertColor(color)); + context.fill(x, y, x2, y2, color.argb()); } - public static void drawText(MatrixStack matrixStack, TextRenderer textRenderer, int x, int y, String text, Color color) { - DrawableHelper.drawTextWithShadow(matrixStack, textRenderer, Text.of(text), x, y - (textRenderer.fontHeight), color.argb()); + public static void drawText(DrawContext context, TextRenderer textRenderer, int x, int y, String text, Color color) { + context.drawTextWithShadow(textRenderer, Text.of(text), x, y - (textRenderer.fontHeight), color.argb()); } private static void drawVertex(Matrix4f m4f, BufferBuilder bb, float x, float y, Color color) { bb.vertex(m4f, x, y, 0f).color(color.red(), color.green(), color.blue(), color.alpha()).next(); } + public static void drawGlow(Matrix4f b4, BufferBuilder bb, float x, float y, float width, float height, float strength, Color color, boolean topLeft, boolean topRight, boolean bottomLeft, boolean bottomRight) { Color end = withOpacity(color, 0); Color glow = withOpacity(color, GLOW_STRENGTH * strength); @@ -105,11 +104,12 @@ public static void drawGlow(Matrix4f b4, BufferBuilder bb, float x, float y, flo drawVertex(b4, bb, x2 + GLOW_SIZE, y, trEnd); // right top // Left - drawVertex(b4, bb, x - GLOW_SIZE, y2, blEnd); // left bottom - drawVertex(b4, bb, x, y2, bl); // right bottom - drawVertex(b4, bb, x, y, tl); // right top - drawVertex(b4, bb, x - GLOW_SIZE, y, tlEnd); // left top + drawVertex(b4, bb, x - GLOW_SIZE, y2, blEnd); // left bottom + drawVertex(b4, bb, x, y2, bl); // right bottom + drawVertex(b4, bb, x, y, tl); // right top + drawVertex(b4, bb, x - GLOW_SIZE, y, tlEnd); // left top } + public static int convertColor(Color color) { return color.rgb() | color.alpha() << 24; } diff --git a/src/main/java/dev/notalpha/dashloader/config/Config.java b/common/src/main/java/dev/notalpha/dashloader/config/Config.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/config/Config.java rename to common/src/main/java/dev/notalpha/dashloader/config/Config.java diff --git a/src/main/java/dev/notalpha/dashloader/config/ConfigHandler.java b/common/src/main/java/dev/notalpha/dashloader/config/ConfigHandler.java similarity index 99% rename from src/main/java/dev/notalpha/dashloader/config/ConfigHandler.java rename to common/src/main/java/dev/notalpha/dashloader/config/ConfigHandler.java index 5b9e5602..73451fb2 100644 --- a/src/main/java/dev/notalpha/dashloader/config/ConfigHandler.java +++ b/common/src/main/java/dev/notalpha/dashloader/config/ConfigHandler.java @@ -15,6 +15,7 @@ public class ConfigHandler { private static final EnumMap OPTION_ACTIVE = new EnumMap<>(Option.class); + static { for (Option value : Option.values()) { OPTION_ACTIVE.put(value, true); diff --git a/src/main/java/dev/notalpha/dashloader/config/Option.java b/common/src/main/java/dev/notalpha/dashloader/config/Option.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/config/Option.java rename to common/src/main/java/dev/notalpha/dashloader/config/Option.java diff --git a/src/main/java/dev/notalpha/dashloader/io/IOHelper.java b/common/src/main/java/dev/notalpha/dashloader/io/IOHelper.java similarity index 97% rename from src/main/java/dev/notalpha/dashloader/io/IOHelper.java rename to common/src/main/java/dev/notalpha/dashloader/io/IOHelper.java index 5ba76b45..ced56ee7 100644 --- a/src/main/java/dev/notalpha/dashloader/io/IOHelper.java +++ b/common/src/main/java/dev/notalpha/dashloader/io/IOHelper.java @@ -1,8 +1,8 @@ package dev.notalpha.dashloader.io; import com.github.luben.zstd.Zstd; -import dev.notalpha.hyphen.io.ByteBufferIO; import dev.notalpha.taski.builtin.StepTask; +import dev.quantumfusion.hyphen.io.ByteBufferIO; import org.apache.commons.io.IOUtils; import org.lwjgl.system.MemoryUtil; @@ -17,7 +17,7 @@ import java.nio.file.Path; import java.nio.file.StandardOpenOption; -public class IOHelper { +public final class IOHelper { public static int[] toArray(IntBuffer buffer) { if (buffer == null) { diff --git a/src/main/java/dev/notalpha/dashloader/io/MappingSerializer.java b/common/src/main/java/dev/notalpha/dashloader/io/MappingSerializer.java similarity index 79% rename from src/main/java/dev/notalpha/dashloader/io/MappingSerializer.java rename to common/src/main/java/dev/notalpha/dashloader/io/MappingSerializer.java index b04be9ac..a29b8ab6 100644 --- a/src/main/java/dev/notalpha/dashloader/io/MappingSerializer.java +++ b/common/src/main/java/dev/notalpha/dashloader/io/MappingSerializer.java @@ -1,14 +1,14 @@ package dev.notalpha.dashloader.io; import dev.notalpha.dashloader.DashLoader; -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.api.RegistryWriter; -import dev.notalpha.dashloader.api.cache.DashModule; +import dev.notalpha.dashloader.api.DashModule; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; import dev.notalpha.dashloader.config.ConfigHandler; -import dev.notalpha.hyphen.io.ByteBufferIO; import dev.notalpha.taski.Task; import dev.notalpha.taski.builtin.StepTask; import dev.notalpha.taski.builtin.WeightedStageTask; +import dev.quantumfusion.hyphen.io.ByteBufferIO; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; @@ -31,7 +31,7 @@ public MappingSerializer(List> cacheHandlers) { @SuppressWarnings({"unchecked", "rawtypes"}) - public void save(Path dir, RegistryWriter writer, List> handlers, StepTask parent) { + public void save(Path dir, RegistryWriter factory, List> handlers, StepTask parent) { List tasks = new ArrayList<>(); for (DashModule value : handlers) { tasks.add(new WeightedStageTask.WeightedStage(value.taskWeight(), new StepTask(value.getDataClass().getSimpleName(), 1))); @@ -45,7 +45,7 @@ public void save(Path dir, RegistryWriter writer, List> handlers, for (DashModule handler : handlers) { Task task = stageTask.getStages().get(i).task; if (handler.isActive()) { - Object object = handler.save(writer, (StepTask) task); + Object object = handler.save(factory, (StepTask) task); Class dataClass = handler.getDataClass(); if (object.getClass() != dataClass) { throw new RuntimeException("Handler DataClass does not match the output of saveMappings on " + handler.getClass()); @@ -54,6 +54,7 @@ public void save(Path dir, RegistryWriter writer, List> handlers, } else { objects.add(null); } + //noinspection DataFlowIssue task.finish(); i++; } @@ -78,9 +79,9 @@ public void save(Path dir, RegistryWriter writer, List> handlers, ByteBufferIO io = ByteBufferIO.createDirect(measure); for (Object object : objects) { if (object == null) { - io.putBoolean(false); + io.putByte((byte) 0); } else { - io.putBoolean(true); + io.putByte((byte) 1); Serializer serializer = this.serializers.get(object.getClass()); serializer.put(io, object); } @@ -99,23 +100,16 @@ public boolean load(Path dir, RegistryReader reader, List> handler try { ByteBufferIO io = IOHelper.load(dir.resolve("mapping.bin")); for (DashModule handler : handlers) { - boolean moduleActive = io.getBoolean(); - if (moduleActive) { - if (!handler.isActive()) { - DashLoader.LOG.info("Recaching as " + handler.getClass().getSimpleName() + " is now inactive."); - return false; - } - + if (io.getByte() == 0 && handler.isActive()) { + DashLoader.LOG.info("Recaching as " + handler.getClass().getSimpleName() + " is now active."); + return false; + } else { Class dataClass = handler.getDataClass(); Serializer serializer = this.serializers.get(dataClass); Object object = serializer.get(io); - handler.load(object, reader, new StepTask("")); - - } else { if (handler.isActive()) { - DashLoader.LOG.info("Recaching as " + handler.getClass().getSimpleName() + " is now active."); - return false; + handler.load(object, reader, new StepTask("")); } } } diff --git a/src/main/java/dev/notalpha/dashloader/io/RegistrySerializer.java b/common/src/main/java/dev/notalpha/dashloader/io/RegistrySerializer.java similarity index 95% rename from src/main/java/dev/notalpha/dashloader/io/RegistrySerializer.java rename to common/src/main/java/dev/notalpha/dashloader/io/RegistrySerializer.java index 866c92c6..33868af7 100644 --- a/src/main/java/dev/notalpha/dashloader/io/RegistrySerializer.java +++ b/common/src/main/java/dev/notalpha/dashloader/io/RegistrySerializer.java @@ -12,14 +12,14 @@ import dev.notalpha.dashloader.io.fragment.Fragment; import dev.notalpha.dashloader.io.fragment.SimplePiece; import dev.notalpha.dashloader.io.fragment.SizePiece; -import dev.notalpha.dashloader.registry.RegistryFactory; +import dev.notalpha.dashloader.registry.RegistryWriterImpl; import dev.notalpha.dashloader.registry.data.ChunkData; import dev.notalpha.dashloader.registry.data.ChunkFactory; import dev.notalpha.dashloader.registry.data.StageData; import dev.notalpha.dashloader.thread.ThreadHandler; -import dev.notalpha.hyphen.io.ByteBufferIO; import dev.notalpha.taski.Task; import dev.notalpha.taski.builtin.StepTask; +import dev.quantumfusion.hyphen.io.ByteBufferIO; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; @@ -29,7 +29,9 @@ import java.util.List; import java.util.function.Consumer; +@SuppressWarnings({"rawtypes", "unchecked"}) public class RegistrySerializer { + // 20MB private static final int MIN_PER_THREAD_FRAGMENT_SIZE = 1024 * 1024 * 20; // 1GB private static final int MAX_FRAGMENT_SIZE = 1024 * 1024 * 1024; @@ -45,11 +47,11 @@ public RegistrySerializer(List> dashObjects) { } } - public > Serializer getSerializer(DashObjectClass dashObject) { + public > Serializer getSerializer(DashObjectClass dashObject) { return (Serializer) this.serializers.get(dashObject.getDashClass()); } - public CacheInfo serialize(Path dir, RegistryFactory factory, Consumer taskConsumer) throws IOException { + public CacheInfo serialize(Path dir, RegistryWriterImpl factory, Consumer taskConsumer) throws IOException { StageData[] stages = factory.export(); SimplePiece[] value = new SimplePiece[stages.length]; diff --git a/src/main/java/dev/notalpha/dashloader/io/Serializer.java b/common/src/main/java/dev/notalpha/dashloader/io/Serializer.java similarity index 70% rename from src/main/java/dev/notalpha/dashloader/io/Serializer.java rename to common/src/main/java/dev/notalpha/dashloader/io/Serializer.java index b224958b..2d5da226 100644 --- a/src/main/java/dev/notalpha/dashloader/io/Serializer.java +++ b/common/src/main/java/dev/notalpha/dashloader/io/Serializer.java @@ -4,15 +4,15 @@ import dev.notalpha.dashloader.io.def.NativeImageData; import dev.notalpha.dashloader.io.def.NativeImageDataDef; import dev.notalpha.dashloader.registry.data.ChunkData; -import dev.notalpha.hyphen.HyphenSerializer; -import dev.notalpha.hyphen.SerializerFactory; -import dev.notalpha.hyphen.io.ByteBufferIO; -import dev.notalpha.hyphen.scan.annotations.DataSubclasses; import dev.notalpha.taski.builtin.StepTask; +import dev.quantumfusion.hyphen.HyphenSerializer; +import dev.quantumfusion.hyphen.SerializerFactory; +import dev.quantumfusion.hyphen.io.ByteBufferIO; +import dev.quantumfusion.hyphen.scan.annotations.DataSubclasses; +import net.minecraft.client.font.UnihexFont; import org.jetbrains.annotations.NotNull; import java.io.IOException; -import java.lang.annotation.Annotation; import java.nio.file.Path; public class Serializer { @@ -20,19 +20,14 @@ public class Serializer { public Serializer(Class aClass) { var factory = SerializerFactory.createDebug(ByteBufferIO.class, aClass); - factory.addAnnotationProvider(ChunkData.class, new DataSubclasses() { - @Override - public Class annotationType() { - return DataSubclasses.class; - } - - @Override - public Class[] value() { - return new Class[] {ChunkData.class}; - } - }); + factory.addGlobalAnnotation(ChunkData.class, DataSubclasses.class, new Class[]{ChunkData.class}); factory.setClassName(getSerializerClassName(aClass)); - factory.addDynamicDef(NativeImageData.class, NativeImageDataDef::new); + factory.addGlobalAnnotation(UnihexFont.BitmapGlyph.class, DataSubclasses.class, new Class[]{ + UnihexFont.FontImage32x16.class, + UnihexFont.FontImage16x16.class, + UnihexFont.FontImage8x16.class, + }); + factory.addDynamicDef(NativeImageData.class, (clazz, serializerHandler) -> new NativeImageDataDef(serializerHandler, clazz)); this.serializer = factory.build(); } diff --git a/src/main/java/dev/notalpha/dashloader/io/data/CacheInfo.java b/common/src/main/java/dev/notalpha/dashloader/io/data/CacheInfo.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/io/data/CacheInfo.java rename to common/src/main/java/dev/notalpha/dashloader/io/data/CacheInfo.java diff --git a/src/main/java/dev/notalpha/dashloader/io/data/ChunkInfo.java b/common/src/main/java/dev/notalpha/dashloader/io/data/ChunkInfo.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/io/data/ChunkInfo.java rename to common/src/main/java/dev/notalpha/dashloader/io/data/ChunkInfo.java diff --git a/src/main/java/dev/notalpha/dashloader/io/data/fragment/CacheFragment.java b/common/src/main/java/dev/notalpha/dashloader/io/data/fragment/CacheFragment.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/io/data/fragment/CacheFragment.java rename to common/src/main/java/dev/notalpha/dashloader/io/data/fragment/CacheFragment.java diff --git a/src/main/java/dev/notalpha/dashloader/io/data/fragment/ChunkFragment.java b/common/src/main/java/dev/notalpha/dashloader/io/data/fragment/ChunkFragment.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/io/data/fragment/ChunkFragment.java rename to common/src/main/java/dev/notalpha/dashloader/io/data/fragment/ChunkFragment.java diff --git a/src/main/java/dev/notalpha/dashloader/io/data/fragment/FragmentSlice.java b/common/src/main/java/dev/notalpha/dashloader/io/data/fragment/FragmentSlice.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/io/data/fragment/FragmentSlice.java rename to common/src/main/java/dev/notalpha/dashloader/io/data/fragment/FragmentSlice.java diff --git a/src/main/java/dev/notalpha/dashloader/io/data/fragment/StageFragment.java b/common/src/main/java/dev/notalpha/dashloader/io/data/fragment/StageFragment.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/io/data/fragment/StageFragment.java rename to common/src/main/java/dev/notalpha/dashloader/io/data/fragment/StageFragment.java diff --git a/src/main/java/dev/notalpha/dashloader/io/def/DataUnsafeByteBuffer.java b/common/src/main/java/dev/notalpha/dashloader/io/def/DataUnsafeByteBuffer.java similarity index 83% rename from src/main/java/dev/notalpha/dashloader/io/def/DataUnsafeByteBuffer.java rename to common/src/main/java/dev/notalpha/dashloader/io/def/DataUnsafeByteBuffer.java index 28f269b4..9c469e2a 100644 --- a/src/main/java/dev/notalpha/dashloader/io/def/DataUnsafeByteBuffer.java +++ b/common/src/main/java/dev/notalpha/dashloader/io/def/DataUnsafeByteBuffer.java @@ -1,6 +1,6 @@ package dev.notalpha.dashloader.io.def; -import dev.notalpha.hyphen.scan.annotations.HyphenAnnotation; +import dev.quantumfusion.hyphen.scan.annotations.HyphenAnnotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/java/dev/notalpha/dashloader/io/def/NativeImageData.java b/common/src/main/java/dev/notalpha/dashloader/io/def/NativeImageData.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/io/def/NativeImageData.java rename to common/src/main/java/dev/notalpha/dashloader/io/def/NativeImageData.java diff --git a/src/main/java/dev/notalpha/dashloader/io/def/NativeImageDataDef.java b/common/src/main/java/dev/notalpha/dashloader/io/def/NativeImageDataDef.java similarity index 61% rename from src/main/java/dev/notalpha/dashloader/io/def/NativeImageDataDef.java rename to common/src/main/java/dev/notalpha/dashloader/io/def/NativeImageDataDef.java index d864a507..59b736bf 100644 --- a/src/main/java/dev/notalpha/dashloader/io/def/NativeImageDataDef.java +++ b/common/src/main/java/dev/notalpha/dashloader/io/def/NativeImageDataDef.java @@ -1,34 +1,31 @@ package dev.notalpha.dashloader.io.def; -import dev.notalpha.hyphen.SerializerGenerator; -import dev.notalpha.hyphen.codegen.MethodWriter; -import dev.notalpha.hyphen.codegen.Variable; -import dev.notalpha.hyphen.codegen.def.BufferDef; -import dev.notalpha.hyphen.codegen.def.MethodDef; -import dev.notalpha.hyphen.codegen.statement.IfElse; -import dev.notalpha.hyphen.scan.struct.ClassStruct; -import dev.notalpha.hyphen.scan.struct.Struct; +import dev.quantumfusion.hyphen.SerializerHandler; +import dev.quantumfusion.hyphen.codegen.MethodHandler; +import dev.quantumfusion.hyphen.codegen.Variable; +import dev.quantumfusion.hyphen.codegen.def.BufferDef; +import dev.quantumfusion.hyphen.codegen.def.MethodDef; +import dev.quantumfusion.hyphen.codegen.statement.IfElse; +import dev.quantumfusion.hyphen.scan.type.Clazz; import org.lwjgl.system.MemoryUtil; import org.objectweb.asm.Opcodes; import java.nio.ByteBuffer; -public class NativeImageDataDef extends MethodDef { +public class NativeImageDataDef extends MethodDef { private ByteBufferDef bytebufferDef; - public NativeImageDataDef(Struct clazz) { - super(clazz); + public NativeImageDataDef(SerializerHandler handler, Clazz clazz) { + super(handler, clazz); } @Override - public void scan(SerializerGenerator handler) { - this.bytebufferDef = new ByteBufferDef(new ClassStruct(ByteBuffer.class)); - this.bytebufferDef.scan(handler); - super.scan(handler); + public void scan(SerializerHandler handler, Clazz clazz) { + this.bytebufferDef = new ByteBufferDef(new Clazz(handler, ByteBuffer.class), handler); } @Override - protected void writeMethodPut(MethodWriter mh, Runnable valueLoad) { + protected void writeMethodPut(MethodHandler mh, Runnable valueLoad) { mh.loadIO(); valueLoad.run(); mh.visitFieldInsn(Opcodes.GETFIELD, NativeImageData.class, "stb", boolean.class); @@ -41,7 +38,7 @@ protected void writeMethodPut(MethodWriter mh, Runnable valueLoad) { } @Override - protected void writeMethodGet(MethodWriter mh) { + protected void writeMethodGet(MethodHandler mh) { mh.typeOp(Opcodes.NEW, NativeImageData.class); mh.op(Opcodes.DUP); @@ -60,7 +57,7 @@ protected void writeMethodGet(MethodWriter mh) { } @Override - protected void writeMethodMeasure(MethodWriter mh, Runnable valueLoad) { + protected void writeMethodMeasure(MethodHandler mh, Runnable valueLoad) { bytebufferDef.writeMeasure(mh, () -> { valueLoad.run(); mh.visitFieldInsn(Opcodes.GETFIELD, NativeImageData.class, "buffer", ByteBuffer.class); @@ -75,12 +72,12 @@ public long getStaticSize() { private static class ByteBufferDef extends BufferDef { private Variable stbVariable; - public ByteBufferDef(Struct clazz) { - super(clazz); + public ByteBufferDef(Clazz clazz, SerializerHandler serializerHandler) { + super(clazz, serializerHandler); } @Override - protected void allocateBuffer(MethodWriter mh) { + protected void allocateBuffer(MethodHandler mh) { mh.varOp(Opcodes.ILOAD, stbVariable); try (var thing = new IfElse(mh, Opcodes.IFEQ)) { mh.op(Opcodes.ICONST_1, Opcodes.SWAP); diff --git a/src/main/java/dev/notalpha/dashloader/io/fragment/Fragment.java b/common/src/main/java/dev/notalpha/dashloader/io/fragment/Fragment.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/io/fragment/Fragment.java rename to common/src/main/java/dev/notalpha/dashloader/io/fragment/Fragment.java diff --git a/src/main/java/dev/notalpha/dashloader/io/fragment/Piece.java b/common/src/main/java/dev/notalpha/dashloader/io/fragment/Piece.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/io/fragment/Piece.java rename to common/src/main/java/dev/notalpha/dashloader/io/fragment/Piece.java diff --git a/src/main/java/dev/notalpha/dashloader/io/fragment/SimplePiece.java b/common/src/main/java/dev/notalpha/dashloader/io/fragment/SimplePiece.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/io/fragment/SimplePiece.java rename to common/src/main/java/dev/notalpha/dashloader/io/fragment/SimplePiece.java diff --git a/src/main/java/dev/notalpha/dashloader/io/fragment/SizePiece.java b/common/src/main/java/dev/notalpha/dashloader/io/fragment/SizePiece.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/io/fragment/SizePiece.java rename to common/src/main/java/dev/notalpha/dashloader/io/fragment/SizePiece.java diff --git a/src/main/java/dev/notalpha/dashloader/misc/HahaManager.java b/common/src/main/java/dev/notalpha/dashloader/misc/HahaManager.java similarity index 98% rename from src/main/java/dev/notalpha/dashloader/misc/HahaManager.java rename to common/src/main/java/dev/notalpha/dashloader/misc/HahaManager.java index c73d7321..ee5c9fa9 100644 --- a/src/main/java/dev/notalpha/dashloader/misc/HahaManager.java +++ b/common/src/main/java/dev/notalpha/dashloader/misc/HahaManager.java @@ -6,7 +6,7 @@ import java.util.ArrayList; import java.util.List; -public class HahaManager { +public final class HahaManager { private static final String[] FACTS = { "Dash was for the cool kids", "fun fact: 1 + 1 = 11", diff --git a/common/src/main/java/dev/notalpha/dashloader/misc/ObjectDumper.java b/common/src/main/java/dev/notalpha/dashloader/misc/ObjectDumper.java new file mode 100644 index 00000000..f8610602 --- /dev/null +++ b/common/src/main/java/dev/notalpha/dashloader/misc/ObjectDumper.java @@ -0,0 +1,146 @@ +package dev.notalpha.dashloader.misc; + +import net.minecraft.client.texture.NativeImage; +import org.apache.commons.lang3.builder.MultilineRecursiveToStringStyle; +import org.apache.commons.lang3.builder.ReflectionToStringBuilder; + +import java.lang.reflect.Field; +import java.lang.reflect.InaccessibleObjectException; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.util.*; + +public class ObjectDumper { + public static String dump(Wrapper object) { + return ReflectionToStringBuilder.toString(object, new Style()); + } + + public static class Wrapper { + public final Object data; + public Wrapper(Object data) { + this.data = data; + } + } + + private static final class Style extends MultilineRecursiveToStringStyle { + public Style() { + setFieldNameValueSeparator(": "); + setUseIdentityHashCode(false); + setUseShortClassName(true); + } + + public void appendDetail(StringBuffer buffer, String fieldName, Object value) { + try { + if (value != null) { + if (Objects.equals(fieldName, "glRef")) { + buffer.append(""); + return; + } + + if (value instanceof ThreadLocal local) { + appendDetail(buffer, fieldName, local.get()); + return; + } + + if (value instanceof HashMap map) { + appendDetail(buffer, fieldName, (Map) map); + return; + } + + if (value instanceof ArrayList list) { + appendDetail(buffer, fieldName, (List) list); + return; + } + + if (value instanceof NativeImage image) { + buffer.append("Image{ format: ").append(image.getFormat()).append(", size: ").append(image.getWidth()).append("x").append(image.getHeight()).append(" }"); + return; + } + + if (value instanceof IntBuffer buffer1) { + buffer.append("IntBuffer ["); + int limit = buffer1.limit(); + if (limit < 50) { + buffer1.rewind(); + for (int i = 0; i < limit; i++) { + float v = buffer1.get(); + buffer.append(v); + buffer.append(", "); + } + } + buffer.append("]"); + return; + } + + if (value instanceof FloatBuffer buffer1) { + buffer.append("FloatBuffer ["); + int limit = buffer1.limit(); + if (limit < 50) { + buffer1.rewind(); + for (int i = 0; i < limit; i++) { + float v = buffer1.get(); + buffer.append(v); + buffer.append(", "); + } + } + buffer.append("]"); + return; + } + + if (value instanceof Enum enumValue) { + buffer.append(enumValue.name()); + return; + } + } else { + buffer.append("null"); + return; + } + + try { + StringBuffer builder = new StringBuffer(); + super.appendDetail(builder, fieldName, value); + String s = builder.toString(); + String result = s.split("@")[0]; + buffer.append(result); + } + catch (InaccessibleObjectException e) { + throw e; + } + catch (Exception e) { + e.printStackTrace(); + + buffer.append("unknown"); + try { + Field spaces = MultilineRecursiveToStringStyle.class.getDeclaredField("spaces"); + spaces.setAccessible(true); + spaces.setInt(this, spaces.getInt(this) - 2); + } catch (IllegalAccessException | NoSuchFieldException ex) { + throw new RuntimeException(ex); + } + } + } catch (Exception e) { + throw new RuntimeException(value == null ? "null" : value.toString(), e); + } + } + + @Override + protected void appendDetail(StringBuffer buffer, String fieldName, Map map) { + buffer.append(this.getArrayStart()); + + // Sort maps to be comparible + List> entries = new ArrayList<>(map.entrySet()); + entries.sort((o1, o2) -> o1.getKey().toString().compareTo(o2.toString())); + entries.forEach((entry) -> { + buffer.append(getArraySeparator()); + this.appendDetail(buffer, String.valueOf(entry.getKey()), entry.getValue()); + }); + buffer.append(this.getArrayEnd()); + } + + @Override + protected void appendIdentityHashCode(StringBuffer buffer, Object object) { + + + } + } +} diff --git a/src/main/java/dev/notalpha/dashloader/misc/ProfilerUtil.java b/common/src/main/java/dev/notalpha/dashloader/misc/ProfilerUtil.java similarity index 94% rename from src/main/java/dev/notalpha/dashloader/misc/ProfilerUtil.java rename to common/src/main/java/dev/notalpha/dashloader/misc/ProfilerUtil.java index bbffce9b..71e5cc90 100644 --- a/src/main/java/dev/notalpha/dashloader/misc/ProfilerUtil.java +++ b/common/src/main/java/dev/notalpha/dashloader/misc/ProfilerUtil.java @@ -1,7 +1,7 @@ package dev.notalpha.dashloader.misc; -public class ProfilerUtil { +public final class ProfilerUtil { public static long RELOAD_START = 0; public static String getTimeStringFromStart(long start) { diff --git a/src/main/java/dev/notalpha/dashloader/misc/UnsafeHelper.java b/common/src/main/java/dev/notalpha/dashloader/misc/UnsafeHelper.java similarity index 96% rename from src/main/java/dev/notalpha/dashloader/misc/UnsafeHelper.java rename to common/src/main/java/dev/notalpha/dashloader/misc/UnsafeHelper.java index ec639038..327a387b 100644 --- a/src/main/java/dev/notalpha/dashloader/misc/UnsafeHelper.java +++ b/common/src/main/java/dev/notalpha/dashloader/misc/UnsafeHelper.java @@ -3,7 +3,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Modifier; -public class UnsafeHelper { +public final class UnsafeHelper { public static final sun.misc.Unsafe UNSAFE = getUnsafeInstance(); diff --git a/src/main/java/dev/notalpha/dashloader/misc/UnsafeImage.java b/common/src/main/java/dev/notalpha/dashloader/misc/UnsafeImage.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/misc/UnsafeImage.java rename to common/src/main/java/dev/notalpha/dashloader/misc/UnsafeImage.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/MixinPlugin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/MixinPlugin.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/MixinPlugin.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/MixinPlugin.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/AbstractTextureAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/AbstractTextureAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/AbstractTextureAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/AbstractTextureAccessor.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/AndMultipartModelSelectorAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/AndMultipartModelSelectorAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/AndMultipartModelSelectorAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/AndMultipartModelSelectorAccessor.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/BasicBakedModelAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/BasicBakedModelAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/BasicBakedModelAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/BasicBakedModelAccessor.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontAccessor.java similarity index 71% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontAccessor.java index 5f724d4d..cfa6bd81 100644 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontAccessor.java +++ b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontAccessor.java @@ -2,6 +2,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import net.minecraft.client.font.BitmapFont; +import net.minecraft.client.font.GlyphContainer; import net.minecraft.client.texture.NativeImage; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; @@ -11,12 +12,12 @@ public interface BitmapFontAccessor { @Invoker("") - static BitmapFont init(NativeImage image, Int2ObjectMap glyphs) { + static BitmapFont init(NativeImage image, GlyphContainer glyphs) { throw new AssertionError(); } @Accessor - Int2ObjectMap getGlyphs(); + GlyphContainer getGlyphs(); @Accessor NativeImage getImage(); diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontGlyphAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontGlyphAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontGlyphAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontGlyphAccessor.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/BuiltinBakedModelAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/BuiltinBakedModelAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/BuiltinBakedModelAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/BuiltinBakedModelAccessor.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/EffectShaderStageAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/EffectShaderStageAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/EffectShaderStageAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/EffectShaderStageAccessor.java diff --git a/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontManagerProviderIndexAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontManagerProviderIndexAccessor.java new file mode 100644 index 00000000..b06d2c7b --- /dev/null +++ b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontManagerProviderIndexAccessor.java @@ -0,0 +1,20 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.client.font.Font; +import net.minecraft.client.font.FontManager; +import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +import java.util.List; +import java.util.Map; + +@Mixin(FontManager.ProviderIndex.class) +public interface FontManagerProviderIndexAccessor { + + @Invoker("") + static FontManager.ProviderIndex create(Map> providers, List allProviders) { + throw new AssertionError(); + } + +} diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontStorageAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontStorageAccessor.java similarity index 87% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/FontStorageAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontStorageAccessor.java index d24f6ebd..4b272087 100644 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontStorageAccessor.java +++ b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontStorageAccessor.java @@ -18,10 +18,10 @@ public interface FontStorageAccessor { void setWhiteRectangleGlyphRenderer(GlyphRenderer renderer); @Accessor - Int2ObjectMap getGlyphRendererCache(); + GlyphContainer getGlyphRendererCache(); @Accessor - Int2ObjectMap getGlyphCache(); + GlyphContainer getGlyphCache(); @Accessor Int2ObjectMap getCharactersByWidth(); diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/GlBlendStateAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/GlBlendStateAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/GlBlendStateAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/GlBlendStateAccessor.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/GlUniformAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/GlUniformAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/GlUniformAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/GlUniformAccessor.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/IdentifierAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/IdentifierAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/IdentifierAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/IdentifierAccessor.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelIdentifierAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelIdentifierAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelIdentifierAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelIdentifierAccessor.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelLoaderAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelLoaderAccessor.java similarity index 93% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelLoaderAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelLoaderAccessor.java index d0dedac6..d1398e13 100644 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelLoaderAccessor.java +++ b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelLoaderAccessor.java @@ -1,6 +1,6 @@ package dev.notalpha.dashloader.mixin.accessor; -import dev.notalpha.hyphen.thr.HyphenException; +import dev.quantumfusion.hyphen.thr.HyphenException; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.client.render.model.ModelLoader; diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListAccessor.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListBakedOverrideAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListBakedOverrideAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListBakedOverrideAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListBakedOverrideAccessor.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListInlinedCondition.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListInlinedCondition.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListInlinedCondition.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListInlinedCondition.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartBakedModelAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartBakedModelAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartBakedModelAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartBakedModelAccessor.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartModelComponentAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartModelComponentAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartModelComponentAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartModelComponentAccessor.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/NativeImageAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/NativeImageAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/NativeImageAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/NativeImageAccessor.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/OrMultipartModelSelectorAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/OrMultipartModelSelectorAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/OrMultipartModelSelectorAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/OrMultipartModelSelectorAccessor.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderProgramAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderProgramAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderProgramAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderProgramAccessor.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderStageAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderStageAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderStageAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderStageAccessor.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/SimpleMultipartModelSelectorAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SimpleMultipartModelSelectorAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/SimpleMultipartModelSelectorAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SimpleMultipartModelSelectorAccessor.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAccessor.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationAccessor.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationFrameAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationFrameAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationFrameAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationFrameAccessor.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteContentsAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteContentsAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteContentsAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteContentsAccessor.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteLoaderStitchResultAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteLoaderStitchResultAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteLoaderStitchResultAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteLoaderStitchResultAccessor.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/TrueTypeFontAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/TrueTypeFontAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/TrueTypeFontAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/TrueTypeFontAccessor.java diff --git a/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/UnihexFontAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/UnihexFontAccessor.java new file mode 100644 index 00000000..ba5b02cf --- /dev/null +++ b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/UnihexFontAccessor.java @@ -0,0 +1,22 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.client.font.GlyphContainer; +import net.minecraft.client.font.UnihexFont; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(UnihexFont.class) +public interface UnihexFontAccessor { + @Invoker("") + static UnihexFont create(GlyphContainer glyphs) { + throw new AssertionError(); + } + + @Accessor + GlyphContainer getGlyphs(); + @Accessor + @Mutable + void setGlyphs(GlyphContainer glyphs); +} diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/VertexFormatAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/VertexFormatAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/VertexFormatAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/VertexFormatAccessor.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelAccessor.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelEntryAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelEntryAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelEntryAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelEntryAccessor.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/ZipResourcePackAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ZipResourcePackAccessor.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/ZipResourcePackAccessor.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ZipResourcePackAccessor.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/main/BootstrapMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/main/BootstrapMixin.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/main/BootstrapMixin.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/main/BootstrapMixin.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/main/KeyboardMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/main/KeyboardMixin.java similarity index 85% rename from src/main/java/dev/notalpha/dashloader/mixin/main/KeyboardMixin.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/main/KeyboardMixin.java index 07c207d1..dd600cc0 100644 --- a/src/main/java/dev/notalpha/dashloader/mixin/main/KeyboardMixin.java +++ b/common/src/main/java/dev/notalpha/dashloader/mixin/main/KeyboardMixin.java @@ -1,6 +1,7 @@ package dev.notalpha.dashloader.mixin.main; import dev.notalpha.dashloader.DashLoader; +import dev.notalpha.dashloader.api.cache.CacheStatus; import dev.notalpha.dashloader.client.DashLoaderClient; import net.minecraft.client.Keyboard; import org.lwjgl.glfw.GLFW; @@ -28,8 +29,10 @@ public class KeyboardMixin { ) private void f3tReloadWorld(int key, CallbackInfoReturnable cir) { if (!this.shiftHeld) { - DashLoader.LOG.info("Clearing cache."); - DashLoaderClient.CACHE.clear(); + if (DashLoaderClient.CACHE.getStatus() == CacheStatus.IDLE) { + DashLoader.LOG.info("Clearing cache."); + DashLoaderClient.CACHE.remove(); + } } } diff --git a/src/main/java/dev/notalpha/dashloader/mixin/main/MainMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/main/MainMixin.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/main/MainMixin.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/main/MainMixin.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/main/MinecraftClientMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/main/MinecraftClientMixin.java similarity index 85% rename from src/main/java/dev/notalpha/dashloader/mixin/main/MinecraftClientMixin.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/main/MinecraftClientMixin.java index 864c0272..df50f39d 100644 --- a/src/main/java/dev/notalpha/dashloader/mixin/main/MinecraftClientMixin.java +++ b/common/src/main/java/dev/notalpha/dashloader/mixin/main/MinecraftClientMixin.java @@ -26,9 +26,9 @@ private void requestReload(CallbackInfoReturnable> cir) @Inject(method = "reloadResources(Z)Ljava/util/concurrent/CompletableFuture;", at = @At(value = "RETURN")) private void reloadComplete(boolean thing, CallbackInfoReturnable> cir) { cir.getReturnValue().thenRun(() -> { - // Reset the manager - if (DashLoaderClient.CACHE.getStatus() == CacheStatus.LOAD) { - DashLoaderClient.CACHE.setStatus(CacheStatus.IDLE); + // If the state is SAVE, then this will reset before the caching process can initialize from the splash screen. + if (DashLoaderClient.CACHE.getStatus() != CacheStatus.SAVE) { + DashLoaderClient.CACHE.reset(); } }); } diff --git a/src/main/java/dev/notalpha/dashloader/mixin/main/ReloadableResourceManagerImplMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/main/ReloadableResourceManagerImplMixin.java similarity index 91% rename from src/main/java/dev/notalpha/dashloader/mixin/main/ReloadableResourceManagerImplMixin.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/main/ReloadableResourceManagerImplMixin.java index 96e3760e..4b5c0c78 100644 --- a/src/main/java/dev/notalpha/dashloader/mixin/main/ReloadableResourceManagerImplMixin.java +++ b/common/src/main/java/dev/notalpha/dashloader/mixin/main/ReloadableResourceManagerImplMixin.java @@ -1,5 +1,6 @@ package dev.notalpha.dashloader.mixin.main; +import dev.notalpha.dashloader.DashLoader; import dev.notalpha.dashloader.client.DashLoaderClient; import dev.notalpha.dashloader.misc.ProfilerUtil; import dev.notalpha.dashloader.mixin.accessor.ZipResourcePackAccessor; @@ -49,7 +50,8 @@ private void reloadDash(Executor prepareExecutor, Executor applyExecutor, Comple } } - DashLoaderClient.CACHE.setHash(DigestUtils.md5Hex(values.toString()).toUpperCase()); - DashLoaderClient.CACHE.start(); + String hash = DigestUtils.md5Hex(values.toString()).toUpperCase(); + DashLoader.LOG.info("Hash changed to " + hash); + DashLoaderClient.CACHE.load(hash); } } diff --git a/src/main/java/dev/notalpha/dashloader/mixin/main/SplashScreenMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/main/SplashScreenMixin.java similarity index 86% rename from src/main/java/dev/notalpha/dashloader/mixin/main/SplashScreenMixin.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/main/SplashScreenMixin.java index 73eb1fc9..326a91d0 100644 --- a/src/main/java/dev/notalpha/dashloader/mixin/main/SplashScreenMixin.java +++ b/common/src/main/java/dev/notalpha/dashloader/mixin/main/SplashScreenMixin.java @@ -1,7 +1,7 @@ package dev.notalpha.dashloader.mixin.main; -import dev.notalpha.dashloader.Cache; import dev.notalpha.dashloader.DashLoader; +import dev.notalpha.dashloader.api.cache.Cache; import dev.notalpha.dashloader.api.cache.CacheStatus; import dev.notalpha.dashloader.client.DashLoaderClient; import dev.notalpha.dashloader.client.ui.DashToast; @@ -11,6 +11,7 @@ import dev.notalpha.dashloader.misc.ProfilerUtil; import dev.notalpha.taski.builtin.StaticTask; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.SplashOverlay; import net.minecraft.client.gui.screen.TitleScreen; import net.minecraft.client.toast.Toast; @@ -44,10 +45,10 @@ public class SplashScreenMixin { private boolean reloading; @Inject( - method = "render(Lnet/minecraft/client/util/math/MatrixStack;IIF)V", + method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/Util;getMeasuringTimeMs()J", shift = At.Shift.BEFORE, ordinal = 1) ) - private void done(MatrixStack matrices, int mouseX, int mouseY, float delta, CallbackInfo ci) { + private void done(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci) { this.client.setOverlay(null); if (this.client.currentScreen != null) { if (this.client.currentScreen instanceof TitleScreen) { @@ -56,9 +57,8 @@ private void done(MatrixStack matrices, int mouseX, int mouseY, float delta, Cal } DashLoader.LOG.info("Minecraft reloaded in {}", ProfilerUtil.getTimeStringFromStart(ProfilerUtil.RELOAD_START)); + Cache cache = DashLoaderClient.CACHE; if (DashLoaderClient.CACHE.getStatus() == CacheStatus.SAVE && client.getToastManager().getToast(DashToast.class, Toast.TYPE) == null) { - Cache cache = DashLoaderClient.CACHE; - DashToastState rawState; if (ConfigHandler.INSTANCE.config.showCachingToast) { DashToast toast = new DashToast(); @@ -88,21 +88,21 @@ private void done(MatrixStack matrices, int mouseX, int mouseY, float delta, Cal state.task = new StaticTask("Crash", 0); state.setStatus(DashToastStatus.CRASHED); } - cache.setStatus(CacheStatus.IDLE); + cache.reset(); state.setDone(); }); thread.setName("dashloader-thread"); thread.start(); } else { - DashLoaderClient.CACHE.setStatus(CacheStatus.IDLE); + cache.reset(); } } @Inject( - method = "render(Lnet/minecraft/client/util/math/MatrixStack;IIF)V", + method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/resource/ResourceReload;isComplete()Z", shift = At.Shift.BEFORE) ) - private void removeMinimumTime(MatrixStack matrices, int mouseX, int mouseY, float delta, CallbackInfo ci) { + private void removeMinimumTime(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci) { if (this.reloadCompleteTime == -1L && this.reload.isComplete()) { this.reloading = false; } diff --git a/src/main/java/dev/notalpha/dashloader/mixin/option/WallBlockMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/option/WallBlockMixin.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/option/WallBlockMixin.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/option/WallBlockMixin.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/option/cache/SplashTextResourceSupplierMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/SplashTextResourceSupplierMixin.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/option/cache/SplashTextResourceSupplierMixin.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/SplashTextResourceSupplierMixin.java diff --git a/common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/font/FontManagerOverride.java b/common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/font/FontManagerOverride.java new file mode 100644 index 00000000..120ed7fa --- /dev/null +++ b/common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/font/FontManagerOverride.java @@ -0,0 +1,44 @@ +package dev.notalpha.dashloader.mixin.option.cache.font; + +import dev.notalpha.dashloader.DashLoader; +import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.client.font.FontModule; +import dev.notalpha.dashloader.mixin.accessor.FontManagerProviderIndexAccessor; +import net.minecraft.client.font.FontManager; +import net.minecraft.resource.ResourceManager; +import net.minecraft.util.profiler.Profiler; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + +@Mixin(FontManager.class) +public class FontManagerOverride { + + @Inject( + method = "loadIndex", + at = @At(value = "HEAD"), + cancellable = true + ) + private void loadFonts(ResourceManager resourceManager, Executor executor, CallbackInfoReturnable> cir) { + FontModule.DATA.visit(CacheStatus.LOAD, data -> { + DashLoader.LOG.info("Providing fonts"); + cir.setReturnValue(CompletableFuture.completedFuture(FontManagerProviderIndexAccessor.create(data.providers, data.allProviders))); + }); + } + + @Inject( + method = "reload(Lnet/minecraft/client/font/FontManager$ProviderIndex;Lnet/minecraft/util/profiler/Profiler;)V", + at = @At(value = "HEAD") + ) + private void saveFonts(FontManager.ProviderIndex index, Profiler profiler, CallbackInfo ci) { + if (FontModule.DATA.active(CacheStatus.SAVE)) { + DashLoader.LOG.info("Saving fonts"); + FontModule.DATA.set(CacheStatus.SAVE, new FontModule.ProviderIndex(index.providers(), index.allProviders())); + } + } +} diff --git a/src/main/java/dev/notalpha/dashloader/mixin/option/cache/font/TrueTypeFontLoaderMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/font/TrueTypeFontLoaderMixin.java similarity index 89% rename from src/main/java/dev/notalpha/dashloader/mixin/option/cache/font/TrueTypeFontLoaderMixin.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/font/TrueTypeFontLoaderMixin.java index d3760dee..b8c59c97 100644 --- a/src/main/java/dev/notalpha/dashloader/mixin/option/cache/font/TrueTypeFontLoaderMixin.java +++ b/common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/font/TrueTypeFontLoaderMixin.java @@ -16,10 +16,9 @@ import org.spongepowered.asm.mixin.injection.callback.LocalCapture; @Mixin(TrueTypeFontLoader.class) -public class TrueTypeFontLoaderMixin { - @Shadow - @Final - private Identifier filename; +public abstract class TrueTypeFontLoaderMixin { + + @Shadow public abstract Identifier location(); @Inject( method = "load", @@ -28,7 +27,7 @@ public class TrueTypeFontLoaderMixin { ) private void loadInject(ResourceManager manager, CallbackInfoReturnable cir, STBTTFontinfo sTBTTFontinfo) { FontModule.FONT_TO_IDENT.visit(CacheStatus.SAVE, map -> { - map.put(sTBTTFontinfo, this.filename); + map.put(sTBTTFontinfo, location()); }); } } diff --git a/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/BakedModelManagerOverride.java b/common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/BakedModelManagerOverride.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/BakedModelManagerOverride.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/BakedModelManagerOverride.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/BlockModelsMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/BlockModelsMixin.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/BlockModelsMixin.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/BlockModelsMixin.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/ModelLoaderMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/ModelLoaderMixin.java similarity index 70% rename from src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/ModelLoaderMixin.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/ModelLoaderMixin.java index 3eb0d72f..59d40293 100644 --- a/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/ModelLoaderMixin.java +++ b/common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/ModelLoaderMixin.java @@ -1,13 +1,15 @@ package dev.notalpha.dashloader.mixin.option.cache.model; +import dev.notalpha.dashloader.CacheImpl; import dev.notalpha.dashloader.DashLoader; import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.client.DashLoaderClient; import dev.notalpha.dashloader.client.model.ModelModule; import dev.notalpha.dashloader.client.model.fallback.UnbakedBakedModel; +import dev.notalpha.dashloader.misc.ObjectDumper; import net.minecraft.block.BlockState; import net.minecraft.client.color.block.BlockColors; -import net.minecraft.client.render.model.ModelLoader; -import net.minecraft.client.render.model.UnbakedModel; +import net.minecraft.client.render.model.*; import net.minecraft.client.render.model.json.JsonUnbakedModel; import net.minecraft.client.texture.Sprite; import net.minecraft.client.util.SpriteIdentifier; @@ -22,6 +24,10 @@ import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -44,22 +50,20 @@ public abstract class ModelLoaderMixin { @Final private Map modelsToBake; + @Shadow @Final private Map bakedModels; + @Inject( method = "", at = @At(value = "INVOKE_STRING", target = "Lnet/minecraft/util/profiler/Profiler;swap(Ljava/lang/String;)V", args = "ldc=static_definitions", shift = At.Shift.AFTER) ) private void injectLoadedModels(BlockColors blockColors, Profiler profiler, Map jsonUnbakedModels, Map> blockStates, CallbackInfo ci) { ModelModule.MODELS_LOAD.visit(CacheStatus.LOAD, dashModels -> { - DashLoader.LOG.info("Injecting {} Cached Models", dashModels.size()); - Map oldUnbakedModels = this.unbakedModels; - Map oldModelsToBake = this.modelsToBake; - this.unbakedModels = new HashMap<>((int) ((oldUnbakedModels.size() + dashModels.size()) / 0.75)); - this.modelsToBake = new HashMap<>((int) ((oldModelsToBake.size() + dashModels.size()) / 0.75)); - + int total = dashModels.size(); + this.unbakedModels.keySet().forEach(dashModels::remove); + this.modelsToBake.keySet().forEach(dashModels::remove); + DashLoader.LOG.info("Injecting {}/{} Cached Models", dashModels.size(), total); this.unbakedModels.putAll(dashModels); - this.unbakedModels.putAll(oldUnbakedModels); this.modelsToBake.putAll(dashModels); - this.modelsToBake.putAll(oldModelsToBake); }); } @@ -108,4 +112,37 @@ private void countModels(BiFunction sprite } } + + @Inject( + method = "bake", + at = @At( + value = "TAIL" + ) + ) + private void debug(BiFunction spriteLoader, CallbackInfo ci) { +//var models = new HashMap(); +//this.bakedModels.forEach((identifier, bakedModel) -> { +// if ( +// bakedModel.getClass() == BasicBakedModel.class || +// bakedModel.getClass() == MultipartBakedModel.class || +// bakedModel.getClass() == WeightedBakedModel.class || +// bakedModel.getClass() == BuiltinBakedModel.class +// ) { +// return; +// } +// +// models.put(identifier, bakedModel); +//}); +// System.out.println(); + +// + //String dump = ObjectDumper.dump(new ObjectDumper.Wrapper(models)); + //try { + // Files.writeString(Path.of("./output." + DashLoaderClient.CACHE.getStatus()), dump); + //} catch (IOException e) { + // throw new RuntimeException(e); + //} + } + + } diff --git a/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/MultipartUnbakedModelMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/MultipartUnbakedModelMixin.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/MultipartUnbakedModelMixin.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/MultipartUnbakedModelMixin.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/option/cache/shader/GameRendererMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/shader/GameRendererMixin.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/option/cache/shader/GameRendererMixin.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/shader/GameRendererMixin.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/option/cache/shader/GlStateManagerMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/shader/GlStateManagerMixin.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/option/cache/shader/GlStateManagerMixin.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/shader/GlStateManagerMixin.java diff --git a/common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/sprite/SpriteLoaderMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/sprite/SpriteLoaderMixin.java new file mode 100644 index 00000000..6894c6c0 --- /dev/null +++ b/common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/sprite/SpriteLoaderMixin.java @@ -0,0 +1,96 @@ +package dev.notalpha.dashloader.mixin.option.cache.sprite; + +import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.client.sprite.DashTextureStitcher; +import dev.notalpha.dashloader.client.sprite.SpriteStitcherModule; +import net.minecraft.client.texture.SpriteContents; +import net.minecraft.client.texture.SpriteLoader; +import net.minecraft.client.texture.TextureStitcher; +import net.minecraft.util.Identifier; +import org.apache.commons.lang3.tuple.Pair; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import java.util.List; +import java.util.concurrent.Executor; + +@Mixin(SpriteLoader.class) +public final class SpriteLoaderMixin { + + @Shadow + @Final + private Identifier id; + + @Redirect( + method = "stitch", + at = @At(value = "NEW", target = "(III)Lnet/minecraft/client/texture/TextureStitcher;") + ) + private TextureStitcher dashloaderStitcherLoad(int maxWidth, int maxHeight, int mipLevel) { + if (SpriteStitcherModule.STITCHERS_LOAD.active(CacheStatus.LOAD)) { + var map = SpriteStitcherModule.STITCHERS_LOAD.get(CacheStatus.LOAD); + var data = map.get(id); + if (data != null) { + return new DashTextureStitcher(maxWidth, maxHeight, mipLevel, data); + } + } + + return new TextureStitcher(maxWidth, maxHeight, mipLevel); + } + + @Inject( + method = "stitch", + at = @At(value = "RETURN"), + locals = LocalCapture.CAPTURE_FAILSOFT + ) + private void dashloaderStitcherSave(List sprites, int mipLevel, Executor executor, CallbackInfoReturnable cir, int i, TextureStitcher textureStitcher) { + SpriteStitcherModule.STITCHERS_SAVE.visit(CacheStatus.SAVE, map -> { + map.add(Pair.of(id, textureStitcher)); + }); + } + + //@Inject( + // method = "load(Lnet/minecraft/resource/ResourceManager;Lnet/minecraft/util/Identifier;ILjava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;", + // at = @At(value = "RETURN"), + // cancellable = true + // ) + // private void dashloaderWrite(ResourceManager resourceManager, Identifier identifier, int i, Executor executor, CallbackInfoReturnable> cir) { + // SpriteModule.ATLASES.visit(CacheStatus.SAVE, map -> { + // SpriteModule.ATLAS_IDS.get(CacheStatus.SAVE).put(id, identifier); + // cir.setReturnValue(cir.getReturnValue().thenApply(stitchResult -> { + // map.put(identifier, stitchResult); + // return stitchResult; + // })); + // }); + // } + // + // @Inject( + // method = "load(Lnet/minecraft/resource/ResourceManager;Lnet/minecraft/util/Identifier;ILjava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;", + // at = @At(value = "HEAD"), + // cancellable = true + // ) + // private void dashloaderRead(ResourceManager resourceManager, Identifier identifier, int m, Executor executor, CallbackInfoReturnable> cir) { + // SpriteModule.ATLASES.visit(CacheStatus.LOAD, map -> { + // SpriteLoader.StitchResult cached = map.get(identifier); + // if (cached != null) { + // int mipLevel = cached.mipLevel(); + // // Correct the executor + // CompletableFuture completableFuture = mipLevel > 0 ? CompletableFuture.runAsync(() -> cached.regions().values().forEach(sprite -> sprite.getContents().generateMipmaps(mipLevel)), executor) : CompletableFuture.completedFuture(null); + // cir.setReturnValue(CompletableFuture.completedFuture(new SpriteLoader.StitchResult( + // cached.width(), + // cached.height(), + // mipLevel, + // cached.missing(), + // cached.regions(), + // completableFuture + // ))); + // cir.cancel(); + // } + // }); + // } +} diff --git a/src/main/java/dev/notalpha/dashloader/mixin/option/misc/AffineTransformationMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/option/misc/AffineTransformationMixin.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/option/misc/AffineTransformationMixin.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/option/misc/AffineTransformationMixin.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/option/misc/MipmapHelperMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/option/misc/MipmapHelperMixin.java similarity index 95% rename from src/main/java/dev/notalpha/dashloader/mixin/option/misc/MipmapHelperMixin.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/option/misc/MipmapHelperMixin.java index b16b1c40..2fae3650 100644 --- a/src/main/java/dev/notalpha/dashloader/mixin/option/misc/MipmapHelperMixin.java +++ b/common/src/main/java/dev/notalpha/dashloader/mixin/option/misc/MipmapHelperMixin.java @@ -21,18 +21,18 @@ private static float getColorFraction(int value) { } @Shadow - protected static boolean hasAlpha(NativeImage image) { + private static boolean hasAlpha(NativeImage image) { return false; } @Shadow - protected static int blend(int one, int two, int three, int four, boolean checkAlpha) { + private static int blend(int one, int two, int three, int four, boolean checkAlpha) { return 0; } /** - * @author - * @reason + * @author notalpha + * @reason fast */ @Overwrite public static NativeImage[] getMipmapLevelsImages(NativeImage[] originals, int mipmap) { diff --git a/src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelIdentifierMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelIdentifierMixin.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelIdentifierMixin.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelIdentifierMixin.java diff --git a/src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelLoaderBakedModelCacheKeyMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelLoaderBakedModelCacheKeyMixin.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelLoaderBakedModelCacheKeyMixin.java rename to common/src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelLoaderBakedModelCacheKeyMixin.java diff --git a/src/main/java/dev/notalpha/dashloader/registry/FactoryBinding.java b/common/src/main/java/dev/notalpha/dashloader/registry/FactoryBinding.java similarity index 88% rename from src/main/java/dev/notalpha/dashloader/registry/FactoryBinding.java rename to common/src/main/java/dev/notalpha/dashloader/registry/FactoryBinding.java index ff808baf..8fc887b5 100644 --- a/src/main/java/dev/notalpha/dashloader/registry/FactoryBinding.java +++ b/common/src/main/java/dev/notalpha/dashloader/registry/FactoryBinding.java @@ -2,7 +2,7 @@ import dev.notalpha.dashloader.DashObjectClass; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryWriter; +import dev.notalpha.dashloader.api.registry.RegistryWriter; import org.jetbrains.annotations.Nullable; import java.lang.invoke.MethodHandle; @@ -10,7 +10,7 @@ import java.lang.invoke.MethodType; import java.util.function.Function; -public final class FactoryBinding> { +public final class FactoryBinding> { private final MethodHandle method; private final FactoryFunction creator; @@ -19,7 +19,7 @@ public FactoryBinding(MethodHandle method, FactoryFunction creator) { this.creator = creator; } - public static > FactoryBinding create(DashObjectClass dashObject) { + public static > FactoryBinding create(DashObjectClass dashObject) { final Class dashClass = dashObject.getDashClass(); var factory = tryScanCreators((look, type) -> look.findConstructor(dashClass, type.changeReturnType(void.class)), dashObject); @@ -47,7 +47,7 @@ public D create(R raw, RegistryWriter writer) { } @Nullable - private static > FactoryBinding tryScanCreators(MethodTester tester, DashObjectClass dashObject) { + private static > FactoryBinding tryScanCreators(MethodTester tester, DashObjectClass dashObject) { for (InvokeType value : InvokeType.values()) { final Class[] apply = value.parameters.apply(dashObject); diff --git a/src/main/java/dev/notalpha/dashloader/registry/MissingHandler.java b/common/src/main/java/dev/notalpha/dashloader/registry/MissingHandler.java similarity index 57% rename from src/main/java/dev/notalpha/dashloader/registry/MissingHandler.java rename to common/src/main/java/dev/notalpha/dashloader/registry/MissingHandler.java index ad1f40e8..08a423b7 100644 --- a/src/main/java/dev/notalpha/dashloader/registry/MissingHandler.java +++ b/common/src/main/java/dev/notalpha/dashloader/registry/MissingHandler.java @@ -1,15 +1,15 @@ package dev.notalpha.dashloader.registry; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryWriter; +import dev.notalpha.dashloader.api.registry.RegistryWriter; import java.util.function.BiFunction; -public final class MissingHandler { +public class MissingHandler { public final Class parentClass; - public final BiFunction> func; + public final BiFunction> func; - public MissingHandler(Class parentClass, BiFunction> func) { + public MissingHandler(Class parentClass, BiFunction> func) { this.parentClass = parentClass; this.func = func; } diff --git a/src/main/java/dev/notalpha/dashloader/registry/RegistryReaderImpl.java b/common/src/main/java/dev/notalpha/dashloader/registry/RegistryReaderImpl.java similarity index 88% rename from src/main/java/dev/notalpha/dashloader/registry/RegistryReaderImpl.java rename to common/src/main/java/dev/notalpha/dashloader/registry/RegistryReaderImpl.java index e88fea27..e6b9ac8d 100644 --- a/src/main/java/dev/notalpha/dashloader/registry/RegistryReaderImpl.java +++ b/common/src/main/java/dev/notalpha/dashloader/registry/RegistryReaderImpl.java @@ -1,7 +1,7 @@ package dev.notalpha.dashloader.registry; -import dev.notalpha.dashloader.api.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryReader; import dev.notalpha.dashloader.io.data.CacheInfo; import dev.notalpha.dashloader.registry.data.StageData; import dev.notalpha.taski.Task; @@ -39,8 +39,8 @@ public final void export(@Nullable Consumer taskConsumer) { } @SuppressWarnings("unchecked") - public final R get(final int id) { + public final R get(final int pointer) { // inlining go brrr - return (R) this.data[id & 0x3f][id >>> 6]; + return (R) this.data[pointer & 0x3f][pointer >>> 6]; } } diff --git a/src/main/java/dev/notalpha/dashloader/registry/RegistryFactory.java b/common/src/main/java/dev/notalpha/dashloader/registry/RegistryWriterImpl.java similarity index 74% rename from src/main/java/dev/notalpha/dashloader/registry/RegistryFactory.java rename to common/src/main/java/dev/notalpha/dashloader/registry/RegistryWriterImpl.java index 639bcbf5..21d94129 100644 --- a/src/main/java/dev/notalpha/dashloader/registry/RegistryFactory.java +++ b/common/src/main/java/dev/notalpha/dashloader/registry/RegistryWriterImpl.java @@ -2,8 +2,9 @@ import dev.notalpha.dashloader.DashObjectClass; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryWriter; -import dev.notalpha.dashloader.misc.RegistryUtil; +import dev.notalpha.dashloader.api.registry.RegistryAddException; +import dev.notalpha.dashloader.api.registry.RegistryUtil; +import dev.notalpha.dashloader.api.registry.RegistryWriter; import dev.notalpha.dashloader.registry.data.ChunkData; import dev.notalpha.dashloader.registry.data.ChunkFactory; import dev.notalpha.dashloader.registry.data.StageData; @@ -15,46 +16,60 @@ import java.util.IdentityHashMap; import java.util.List; -public final class RegistryFactory implements RegistryWriter { +public final class RegistryWriterImpl implements RegistryWriter { private final IdentityHashMap dedup = new IdentityHashMap<>(); private final Object2ByteMap> target2chunkMappings; private final Object2ByteMap> dash2chunkMappings; private final List> missingHandlers; public final ChunkFactory[] chunks; - private RegistryFactory(ChunkFactory[] chunks, List> missingHandlers) { + private RegistryWriterImpl(ChunkFactory[] chunks, List> missingHandlers) { this.target2chunkMappings = new Object2ByteOpenHashMap<>(); + this.target2chunkMappings.defaultReturnValue((byte) -1); + this.dash2chunkMappings = new Object2ByteOpenHashMap<>(); + this.dash2chunkMappings.defaultReturnValue((byte) -1); + this.missingHandlers = missingHandlers; this.chunks = chunks; } - public static > RegistryFactory create(List> missingHandlers, List> dashObjects) { + public static > RegistryWriterImpl create(List> missingHandlers, List> dashObjects) { + if (dashObjects.size() > 63) { + throw new RuntimeException("Hit group limit of 63. Please contact notalpha if you hit this limit!"); + } //noinspection unchecked ChunkFactory[] chunks = new ChunkFactory[dashObjects.size()]; - RegistryFactory writer = new RegistryFactory(chunks, missingHandlers); + RegistryWriterImpl writer = new RegistryWriterImpl(chunks, missingHandlers); - if (dashObjects.size() > 63) { - throw new RuntimeException("Hit group limit of 63. Please contact QuantumFusion if you hit this limit!"); - } for (int i = 0; i < dashObjects.size(); i++) { final DashObjectClass dashObject = (DashObjectClass) dashObjects.get(i); - var factory = FactoryBinding.create(dashObject); + var dashClass = dashObject.getDashClass(); - var name = dashClass.getSimpleName(); - chunks[i] = new ChunkFactory<>((byte) i, name, factory, dashObject); + var targetClass = dashObject.getTargetClass(); + byte old = writer.target2chunkMappings.put(targetClass, (byte) i); + if (old != -1) { + DashObjectClass conflicting = dashObjects.get(old); + throw new IllegalStateException("DashObjects \"" + dashObject.getDashClass() + "\" and \"" + conflicting.getDashClass() + "\" have the same target class \"" + targetClass + "\"."); + } - writer.target2chunkMappings.put(dashObject.getTargetClass(), (byte) i); writer.dash2chunkMappings.put(dashClass, (byte) i); + var factory = FactoryBinding.create(dashObject); + var name = dashClass.getSimpleName(); + chunks[i] = new ChunkFactory<>((byte) i, name, factory, dashObject); } return writer; } - @SuppressWarnings("unchecked") public int add(R object) { + return this.addObject(object); + } + + @SuppressWarnings("unchecked") + private > int addObject(R object) { if (this.dedup.containsKey(object)) { return this.dedup.get(object); } @@ -67,10 +82,10 @@ public int add(R object) { Integer pointer = null; // If we have a dashObject supporting the target we create using its factory constructor { - byte chunkPos = this.target2chunkMappings.getOrDefault(targetClass, (byte) -1); + byte chunkPos = this.target2chunkMappings.getByte(targetClass); if (chunkPos != -1) { - var chunk = (ChunkFactory) this.chunks[chunkPos]; - var entry = TrackedRegistryFactory.create(this, writer -> { + var chunk = (ChunkFactory) this.chunks[chunkPos]; + var entry = TrackingRegistryWriterImpl.create(this, writer -> { return chunk.create(object, writer); }); pointer = chunk.add(entry, this); @@ -81,16 +96,16 @@ public int add(R object) { if (pointer == null) { for (MissingHandler missingHandler : this.missingHandlers) { if (missingHandler.parentClass.isAssignableFrom(targetClass)) { - var entry = TrackedRegistryFactory.create(this, writer -> { - return missingHandler.func.apply(object, writer); + var entry = TrackingRegistryWriterImpl.create(this, writer -> { + return (D) missingHandler.func.apply(object, writer); }); if (entry.data != null) { var dashClass = entry.data.getClass(); - byte chunkPos = this.dash2chunkMappings.getOrDefault(dashClass, (byte) -1); + byte chunkPos = this.dash2chunkMappings.getByte(dashClass); if (chunkPos == -1) { throw new RuntimeException("Could not find a ChunkWriter for DashClass " + dashClass); } - var chunk = (ChunkFactory) this.chunks[chunkPos]; + var chunk = (ChunkFactory) this.chunks[chunkPos]; pointer = chunk.add(entry, this); break; } diff --git a/src/main/java/dev/notalpha/dashloader/registry/TrackedRegistryFactory.java b/common/src/main/java/dev/notalpha/dashloader/registry/TrackingRegistryWriterImpl.java similarity index 52% rename from src/main/java/dev/notalpha/dashloader/registry/TrackedRegistryFactory.java rename to common/src/main/java/dev/notalpha/dashloader/registry/TrackingRegistryWriterImpl.java index 4e50a16f..8a0bff30 100644 --- a/src/main/java/dev/notalpha/dashloader/registry/TrackedRegistryFactory.java +++ b/common/src/main/java/dev/notalpha/dashloader/registry/TrackingRegistryWriterImpl.java @@ -1,6 +1,7 @@ package dev.notalpha.dashloader.registry; -import dev.notalpha.dashloader.api.RegistryWriter; +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryWriter; import dev.notalpha.dashloader.registry.data.ChunkFactory; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; @@ -9,27 +10,24 @@ /** * The Writers job is to allow dashObject to add dependencies by adding them to the registry and allowing parallelization. - * The logic is actually in RegistryFactory but we need to be able to track what added what so the writer gets issued on the invocation of the creator. + * The logic is actually in RegistryFactory, but we need to be able to track what added what so the writer gets issued on the invocation of the creator. */ -class TrackedRegistryFactory implements RegistryWriter { - private final RegistryFactory factory; +public final class TrackingRegistryWriterImpl implements RegistryWriter { + private final RegistryWriterImpl factory; private final IntList dependencies = new IntArrayList(); - private TrackedRegistryFactory(RegistryFactory factory) { + private TrackingRegistryWriterImpl(RegistryWriterImpl factory) { this.factory = factory; } - /** - * @see TrackedRegistryFactory#add(Object) - */ public int add(R object) { int value = factory.add(object); dependencies.add(value); return value; } - static ChunkFactory.Entry create(RegistryFactory factory, Function function) { - TrackedRegistryFactory writer = new TrackedRegistryFactory(factory); + static > ChunkFactory.Entry create(RegistryWriterImpl factory, Function function) { + TrackingRegistryWriterImpl writer = new TrackingRegistryWriterImpl(factory); D data = function.apply(writer); int[] dependencies = writer.dependencies.toIntArray(); return new ChunkFactory.Entry<>(data, dependencies); diff --git a/src/main/java/dev/notalpha/dashloader/registry/data/ChunkData.java b/common/src/main/java/dev/notalpha/dashloader/registry/data/ChunkData.java similarity index 78% rename from src/main/java/dev/notalpha/dashloader/registry/data/ChunkData.java rename to common/src/main/java/dev/notalpha/dashloader/registry/data/ChunkData.java index 73255c0e..fbe05aa5 100644 --- a/src/main/java/dev/notalpha/dashloader/registry/data/ChunkData.java +++ b/common/src/main/java/dev/notalpha/dashloader/registry/data/ChunkData.java @@ -2,10 +2,10 @@ import dev.notalpha.dashloader.DashObjectClass; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.registry.RegistryReaderImpl; +import dev.notalpha.dashloader.api.registry.RegistryReader; import dev.notalpha.dashloader.thread.ThreadHandler; -public class ChunkData> { +public class ChunkData> { public final byte chunkId; public final String name; public final DashObjectClass dashObject; @@ -18,17 +18,17 @@ public ChunkData(byte chunkId, String name, DashObjectClass dashObject, En this.dashables = dashables; } - public void preExport(RegistryReaderImpl reader) { + public void preExport(RegistryReader reader) { for (Entry entry : this.dashables) { entry.data.preExport(reader); } } - public void export(Object[] data, RegistryReaderImpl registry) { + public void export(Object[] data, RegistryReader registry) { ThreadHandler.INSTANCE.parallelExport(this.dashables, data, registry); } - public void postExport(RegistryReaderImpl reader) { + public void postExport(RegistryReader reader) { for (Entry entry : this.dashables) { entry.data.postExport(reader); } diff --git a/src/main/java/dev/notalpha/dashloader/registry/data/ChunkFactory.java b/common/src/main/java/dev/notalpha/dashloader/registry/data/ChunkFactory.java similarity index 86% rename from src/main/java/dev/notalpha/dashloader/registry/data/ChunkFactory.java rename to common/src/main/java/dev/notalpha/dashloader/registry/data/ChunkFactory.java index 73478947..dd712d55 100644 --- a/src/main/java/dev/notalpha/dashloader/registry/data/ChunkFactory.java +++ b/common/src/main/java/dev/notalpha/dashloader/registry/data/ChunkFactory.java @@ -2,17 +2,17 @@ import dev.notalpha.dashloader.DashObjectClass; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryWriter; -import dev.notalpha.dashloader.misc.RegistryUtil; +import dev.notalpha.dashloader.api.registry.RegistryUtil; +import dev.notalpha.dashloader.api.registry.RegistryWriter; import dev.notalpha.dashloader.registry.FactoryBinding; -import dev.notalpha.dashloader.registry.RegistryFactory; +import dev.notalpha.dashloader.registry.RegistryWriterImpl; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import java.util.ArrayList; import java.util.List; -public class ChunkFactory> { +public class ChunkFactory> { public final byte chunkId; public final String name; public final DashObjectClass dashObject; @@ -31,7 +31,7 @@ public D create(R raw, RegistryWriter writer) { return this.factory.create(raw, writer); } - public int add(Entry entry, RegistryFactory factory) { + public int add(Entry entry, RegistryWriterImpl factory) { int existing = deduplication.getOrDefault(entry.data, -1); if (existing != -1) { return RegistryUtil.createId(existing, chunkId); diff --git a/src/main/java/dev/notalpha/dashloader/registry/data/StageData.java b/common/src/main/java/dev/notalpha/dashloader/registry/data/StageData.java similarity index 66% rename from src/main/java/dev/notalpha/dashloader/registry/data/StageData.java rename to common/src/main/java/dev/notalpha/dashloader/registry/data/StageData.java index 13e646d2..d5e9e06c 100644 --- a/src/main/java/dev/notalpha/dashloader/registry/data/StageData.java +++ b/common/src/main/java/dev/notalpha/dashloader/registry/data/StageData.java @@ -1,7 +1,6 @@ package dev.notalpha.dashloader.registry.data; - -import dev.notalpha.dashloader.registry.RegistryReaderImpl; +import dev.notalpha.dashloader.api.registry.RegistryReader; public class StageData { public final ChunkData[] chunks; @@ -10,21 +9,21 @@ public StageData(ChunkData[] chunks) { this.chunks = chunks; } - public void preExport(RegistryReaderImpl reader) { + public void preExport(RegistryReader reader) { for (ChunkData chunk : chunks) { chunk.preExport(reader); } } - public void export(Object[][] data, RegistryReaderImpl registry) { + public void export(Object[][] data, RegistryReader registry) { for (int i = 0; i < chunks.length; i++) { ChunkData chunk = chunks[i]; chunk.export(data[i], registry); } } - public void postExport(RegistryReaderImpl reader) { + public void postExport(RegistryReader reader) { for (ChunkData chunk : chunks) { chunk.postExport(reader); } diff --git a/src/main/java/dev/notalpha/dashloader/thread/IndexedArrayMapTask.java b/common/src/main/java/dev/notalpha/dashloader/thread/IndexedArrayMapTask.java similarity index 100% rename from src/main/java/dev/notalpha/dashloader/thread/IndexedArrayMapTask.java rename to common/src/main/java/dev/notalpha/dashloader/thread/IndexedArrayMapTask.java diff --git a/src/main/java/dev/notalpha/dashloader/thread/ThreadHandler.java b/common/src/main/java/dev/notalpha/dashloader/thread/ThreadHandler.java similarity index 60% rename from src/main/java/dev/notalpha/dashloader/thread/ThreadHandler.java rename to common/src/main/java/dev/notalpha/dashloader/thread/ThreadHandler.java index 39308754..bcfe6d30 100644 --- a/src/main/java/dev/notalpha/dashloader/thread/ThreadHandler.java +++ b/common/src/main/java/dev/notalpha/dashloader/thread/ThreadHandler.java @@ -1,12 +1,15 @@ package dev.notalpha.dashloader.thread; import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.registry.RegistryReaderImpl; +import dev.notalpha.dashloader.api.registry.RegistryReader; import dev.notalpha.dashloader.registry.data.ChunkData; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.IntFunction; public final class ThreadHandler { public static final int THREADS = Runtime.getRuntime().availableProcessors(); @@ -31,15 +34,41 @@ public static int calcThreshold(final int tasks) { return Math.max(tasks / (THREADS * 8), 4); } - public > void parallelExport(ChunkData.Entry[] in, R[] out, RegistryReaderImpl reader) { + // Fork Join Methods + public > void parallelExport(ChunkData.Entry[] in, R[] out, RegistryReader reader) { this.threadPool.invoke(new IndexedArrayMapTask<>(in, out, d -> d.export(reader))); } + + // Basic Methods + public void parallelRunnable(Runnable... runnables) { + this.parallelRunnable(List.of(runnables)); + } + public void parallelRunnable(Collection runnables) { for (Future future : this.threadPool.invokeAll(runnables.stream().map(Executors::callable).toList())) { this.acquire(future); } } + @SafeVarargs + public final O[] parallelCallable(IntFunction creator, Callable... callables) { + O[] out = creator.apply(callables.length); + var futures = this.threadPool.invokeAll(List.of(callables)); + for (int i = 0, futuresSize = futures.size(); i < futuresSize; i++) { + out[i] = (this.acquire(futures.get(i))); + } + return out; + } + + public Collection parallelCallable(Collection> callables) { + List out = new ArrayList<>(); + var futures = this.threadPool.invokeAll(callables); + for (Future future : futures) { + out.add(this.acquire(future)); + } + return out; + } + private O acquire(Future future) { try { return future.get(); diff --git a/src/main/resources/dashloader.accesswidener b/common/src/main/resources/dashloader.accesswidener similarity index 72% rename from src/main/resources/dashloader.accesswidener rename to common/src/main/resources/dashloader.accesswidener index f78416c2..abad3b9a 100644 --- a/src/main/resources/dashloader.accesswidener +++ b/common/src/main/resources/dashloader.accesswidener @@ -8,8 +8,18 @@ accessible class net/minecraft/client/render/model/json/ModelOverrideList$BakedO accessible class net/minecraft/client/render/model/json/ModelOverrideList$InlinedCondition accessible class net/minecraft/client/render/model/BakedModelManager$BakingResult accessible class net/minecraft/client/render/model/ModelLoader$BakedModelCacheKey -accessible class net/minecraft/client/font/UnicodeTextureFont$FontImage +accessible class net/minecraft/client/font/UnihexFont$UnicodeTextureGlyph +accessible class net/minecraft/client/font/UnihexFont$FontImage16x16 +accessible class net/minecraft/client/font/UnihexFont$FontImage8x16 +accessible class net/minecraft/client/font/UnihexFont$FontImage32x16 +accessible class net/minecraft/client/font/FontStorage$GlyphPair accessible class net/minecraft/util/Identifier$ExtraData +accessible class net/minecraft/client/font/FontStorage$GlyphPair +accessible class net/minecraft/client/font/FontManager$ProviderIndex +accessible method net/minecraft/client/font/UnihexFont$FontImage8x16 ([B)V +accessible method net/minecraft/client/font/UnihexFont$FontImage16x16 ([S)V +accessible method net/minecraft/client/font/UnihexFont$FontImage32x16 ([II)V +accessible method net/minecraft/client/font/UnihexFont$UnicodeTextureGlyph (Lnet/minecraft/client/font/UnihexFont$BitmapGlyph;II)V mutable field net/minecraft/client/gl/ShaderProgram modelViewMat Lnet/minecraft/client/gl/GlUniform; mutable field net/minecraft/client/gl/ShaderProgram projectionMat Lnet/minecraft/client/gl/GlUniform; mutable field net/minecraft/client/gl/ShaderProgram viewRotationMat Lnet/minecraft/client/gl/GlUniform; diff --git a/src/main/resources/dashloader.mixins.json b/common/src/main/resources/dashloader.mixins.json similarity index 93% rename from src/main/resources/dashloader.mixins.json rename to common/src/main/resources/dashloader.mixins.json index ba5803ad..9676a0b2 100644 --- a/src/main/resources/dashloader.mixins.json +++ b/common/src/main/resources/dashloader.mixins.json @@ -12,7 +12,7 @@ "accessor.BitmapFontGlyphAccessor", "accessor.BuiltinBakedModelAccessor", "accessor.EffectShaderStageAccessor", - "accessor.FontManagerAccessor", + "accessor.FontManagerProviderIndexAccessor", "accessor.FontStorageAccessor", "accessor.GlBlendStateAccessor", "accessor.GlUniformAccessor", @@ -34,7 +34,7 @@ "accessor.SpriteAnimationFrameAccessor", "accessor.SpriteLoaderStitchResultAccessor", "accessor.TrueTypeFontAccessor", - "accessor.UnicodeTextureFontAccessor", + "accessor.UnihexFontAccessor", "accessor.WeightedBakedModelAccessor", "accessor.WeightedBakedModelEntryAccessor", "accessor.ZipResourcePackAccessor", @@ -47,7 +47,6 @@ "option.WallBlockMixin", "option.cache.SplashTextResourceSupplierMixin", "option.cache.font.FontManagerOverride", - "option.cache.font.FontManagerOverride$LeoFontSolution", "option.cache.font.TrueTypeFontLoaderMixin", "option.cache.model.BakedModelManagerOverride", "option.cache.model.BlockModelsMixin", @@ -63,7 +62,6 @@ "defaultRequire": 1 }, "client": [ - "accessor.FontImageAccessor", "accessor.ModelIdentifierAccessor", "accessor.ShaderStageAccessor$TypeAccessor", "accessor.SpriteContentsAccessor", diff --git a/src/main/resources/dashloader/lang/en_us.json b/common/src/main/resources/dashloader/lang/en_us.json similarity index 100% rename from src/main/resources/dashloader/lang/en_us.json rename to common/src/main/resources/dashloader/lang/en_us.json diff --git a/src/main/resources/dashloader/lang/lol_us.json b/common/src/main/resources/dashloader/lang/lol_us.json similarity index 100% rename from src/main/resources/dashloader/lang/lol_us.json rename to common/src/main/resources/dashloader/lang/lol_us.json diff --git a/src/main/resources/dashloader/lang/sv_se.json b/common/src/main/resources/dashloader/lang/sv_se.json similarity index 100% rename from src/main/resources/dashloader/lang/sv_se.json rename to common/src/main/resources/dashloader/lang/sv_se.json diff --git a/src/main/resources/dashloader/textures/icon.png b/common/src/main/resources/dashloader/textures/icon.png similarity index 100% rename from src/main/resources/dashloader/textures/icon.png rename to common/src/main/resources/dashloader/textures/icon.png diff --git a/forge/build.gradle b/forge/build.gradle new file mode 100644 index 00000000..dde3908d --- /dev/null +++ b/forge/build.gradle @@ -0,0 +1,92 @@ +plugins { + id 'com.github.johnrengelman.shadow' +} + +loom { + forge { + mixinConfig "dashloader.mixins.json" + } +} + +architectury { + platformSetupLoomIde() + forge() +} + +repositories { + maven{ + url = 'https://cursemaven.com' + } + mavenCentral() + mavenLocal() + maven { + name "Sonatype Snapshots" + url "https://s01.oss.sonatype.org/content/repositories/snapshots/" + } + maven { + url 'https://jitpack.io' + } + maven { + url "https://notalpha.dev/maven/releases" + } +} + +configurations { + common { + canBeResolved = true + canBeConsumed = false + } + compileClasspath.extendsFrom common + runtimeClasspath.extendsFrom common + developmentForge.extendsFrom common + + // Files in this configuration will be bundled into your mod using the Shadow plugin. + // Don't use the `shadow` configuration from the plugin itself as it's meant for excluding files. + shadowBundle { + canBeResolved = true + canBeConsumed = false + } +} + +dependencies { + mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" + forge "net.minecraftforge:forge:$rootProject.forge_version" + + modImplementation "curse.maven:forgified-fabric-api-889079:5990306" + modImplementation "dev.architectury:architectury-forge:$rootProject.architectury_api_version" + + implementation "dev.quantumfusion:Hyphen:0.4.0-rc.3" + include "dev.quantumfusion:Hyphen:0.4.0-rc.3" + + implementation "dev.notalpha:Taski:2.1.0" + include "dev.notalpha:Taski:2.1.0" + + implementation 'com.github.luben:zstd-jni:1.5.2-2' + include 'com.github.luben:zstd-jni:1.5.2-2' + + implementation 'com.github.luben:zstd-jni:1.5.2-2' + + common(project(path: ':common', configuration: 'namedElements')) { transitive false } + //shadowBundle project(path: ':common', configuration: 'transformProductionForge') +} + +processResources { + inputs.property 'version', project.version + + filesMatching('META-INF/mods.toml') { + expand version: project.version + } +} + +shadowJar { + configurations = [project.configurations.shadowBundle] + archiveClassifier = 'dev-shadow' +} + +remapJar { + input.set shadowJar.archiveFile +} + +loom { + accessWidenerPath = file("src/main/resources/dashloader.accesswidener") +} diff --git a/forge/gradle.properties b/forge/gradle.properties new file mode 100644 index 00000000..82425854 --- /dev/null +++ b/forge/gradle.properties @@ -0,0 +1 @@ +loom.platform=forge diff --git a/forge/src/main/java/cn/ksmcbrigade/dashloader/forge/DashloaderForge.java b/forge/src/main/java/cn/ksmcbrigade/dashloader/forge/DashloaderForge.java new file mode 100644 index 00000000..9457a7ec --- /dev/null +++ b/forge/src/main/java/cn/ksmcbrigade/dashloader/forge/DashloaderForge.java @@ -0,0 +1,14 @@ +package cn.ksmcbrigade.dashloader.forge; + +import cn.ksmcbrigade.dashloader.Dashloader; +import net.minecraftforge.fml.common.Mod; + +@Mod(Dashloader.MOD_ID) +public final class DashloaderForge { + public DashloaderForge() { + // Submit our event bus to let Architectury API register our content on the right time. + + // Run our common setup. + Dashloader.init(); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/CacheFactoryImpl.java b/forge/src/main/java/dev/notalpha/dashloader/CacheFactoryImpl.java new file mode 100644 index 00000000..2b83261a --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/CacheFactoryImpl.java @@ -0,0 +1,77 @@ +package dev.notalpha.dashloader; + +import dev.notalpha.dashloader.api.DashModule; +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.registry.MissingHandler; +import dev.notalpha.dashloader.api.cache.Cache; +import dev.notalpha.dashloader.api.cache.CacheFactory; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.function.BiFunction; + +public class CacheFactoryImpl implements CacheFactory { + private static final Logger LOGGER = LogManager.getLogger("CacheFactory"); + private final List> dashObjects; + private final List> modules; + private final List> missingHandlers; + private boolean failed = false; + + public CacheFactoryImpl() { + this.dashObjects = new ArrayList<>(); + this.modules = new ArrayList<>(); + this.missingHandlers = new ArrayList<>(); + } + + @Override + public void addDashObject(Class> dashClass) { + final Class[] interfaces = dashClass.getInterfaces(); + if (interfaces.length == 0) { + LOGGER.error("No DashObject interface found. Class: {}", dashClass.getSimpleName()); + this.failed = true; + return; + } + this.dashObjects.add(new DashObjectClass<>(dashClass)); + } + + @Override + public void addModule(DashModule module) { + this.modules.add(module); + } + + @Override + public void addMissingHandler(Class rClass, BiFunction> func) { + this.missingHandlers.add(new MissingHandler<>(rClass, func)); + } + + @Override + public Cache build(Path cacheDir) { + if (this.failed) { + throw new RuntimeException("Failed to initialize the API"); + } + + // Set dashobject ids + this.dashObjects.sort(Comparator.comparing(o -> o.getDashClass().getName())); + this.modules.sort(Comparator.comparing(o -> o.getDataClass().getName())); + + int id = 0; + Class lastClass = null; + for (DashObjectClass dashObject : this.dashObjects) { + if (dashObject.getDashClass() == lastClass) { + DashLoader.LOG.warn("Duplicate DashObject found: {}", dashObject.getDashClass()); + continue; + } + lastClass = dashObject.getDashClass(); + dashObject.dashObjectId = id; + id += 1; + } + + return new CacheImpl(cacheDir.resolve(DashLoader.MOD_HASH + "/"), modules, dashObjects, this.missingHandlers); + + } +} \ No newline at end of file diff --git a/forge/src/main/java/dev/notalpha/dashloader/CacheImpl.java b/forge/src/main/java/dev/notalpha/dashloader/CacheImpl.java new file mode 100644 index 00000000..50e6fa33 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/CacheImpl.java @@ -0,0 +1,224 @@ +package dev.notalpha.dashloader; + +import dev.notalpha.dashloader.api.DashModule; +import dev.notalpha.dashloader.registry.MissingHandler; +import dev.notalpha.dashloader.api.cache.Cache; +import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.config.ConfigHandler; +import dev.notalpha.dashloader.io.MappingSerializer; +import dev.notalpha.dashloader.io.RegistrySerializer; +import dev.notalpha.dashloader.io.data.CacheInfo; +import dev.notalpha.dashloader.misc.ProfilerUtil; +import dev.notalpha.dashloader.registry.RegistryReaderImpl; +import dev.notalpha.dashloader.registry.RegistryWriterImpl; +import dev.notalpha.dashloader.registry.data.StageData; +import dev.notalpha.taski.builtin.StepTask; +import org.apache.commons.io.FileUtils; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileTime; +import java.util.List; +import java.util.function.Consumer; +import java.util.stream.Stream; + +public final class CacheImpl implements Cache { + private static final String METADATA_FILE_NAME = "metadata.bin"; + private CacheStatus status; + private String hash; + private final Path cacheDir; + + // DashLoader metadata + private final List> cacheHandlers; + private final List> dashObjects; + private final List> missingHandlers; + + // Serializers + private final RegistrySerializer registrySerializer; + private final MappingSerializer mappingsSerializer; + + CacheImpl(Path cacheDir, List> cacheHandlers, List> dashObjects, List> missingHandlers) { + this.cacheDir = cacheDir; + this.cacheHandlers = cacheHandlers; + this.dashObjects = dashObjects; + this.missingHandlers = missingHandlers; + this.registrySerializer = new RegistrySerializer(dashObjects); + this.mappingsSerializer = new MappingSerializer(cacheHandlers); + } + + public void load(String name) { + this.hash = name; + + if (this.exists()) { + this.setStatus(CacheStatus.LOAD); + this.loadCache(); + } else { + this.setStatus(CacheStatus.SAVE); + } + } + + public boolean save(@Nullable Consumer taskConsumer) { + if (status != CacheStatus.SAVE) { + throw new RuntimeException("Status is not SAVE"); + } + DashLoader.LOG.info("Starting DashLoader Caching"); + try { + + Path ourDir = getDir(); + + // Max caches + int maxCaches = ConfigHandler.INSTANCE.config.maxCaches; + if (maxCaches != -1) { + DashLoader.LOG.info("Checking for cache count."); + try { + FileTime oldestTime = null; + Path oldestPath = null; + int cacheCount = 1; + try (Stream stream = Files.list(cacheDir)) { + for (Path path : stream.toList()) { + if (!Files.isDirectory(path)) { + continue; + } + + if (path.equals(ourDir)) { + continue; + } + cacheCount += 1; + + try { + BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class); + FileTime lastAccessTime = attrs.lastAccessTime(); + if (oldestTime == null || lastAccessTime.compareTo(oldestTime) < 0) { + oldestTime = lastAccessTime; + oldestPath = path; + } + } catch (IOException e) { + DashLoader.LOG.warn("Could not find access time for cache.", e); + } + } + } + + if (oldestPath != null && cacheCount > maxCaches) { + DashLoader.LOG.info("Removing {} as we are currently above the maximum caches.", oldestPath); + if (!FileUtils.deleteQuietly(oldestPath.toFile())) { + DashLoader.LOG.error("Could not remove cache {}", oldestPath); + } + } + } catch (NoSuchFileException ignored) { + } catch (IOException io) { + DashLoader.LOG.error("Could not enforce maximum cache ", io); + } + } + + long start = System.currentTimeMillis(); + + StepTask main = new StepTask("save", 2); + if (taskConsumer != null) { + taskConsumer.accept(main); + } + + RegistryWriterImpl factory = RegistryWriterImpl.create(missingHandlers, dashObjects); + + // Mappings + mappingsSerializer.save(ourDir, factory, cacheHandlers, main); + main.next(); + + // serialization + main.run(new StepTask("serialize", 2), (task) -> { + try { + CacheInfo info = this.registrySerializer.serialize(ourDir, factory, task::setSubTask); + task.next(); + DashLoader.METADATA_SERIALIZER.save(ourDir.resolve(METADATA_FILE_NAME), new StepTask("hi"), info); + } catch (IOException e) { + throw new RuntimeException(e); + } + task.next(); + }); + + DashLoader.LOG.info("Saved cache in " + ProfilerUtil.getTimeStringFromStart(start)); + return true; + } catch (Throwable thr) { + DashLoader.LOG.error("Failed caching", thr); + this.setStatus(CacheStatus.SAVE); + this.remove(); + return false; + } + } + + private void loadCache() { + if (status != CacheStatus.LOAD) { + throw new RuntimeException("Status is not LOAD"); + } + + long start = System.currentTimeMillis(); + try { + StepTask task = new StepTask("Loading DashCache", 3); + Path cacheDir = getDir(); + + // Get metadata + Path metadataPath = cacheDir.resolve(METADATA_FILE_NAME); + CacheInfo info = DashLoader.METADATA_SERIALIZER.load(metadataPath); + + // File reading + StageData[] stageData = registrySerializer.deserialize(cacheDir, info, dashObjects); + RegistryReaderImpl reader = new RegistryReaderImpl(info, stageData); + + // Exporting assets + task.run(() -> reader.export(task::setSubTask)); + + // Loading mappings + if (!mappingsSerializer.load(cacheDir, reader, cacheHandlers)) { + this.setStatus(CacheStatus.SAVE); + this.remove(); + return; + } + + DashLoader.LOG.info("Loaded cache in {}", ProfilerUtil.getTimeStringFromStart(start)); + } catch (Exception e) { + DashLoader.LOG.error("Summoned CrashLoader in {}", ProfilerUtil.getTimeStringFromStart(start), e); + this.setStatus(CacheStatus.SAVE); + this.remove(); + } + } + + public boolean exists() { + return Files.exists(this.getDir()); + } + + public void remove() { + try { + FileUtils.deleteDirectory(this.getDir().toFile()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Override + public void reset() { + this.setStatus(CacheStatus.IDLE); + } + + public Path getDir() { + if (hash == null) { + throw new RuntimeException("Cache hash has not been set."); + } + return cacheDir.resolve(hash + "/"); + } + + + public CacheStatus getStatus() { + return status; + } + + private void setStatus(CacheStatus status) { + if (this.status != status) { + this.status = status; + DashLoader.LOG.info("\u001B[46m\u001B[30m DashLoader Status change {}\n\u001B[0m", status); + this.cacheHandlers.forEach(handler -> handler.reset(this)); + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/DashLoader.java b/forge/src/main/java/dev/notalpha/dashloader/DashLoader.java new file mode 100644 index 00000000..4805a6d3 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/DashLoader.java @@ -0,0 +1,47 @@ +package dev.notalpha.dashloader; + +import dev.notalpha.dashloader.io.Serializer; +import dev.notalpha.dashloader.io.data.CacheInfo; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.ArrayList; +import java.util.Comparator; + + +public final class DashLoader { + private static final String VERSION ="5.0.0-beta.3+1.20.0"; + public static final Logger LOG = LogManager.getLogger("DashLoader"); + public static final Serializer METADATA_SERIALIZER = new Serializer<>(CacheInfo.class); + public static final String MOD_HASH; + + static { + /*ArrayList versions = new ArrayList<>(); + for (ModContainer mod : FabricLoader.getInstance().getAllMods()) { + ModMetadata metadata = mod.getMetadata(); + versions.add(metadata); + } + + versions.sort(Comparator.comparing(ModMetadata::getId)); +*/ + StringBuilder stringBuilder = new StringBuilder(); + /*for (int i = 0; i < versions.size(); i++) { + ModMetadata metadata = versions.get(i); + stringBuilder.append(i).append("$").append(metadata.getId()).append('&').append(metadata.getVersion().getFriendlyString()); + }*/ + + MOD_HASH = DigestUtils.md5Hex(stringBuilder.toString()).toUpperCase(); + } + + @SuppressWarnings("EmptyMethod") + public static void bootstrap() { + } + + private DashLoader() { + LOG.info("Initializing DashLoader " + VERSION + "."); + /*if (FabricLoader.getInstance().isDevelopmentEnvironment()) { + LOG.warn("DashLoader launched in dev."); + }*/ + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/DashObjectClass.java b/forge/src/main/java/dev/notalpha/dashloader/DashObjectClass.java new file mode 100644 index 00000000..d9f57bbf --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/DashObjectClass.java @@ -0,0 +1,80 @@ +package dev.notalpha.dashloader; + +import dev.notalpha.dashloader.api.DashObject; +import dev.quantumfusion.hyphen.util.ScanUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; + + +/** + * A DashObject which is an object with adds Dash support to a target object.
+ * This class is very lazy as reflection is really slow + * + * @param Raw + * @param Dashable + */ +public final class DashObjectClass> { + private final Class dashClass; + @Nullable + private Class targetClass; + int dashObjectId; + + public DashObjectClass(Class dashClass) { + //noinspection unchecked + this.dashClass = (Class) dashClass; + } + + public Class getDashClass() { + return this.dashClass; + } + + // lazy + @NotNull + public Class getTargetClass() { + if (this.targetClass == null) { + Type[] genericInterfaces = this.dashClass.getGenericInterfaces(); + if (genericInterfaces.length == 0) { + throw new RuntimeException(this.dashClass + " does not implement DashObject."); + } + + boolean foundDashObject = false; + for (Type genericInterface : genericInterfaces) { + if (ScanUtil.getClassFrom(genericInterface) == DashObject.class) { + foundDashObject = true; + if (genericInterface instanceof ParameterizedType targetClass) { + Type[] actualTypeArguments = targetClass.getActualTypeArguments(); + Class classFrom = ScanUtil.getClassFrom(actualTypeArguments[0]); + if (classFrom == null) { + throw new RuntimeException(this.dashClass + " has a non resolvable DashObject parameter"); + } + this.targetClass = (Class) classFrom; + } else { + throw new RuntimeException(this.dashClass + " implements raw DashObject"); + } + } + } + + if (!foundDashObject) { + throw new RuntimeException(this.dashClass + " must implement DashObject"); + } + } + return this.targetClass; + } + + + public int getDashObjectId() { + return dashObjectId; + } + + @Override + public String toString() { + return "DashObjectClass{" + + "dashClass=" + dashClass + + ", targetClass=" + targetClass + + ", dashObjectId=" + dashObjectId + + '}'; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/api/CachingData.java b/forge/src/main/java/dev/notalpha/dashloader/api/CachingData.java new file mode 100644 index 00000000..44324625 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/api/CachingData.java @@ -0,0 +1,77 @@ +package dev.notalpha.dashloader.api; + +import dev.notalpha.dashloader.api.cache.Cache; +import dev.notalpha.dashloader.api.cache.CacheStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Consumer; + +public class CachingData { + @Nullable + private D data; + + private Cache cacheManager; + + @Nullable + private CacheStatus dataStatus; + + @Nullable + private final CacheStatus onlyOn; + + public CachingData(@Nullable CacheStatus onlyOn) { + this.data = null; + this.onlyOn = onlyOn; + } + + public CachingData() { + this(null); + } + + public void visit(CacheStatus status, Consumer consumer) { + if (this.active(status)) { + consumer.accept(this.data); + } + } + + + /** + * Gets the value or returns null if its status does not match the current state. + **/ + public @Nullable D get(CacheStatus status) { + if (this.active(status)) { + return this.data; + } + return null; + } + + public void reset(Cache cacheManager, @NotNull D data) { + this.cacheManager = cacheManager; + set(cacheManager.getStatus(), data); + } + + /** + * Sets the optional data to the intended status + **/ + public void set(CacheStatus status, @NotNull D data) { + if (onlyOn != null && onlyOn != status) { + this.data = null; + this.dataStatus = null; + return; + } + + if (cacheManager == null) { + throw new RuntimeException("cacheManager is null. This OptionData has never been reset in its handler."); + } + + CacheStatus currentStatus = cacheManager.getStatus(); + if (status == currentStatus) { + this.dataStatus = status; + this.data = data; + } + } + + public boolean active(CacheStatus status) { + return status == this.dataStatus && status == cacheManager.getStatus() && this.data != null && (onlyOn == null || onlyOn == status); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/api/DashEntrypoint.java b/forge/src/main/java/dev/notalpha/dashloader/api/DashEntrypoint.java new file mode 100644 index 00000000..7aba27ac --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/api/DashEntrypoint.java @@ -0,0 +1,18 @@ +package dev.notalpha.dashloader.api; + + +import dev.notalpha.dashloader.api.cache.CacheFactory; + +import java.util.List; + +/** + * The DashEntrypoint allows operations on the DashLoader Minecraft cache, like adding support to external DashObjects, Modules or MissingHandlers. + */ +public interface DashEntrypoint { + /** + * Runs on DashLoader initialization. This is quite early compared to the cache. + * + * @param factory Factory to register your DashObjects/Modules to. + */ + void onDashLoaderInit(CacheFactory factory); +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/api/DashModule.java b/forge/src/main/java/dev/notalpha/dashloader/api/DashModule.java new file mode 100644 index 00000000..62cbe660 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/api/DashModule.java @@ -0,0 +1,68 @@ +package dev.notalpha.dashloader.api; + +import dev.notalpha.dashloader.api.cache.Cache; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.taski.builtin.StepTask; + +/** + * A DashModule is a manager of data in a Cache. + * It's responsible for providing and consuming objects from/to the registry and saving the resulting id's and/or other data into the data class. + *

+ * These may conditionally be disabled by {@link DashModule#isActive()}. + * + * @param The Data class which will be saved + */ +public interface DashModule { + /** + * This runs when the module gets reset by dashloader. + * This is used to reset CachingData instances to their correct state. + * + * @param cache The cache object which is resetting. + */ + void reset(Cache cache); + + /** + * Runs when DashLoader is creating a save. + * This should fill the RegistryFactory with objects that it wants available on next load. + * + * @param writer RegistryWriter to provide objects to. + * @param task Task to track progress of the saving. + * @return The DataObject which will be saved for next load. + */ + D save(RegistryWriter writer, StepTask task); + + /** + * Runs when DashLoader is loading back a save. + * This should read back the objects from the RegistryReading with the ids commonly saved in the DataObject. + * + * @param data DataObject which got saved in {@link DashModule#save(RegistryWriter, StepTask)} + * @param reader RegistryReader which contains objects which got cached. + * @param task Task to track progress of the loading. + */ + void load(D data, RegistryReader reader, StepTask task); + + /** + * Gets the DataClass which the module uses to save data for the cache load. + */ + Class getDataClass(); + + /** + * Returns if the module is currently active. + *

+ * When saving, if the module is active it will run the save method and then save the data object to the cache. + *

+ * When loading back the cache. If the cache did not have the module in the same state as now, it will force a recache. + */ + default boolean isActive() { + return true; + } + + /** + * The weight of the module in the progress task. + * The bigger the value the more space the module will use in the progress. + */ + default float taskWeight() { + return 100; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/api/DashObject.java b/forge/src/main/java/dev/notalpha/dashloader/api/DashObject.java new file mode 100644 index 00000000..bc835637 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/api/DashObject.java @@ -0,0 +1,38 @@ +package dev.notalpha.dashloader.api; + +import dev.notalpha.dashloader.api.registry.RegistryReader; + +/** + * A DashObject is responsible for making normal objects serializable + * by mapping them to a more serializable format and deduplicating inner objects through the registry. + * + * @param The target object which it's adding support to. + */ +@SuppressWarnings("unused") +public interface DashObject { + /** + * Runs before export on the main thread. + * + * @see DashObject#export(RegistryReader) + */ + @SuppressWarnings("unused") + default void preExport(RegistryReader reader) { + } + + /** + * The export method converts the DashObject into the original counterpart which was provided on save. + *

+ * Note: This runs in parallel meaning that it does not run on the Main thread. If you need to load things on the main thread use {@link DashObject#postExport(RegistryReader)} + */ + @SuppressWarnings("unused") + O export(RegistryReader reader); + + /** + * Runs after export on the main thread. + * + * @see DashObject#export(RegistryReader) + */ + @SuppressWarnings("unused") + default void postExport(RegistryReader reader) { + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/api/cache/Cache.java b/forge/src/main/java/dev/notalpha/dashloader/api/cache/Cache.java new file mode 100644 index 00000000..71253f50 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/api/cache/Cache.java @@ -0,0 +1,52 @@ +package dev.notalpha.dashloader.api.cache; + +import dev.notalpha.taski.builtin.StepTask; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; +import java.util.function.Consumer; + +/** + * The Cache is responsible for managing, saving and loading caches from its assigned directory. + * + * @see CacheFactory + */ +public interface Cache { + /** + * Attempt to load the DashLoader cache with the current name if it exists, + * else it will set the cache into SAVE status and reset managers to be ready for caching. + * + * @param name The cache name which will be used. + */ + void load(String name); + + /** + * Create and save a cache from the modules which are currently enabled. + * + * @param taskConsumer An optional task function which allows you to track the progress. + * @return If the cache creation was successful + */ + boolean save(@Nullable Consumer taskConsumer); + + /** + * Resets the cache into an IDLE state where it resets the cache storages to save memory. + */ + void reset(); + + /** + * Remove the existing cache if it exists. + */ + void remove(); + + /** + * Gets the current status or state of the Cache. + */ + CacheStatus getStatus(); + + /** + * Gets the current directory of the cache. + * + * @return Path to the cache directory which contains the data. + */ + Path getDir(); +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/api/cache/CacheFactory.java b/forge/src/main/java/dev/notalpha/dashloader/api/cache/CacheFactory.java new file mode 100644 index 00000000..14628d2c --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/api/cache/CacheFactory.java @@ -0,0 +1,54 @@ +package dev.notalpha.dashloader.api.cache; + +import dev.notalpha.dashloader.CacheFactoryImpl; +import dev.notalpha.dashloader.api.DashModule; +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryWriter; + +import java.nio.file.Path; +import java.util.function.BiFunction; + +/** + * The CacheFactory is used to construct a {@link Cache} + */ +public interface CacheFactory { + /** + * Creates a new Factory + * + * @return CacheFactory + */ + static CacheFactory create() { + return new CacheFactoryImpl(); + } + + /** + * Adds a DashObject to the Cache, this will allow the Cache to cache the DashObject's target. + * + * @param dashClass The class + */ + void addDashObject(Class> dashClass); + + /** + * Adds a module to the Cache. Please note only enabled Modules will actually be cached. + */ + void addModule(DashModule module); + + /** + * Adds a missing handler to the Cache, a missing handler is used when an Object does not have a DashObject directly bound to it. + * The registry will go through every missing handler until it finds one which does not return {@code null}. + * @param rClass The class which the object needs to implement. + * If you want to go through any object you can insert {@code Object.class} because every java object inherits this. + * @param func The consumer function for an object which fits the {@code rClass}. + * If this function returns a non-null value, it will use that DashObject for serialization of that object. + * @param The super class of the objects being missed. + */ + void addMissingHandler(Class rClass, BiFunction> func); + + /** + * Builds the cache object. + * + * @param path The directory which contains the caches. + * @return A DashLoader cache object. + */ + Cache build(Path path); +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/api/cache/CacheStatus.java b/forge/src/main/java/dev/notalpha/dashloader/api/cache/CacheStatus.java new file mode 100644 index 00000000..02c7b5d6 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/api/cache/CacheStatus.java @@ -0,0 +1,19 @@ +package dev.notalpha.dashloader.api.cache; + +/** + * Status/State values for a given Cache. + */ +public enum CacheStatus { + /** + * The cache is in an IDLE state where there are no temporary resources in memory. + */ + IDLE, + /** + * The Cache is loading back an existing cache from a file. + */ + LOAD, + /** + * The Cache is trying to create/save a cache. + */ + SAVE, +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/api/collection/IntIntList.java b/forge/src/main/java/dev/notalpha/dashloader/api/collection/IntIntList.java new file mode 100644 index 00000000..6a82ada4 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/api/collection/IntIntList.java @@ -0,0 +1,26 @@ +package dev.notalpha.dashloader.api.collection; + +import java.util.ArrayList; +import java.util.List; + +public record IntIntList(List list) { + public IntIntList() { + this(new ArrayList<>()); + } + + public void put(int key, int value) { + this.list.add(new IntInt(key, value)); + } + + public void forEach(IntIntConsumer c) { + this.list.forEach(v -> c.accept(v.key, v.value)); + } + + @FunctionalInterface + public interface IntIntConsumer { + void accept(int key, int value); + } + + public record IntInt(int key, int value) { + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/api/collection/IntObjectList.java b/forge/src/main/java/dev/notalpha/dashloader/api/collection/IntObjectList.java new file mode 100644 index 00000000..46f7104c --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/api/collection/IntObjectList.java @@ -0,0 +1,26 @@ +package dev.notalpha.dashloader.api.collection; + +import java.util.ArrayList; +import java.util.List; + +public record IntObjectList(List> list) { + public IntObjectList() { + this(new ArrayList<>()); + } + + public void put(int key, V value) { + this.list.add(new IntObjectEntry<>(key, value)); + } + + public void forEach(IntObjectConsumer c) { + this.list.forEach(v -> c.accept(v.key, v.value)); + } + + @FunctionalInterface + public interface IntObjectConsumer { + void accept(int key, V value); + } + + public record IntObjectEntry(int key, V value) { + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/api/collection/ObjectIntList.java b/forge/src/main/java/dev/notalpha/dashloader/api/collection/ObjectIntList.java new file mode 100644 index 00000000..2b1c0b41 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/api/collection/ObjectIntList.java @@ -0,0 +1,26 @@ +package dev.notalpha.dashloader.api.collection; + +import java.util.ArrayList; +import java.util.List; + +public record ObjectIntList(List> list) { + public ObjectIntList() { + this(new ArrayList<>()); + } + + public void put(K key, int value) { + this.list.add(new ObjectIntEntry<>(key, value)); + } + + public void forEach(ObjectIntConsumer c) { + this.list.forEach(v -> c.accept(v.key, v.value)); + } + + @FunctionalInterface + public interface ObjectIntConsumer { + void accept(K key, int value); + } + + public record ObjectIntEntry(K key, int value) { + } +} \ No newline at end of file diff --git a/forge/src/main/java/dev/notalpha/dashloader/api/collection/ObjectObjectList.java b/forge/src/main/java/dev/notalpha/dashloader/api/collection/ObjectObjectList.java new file mode 100644 index 00000000..d9c0a48d --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/api/collection/ObjectObjectList.java @@ -0,0 +1,22 @@ +package dev.notalpha.dashloader.api.collection; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiConsumer; + +public record ObjectObjectList(List> list) { + public ObjectObjectList() { + this(new ArrayList<>()); + } + + public void put(K key, V value) { + this.list.add(new ObjectObjectEntry<>(key, value)); + } + + public void forEach(BiConsumer c) { + this.list.forEach(v -> c.accept(v.key, v.value)); + } + + public record ObjectObjectEntry(K key, V value) { + } +} \ No newline at end of file diff --git a/forge/src/main/java/dev/notalpha/dashloader/api/registry/RegistryAddException.java b/forge/src/main/java/dev/notalpha/dashloader/api/registry/RegistryAddException.java new file mode 100644 index 00000000..30fc972f --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/api/registry/RegistryAddException.java @@ -0,0 +1,17 @@ +package dev.notalpha.dashloader.api.registry; + +public class RegistryAddException extends RuntimeException { + public final Class targetClass; + public final Object object; + + public RegistryAddException(Class targetClass, Object object) { + super(); + this.targetClass = targetClass; + this.object = object; + } + + @Override + public String getMessage() { + return "Could not find a ChunkWriter for " + targetClass + ": " + object; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/api/registry/RegistryReader.java b/forge/src/main/java/dev/notalpha/dashloader/api/registry/RegistryReader.java new file mode 100644 index 00000000..d114f330 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/api/registry/RegistryReader.java @@ -0,0 +1,18 @@ +package dev.notalpha.dashloader.api.registry; + +/** + * The RegistryReader is used to read objects from the cache's registry. + * + * @see RegistryWriter + */ +public interface RegistryReader { + /** + * Gets an object from the Cache. + * + * @param pointer The registry pointer to the object. + * @param Target object class. + * @return The object that got cached. + * @see RegistryWriter#add(Object) + */ + R get(final int pointer); +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/api/registry/RegistryUtil.java b/forge/src/main/java/dev/notalpha/dashloader/api/registry/RegistryUtil.java new file mode 100644 index 00000000..6f4aa41f --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/api/registry/RegistryUtil.java @@ -0,0 +1,43 @@ +package dev.notalpha.dashloader.api.registry; + +/** + * Contains utilities for handling RegistryIds + */ +public final class RegistryUtil { + /** + * Creates a new registry id. + * + * @param objectPos The chunk object position. + * @param chunkPos The index to the chunk the object is in. + * @return Registry ID + */ + public static int createId(int objectPos, byte chunkPos) { + if (chunkPos > 0b111111) { + throw new IllegalStateException("Chunk pos is too big. " + chunkPos + " > " + 0x3f); + } + if (objectPos > 0x3ffffff) { + throw new IllegalStateException("Object pos is too big. " + objectPos + " > " + 0x3ffffff); + } + return objectPos << 6 | (chunkPos & 0x3f); + } + + /** + * Gets the chunk id portion of the Registry ID + * + * @param id Registry ID + * @return Chunk index. + */ + public static byte getChunkId(int id) { + return (byte) (id & 0x3f); + } + + /** + * Gets the object id portion of the Registry ID + * + * @param id Registry ID + * @return The index of the object in the chunk. + */ + public static int getObjectId(int id) { + return id >>> 6; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/api/registry/RegistryWriter.java b/forge/src/main/java/dev/notalpha/dashloader/api/registry/RegistryWriter.java new file mode 100644 index 00000000..8b93f32e --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/api/registry/RegistryWriter.java @@ -0,0 +1,19 @@ +package dev.notalpha.dashloader.api.registry; + +/** + * A RegistryWriter is provided to DashObjects and Modules on save minecraft objects to the cache by converting them into DashObjects. + * On cache load, a RegistryReader is provided so you can read back the objects from the cache. + * + * @see RegistryReader + */ +public interface RegistryWriter { + /** + * Adds an object to the Cache, the object needs to have a DashObject backing it else it will fail. + * + * @param object The Object to add to the cache. + * @param The target class being cached. + * @return A registry id which points to the object. + * @see RegistryReader#get(int) + */ + int add(R object); +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/DashLoaderClient.java b/forge/src/main/java/dev/notalpha/dashloader/client/DashLoaderClient.java new file mode 100644 index 00000000..a05ee11f --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/DashLoaderClient.java @@ -0,0 +1,122 @@ +package dev.notalpha.dashloader.client; + +import dev.notalpha.dashloader.api.DashEntrypoint; +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.cache.Cache; +import dev.notalpha.dashloader.api.cache.CacheFactory; +import dev.notalpha.dashloader.client.blockstate.DashBlockState; +import dev.notalpha.dashloader.client.font.*; +import dev.notalpha.dashloader.client.identifier.DashIdentifier; +import dev.notalpha.dashloader.client.identifier.DashModelIdentifier; +import dev.notalpha.dashloader.client.identifier.DashSpriteIdentifier; +import dev.notalpha.dashloader.client.model.*; +import dev.notalpha.dashloader.client.model.components.DashBakedQuad; +import dev.notalpha.dashloader.client.model.components.DashBakedQuadCollection; +import dev.notalpha.dashloader.client.model.predicates.*; +import dev.notalpha.dashloader.client.shader.DashShader; +import dev.notalpha.dashloader.client.shader.DashVertexFormat; +import dev.notalpha.dashloader.client.shader.ShaderModule; +import dev.notalpha.dashloader.client.splash.SplashModule; +import dev.notalpha.dashloader.client.sprite.DashImage; +import dev.notalpha.dashloader.client.sprite.DashSprite; +import dev.notalpha.dashloader.client.sprite.SpriteStitcherModule; +import net.minecraft.client.render.model.json.AndMultipartModelSelector; +import net.minecraft.client.render.model.json.MultipartModelSelector; +import net.minecraft.client.render.model.json.OrMultipartModelSelector; +import net.minecraft.client.render.model.json.SimpleMultipartModelSelector; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.ModelIdentifier; +import net.minecraft.util.Identifier; + +import java.nio.file.Path; + +public class DashLoaderClient implements DashEntrypoint { + public static final Cache CACHE; + public static boolean NEEDS_RELOAD = false; + + static { + CacheFactory cacheManagerFactory = CacheFactory.create(); + /*List entryPoints = FabricLoader.getInstance().getEntrypoints("dashloader", DashEntrypoint.class); + for (DashEntrypoint entryPoint : entryPoints) { + entryPoint.onDashLoaderInit(cacheManagerFactory); + }*/ + new DashLoaderClient().onDashLoaderInit(cacheManagerFactory); + + CACHE = cacheManagerFactory.build(Path.of("./dashloader-cache/client/")); + System.out.println("DashLoaderForge loaded."); + } + + @Override + public void onDashLoaderInit(CacheFactory factory) { + factory.addModule(new FontModule()); + factory.addModule(new ModelModule()); + factory.addModule(new ShaderModule()); + factory.addModule(new SplashModule()); + factory.addModule(new SpriteStitcherModule()); + + factory.addMissingHandler( + Identifier.class, + (identifier, registryWriter) -> { + if (identifier instanceof ModelIdentifier m) { + return new DashModelIdentifier(m); + } else { + return new DashIdentifier(identifier); + } + } + ); + + factory.addMissingHandler( + Sprite.class, + DashSprite::new + ); + factory.addMissingHandler( + MultipartModelSelector.class, + (selector, writer) -> { + if (selector == MultipartModelSelector.TRUE) { + return new DashStaticPredicate(true); + } else if (selector == MultipartModelSelector.FALSE) { + return new DashStaticPredicate(false); + } else if (selector instanceof AndMultipartModelSelector s) { + return new DashAndPredicate(s, writer); + } else if (selector instanceof OrMultipartModelSelector s) { + return new DashOrPredicate(s, writer); + } else if (selector instanceof SimpleMultipartModelSelector s) { + return new DashSimplePredicate(s); + } else if (selector instanceof BooleanSelector s) { + return new DashStaticPredicate(s.selector); + } else { + throw new RuntimeException("someone is having fun with lambda selectors again"); + } + } + ); + + //noinspection unchecked + for (Class> aClass : new Class[]{ + DashIdentifier.class, + DashModelIdentifier.class, + DashBasicBakedModel.class, + DashBuiltinBakedModel.class, + DashMultipartBakedModel.class, + DashWeightedBakedModel.class, + DashBakedQuad.class, + DashBakedQuadCollection.class, + DashSpriteIdentifier.class, + DashAndPredicate.class, + DashOrPredicate.class, + DashSimplePredicate.class, + DashStaticPredicate.class, + DashImage.class, + DashSprite.class, + DashBitmapFont.class, + DashBlankFont.class, + DashSpaceFont.class, + DashTrueTypeFont.class, + DashUnihexFont.class, + DashBlockState.class, + DashVertexFormat.class, + DashShader.class + }) { + factory.addDashObject(aClass); + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/Dazy.java b/forge/src/main/java/dev/notalpha/dashloader/client/Dazy.java new file mode 100644 index 00000000..fce79c4a --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/Dazy.java @@ -0,0 +1,23 @@ +package dev.notalpha.dashloader.client; + +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.SpriteIdentifier; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Function; + +// its lazy, but dash! Used for resolution of sprites. +public abstract class Dazy { + @Nullable + private transient V loaded; + + protected abstract V resolve(Function spriteLoader); + public V get(Function spriteLoader) { + if (loaded != null) { + return loaded; + } + + loaded = resolve(spriteLoader); + return loaded; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/blockstate/DashBlockState.java b/forge/src/main/java/dev/notalpha/dashloader/client/blockstate/DashBlockState.java new file mode 100644 index 00000000..68d62fbd --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/blockstate/DashBlockState.java @@ -0,0 +1,86 @@ +package dev.notalpha.dashloader.client.blockstate; + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.mixin.accessor.ModelLoaderAccessor; +import net.minecraft.block.BlockState; +import net.minecraft.registry.Registries; +import net.minecraft.util.Identifier; + +public final class DashBlockState implements DashObject { + public static final Identifier ITEM_FRAME = new Identifier("dashloader:itemframewhy"); + public final int owner; + public final int pos; + + public DashBlockState(int owner, int pos) { + this.owner = owner; + this.pos = pos; + } + + public DashBlockState(BlockState blockState, RegistryWriter writer) { + var block = blockState.getBlock(); + int pos = -1; + + Identifier owner = null; + { + var states = ModelLoaderAccessor.getTheItemFrameThing().getStates(); + for (int i = 0; i < states.size(); i++) { + BlockState state = states.get(i); + if (state.equals(blockState)) { + pos = i; + owner = ITEM_FRAME; + break; + } + } + } + + if (pos == -1) { + var states = block.getStateManager().getStates(); + for (int i = 0; i < states.size(); i++) { + BlockState state = states.get(i); + if (state.equals(blockState)) { + pos = i; + owner = Registries.BLOCK.getId(block); + break; + } + } + } + + if (owner == null) { + throw new RuntimeException("Could not find a blockstate for " + blockState); + } + + this.owner = writer.add(owner); + this.pos = pos; + } + + @Override + public BlockState export(final RegistryReader reader) { + final Identifier id = reader.get(this.owner); + // if its item frame get its state from the model loader as mojank is mojank + if (id.equals(ITEM_FRAME)) { + return ModelLoaderAccessor.getTheItemFrameThing().getStates().get(this.pos); + } else { + return Registries.BLOCK.get(id).getStateManager().getStates().get(this.pos); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DashBlockState that = (DashBlockState) o; + + if (owner != that.owner) return false; + return pos == that.pos; + } + + @Override + public int hashCode() { + int result = owner; + result = 31 * result + pos; + return result; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFont.java b/forge/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFont.java new file mode 100644 index 00000000..247f6541 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFont.java @@ -0,0 +1,39 @@ +package dev.notalpha.dashloader.client.font; + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.collection.IntObjectList; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.mixin.accessor.BitmapFontAccessor; +import net.minecraft.client.font.BitmapFont; +import net.minecraft.client.font.GlyphContainer; + +import java.util.ArrayList; + +public final class DashBitmapFont implements DashObject { + public final int image; + public final IntObjectList glyphs; + + public DashBitmapFont(int image, + IntObjectList glyphs) { + this.image = image; + this.glyphs = glyphs; + } + + public DashBitmapFont(BitmapFont bitmapFont, RegistryWriter writer) { + BitmapFontAccessor font = ((BitmapFontAccessor) bitmapFont); + this.image = writer.add(font.getImage()); + this.glyphs = new IntObjectList<>(new ArrayList<>()); + font.getGlyphs().forEachGlyph((integer, bitmapFontGlyph) -> this.glyphs.put(integer, new DashBitmapFontGlyph(bitmapFontGlyph, writer))); + } + + public BitmapFont export(RegistryReader reader) { + GlyphContainer out = new GlyphContainer<>( + BitmapFont.BitmapFontGlyph[]::new, + BitmapFont.BitmapFontGlyph[][]::new + ); + this.glyphs.forEach((key, value) -> out.put(key, value.export(reader))); + return BitmapFontAccessor.init(reader.get(this.image), out); + } + +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFontGlyph.java b/forge/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFontGlyph.java new file mode 100644 index 00000000..3aa4ee29 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFontGlyph.java @@ -0,0 +1,44 @@ +package dev.notalpha.dashloader.client.font; + +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.mixin.accessor.BitmapFontGlyphAccessor; +import net.minecraft.client.font.BitmapFont; + +public final class DashBitmapFontGlyph { + public final float scaleFactor; + public final int image; + public final int x; + public final int y; + public final int width; + public final int height; + public final int advance; + public final int ascent; + + public DashBitmapFontGlyph(float scaleFactor, int image, int x, int y, int width, int height, int advance, int ascent) { + this.scaleFactor = scaleFactor; + this.image = image; + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.advance = advance; + this.ascent = ascent; + } + + public DashBitmapFontGlyph(BitmapFont.BitmapFontGlyph bitmapFontGlyph, RegistryWriter writer) { + BitmapFontGlyphAccessor font = ((BitmapFontGlyphAccessor) (Object) bitmapFontGlyph); + this.scaleFactor = font.getScaleFactor(); + this.image = writer.add(font.getImage()); + this.x = font.getX(); + this.y = font.getY(); + this.width = font.getWidth(); + this.height = font.getHeight(); + this.advance = font.getAdvance(); + this.ascent = font.getAscent(); + } + + public BitmapFont.BitmapFontGlyph export(RegistryReader handler) { + return BitmapFontGlyphAccessor.init(this.scaleFactor, handler.get(this.image), this.x, this.y, this.width, this.height, this.advance, this.ascent); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/font/DashBlankFont.java b/forge/src/main/java/dev/notalpha/dashloader/client/font/DashBlankFont.java new file mode 100644 index 00000000..24414c1d --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/font/DashBlankFont.java @@ -0,0 +1,12 @@ +package dev.notalpha.dashloader.client.font; + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import net.minecraft.client.font.BlankFont; + +public final class DashBlankFont implements DashObject { + @Override + public BlankFont export(RegistryReader exportHandler) { + return new BlankFont(); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/font/DashSpaceFont.java b/forge/src/main/java/dev/notalpha/dashloader/client/font/DashSpaceFont.java new file mode 100644 index 00000000..720dae61 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/font/DashSpaceFont.java @@ -0,0 +1,38 @@ +package dev.notalpha.dashloader.client.font; + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import it.unimi.dsi.fastutil.ints.Int2FloatArrayMap; +import it.unimi.dsi.fastutil.ints.IntSet; +import net.minecraft.client.font.Glyph; +import net.minecraft.client.font.SpaceFont; + +public final class DashSpaceFont implements DashObject { + public final int[] ints; + public final float[] floats; + + public DashSpaceFont(int[] ints, float[] floats) { + this.ints = ints; + this.floats = floats; + } + + public DashSpaceFont(SpaceFont font) { + IntSet glyphs = font.getProvidedGlyphs(); + this.ints = new int[glyphs.size()]; + this.floats = new float[glyphs.size()]; + int i = 0; + for (Integer providedGlyph : glyphs) { + Glyph glyph = font.getGlyph(providedGlyph); + assert glyph != null; + this.ints[i] = providedGlyph; + this.floats[i] = glyph.getAdvance(); + i++; + } + } + + + @Override + public SpaceFont export(RegistryReader exportHandler) { + return new SpaceFont(new Int2FloatArrayMap(ints, floats)); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/font/DashTrueTypeFont.java b/forge/src/main/java/dev/notalpha/dashloader/client/font/DashTrueTypeFont.java new file mode 100644 index 00000000..97181696 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/font/DashTrueTypeFont.java @@ -0,0 +1,90 @@ +package dev.notalpha.dashloader.client.font; + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.io.IOHelper; +import dev.notalpha.dashloader.misc.UnsafeHelper; +import dev.notalpha.dashloader.mixin.accessor.TrueTypeFontAccessor; +import it.unimi.dsi.fastutil.ints.IntArraySet; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TrueTypeFont; +import net.minecraft.resource.Resource; +import net.minecraft.util.Identifier; +import org.lwjgl.stb.STBTTFontinfo; +import org.lwjgl.stb.STBTruetype; +import org.lwjgl.system.MemoryUtil; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public final class DashTrueTypeFont implements DashObject { + public final byte[] ttfBuffer; + public final float oversample; + public final List excludedCharacters; + public final float shiftX; + public final float shiftY; + public final float scaleFactor; + public final float ascent; + + + public DashTrueTypeFont(byte[] ttfBuffer, float oversample, List excludedCharacters, float shiftX, float shiftY, float scaleFactor, float ascent) { + this.ttfBuffer = ttfBuffer; + this.oversample = oversample; + this.excludedCharacters = excludedCharacters; + this.shiftX = shiftX; + this.shiftY = shiftY; + this.scaleFactor = scaleFactor; + this.ascent = ascent; + } + + public DashTrueTypeFont(TrueTypeFont font) { + TrueTypeFontAccessor fontAccess = (TrueTypeFontAccessor) font; + final Identifier ttFont = FontModule.FONT_TO_IDENT.get(CacheStatus.SAVE).get(fontAccess.getInfo()); + byte[] data = null; + try { + Optional resource = MinecraftClient.getInstance().getResourceManager().getResource(new Identifier(ttFont.getNamespace(), "font/" + ttFont.getPath())); + if (resource.isPresent()) { + data = IOHelper.streamToArray(resource.get().getInputStream()); + } + } catch (IOException e) { + e.printStackTrace(); + } + this.ttfBuffer = data; + this.oversample = fontAccess.getOversample(); + this.excludedCharacters = new ArrayList<>(fontAccess.getExcludedCharacters()); + this.shiftX = fontAccess.getShiftX(); + this.shiftY = fontAccess.getShiftY(); + this.scaleFactor = fontAccess.getScaleFactor(); + this.ascent = fontAccess.getAscent(); + } + + @Override + public TrueTypeFont export(RegistryReader handler) { + STBTTFontinfo sTBTTFontinfo = STBTTFontinfo.malloc(); + ByteBuffer byteBuffer2 = MemoryUtil.memAlloc(this.ttfBuffer.length); + byteBuffer2.put(this.ttfBuffer); + byteBuffer2.flip(); + if (!STBTruetype.stbtt_InitFont(sTBTTFontinfo, byteBuffer2)) { + try { + throw new IOException("Invalid ttf"); + } catch (IOException e) { + e.printStackTrace(); + } + } + TrueTypeFont trueTypeFont = UnsafeHelper.allocateInstance(TrueTypeFont.class); + TrueTypeFontAccessor trueTypeFontAccess = (TrueTypeFontAccessor) trueTypeFont; + trueTypeFontAccess.setInfo(sTBTTFontinfo); + trueTypeFontAccess.setOversample(this.oversample); + trueTypeFontAccess.setBuffer(byteBuffer2); + trueTypeFontAccess.setExcludedCharacters(new IntArraySet(this.excludedCharacters)); + trueTypeFontAccess.setShiftX(this.shiftX); + trueTypeFontAccess.setShiftY(this.shiftY); + trueTypeFontAccess.setScaleFactor(this.scaleFactor); + trueTypeFontAccess.setAscent(this.ascent); + return trueTypeFont; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/font/DashUnihexFont.java b/forge/src/main/java/dev/notalpha/dashloader/client/font/DashUnihexFont.java new file mode 100644 index 00000000..3da2da0b --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/font/DashUnihexFont.java @@ -0,0 +1,54 @@ +package dev.notalpha.dashloader.client.font; + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.collection.IntObjectList; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.mixin.accessor.UnihexFontAccessor; +import net.minecraft.client.font.GlyphContainer; +import net.minecraft.client.font.UnihexFont; + +public final class DashUnihexFont implements DashObject { + + + public final IntObjectList glyphs; + + public DashUnihexFont(IntObjectList glyphs) { + this.glyphs = glyphs; + } + + public DashUnihexFont(UnihexFont rawFont, RegistryWriter writer) { + this.glyphs = new IntObjectList<>(); + var font = ((UnihexFontAccessor) rawFont); + var fontImages = font.getGlyphs(); + fontImages.forEachGlyph(this.glyphs::put); + } + + + public UnihexFont export(RegistryReader handler) { + GlyphContainer container = new GlyphContainer<>( + UnihexFont.UnicodeTextureGlyph[]::new, + UnihexFont.UnicodeTextureGlyph[][]::new + ); + this.glyphs.forEach(container::put); + return UnihexFontAccessor.create(container); + } + + public static class DashUnicodeTextureGlyph { + public final UnihexFont.BitmapGlyph contents; + public final int left; + public final int right; + + public DashUnicodeTextureGlyph(UnihexFont.BitmapGlyph contents, int left, int right) { + this.contents = contents; + this.left = left; + this.right = right; + } + + public DashUnicodeTextureGlyph(UnihexFont.UnicodeTextureGlyph glyph) { + this.contents = glyph.contents(); + this.left = glyph.left(); + this.right = glyph.right(); + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/font/FontModule.java b/forge/src/main/java/dev/notalpha/dashloader/client/font/FontModule.java new file mode 100644 index 00000000..ef2dcd2f --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/font/FontModule.java @@ -0,0 +1,127 @@ +package dev.notalpha.dashloader.client.font; + +import dev.notalpha.dashloader.api.CachingData; +import dev.notalpha.dashloader.api.DashModule; +import dev.notalpha.dashloader.api.cache.Cache; +import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.api.collection.IntObjectList; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.config.ConfigHandler; +import dev.notalpha.dashloader.config.Option; +import dev.notalpha.taski.builtin.StepTask; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.client.font.Font; +import net.minecraft.client.font.FontManager; +import net.minecraft.util.Identifier; +import org.apache.commons.lang3.tuple.Pair; +import org.lwjgl.stb.STBTTFontinfo; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class FontModule implements DashModule { + public static final CachingData DATA = new CachingData<>(); + public static final CachingData> FONT_TO_IDENT = new CachingData<>(); + + @Override + public void reset(Cache cache) { + DATA.reset(cache, new ProviderIndex(new HashMap<>(), new ArrayList<>())); + FONT_TO_IDENT.reset(cache, new HashMap<>()); + } + + @Override + public Data save(RegistryWriter factory, StepTask task) { + ProviderIndex providerIndex = DATA.get(CacheStatus.SAVE); + assert providerIndex != null; + + + int taskSize = 0; + for (List value : providerIndex.providers.values()) { + taskSize += value.size(); + } + taskSize += providerIndex.allProviders.size(); + task.reset(taskSize); + + var providers = new IntObjectList>(); + providerIndex.providers.forEach((identifier, fonts) -> { + var values = new ArrayList(); + for (Font font : fonts) { + values.add(factory.add(font)); + task.next(); + } + providers.put(factory.add(identifier), values); + }); + + var allProviders = new ArrayList(); + for (Font allProvider : providerIndex.allProviders) { + allProviders.add(factory.add(allProvider)); + task.next(); + } + + return new Data(new DashProviderIndex(providers, allProviders)); + } + + @Override + public void load(Data data, RegistryReader reader, StepTask task) { + ProviderIndex index = new ProviderIndex(new HashMap<>(), new ArrayList<>()); + data.fontMap.providers.forEach((key, value) -> { + var fonts = new ArrayList(); + for (Integer i : value) { + fonts.add(reader.get(i)); + } + index.providers.put(reader.get(key), fonts); + }); + + data.fontMap.allProviders.forEach((value) -> { + index.allProviders.add(reader.get(value)); + }); + DATA.set(CacheStatus.LOAD, index); + } + + @Override + public Class getDataClass() { + return Data.class; + } + + @Override + public boolean isActive() { + return ConfigHandler.optionActive(Option.CACHE_FONT); + } + + public static final class Data { + public final DashProviderIndex fontMap; + + public Data(DashProviderIndex fontMap) { + this.fontMap = fontMap; + } + } + + public static final class DashProviderIndex { + public final IntObjectList> providers; + public final List allProviders; + + public DashProviderIndex(IntObjectList> providers, List allProviders) { + this.providers = providers; + this.allProviders = allProviders; + } + } + + public static final class ProviderIndex { + public final Map> providers; + public final List allProviders; + + + public ProviderIndex(Map> providers, List allProviders) { + this.providers = providers; + this.allProviders = allProviders; + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/identifier/DashIdentifier.java b/forge/src/main/java/dev/notalpha/dashloader/client/identifier/DashIdentifier.java new file mode 100644 index 00000000..6e194119 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/identifier/DashIdentifier.java @@ -0,0 +1,44 @@ +package dev.notalpha.dashloader.client.identifier; + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.mixin.accessor.IdentifierAccessor; +import net.minecraft.util.Identifier; + +public final class DashIdentifier implements DashObject { + public final String namespace; + public final String path; + + public DashIdentifier(String namespace, String path) { + this.namespace = namespace; + this.path = path; + } + + public DashIdentifier(Identifier identifier) { + this.namespace = identifier.getNamespace(); + this.path = identifier.getPath(); + } + + @Override + public Identifier export(RegistryReader exportHandler) { + return IdentifierAccessor.init(this.namespace, this.path, null); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DashIdentifier that = (DashIdentifier) o; + + if (!namespace.equals(that.namespace)) return false; + return path.equals(that.path); + } + + @Override + public int hashCode() { + int result = namespace.hashCode(); + result = 31 * result + path.hashCode(); + return result; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/identifier/DashModelIdentifier.java b/forge/src/main/java/dev/notalpha/dashloader/client/identifier/DashModelIdentifier.java new file mode 100644 index 00000000..8eaaa499 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/identifier/DashModelIdentifier.java @@ -0,0 +1,50 @@ +package dev.notalpha.dashloader.client.identifier; + + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.mixin.accessor.ModelIdentifierAccessor; +import net.minecraft.client.util.ModelIdentifier; + +public final class DashModelIdentifier implements DashObject { + public final String namespace; + public final String path; + public final String variant; + + public DashModelIdentifier(ModelIdentifier identifier) { + this.namespace = identifier.getNamespace(); + this.path = identifier.getPath(); + this.variant = identifier.getVariant(); + } + + public DashModelIdentifier(String namespace, String path, String variant) { + this.namespace = namespace; + this.path = path; + this.variant = variant; + } + + @Override + public ModelIdentifier export(RegistryReader exportHandler) { + return ModelIdentifierAccessor.init(namespace, path, variant, null); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DashModelIdentifier that = (DashModelIdentifier) o; + + if (!namespace.equals(that.namespace)) return false; + if (!path.equals(that.path)) return false; + return variant.equals(that.variant); + } + + @Override + public int hashCode() { + int result = namespace.hashCode(); + result = 31 * result + path.hashCode(); + result = 31 * result + variant.hashCode(); + return result; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/identifier/DashSpriteIdentifier.java b/forge/src/main/java/dev/notalpha/dashloader/client/identifier/DashSpriteIdentifier.java new file mode 100644 index 00000000..bdd32526 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/identifier/DashSpriteIdentifier.java @@ -0,0 +1,27 @@ +package dev.notalpha.dashloader.client.identifier; + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import net.minecraft.client.util.SpriteIdentifier; +import net.minecraft.util.Identifier; + +public class DashSpriteIdentifier implements DashObject { + public final int atlas; + public final int texture; + + public DashSpriteIdentifier(int atlas, int texture) { + this.atlas = atlas; + this.texture = texture; + } + + public DashSpriteIdentifier(SpriteIdentifier identifier, RegistryWriter writer) { + this.atlas = writer.add(identifier.getAtlasId()); + this.texture = writer.add(identifier.getTextureId()); + } + + @Override + public SpriteIdentifier export(RegistryReader reader) { + return new SpriteIdentifier(reader.get(atlas), reader.get(texture)); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/model/DashBasicBakedModel.java b/forge/src/main/java/dev/notalpha/dashloader/client/model/DashBasicBakedModel.java new file mode 100644 index 00000000..d62680de --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/model/DashBasicBakedModel.java @@ -0,0 +1,172 @@ +package dev.notalpha.dashloader.client.model; + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.collection.ObjectObjectList; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.client.Dazy; +import dev.notalpha.dashloader.client.model.components.BakedQuadCollection; +import dev.notalpha.dashloader.client.model.components.DashBakedQuadCollection; +import dev.notalpha.dashloader.client.model.components.DashModelOverrideList; +import dev.notalpha.dashloader.client.model.components.DashModelTransformation; +import dev.notalpha.dashloader.client.sprite.DashSprite; +import dev.notalpha.dashloader.mixin.accessor.BasicBakedModelAccessor; +import dev.quantumfusion.hyphen.scan.annotations.DataNullable; +import net.minecraft.client.render.model.BakedQuad; +import net.minecraft.client.render.model.BasicBakedModel; +import net.minecraft.client.render.model.json.ModelOverrideList; +import net.minecraft.client.render.model.json.ModelTransformation; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.SpriteIdentifier; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.random.Random; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; + +public final class DashBasicBakedModel implements DashObject { + public final int quads; + public final ObjectObjectList faceQuads; + public final boolean usesAo; + public final boolean hasDepth; + public final boolean isSideLit; + @DataNullable + public final DashModelTransformation transformation; + public final DashModelOverrideList itemPropertyOverrides; + public final int spritePointer; + + public DashBasicBakedModel(int quads, + ObjectObjectList faceQuads, + boolean usesAo, boolean hasDepth, boolean isSideLit, + DashModelTransformation transformation, + DashModelOverrideList itemPropertyOverrides, + int spritePointer) { + this.quads = quads; + this.faceQuads = faceQuads; + this.usesAo = usesAo; + this.hasDepth = hasDepth; + this.isSideLit = isSideLit; + this.transformation = transformation; + this.itemPropertyOverrides = itemPropertyOverrides; + this.spritePointer = spritePointer; + } + + + public DashBasicBakedModel(BasicBakedModel basicBakedModel, RegistryWriter writer) { + BasicBakedModelAccessor access = ((BasicBakedModelAccessor) basicBakedModel); + + Random random = Random.create(); + this.quads = writer.add(new BakedQuadCollection(basicBakedModel.getQuads(null, null, random))); + this.faceQuads = new ObjectObjectList<>(); + for (Direction value : Direction.values()) { + this.faceQuads.put(value, writer.add(new BakedQuadCollection(basicBakedModel.getQuads(null, value, random)))); + } + + this.itemPropertyOverrides = new DashModelOverrideList(access.getItemPropertyOverrides(), writer); + this.usesAo = access.getUsesAo(); + this.hasDepth = access.getHasDepth(); + this.isSideLit = access.getIsSideLit(); + this.transformation = DashModelTransformation.createDashOrReturnNullIfDefault(access.getTransformation()); + this.spritePointer = writer.add(access.getSprite()); + } + + + @Override + public DazyImpl export(final RegistryReader reader) { + final DashSprite.DazyImpl sprite = reader.get(this.spritePointer); + final DashBakedQuadCollection.DazyImpl quads = reader.get(this.quads); + + var faceQuads = new HashMap(); + for (var entry : this.faceQuads.list()) { + DashBakedQuadCollection.DazyImpl collection = reader.get(entry.value()); + faceQuads.put(entry.key(), collection); + } + + return new DazyImpl( + quads, + faceQuads, + usesAo, + isSideLit, + hasDepth, + DashModelTransformation.exportOrDefault(this.transformation), + this.itemPropertyOverrides.export(reader), + sprite + ); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DashBasicBakedModel that = (DashBasicBakedModel) o; + + if (quads != that.quads) return false; + if (usesAo != that.usesAo) return false; + if (hasDepth != that.hasDepth) return false; + if (isSideLit != that.isSideLit) return false; + if (spritePointer != that.spritePointer) return false; + if (!faceQuads.equals(that.faceQuads)) return false; + if (!Objects.equals(transformation, that.transformation)) + return false; + return itemPropertyOverrides.equals(that.itemPropertyOverrides); + } + + @Override + public int hashCode() { + int result = quads; + result = 31 * result + faceQuads.hashCode(); + result = 31 * result + (usesAo ? 1 : 0); + result = 31 * result + (hasDepth ? 1 : 0); + result = 31 * result + (isSideLit ? 1 : 0); + result = 31 * result + (transformation != null ? transformation.hashCode() : 0); + result = 31 * result + itemPropertyOverrides.hashCode(); + result = 31 * result + spritePointer; + return result; + } + + public static class DazyImpl extends Dazy { + public final DashBakedQuadCollection.DazyImpl quads; + public final Map faceQuads; + public final boolean usesAo; + public final boolean isSideLit; + public final boolean hasDepth; + public final ModelTransformation transformation; + public final DashModelOverrideList.DazyImpl itemPropertyOverrides; + public final DashSprite.DazyImpl sprite; + + public DazyImpl(DashBakedQuadCollection.DazyImpl quads, + Map faceQuads, + boolean usesAo, + boolean isSideLit, + boolean hasDepth, + ModelTransformation transformation, + DashModelOverrideList.DazyImpl itemPropertyOverrides, + DashSprite.DazyImpl sprite) { + this.quads = quads; + this.faceQuads = faceQuads; + this.usesAo = usesAo; + this.isSideLit = isSideLit; + this.hasDepth = hasDepth; + this.transformation = transformation; + this.itemPropertyOverrides = itemPropertyOverrides; + this.sprite = sprite; + } + + @Override + protected BasicBakedModel resolve(Function spriteLoader) { + List quads = this.quads.get(spriteLoader); + var faceQuadsOut = new HashMap>(); + this.faceQuads.forEach((direction, dazy) -> { + faceQuadsOut.put(direction, dazy.get(spriteLoader)); + }); + + Sprite sprite = this.sprite.get(spriteLoader); + ModelOverrideList list = itemPropertyOverrides.get(spriteLoader); + return new BasicBakedModel(quads, faceQuadsOut, usesAo, isSideLit, hasDepth, sprite, transformation, list); + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/model/DashBuiltinBakedModel.java b/forge/src/main/java/dev/notalpha/dashloader/client/model/DashBuiltinBakedModel.java new file mode 100644 index 00000000..8efca594 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/model/DashBuiltinBakedModel.java @@ -0,0 +1,95 @@ +package dev.notalpha.dashloader.client.model; + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.client.Dazy; +import dev.notalpha.dashloader.client.model.components.DashModelOverrideList; +import dev.notalpha.dashloader.client.model.components.DashModelTransformation; +import dev.notalpha.dashloader.client.sprite.DashSprite; +import dev.notalpha.dashloader.mixin.accessor.BuiltinBakedModelAccessor; +import dev.quantumfusion.hyphen.scan.annotations.DataNullable; +import net.minecraft.client.render.model.BuiltinBakedModel; +import net.minecraft.client.render.model.json.ModelOverrideList; +import net.minecraft.client.render.model.json.ModelTransformation; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.SpriteIdentifier; + +import java.util.Objects; +import java.util.function.Function; + +public final class DashBuiltinBakedModel implements DashObject { + @DataNullable + public final DashModelTransformation transformation; + public final DashModelOverrideList itemPropertyOverrides; + public final int spritePointer; + public final boolean sideLit; + + public DashBuiltinBakedModel(DashModelTransformation transformation, DashModelOverrideList itemPropertyOverrides, int spritePointer, boolean sideLit) { + this.transformation = transformation; + this.itemPropertyOverrides = itemPropertyOverrides; + this.spritePointer = spritePointer; + this.sideLit = sideLit; + } + + public DashBuiltinBakedModel(BuiltinBakedModel builtinBakedModel, RegistryWriter writer) { + BuiltinBakedModelAccessor access = ((BuiltinBakedModelAccessor) builtinBakedModel); + final ModelTransformation transformation = access.getTransformation(); + this.transformation = DashModelTransformation.createDashOrReturnNullIfDefault(transformation); + this.itemPropertyOverrides = new DashModelOverrideList(access.getItemPropertyOverrides(), writer); + this.spritePointer = writer.add(access.getSprite()); + this.sideLit = access.getSideLit(); + } + + + @Override + public DazyImpl export(RegistryReader reader) { + DashSprite.DazyImpl sprite = reader.get(this.spritePointer); + DashModelOverrideList.DazyImpl export = this.itemPropertyOverrides.export(reader); + return new DazyImpl(DashModelTransformation.exportOrDefault(this.transformation), export, sprite, this.sideLit); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DashBuiltinBakedModel that = (DashBuiltinBakedModel) o; + + if (spritePointer != that.spritePointer) return false; + if (sideLit != that.sideLit) return false; + if (!Objects.equals(transformation, that.transformation)) + return false; + return itemPropertyOverrides.equals(that.itemPropertyOverrides); + } + + @Override + public int hashCode() { + int result = transformation != null ? transformation.hashCode() : 0; + result = 31 * result + itemPropertyOverrides.hashCode(); + result = 31 * result + spritePointer; + result = 31 * result + (sideLit ? 1 : 0); + return result; + } + + public static class DazyImpl extends Dazy { + public final ModelTransformation transformation; + public final DashModelOverrideList.DazyImpl itemPropertyOverrides; + public final DashSprite.DazyImpl sprite; + public final boolean sideLit; + + public DazyImpl(ModelTransformation transformation, DashModelOverrideList.DazyImpl itemPropertyOverrides, DashSprite.DazyImpl sprite, boolean sideLit) { + this.transformation = transformation; + this.itemPropertyOverrides = itemPropertyOverrides; + this.sprite = sprite; + this.sideLit = sideLit; + } + + @Override + protected BuiltinBakedModel resolve(Function spriteLoader) { + Sprite sprite = this.sprite.get(spriteLoader); + ModelOverrideList list = itemPropertyOverrides.get(spriteLoader); + return new BuiltinBakedModel(transformation, list, sprite, sideLit); + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/model/DashMultipartBakedModel.java b/forge/src/main/java/dev/notalpha/dashloader/client/model/DashMultipartBakedModel.java new file mode 100644 index 00000000..a05463de --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/model/DashMultipartBakedModel.java @@ -0,0 +1,148 @@ +package dev.notalpha.dashloader.client.model; + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.client.Dazy; +import dev.notalpha.dashloader.mixin.accessor.MultipartBakedModelAccessor; +import net.minecraft.block.BlockState; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.MultipartBakedModel; +import net.minecraft.client.render.model.json.MultipartModelSelector; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.SpriteIdentifier; +import net.minecraft.util.Identifier; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.function.Function; +import java.util.function.Predicate; + +public class DashMultipartBakedModel implements DashObject { + public final List components; + + public DashMultipartBakedModel(List components) { + this.components = components; + } + + public DashMultipartBakedModel(MultipartBakedModel model, RegistryWriter writer) { + var access = ((MultipartBakedModelAccessor) model); + var accessComponents = access.getComponents(); + int size = accessComponents.size(); + this.components = new ArrayList<>(); + + var selectors = ModelModule.MULTIPART_PREDICATES.get(CacheStatus.SAVE).get(model); + + for (int i = 0; i < size; i++) { + BakedModel componentModel = accessComponents.get(i).getRight(); + MultipartModelSelector selector = selectors.getKey().get(i); + Identifier componentIdentifier = ModelModule.getStateManagerIdentifier(selectors.getRight()); + this.components.add(new Component( + writer.add(componentModel), + writer.add(selector), + writer.add(componentIdentifier) + )); + } + } + + @Override + public DazyImpl export(RegistryReader reader) { + List componentsOut = new ArrayList<>(this.components.size()); + this.components.forEach(component -> { + Dazy compModel = reader.get(component.model); + Identifier compIdentifier = reader.get(component.identifier); + MultipartModelSelector compSelector = reader.get(component.selector); + Predicate predicate = compSelector.getPredicate(ModelModule.getStateManager(compIdentifier)); + componentsOut.add(new DazyImpl.Component(compModel, predicate)); + }); + return new DazyImpl(componentsOut); + } + + public static final class Component { + public final int model; + public final int selector; + public final int identifier; + + + public Component(int model, int selector, int identifier) { + this.model = model; + this.selector = selector; + this.identifier = identifier; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Component component = (Component) o; + + if (model != component.model) return false; + if (selector != component.selector) return false; + return identifier == component.identifier; + } + + @Override + public int hashCode() { + int result = model; + result = 31 * result + selector; + result = 31 * result + identifier; + return result; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DashMultipartBakedModel that = (DashMultipartBakedModel) o; + + return components.equals(that.components); + } + + @Override + public int hashCode() { + return components.hashCode(); + } + + public static class DazyImpl extends Dazy { + public final List components; + + public DazyImpl(List components) { + this.components = components; + } + + @Override + protected MultipartBakedModel resolve(Function spriteLoader) { + List, BakedModel>> componentsOut = new ArrayList<>(this.components.size()); + + for (Component component : components) { + var model = component.model.get(spriteLoader); + var selector = component.selector; + componentsOut.add(Pair.of(selector, model)); + } + + MultipartBakedModel multipartBakedModel = new MultipartBakedModel(componentsOut); + MultipartBakedModelAccessor access = (MultipartBakedModelAccessor) multipartBakedModel; + // Fixes race condition which strangely does not happen in vanilla a ton? + access.setStateCache(Collections.synchronizedMap(access.getStateCache())); + return multipartBakedModel; + } + + + public static class Component { + public final Dazy model; + public final Predicate selector; + + public Component(Dazy model, Predicate selector) { + this.model = model; + this.selector = selector; + } + } + } +} + diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/model/DashWeightedBakedModel.java b/forge/src/main/java/dev/notalpha/dashloader/client/model/DashWeightedBakedModel.java new file mode 100644 index 00000000..49d759ab --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/model/DashWeightedBakedModel.java @@ -0,0 +1,84 @@ +package dev.notalpha.dashloader.client.model; + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.client.Dazy; +import dev.notalpha.dashloader.client.model.components.DashWeightedModelEntry; +import dev.notalpha.dashloader.mixin.accessor.WeightedBakedModelAccessor; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.WeightedBakedModel; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.SpriteIdentifier; +import net.minecraft.util.collection.Weighted; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +public final class DashWeightedBakedModel implements DashObject { + public final List models; + + public DashWeightedBakedModel(List models) { + this.models = models; + } + + public DashWeightedBakedModel(WeightedBakedModel model, RegistryWriter writer) { + this.models = new ArrayList<>(); + for (var weightedModel : ((WeightedBakedModelAccessor) model).getBakedModels()) { + this.models.add(new DashWeightedModelEntry(weightedModel, writer)); + } + } + + @Override + public DazyImpl export(RegistryReader reader) { + var modelsOut = new ArrayList(); + for (DashWeightedModelEntry model : this.models) { + modelsOut.add(model.export(reader)); + } + return new DazyImpl(modelsOut); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DashWeightedBakedModel that = (DashWeightedBakedModel) o; + + return models.equals(that.models); + } + + @Override + public int hashCode() { + return models.hashCode(); + } + + public static class DazyImpl extends Dazy { + public final List entries; + + public DazyImpl(List entries) { + this.entries = entries; + } + + @Override + protected WeightedBakedModel resolve(Function spriteLoader) { + List> models = new ArrayList<>(); + for (Entry entry : this.entries) { + BakedModel model = entry.model.get(spriteLoader); + models.add(Weighted.of(model, entry.weight)); + } + return new WeightedBakedModel(models); + } + + public static class Entry { + public final int weight; + public final Dazy model; + + public Entry(int weight, Dazy model) { + this.weight = weight; + this.model = model; + } + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/model/ModelModule.java b/forge/src/main/java/dev/notalpha/dashloader/client/model/ModelModule.java new file mode 100644 index 00000000..bc6588ee --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/model/ModelModule.java @@ -0,0 +1,148 @@ +package dev.notalpha.dashloader.client.model; + +import dev.notalpha.dashloader.DashLoader; +import dev.notalpha.dashloader.api.CachingData; +import dev.notalpha.dashloader.api.DashModule; +import dev.notalpha.dashloader.api.cache.Cache; +import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.api.collection.IntIntList; +import dev.notalpha.dashloader.api.registry.RegistryAddException; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.client.Dazy; +import dev.notalpha.dashloader.client.model.fallback.UnbakedBakedModel; +import dev.notalpha.dashloader.config.ConfigHandler; +import dev.notalpha.dashloader.config.Option; +import dev.notalpha.dashloader.mixin.accessor.ModelLoaderAccessor; +import dev.notalpha.taski.builtin.StepTask; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.client.render.block.BlockModels; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.json.MultipartModelSelector; +import net.minecraft.client.util.ModelIdentifier; +import net.minecraft.registry.Registries; +import net.minecraft.state.StateManager; +import net.minecraft.util.Identifier; +import org.apache.commons.lang3.tuple.Pair; +import org.jetbrains.annotations.NotNull; + +import java.util.*; + +public class ModelModule implements DashModule { + public static final CachingData> MODELS_SAVE = new CachingData<>(CacheStatus.SAVE); + public static final CachingData> MODELS_LOAD = new CachingData<>(CacheStatus.LOAD); + public static final CachingData> MISSING_READ = new CachingData<>(); + public static final CachingData, StateManager>>> MULTIPART_PREDICATES = new CachingData<>(CacheStatus.SAVE); + + @Override + public void reset(Cache cache) { + MODELS_SAVE.reset(cache, new HashMap<>()); + MODELS_LOAD.reset(cache, new HashMap<>()); + MISSING_READ.reset(cache, new HashMap<>()); + MULTIPART_PREDICATES.reset(cache, new HashMap<>()); + } + + @Override + public Data save(RegistryWriter factory, StepTask task) { + var models = MODELS_SAVE.get(CacheStatus.SAVE); + + if (models == null) { + return null; + } else { + var outModels = new IntIntList(new ArrayList<>(models.size())); + var missingModels = new IntIntList(); + + final HashSet out = new HashSet<>(); + task.doForEach(models, (identifier, bakedModel) -> { + if (bakedModel != null) { + try { + final int add = factory.add(bakedModel); + outModels.put(factory.add(identifier), add); + out.add(identifier); + } catch (RegistryAddException ignored) { + // Fallback is checked later with the blockstates missing. + } + } + }); + + + // Check missing models for blockstates. + for (Block block : Registries.BLOCK) { + block.getStateManager().getStates().forEach((blockState) -> { + final ModelIdentifier modelId = BlockModels.getModelId(blockState); + if (!out.contains(modelId)) { + missingModels.put(factory.add(blockState), factory.add(modelId)); + } + }); + } + + return new Data(outModels, missingModels); + } + } + + @Override + public void load(Data data, RegistryReader reader, StepTask task) { + final HashMap out = new HashMap<>(data.models.list().size()); + data.models.forEach((key, value) -> { + Dazy model = reader.get(value); + Identifier identifier = reader.get(key); + out.put(identifier, new UnbakedBakedModel(model)); + }); + + var missingModelsRead = new HashMap(); + data.missingModels.forEach((blockState, modelId) -> { + missingModelsRead.put(reader.get(blockState), reader.get(modelId)); + }); + + DashLoader.LOG.info("Found {} Missing BlockState Models", missingModelsRead.size()); + MISSING_READ.set(CacheStatus.LOAD, missingModelsRead); + MODELS_LOAD.set(CacheStatus.LOAD, out); + } + + @Override + public Class getDataClass() { + return Data.class; + } + + @Override + public float taskWeight() { + return 1000; + } + + @Override + public boolean isActive() { + return ConfigHandler.optionActive(Option.CACHE_MODEL_LOADER); + } + + public static StateManager getStateManager(Identifier identifier) { + StateManager staticDef = ModelLoaderAccessor.getStaticDefinitions().get(identifier); + if (staticDef != null) { + return staticDef; + } else { + return Registries.BLOCK.get(identifier).getStateManager(); + } + } + + @NotNull + public static Identifier getStateManagerIdentifier(StateManager stateManager) { + // Static definitions like itemframes. + for (Map.Entry> entry : ModelLoaderAccessor.getStaticDefinitions().entrySet()) { + if (entry.getValue() == stateManager) { + return entry.getKey(); + } + } + + return Registries.BLOCK.getId(stateManager.getOwner()); + } + + public static final class Data { + public final IntIntList models; // identifier to model list + public final IntIntList missingModels; + + public Data(IntIntList models, IntIntList missingModels) { + this.models = models; + this.missingModels = missingModels; + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/model/components/BakedQuadCollection.java b/forge/src/main/java/dev/notalpha/dashloader/client/model/components/BakedQuadCollection.java new file mode 100644 index 00000000..71266611 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/model/components/BakedQuadCollection.java @@ -0,0 +1,13 @@ +package dev.notalpha.dashloader.client.model.components; + +import net.minecraft.client.render.model.BakedQuad; + +import java.util.List; + +public class BakedQuadCollection { + public final List quads; + + public BakedQuadCollection(List quads) { + this.quads = quads; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuad.java b/forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuad.java new file mode 100644 index 00000000..97be8df4 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuad.java @@ -0,0 +1,85 @@ +package dev.notalpha.dashloader.client.model.components; + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.client.Dazy; +import dev.notalpha.dashloader.client.sprite.DashSprite; +import net.minecraft.client.render.model.BakedQuad; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.SpriteIdentifier; +import net.minecraft.util.math.Direction; + +import java.util.Arrays; +import java.util.function.Function; + +public final class DashBakedQuad implements DashObject { + public final int[] vertexData; + public final int colorIndex; + public final Direction face; + public final boolean shade; + public final int sprite; + + public DashBakedQuad(int[] vertexData, int colorIndex, Direction face, boolean shade, + int sprite) { + this.vertexData = vertexData; + this.colorIndex = colorIndex; + this.face = face; + this.shade = shade; + this.sprite = sprite; + } + + public DashBakedQuad(BakedQuad bakedQuad, RegistryWriter writer) { + this(bakedQuad.getVertexData(), bakedQuad.getColorIndex(), bakedQuad.getFace(), bakedQuad.hasShade(), writer.add(bakedQuad.getSprite())); + } + + public DazyImpl export(RegistryReader handler) { + return new DazyImpl(this.vertexData, this.colorIndex, this.face, this.shade, handler.get(this.sprite)); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DashBakedQuad that = (DashBakedQuad) o; + + if (colorIndex != that.colorIndex) return false; + if (shade != that.shade) return false; + if (sprite != that.sprite) return false; + if (!Arrays.equals(vertexData, that.vertexData)) return false; + return face == that.face; + } + + @Override + public int hashCode() { + int result = Arrays.hashCode(vertexData); + result = 31 * result + colorIndex; + result = 31 * result + face.hashCode(); + result = 31 * result + (shade ? 1 : 0); + result = 31 * result + sprite; + return result; + } + + public static class DazyImpl extends Dazy { + public final int[] vertexData; + public final int colorIndex; + public final Direction face; + public final boolean shade; + public final DashSprite.DazyImpl sprite; + + public DazyImpl(int[] vertexData, int colorIndex, Direction face, boolean shade, DashSprite.DazyImpl sprite) { + this.vertexData = vertexData; + this.colorIndex = colorIndex; + this.face = face; + this.shade = shade; + this.sprite = sprite; + } + + @Override + protected BakedQuad resolve(Function spriteLoader) { + Sprite sprite = this.sprite.get(spriteLoader); + return new BakedQuad(vertexData, colorIndex, face, sprite, shade); + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuadCollection.java b/forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuadCollection.java new file mode 100644 index 00000000..9dd82cb8 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuadCollection.java @@ -0,0 +1,71 @@ +package dev.notalpha.dashloader.client.model.components; + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.client.Dazy; +import net.minecraft.client.render.model.BakedQuad; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.SpriteIdentifier; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +public class DashBakedQuadCollection implements DashObject { + public final List quads; + + public DashBakedQuadCollection(List quads) { + this.quads = quads; + } + + public DashBakedQuadCollection(BakedQuadCollection quads, RegistryWriter writer) { + this.quads = new ArrayList<>(); + for (BakedQuad quad : quads.quads) { + this.quads.add(writer.add(quad)); + } + } + + @Override + public DazyImpl export(RegistryReader reader) { + var out = new ArrayList(this.quads.size()); + for (Integer quad : this.quads) { + out.add(reader.get(quad)); + } + return new DazyImpl(out); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DashBakedQuadCollection that = (DashBakedQuadCollection) o; + + return quads.equals(that.quads); + } + + @Override + public int hashCode() { + return quads.hashCode(); + } + + public static class DazyImpl extends Dazy> { + public final List quads; + + public DazyImpl(List quads) { + this.quads = quads; + } + + @Override + protected List resolve(Function spriteLoader) { + var out = new ArrayList(quads.size()); + quads.forEach( + dazyBakedQuad -> { + out.add(dazyBakedQuad.get(spriteLoader)); + } + ); + return out; + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashMesh.java b/forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashMesh.java new file mode 100644 index 00000000..b08ae9e8 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashMesh.java @@ -0,0 +1,84 @@ +package dev.notalpha.dashloader.client.model.components; + +import dev.notalpha.dashloader.misc.UnsafeHelper; + +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public final class DashMesh { + public static final Map> CLASS_CACHE = new ConcurrentHashMap<>(); + + public final int[] data; + public final String className; + + + public DashMesh(int[] data, String className) { + this.data = data; + this.className = className; + } + + /*public DashMesh(Mesh mesh) { + this(getData(mesh), mesh.getClass().getName()); + } + + private static int[] getData(Mesh mesh) { + final int[] data; + try { + final Field field = mesh.getClass().getDeclaredField("data"); + field.setAccessible(true); + data = (int[]) field.get(mesh); + } catch (IllegalAccessException | NoSuchFieldException e) { + throw new RuntimeException("Could not use Mesh field hack. ", e); + } + return data; + } + + public Mesh export() { + final Class aClass = getClass(this.className); + final Mesh mesh = (Mesh) UnsafeHelper.allocateInstance(aClass); + try { + assert aClass != null; + final Field data = aClass.getDeclaredField("data"); + data.setAccessible(true); + data.set(mesh, this.data); + } catch (IllegalAccessException | NoSuchFieldException e) { + throw new RuntimeException("Could not use Mesh field hack. ", e); + } + return mesh; + } + + public static Class getClass(final String className) { + final Class closs = CLASS_CACHE.get(className); + if (closs != null) { + return closs; + } + try { + final Class clz = Class.forName(className); + CLASS_CACHE.put(className, clz); + return clz; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DashMesh dashMesh = (DashMesh) o; + + if (!Arrays.equals(data, dashMesh.data)) return false; + return className.equals(dashMesh.className); + } + + @Override + public int hashCode() { + int result = Arrays.hashCode(data); + result = 31 * result + className.hashCode(); + return result; + }*/ +} \ No newline at end of file diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideList.java b/forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideList.java new file mode 100644 index 00000000..0e13f458 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideList.java @@ -0,0 +1,96 @@ +package dev.notalpha.dashloader.client.model.components; + +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.client.Dazy; +import dev.notalpha.dashloader.mixin.accessor.ModelOverrideListAccessor; +import net.minecraft.client.render.model.json.ModelOverrideList; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.SpriteIdentifier; +import net.minecraft.util.Identifier; + +import java.util.Arrays; +import java.util.function.Function; + +public final class DashModelOverrideList { + public final DashModelOverrideListBakedOverride[] overrides; + public final int[] conditionTypes; //identifiers + + public DashModelOverrideList(DashModelOverrideListBakedOverride[] overrides, int[] conditionTypes) { + this.overrides = overrides; + this.conditionTypes = conditionTypes; + } + + public DashModelOverrideList(ModelOverrideList modelOverrideList, RegistryWriter writer) { + final ModelOverrideList.BakedOverride[] overrides = ((ModelOverrideListAccessor) modelOverrideList).getOverrides(); + final Identifier[] conditionTypes = ((ModelOverrideListAccessor) modelOverrideList).getConditionTypes(); + + this.overrides = new DashModelOverrideListBakedOverride[overrides.length]; + this.conditionTypes = new int[conditionTypes.length]; + + for (int i = 0; i < overrides.length; i++) { + this.overrides[i] = new DashModelOverrideListBakedOverride(overrides[i], writer); + } + + for (int i = 0; i < conditionTypes.length; i++) { + this.conditionTypes[i] = writer.add(conditionTypes[i]); + } + } + + public DazyImpl export(RegistryReader reader) { + var conditionTypesOut = new Identifier[this.conditionTypes.length]; + for (int i = 0; i < this.conditionTypes.length; i++) { + conditionTypesOut[i] = reader.get(this.conditionTypes[i]); + } + + var overridesOut = new DashModelOverrideListBakedOverride.DazyImpl[this.overrides.length]; + for (int i = 0; i < this.overrides.length; i++) { + overridesOut[i] = this.overrides[i].export(reader); + } + + return new DazyImpl(overridesOut, conditionTypesOut); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DashModelOverrideList that = (DashModelOverrideList) o; + + // Probably incorrect - comparing Object[] arrays with Arrays.equals + if (!Arrays.equals(overrides, that.overrides)) return false; + return Arrays.equals(conditionTypes, that.conditionTypes); + } + + @Override + public int hashCode() { + int result = Arrays.hashCode(overrides); + result = 31 * result + Arrays.hashCode(conditionTypes); + return result; + } + + public static class DazyImpl extends Dazy { + public final DashModelOverrideListBakedOverride.DazyImpl[] overrides; + public final Identifier[] conditionTypes; //identifiers + + public DazyImpl(DashModelOverrideListBakedOverride.DazyImpl[] overrides, Identifier[] conditionTypes) { + this.overrides = overrides; + this.conditionTypes = conditionTypes; + } + + @Override + protected ModelOverrideList resolve(Function spriteLoader) { + var out = ModelOverrideListAccessor.newModelOverrideList(); + ModelOverrideListAccessor access = (ModelOverrideListAccessor) out; + + var overridesOut = new ModelOverrideList.BakedOverride[this.overrides.length]; + for (int i = 0; i < this.overrides.length; i++) { + overridesOut[i] = this.overrides[i].get(spriteLoader); + } + access.setConditionTypes(conditionTypes); + access.setOverrides(overridesOut); + return out; + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListBakedOverride.java b/forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListBakedOverride.java new file mode 100644 index 00000000..84b11e43 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListBakedOverride.java @@ -0,0 +1,84 @@ +package dev.notalpha.dashloader.client.model.components; + +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.client.Dazy; +import dev.notalpha.dashloader.mixin.accessor.ModelOverrideListBakedOverrideAccessor; +import dev.quantumfusion.hyphen.scan.annotations.DataNullable; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.json.ModelOverrideList; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.SpriteIdentifier; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.Objects; +import java.util.function.Function; + +public final class DashModelOverrideListBakedOverride { + public final DashModelOverrideListInlinedCondition[] conditions; + @DataNullable + public final Integer model; + + public DashModelOverrideListBakedOverride(DashModelOverrideListInlinedCondition[] conditions, @Nullable Integer model) { + this.conditions = conditions; + this.model = model; + } + + public DashModelOverrideListBakedOverride(ModelOverrideList.BakedOverride override, RegistryWriter writer) { + final ModelOverrideList.InlinedCondition[] conditionsIn = ((ModelOverrideListBakedOverrideAccessor) override).getConditions(); + BakedModel bakedModel = ((ModelOverrideListBakedOverrideAccessor) override).getModel(); + this.model = bakedModel == null ? null : writer.add(bakedModel); + + this.conditions = new DashModelOverrideListInlinedCondition[conditionsIn.length]; + for (int i = 0; i < conditionsIn.length; i++) { + this.conditions[i] = new DashModelOverrideListInlinedCondition(conditionsIn[i]); + } + } + + public DazyImpl export(RegistryReader reader) { + var conditionsOut = new ModelOverrideList.InlinedCondition[this.conditions.length]; + for (int i = 0; i < this.conditions.length; i++) { + conditionsOut[i] = this.conditions[i].export(); + } + + return new DazyImpl(conditionsOut, this.model == null ? null : reader.get(this.model)); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DashModelOverrideListBakedOverride that = (DashModelOverrideListBakedOverride) o; + + // Probably incorrect - comparing Object[] arrays with Arrays.equals + if (!Arrays.equals(conditions, that.conditions)) return false; + return Objects.equals(model, that.model); + } + + @Override + public int hashCode() { + int result = Arrays.hashCode(conditions); + result = 31 * result + (model != null ? model.hashCode() : 0); + return result; + } + + + public static class DazyImpl extends Dazy { + public final ModelOverrideList.InlinedCondition[] conditions; + @Nullable + public final Dazy model; + + public DazyImpl(ModelOverrideList.InlinedCondition[] conditions, Dazy model) { + this.conditions = conditions; + this.model = model; + } + + @Override + protected ModelOverrideList.BakedOverride resolve(Function spriteLoader) { + BakedModel bakedModel = model == null ? null : model.get(spriteLoader); + return ModelOverrideListBakedOverrideAccessor.newModelOverrideListBakedOverride(conditions, bakedModel); + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListInlinedCondition.java b/forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListInlinedCondition.java new file mode 100644 index 00000000..88ca2f05 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListInlinedCondition.java @@ -0,0 +1,40 @@ +package dev.notalpha.dashloader.client.model.components; + +import dev.notalpha.dashloader.mixin.accessor.ModelOverrideListInlinedCondition; +import net.minecraft.client.render.model.json.ModelOverrideList; + +public final class DashModelOverrideListInlinedCondition { + public final int index; + public final float threshold; + + public DashModelOverrideListInlinedCondition(int index, float threshold) { + this.index = index; + this.threshold = threshold; + } + + public DashModelOverrideListInlinedCondition(ModelOverrideList.InlinedCondition inlinedCondition) { + this(inlinedCondition.index, inlinedCondition.threshold); + } + + public ModelOverrideList.InlinedCondition export() { + return ModelOverrideListInlinedCondition.newModelOverrideListInlinedCondition(this.index, this.threshold); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DashModelOverrideListInlinedCondition that = (DashModelOverrideListInlinedCondition) o; + + if (index != that.index) return false; + return Float.compare(that.threshold, threshold) == 0; + } + + @Override + public int hashCode() { + int result = index; + result = 31 * result + (threshold != +0.0f ? Float.floatToIntBits(threshold) : 0); + return result; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelTransformation.java b/forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelTransformation.java new file mode 100644 index 00000000..21c9a51a --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelTransformation.java @@ -0,0 +1,127 @@ +package dev.notalpha.dashloader.client.model.components; + +import dev.quantumfusion.hyphen.scan.annotations.DataNullable; +import net.minecraft.client.render.model.json.ModelTransformation; +import net.minecraft.client.render.model.json.Transformation; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +@DataNullable +public final class DashModelTransformation { + public final Transformation thirdPersonLeftHand; + public final Transformation thirdPersonRightHand; + public final Transformation firstPersonLeftHand; + public final Transformation firstPersonRightHand; + public final Transformation head; + public final Transformation gui; + public final Transformation ground; + public final Transformation fixed; + + public transient int nullTransformations = 0; + + public DashModelTransformation(@Nullable Transformation thirdPersonLeftHand, @Nullable Transformation thirdPersonRightHand, @Nullable Transformation firstPersonLeftHand, @Nullable Transformation firstPersonRightHand, @Nullable Transformation head, @Nullable Transformation gui, @Nullable Transformation ground, @Nullable Transformation fixed) { + this.thirdPersonLeftHand = thirdPersonLeftHand; + this.thirdPersonRightHand = thirdPersonRightHand; + this.firstPersonLeftHand = firstPersonLeftHand; + this.firstPersonRightHand = firstPersonRightHand; + this.head = head; + this.gui = gui; + this.ground = ground; + this.fixed = fixed; + } + + public DashModelTransformation(ModelTransformation other) { + this.thirdPersonLeftHand = this.createTransformation(other.thirdPersonLeftHand); + this.thirdPersonRightHand = this.createTransformation(other.thirdPersonRightHand); + this.firstPersonLeftHand = this.createTransformation(other.firstPersonLeftHand); + this.firstPersonRightHand = this.createTransformation(other.firstPersonRightHand); + this.head = this.createTransformation(other.head); + this.gui = this.createTransformation(other.gui); + this.ground = this.createTransformation(other.ground); + this.fixed = this.createTransformation(other.fixed); + } + + @Nullable + public static DashModelTransformation createDashOrReturnNullIfDefault(ModelTransformation other) { + if (other == ModelTransformation.NONE) { + return null; + } + + DashModelTransformation out = new DashModelTransformation(other); + + if (out.nullTransformations == 8) { + return null; + } + + return out; + } + + public static ModelTransformation exportOrDefault(@Nullable DashModelTransformation other) { + if (other == null) { + return ModelTransformation.NONE; + } + + return other.export(); + } + + private Transformation createTransformation(Transformation transformation) { + if (transformation == Transformation.IDENTITY) { + this.nullTransformations++; + return null; + } else { + return transformation; + } + } + + private Transformation unTransformation(Transformation transformation) { + return transformation == null ? Transformation.IDENTITY : transformation; + } + + public ModelTransformation export() { + return new ModelTransformation( + this.unTransformation(this.thirdPersonLeftHand), + this.unTransformation(this.thirdPersonRightHand), + this.unTransformation(this.firstPersonLeftHand), + this.unTransformation(this.firstPersonRightHand), + this.unTransformation(this.head), + this.unTransformation(this.gui), + this.unTransformation(this.ground), + this.unTransformation(this.fixed) + ); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DashModelTransformation that = (DashModelTransformation) o; + + if (!Objects.equals(thirdPersonLeftHand, that.thirdPersonLeftHand)) + return false; + if (!Objects.equals(thirdPersonRightHand, that.thirdPersonRightHand)) + return false; + if (!Objects.equals(firstPersonLeftHand, that.firstPersonLeftHand)) + return false; + if (!Objects.equals(firstPersonRightHand, that.firstPersonRightHand)) + return false; + if (!Objects.equals(head, that.head)) return false; + if (!Objects.equals(gui, that.gui)) return false; + if (!Objects.equals(ground, that.ground)) return false; + return Objects.equals(fixed, that.fixed); + } + + @Override + public int hashCode() { + int result = thirdPersonLeftHand != null ? thirdPersonLeftHand.hashCode() : 0; + result = 31 * result + (thirdPersonRightHand != null ? thirdPersonRightHand.hashCode() : 0); + result = 31 * result + (firstPersonLeftHand != null ? firstPersonLeftHand.hashCode() : 0); + result = 31 * result + (firstPersonRightHand != null ? firstPersonRightHand.hashCode() : 0); + result = 31 * result + (head != null ? head.hashCode() : 0); + result = 31 * result + (gui != null ? gui.hashCode() : 0); + result = 31 * result + (ground != null ? ground.hashCode() : 0); + result = 31 * result + (fixed != null ? fixed.hashCode() : 0); + return result; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashWeightedModelEntry.java b/forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashWeightedModelEntry.java new file mode 100644 index 00000000..f7dcd5db --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashWeightedModelEntry.java @@ -0,0 +1,44 @@ +package dev.notalpha.dashloader.client.model.components; + +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.client.model.DashWeightedBakedModel; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.util.collection.Weighted; + +public final class DashWeightedModelEntry { + public final int model; + public final int weight; + + public DashWeightedModelEntry(int model, int weight) { + this.model = model; + this.weight = weight; + } + + public DashWeightedModelEntry(Weighted.Present entry, RegistryWriter writer) { + this(writer.add(entry.getData()), entry.getWeight().getValue()); + } + + + public DashWeightedBakedModel.DazyImpl.Entry export(RegistryReader handler) { + return new DashWeightedBakedModel.DazyImpl.Entry(this.weight, handler.get(this.model)); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DashWeightedModelEntry that = (DashWeightedModelEntry) o; + + if (model != that.model) return false; + return weight == that.weight; + } + + @Override + public int hashCode() { + int result = model; + result = 31 * result + weight; + return result; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/model/fallback/UnbakedBakedModel.java b/forge/src/main/java/dev/notalpha/dashloader/client/model/fallback/UnbakedBakedModel.java new file mode 100644 index 00000000..903a7876 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/model/fallback/UnbakedBakedModel.java @@ -0,0 +1,42 @@ +package dev.notalpha.dashloader.client.model.fallback; + +import dev.notalpha.dashloader.client.Dazy; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.Baker; +import net.minecraft.client.render.model.ModelBakeSettings; +import net.minecraft.client.render.model.UnbakedModel; +import net.minecraft.client.render.model.json.JsonUnbakedModel; +import net.minecraft.client.render.model.json.ModelTransformation; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.SpriteIdentifier; +import net.minecraft.util.Identifier; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +/** + * An unbaked model which holds a baked model, used for fallback to reuse cached models. + */ +public class UnbakedBakedModel implements UnbakedModel { + private final Dazy bakedModel; + + public UnbakedBakedModel(Dazy bakedModel) { + this.bakedModel = bakedModel; + } + + @Override + public Collection getModelDependencies() { + return List.of(); + } + + @Override + public void setParents(Function modelLoader) { + } + + @Override + public BakedModel bake(Baker baker, Function textureGetter, ModelBakeSettings rotationContainer, Identifier modelId) { + return this.bakedModel.get(textureGetter); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/model/predicates/BooleanSelector.java b/forge/src/main/java/dev/notalpha/dashloader/client/model/predicates/BooleanSelector.java new file mode 100644 index 00000000..c699e8c8 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/model/predicates/BooleanSelector.java @@ -0,0 +1,25 @@ +package dev.notalpha.dashloader.client.model.predicates; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.client.render.model.json.MultipartModelSelector; +import net.minecraft.state.StateManager; + +import java.util.function.Predicate; + +public class BooleanSelector implements MultipartModelSelector { + public final boolean selector; + + public BooleanSelector(boolean selector) { + this.selector = selector; + } + + public BooleanSelector(MultipartModelSelector selector) { + this.selector = selector == MultipartModelSelector.TRUE; + } + + @Override + public Predicate getPredicate(StateManager stateFactory) { + return blockState -> selector; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashAndPredicate.java b/forge/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashAndPredicate.java new file mode 100644 index 00000000..45377653 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashAndPredicate.java @@ -0,0 +1,61 @@ +package dev.notalpha.dashloader.client.model.predicates; + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.mixin.accessor.AndMultipartModelSelectorAccessor; +import net.minecraft.client.render.model.json.AndMultipartModelSelector; +import net.minecraft.client.render.model.json.MultipartModelSelector; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public final class DashAndPredicate implements DashObject { + public final int[] selectors; + + public DashAndPredicate(int[] selectors) { + this.selectors = selectors; + } + + public DashAndPredicate(AndMultipartModelSelector selector, RegistryWriter writer) { + AndMultipartModelSelectorAccessor access = ((AndMultipartModelSelectorAccessor) selector); + + Iterable accessSelectors = access.getSelectors(); + int count = 0; + for (MultipartModelSelector ignored : accessSelectors) { + count += 1; + } + this.selectors = new int[count]; + + int i = 0; + for (MultipartModelSelector accessSelector : accessSelectors) { + this.selectors[i++] = writer.add(accessSelector); + } + } + + @Override + public AndMultipartModelSelector export(RegistryReader handler) { + final List selectors = new ArrayList<>(this.selectors.length); + for (int accessSelector : this.selectors) { + selectors.add(handler.get(accessSelector)); + } + + return new AndMultipartModelSelector(selectors); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DashAndPredicate that = (DashAndPredicate) o; + + return Arrays.equals(selectors, that.selectors); + } + + @Override + public int hashCode() { + return Arrays.hashCode(selectors); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashOrPredicate.java b/forge/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashOrPredicate.java new file mode 100644 index 00000000..9a208f5a --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashOrPredicate.java @@ -0,0 +1,62 @@ +package dev.notalpha.dashloader.client.model.predicates; + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.mixin.accessor.OrMultipartModelSelectorAccessor; +import net.minecraft.client.render.model.json.MultipartModelSelector; +import net.minecraft.client.render.model.json.OrMultipartModelSelector; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + + +public final class DashOrPredicate implements DashObject { + public final int[] selectors; + + public DashOrPredicate(int[] selectors) { + this.selectors = selectors; + } + + public DashOrPredicate(OrMultipartModelSelector selector, RegistryWriter writer) { + OrMultipartModelSelectorAccessor access = ((OrMultipartModelSelectorAccessor) selector); + + Iterable accessSelectors = access.getSelectors(); + int count = 0; + for (MultipartModelSelector ignored : accessSelectors) { + count += 1; + } + this.selectors = new int[count]; + + int i = 0; + for (MultipartModelSelector accessSelector : accessSelectors) { + this.selectors[i++] = writer.add(accessSelector); + } + } + + @Override + public OrMultipartModelSelector export(RegistryReader handler) { + final List selectors = new ArrayList<>(this.selectors.length); + for (int accessSelector : this.selectors) { + selectors.add(handler.get(accessSelector)); + } + + return new OrMultipartModelSelector(selectors); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DashOrPredicate that = (DashOrPredicate) o; + + return Arrays.equals(selectors, that.selectors); + } + + @Override + public int hashCode() { + return Arrays.hashCode(selectors); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashSimplePredicate.java b/forge/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashSimplePredicate.java new file mode 100644 index 00000000..9395653b --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashSimplePredicate.java @@ -0,0 +1,46 @@ +package dev.notalpha.dashloader.client.model.predicates; + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.mixin.accessor.SimpleMultipartModelSelectorAccessor; +import net.minecraft.client.render.model.json.SimpleMultipartModelSelector; + + +public final class DashSimplePredicate implements DashObject { + public final String key; + public final String valueString; + + public DashSimplePredicate(String key, String valueString) { + this.key = key; + this.valueString = valueString; + } + + public DashSimplePredicate(SimpleMultipartModelSelector simpleMultipartModelSelector) { + var access = ((SimpleMultipartModelSelectorAccessor) simpleMultipartModelSelector); + this.key = access.getKey(); + this.valueString = access.getValueString(); + } + + @Override + public SimpleMultipartModelSelector export(RegistryReader handler) { + return new SimpleMultipartModelSelector(this.key, this.valueString); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DashSimplePredicate that = (DashSimplePredicate) o; + + if (!key.equals(that.key)) return false; + return valueString.equals(that.valueString); + } + + @Override + public int hashCode() { + int result = key.hashCode(); + result = 31 * result + valueString.hashCode(); + return result; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashStaticPredicate.java b/forge/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashStaticPredicate.java new file mode 100644 index 00000000..f4419be8 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashStaticPredicate.java @@ -0,0 +1,36 @@ +package dev.notalpha.dashloader.client.model.predicates; + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryReader; + +public final class DashStaticPredicate implements DashObject { + public final boolean value; + + public DashStaticPredicate(boolean value) { + this.value = value; + } + + public DashStaticPredicate(BooleanSelector multipartModelSelector) { + this.value = multipartModelSelector.selector; + } + + @Override + public BooleanSelector export(RegistryReader exportHandler) { + return new BooleanSelector(value); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DashStaticPredicate that = (DashStaticPredicate) o; + + return value == that.value; + } + + @Override + public int hashCode() { + return (value ? 1 : 0); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/shader/DashGlBlendState.java b/forge/src/main/java/dev/notalpha/dashloader/client/shader/DashGlBlendState.java new file mode 100644 index 00000000..4f26f7ca --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/shader/DashGlBlendState.java @@ -0,0 +1,45 @@ +package dev.notalpha.dashloader.client.shader; + +import dev.notalpha.dashloader.mixin.accessor.GlBlendStateAccessor; +import net.minecraft.client.gl.GlBlendState; + +public final class DashGlBlendState { + public final int srcRgb; + public final int srcAlpha; + public final int dstRgb; + public final int dstAlpha; + public final int mode; + public final boolean separateBlend; + public final boolean blendDisabled; + + public DashGlBlendState( + int srcRgb, int srcAlpha, int dstRgb, int dstAlpha, int mode, boolean separateBlend, boolean blendDisabled) { + this.srcRgb = srcRgb; + this.srcAlpha = srcAlpha; + this.dstRgb = dstRgb; + this.dstAlpha = dstAlpha; + this.mode = mode; + this.separateBlend = separateBlend; + this.blendDisabled = blendDisabled; + } + + + public DashGlBlendState(GlBlendStateAccessor blendStateAccess) { + this( + blendStateAccess.getSrcRgb(), + blendStateAccess.getSrcAlpha(), + blendStateAccess.getDstRgb(), + blendStateAccess.getDstAlpha(), + blendStateAccess.getMode(), + blendStateAccess.getSeparateBlend(), + blendStateAccess.getBlendDisabled()); + } + + public DashGlBlendState(GlBlendState blendState) { + this((GlBlendStateAccessor) blendState); + } + + public GlBlendState export() { + return GlBlendStateAccessor.create(this.separateBlend, this.blendDisabled, this.srcRgb, this.dstRgb, this.srcAlpha, this.dstAlpha, this.mode); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/shader/DashGlUniform.java b/forge/src/main/java/dev/notalpha/dashloader/client/shader/DashGlUniform.java new file mode 100644 index 00000000..d563c837 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/shader/DashGlUniform.java @@ -0,0 +1,43 @@ +package dev.notalpha.dashloader.client.shader; + +import dev.notalpha.dashloader.io.IOHelper; +import dev.notalpha.dashloader.mixin.accessor.GlUniformAccessor; +import dev.quantumfusion.hyphen.scan.annotations.DataNullable; +import net.minecraft.client.gl.GlUniform; +import net.minecraft.client.gl.ShaderProgram; + +public final class DashGlUniform { + public final int dataType; + public final boolean loaded; + + public final String name; + public final int @DataNullable [] intData; + + public final float @DataNullable [] floatData; + + public DashGlUniform(int dataType, boolean loaded, String name, int[] intData, float[] floatData) { + this.dataType = dataType; + this.loaded = loaded; + this.name = name; + this.intData = intData; + this.floatData = floatData; + } + + public DashGlUniform(GlUniform glUniform, boolean loaded) { + GlUniformAccessor access = (GlUniformAccessor) glUniform; + this.intData = IOHelper.toArray(access.getIntData()); + this.floatData = IOHelper.toArray(access.getFloatData()); + this.dataType = glUniform.getDataType(); + this.name = glUniform.getName(); + this.loaded = loaded; + } + + + public GlUniform export(ShaderProgram shader) { + GlUniform glUniform = new GlUniform(this.name, this.dataType, 0, shader); + GlUniformAccessor access = (GlUniformAccessor) glUniform; + access.setIntData(IOHelper.fromArray(this.intData)); + access.setFloatData(IOHelper.fromArray(this.floatData)); + return glUniform; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/shader/DashShader.java b/forge/src/main/java/dev/notalpha/dashloader/client/shader/DashShader.java new file mode 100644 index 00000000..8aecd44f --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/shader/DashShader.java @@ -0,0 +1,154 @@ +package dev.notalpha.dashloader.client.shader; + +import com.google.common.collect.ImmutableList; +import com.mojang.blaze3d.platform.GlStateManager; +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.misc.UnsafeHelper; +import dev.notalpha.dashloader.mixin.accessor.ShaderProgramAccessor; +import dev.quantumfusion.hyphen.scan.annotations.DataNullable; +import dev.quantumfusion.hyphen.scan.annotations.DataSubclasses; +import net.minecraft.client.gl.GlProgramManager; +import net.minecraft.client.gl.GlUniform; +import net.minecraft.client.gl.ShaderProgram; + +import java.util.*; + +public final class DashShader implements DashObject { + public final Map samplers; + public final String name; + public final DashGlBlendState blendState; + public final List attributeNames; + public final DashShaderStage vertexShader; + public final DashShaderStage fragmentShader; + public final int format; + public final List uniforms; + public final List samplerNames; + public transient ShaderProgram toApply; + + public DashShader(Map samplers, String name, DashGlBlendState blendState, List attributeNames, DashShaderStage vertexShader, DashShaderStage fragmentShader, int format, List uniforms, List samplerNames) { + this.samplers = samplers; + this.name = name; + this.blendState = blendState; + this.attributeNames = attributeNames; + this.vertexShader = vertexShader; + this.fragmentShader = fragmentShader; + this.format = format; + this.uniforms = uniforms; + this.samplerNames = samplerNames; + } + + public DashShader(ShaderProgram shader, RegistryWriter writer) { + ShaderProgramAccessor shaderAccess = (ShaderProgramAccessor) shader; + + this.samplers = new LinkedHashMap<>(); + shaderAccess.getSamplers().forEach((s, o) -> this.samplers.put(s, new Sampler(o))); + this.name = shader.getName(); + + this.blendState = new DashGlBlendState(shaderAccess.getBlendState()); + this.attributeNames = shaderAccess.getAttributeNames(); + this.vertexShader = new DashShaderStage(shader.getVertexShader()); + this.fragmentShader = new DashShaderStage(shader.getFragmentShader()); + this.format = writer.add(shader.getFormat()); + this.uniforms = new ArrayList<>(); + Map loadedUniforms = shaderAccess.getLoadedUniforms(); + shaderAccess.getUniforms().forEach((glUniform) -> { + this.uniforms.add(new DashGlUniform(glUniform, loadedUniforms.containsKey(glUniform.getName()))); + }); + this.samplerNames = shaderAccess.getSamplerNames(); + } + + + @Override + public ShaderProgram export(RegistryReader reader) { + this.toApply = UnsafeHelper.allocateInstance(ShaderProgram.class); + ShaderProgramAccessor shaderAccess = (ShaderProgramAccessor) this.toApply; + //object init + shaderAccess.setLoadedSamplerIds(new ArrayList<>()); + shaderAccess.setLoadedUniformIds(new ArrayList<>()); + shaderAccess.setLoadedAttributeIds(new ArrayList<>()); + + shaderAccess.setSamplerNames(new ArrayList<>(this.samplerNames)); + + // top + shaderAccess.setName(this.name); + shaderAccess.setFormat(reader.get(this.format)); + + + //JsonHelper.getArray(jsonObject, "samplers", (JsonArray)null) + var samplersOut = new HashMap(); + this.samplers.forEach((s, o) -> samplersOut.put(s, o.sampler)); + shaderAccess.setSamplers(samplersOut); + + // JsonHelper.getArray(jsonObject, "attributes", (JsonArray)null); + shaderAccess.setAttributeNames(new ArrayList<>(this.attributeNames)); + + final ArrayList uniforms = new ArrayList<>(); + shaderAccess.setUniforms(uniforms); + var uniformsOut = new HashMap(); + this.uniforms.forEach((dashGlUniform) -> { + GlUniform uniform = dashGlUniform.export(this.toApply); + uniforms.add(uniform); + if (dashGlUniform.loaded) { + uniformsOut.put(dashGlUniform.name, uniform); + } + }); + shaderAccess.setLoadedUniforms(uniformsOut); + + + // JsonHelper.getArray(jsonObject, "uniforms", (JsonArray)null); + this.toApply.markUniformsDirty(); + this.toApply.modelViewMat = uniformsOut.get("ModelViewMat"); + this.toApply.projectionMat = uniformsOut.get("ProjMat"); + this.toApply.viewRotationMat = uniformsOut.get("IViewRotMat"); + this.toApply.textureMat = uniformsOut.get("TextureMat"); + this.toApply.screenSize = uniformsOut.get("ScreenSize"); + this.toApply.colorModulator = uniformsOut.get("ColorModulator"); + this.toApply.light0Direction = uniformsOut.get("Light0_Direction"); + this.toApply.light1Direction = uniformsOut.get("Light1_Direction"); + this.toApply.fogStart = uniformsOut.get("FogStart"); + this.toApply.fogEnd = uniformsOut.get("FogEnd"); + this.toApply.fogColor = uniformsOut.get("FogColor"); + this.toApply.fogShape = uniformsOut.get("FogShape"); + this.toApply.lineWidth = uniformsOut.get("LineWidth"); + this.toApply.gameTime = uniformsOut.get("GameTime"); + this.toApply.chunkOffset = uniformsOut.get("ChunkOffset"); + return this.toApply; + } + + + @Override + public void postExport(RegistryReader reader) { + ShaderProgramAccessor shaderAccess = (ShaderProgramAccessor) this.toApply; + shaderAccess.setBlendState(this.blendState.export()); + shaderAccess.setVertexShader(this.vertexShader.exportProgram()); + shaderAccess.setFragmentShader(this.fragmentShader.exportProgram()); + final List loadedAttributeIds = shaderAccess.getLoadedAttributeIds(); + + final int programId = GlStateManager.glCreateProgram(); + shaderAccess.setGlRef(programId); + + if (this.attributeNames != null) { + ImmutableList names = this.toApply.getFormat().getAttributeNames(); + for (int i = 0; i < names.size(); i++) { + String attributeName = names.get(i); + GlUniform.bindAttribLocation(programId, i, attributeName); + loadedAttributeIds.add(i); + } + } + GlProgramManager.linkProgram(this.toApply); + shaderAccess.loadref(); + } + + public static class Sampler { + @DataNullable + @DataSubclasses({Integer.class, String.class}) + public final Object sampler; + + public Sampler(Object sampler) { + this.sampler = sampler; + } + } + +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/shader/DashShaderStage.java b/forge/src/main/java/dev/notalpha/dashloader/client/shader/DashShaderStage.java new file mode 100644 index 00000000..fc008626 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/shader/DashShaderStage.java @@ -0,0 +1,54 @@ +package dev.notalpha.dashloader.client.shader; + +import com.mojang.blaze3d.platform.GlConst; +import com.mojang.blaze3d.platform.GlStateManager; +import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.mixin.accessor.ShaderStageAccessor; +import net.minecraft.client.gl.ShaderStage; +import org.apache.commons.lang3.StringUtils; + +import java.util.List; +import java.util.Map; + +public final class DashShaderStage { + public final ShaderStage.Type shaderType; + public final String name; + public final List shader; + + public DashShaderStage(ShaderStage.Type shaderType, String name, List shader) { + this.shaderType = shaderType; + this.name = name; + this.shader = shader; + } + + public DashShaderStage(ShaderStage program) { + ShaderStageAccessor access = (ShaderStageAccessor) program; + this.shaderType = access.getType(); + this.name = program.getName(); + List shader = ShaderModule.WRITE_PROGRAM_SOURCES.get(CacheStatus.SAVE).get(access.getGlRef()); + if (shader == null) { + throw new RuntimeException(); + } + this.shader = shader; + } + + public int createProgram(ShaderStage.Type type) { + //noinspection ConstantConditions (MixinAccessor shit) + int id = GlStateManager.glCreateShader(((ShaderStageAccessor.TypeAccessor) (Object) type).getGlType()); + GlStateManager.glShaderSource(id, this.shader); + GlStateManager.glCompileShader(id); + if (GlStateManager.glGetShaderi(id, GlConst.GL_COMPILE_STATUS) == 0) { + String errorString = StringUtils.trim(GlStateManager.glGetShaderInfoLog(id, 32768)); + throw new RuntimeException("Couldn't compile " + type.getName() + " : " + errorString); + } else { + return id; + } + } + + public ShaderStage exportProgram() { + Map loadedShaders = this.shaderType.getLoadedShaders(); + final ShaderStage program = ShaderStageAccessor.create(this.shaderType, this.createProgram(this.shaderType), this.name); + loadedShaders.put(this.name, program); + return program; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormat.java b/forge/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormat.java new file mode 100644 index 00000000..f98a073c --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormat.java @@ -0,0 +1,80 @@ +package dev.notalpha.dashloader.client.shader; + +import com.google.common.collect.ImmutableMap; +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.mixin.accessor.VertexFormatAccessor; +import dev.quantumfusion.hyphen.scan.annotations.DataNullable; +import net.minecraft.client.render.VertexFormat; +import net.minecraft.client.render.VertexFormatElement; +import net.minecraft.client.render.VertexFormats; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class DashVertexFormat implements DashObject { + public static final List BUILT_IN = new ArrayList<>(); + + static { + BUILT_IN.add(VertexFormats.BLIT_SCREEN); + BUILT_IN.add(VertexFormats.POSITION_COLOR_TEXTURE_LIGHT_NORMAL); + BUILT_IN.add(VertexFormats.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL); + BUILT_IN.add(VertexFormats.POSITION_TEXTURE_COLOR_LIGHT); + BUILT_IN.add(VertexFormats.POSITION); + BUILT_IN.add(VertexFormats.POSITION_COLOR); + BUILT_IN.add(VertexFormats.LINES); + BUILT_IN.add(VertexFormats.POSITION_COLOR_LIGHT); + BUILT_IN.add(VertexFormats.POSITION_TEXTURE); + BUILT_IN.add(VertexFormats.POSITION_COLOR_TEXTURE); + BUILT_IN.add(VertexFormats.POSITION_TEXTURE_COLOR); + BUILT_IN.add(VertexFormats.POSITION_COLOR_TEXTURE_LIGHT); + BUILT_IN.add(VertexFormats.POSITION_TEXTURE_LIGHT_COLOR); + BUILT_IN.add(VertexFormats.POSITION_TEXTURE_COLOR_NORMAL); + } + + @DataNullable + public final Map elementMap; + + public final int builtin; + + public DashVertexFormat(Map elementMap, int builtin) { + this.elementMap = elementMap; + this.builtin = builtin; + } + + public DashVertexFormat(VertexFormat vertexFormat) { + int builtin = -1; + for (int i = 0; i < BUILT_IN.size(); i++) { + VertexFormat format = BUILT_IN.get(i); + if (format == vertexFormat) { + builtin = i; + break; + } + } + this.builtin = builtin; + if (builtin == -1) { + this.elementMap = new HashMap<>(); + ((VertexFormatAccessor) vertexFormat).getElementMap().forEach((s, element) -> { + this.elementMap.put(s, new DashVertexFormatElement(element)); + }); + } else { + this.elementMap = null; + } + } + + @Override + public VertexFormat export(RegistryReader reader) { + if (this.builtin != -1) { + return BUILT_IN.get(this.builtin); + } else { + ImmutableMap.Builder out = ImmutableMap.builderWithExpectedSize(elementMap.size()); + elementMap.forEach((s, dashVertexFormatElement) -> { + VertexFormatElement export = dashVertexFormatElement.export(reader); + out.put(s, export); + }); + return new VertexFormat(out.build()); + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormatElement.java b/forge/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormatElement.java new file mode 100644 index 00000000..f37b0a4a --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormatElement.java @@ -0,0 +1,78 @@ +package dev.notalpha.dashloader.client.shader; + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.quantumfusion.hyphen.scan.annotations.DataNullable; +import net.minecraft.client.render.VertexFormatElement; +import net.minecraft.client.render.VertexFormats; + +import java.util.ArrayList; +import java.util.List; + +public class DashVertexFormatElement implements DashObject { + public static final List BUILT_IN = new ArrayList<>(); + + static { + BUILT_IN.add(VertexFormats.POSITION_ELEMENT); + BUILT_IN.add(VertexFormats.COLOR_ELEMENT); + BUILT_IN.add(VertexFormats.TEXTURE_ELEMENT); + BUILT_IN.add(VertexFormats.OVERLAY_ELEMENT); + BUILT_IN.add(VertexFormats.LIGHT_ELEMENT); + BUILT_IN.add(VertexFormats.NORMAL_ELEMENT); + BUILT_IN.add(VertexFormats.PADDING_ELEMENT); + BUILT_IN.add(VertexFormats.UV_ELEMENT); + } + + @DataNullable + public final DashVertexFormatElementData data; + + public final int builtin; + + public DashVertexFormatElement(@DataNullable DashVertexFormatElementData data, int builtin) { + this.data = data; + this.builtin = builtin; + } + + public DashVertexFormatElement(VertexFormatElement element) { + var builtin = -1; + for (int i = 0; i < BUILT_IN.size(); i++) { + if (BUILT_IN.get(i) == element) { + builtin = i; + break; + } + } + this.data = builtin == -1 ? new DashVertexFormatElementData(element) : null; + this.builtin = builtin; + } + + + @Override + public VertexFormatElement export(RegistryReader reader) { + if (this.builtin != -1) { + return BUILT_IN.get(this.builtin); + } else { + return new VertexFormatElement(this.data.uvIndex, this.data.componentType, this.data.type, this.data.componentCount); + } + } + + public static class DashVertexFormatElementData { + public final VertexFormatElement.ComponentType componentType; + public final VertexFormatElement.Type type; + public final int uvIndex; + public final int componentCount; + + public DashVertexFormatElementData(VertexFormatElement.ComponentType componentType, VertexFormatElement.Type type, int uvIndex, int componentCount) { + this.componentType = componentType; + this.type = type; + this.uvIndex = uvIndex; + this.componentCount = componentCount; + } + + public DashVertexFormatElementData(VertexFormatElement element) { + this.componentType = element.getComponentType(); + this.type = element.getType(); + this.uvIndex = element.getUvIndex(); + this.componentCount = element.getComponentCount(); + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/shader/ShaderModule.java b/forge/src/main/java/dev/notalpha/dashloader/client/shader/ShaderModule.java new file mode 100644 index 00000000..0136eddb --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/shader/ShaderModule.java @@ -0,0 +1,69 @@ +package dev.notalpha.dashloader.client.shader; + +import dev.notalpha.dashloader.api.CachingData; +import dev.notalpha.dashloader.api.DashModule; +import dev.notalpha.dashloader.api.cache.Cache; +import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.api.collection.ObjectIntList; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.config.ConfigHandler; +import dev.notalpha.dashloader.config.Option; +import dev.notalpha.taski.builtin.StepTask; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import net.minecraft.client.gl.ShaderProgram; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +public class ShaderModule implements DashModule { + public static final CachingData> SHADERS = new CachingData<>(); + public static final CachingData>> WRITE_PROGRAM_SOURCES = new CachingData<>(CacheStatus.SAVE); + + @Override + public void reset(Cache cache) { + SHADERS.reset(cache, new HashMap<>()); + WRITE_PROGRAM_SOURCES.reset(cache, new Int2ObjectOpenHashMap<>()); + } + + @Override + public Data save(RegistryWriter factory, StepTask task) { + final Map minecraftData = SHADERS.get(CacheStatus.SAVE); + if (minecraftData == null) { + return null; + } + + var shaders = new ObjectIntList(); + task.doForEach(minecraftData, (s, shader) -> shaders.put(s, factory.add(shader))); + + return new Data(shaders); + } + + @Override + public void load(Data data, RegistryReader reader, StepTask task) { + HashMap out = new HashMap<>(); + data.shaders.forEach((key, value) -> out.put(key, reader.get(value))); + SHADERS.set(CacheStatus.LOAD, out); + } + + @Override + public Class getDataClass() { + return Data.class; + } + + @Override + public boolean isActive() { + return ConfigHandler.optionActive(Option.CACHE_SHADER); + } + + public static final class Data { + public final ObjectIntList shaders; + + public Data(ObjectIntList shaders) { + this.shaders = shaders; + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/splash/SplashModule.java b/forge/src/main/java/dev/notalpha/dashloader/client/splash/SplashModule.java new file mode 100644 index 00000000..642da159 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/splash/SplashModule.java @@ -0,0 +1,57 @@ +package dev.notalpha.dashloader.client.splash; + +import dev.notalpha.dashloader.api.CachingData; +import dev.notalpha.dashloader.api.DashModule; +import dev.notalpha.dashloader.api.cache.Cache; +import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.config.ConfigHandler; +import dev.notalpha.dashloader.config.Option; +import dev.notalpha.taski.builtin.StepTask; + +import java.util.ArrayList; +import java.util.List; + + +public class SplashModule implements DashModule { + public static final CachingData> TEXTS = new CachingData<>(); + + @Override + public void reset(Cache cache) { + TEXTS.reset(cache, new ArrayList<>()); + } + + @Override + public Data save(RegistryWriter writer, StepTask task) { + return new Data(TEXTS.get(CacheStatus.SAVE)); + } + + @Override + public void load(Data data, RegistryReader reader, StepTask task) { + TEXTS.set(CacheStatus.LOAD, data.splashList); + } + + @Override + public Class getDataClass() { + return Data.class; + } + + @Override + public boolean isActive() { + return ConfigHandler.optionActive(Option.CACHE_SPLASH_TEXT); + } + + @Override + public float taskWeight() { + return 1; + } + + public static final class Data { + public final List splashList; + + public Data(List splashList) { + this.splashList = splashList; + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashImage.java b/forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashImage.java new file mode 100644 index 00000000..7ad960c6 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashImage.java @@ -0,0 +1,55 @@ +package dev.notalpha.dashloader.client.sprite; + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.io.def.NativeImageData; +import dev.notalpha.dashloader.mixin.accessor.NativeImageAccessor; +import net.minecraft.client.texture.NativeImage; +import org.lwjgl.system.MemoryUtil; + +import java.nio.ByteBuffer; + +public final class DashImage implements DashObject { + public final NativeImageData image; + public final NativeImage.Format format; + public final boolean useSTB; + public final int width; + public final int height; + + public DashImage(NativeImage nativeImage) { + NativeImageAccessor nativeImageAccess = (NativeImageAccessor) (Object) nativeImage; + this.format = nativeImage.getFormat(); + this.width = nativeImage.getWidth(); + this.height = nativeImage.getHeight(); + + final int capacity = this.width * this.height * this.format.getChannelCount(); + final long pointer = nativeImageAccess.getPointer(); + + this.useSTB = nativeImageAccess.getIsStbImage(); + + ByteBuffer image1 = MemoryUtil.memByteBuffer(pointer, capacity); + image1.limit(capacity); + this.image = new NativeImageData(image1, this.useSTB); + } + + public DashImage(NativeImageData image, NativeImage.Format format, boolean useSTB, int width, int height) { + this.image = image; + this.format = format; + this.useSTB = useSTB; + this.width = width; + this.height = height; + } + + /** + *

I can bet that next dashloader version will change this again. This method needs some serious over engineering.

+ * + * @param registry da registry + * @return da image + */ + @Override + public NativeImage export(final RegistryReader registry) { + image.buffer.rewind(); + long pointer = MemoryUtil.memAddress(image.buffer); + return NativeImageAccessor.init(this.format, this.width, this.height, this.useSTB, pointer); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashSprite.java b/forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashSprite.java new file mode 100644 index 00000000..58ddbae6 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashSprite.java @@ -0,0 +1,54 @@ +package dev.notalpha.dashloader.client.sprite; + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.client.Dazy; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.SpriteIdentifier; + +import java.util.function.Function; + +public class DashSprite implements DashObject { + public final int id; + + public DashSprite(int id) { + this.id = id; + } + + public DashSprite(Sprite sprite, RegistryWriter writer) { + this.id = writer.add(new SpriteIdentifier(sprite.getAtlasId(), sprite.getContents().getId())); + } + + @Override + public DazyImpl export(final RegistryReader registry) { + return new DazyImpl(registry.get(id)); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DashSprite that = (DashSprite) o; + + return id == that.id; + } + + @Override + public int hashCode() { + return id; + } + + public static class DazyImpl extends Dazy { + public final SpriteIdentifier location; + + public DazyImpl(SpriteIdentifier location) { + this.location = location; + } + @Override + protected Sprite resolve(Function spriteLoader) { + return spriteLoader.apply(location); + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimation.java b/forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimation.java new file mode 100644 index 00000000..ec3ef01e --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimation.java @@ -0,0 +1,69 @@ +package dev.notalpha.dashloader.client.sprite; + +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.mixin.accessor.SpriteAnimationAccessor; +import net.minecraft.client.texture.SpriteContents; + +import java.util.ArrayList; +import java.util.List; + +public final class DashSpriteAnimation { + public final List frames; + public final int frameCount; + public final boolean interpolation; + + public DashSpriteAnimation( + List frames, + int frameCount, + boolean interpolation) { + this.frames = frames; + this.frameCount = frameCount; + this.interpolation = interpolation; + } + + + public DashSpriteAnimation(SpriteContents.Animation animation) { + SpriteAnimationAccessor access = ((SpriteAnimationAccessor) animation); + this.frames = new ArrayList<>(); + for (var frame : access.getFrames()) { + this.frames.add(new DashSpriteAnimationFrame(frame)); + } + this.frameCount = access.getFrameCount(); + this.interpolation = access.getInterpolation(); + } + + + public SpriteContents.Animation export(SpriteContents owner, RegistryReader registry) { + var framesOut = new ArrayList(); + for (var frame : this.frames) { + framesOut.add(frame.export(registry)); + } + + return SpriteAnimationAccessor.init( + owner, + framesOut, + this.frameCount, + this.interpolation + ); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DashSpriteAnimation that = (DashSpriteAnimation) o; + + if (frameCount != that.frameCount) return false; + if (interpolation != that.interpolation) return false; + return frames.equals(that.frames); + } + + @Override + public int hashCode() { + int result = frames.hashCode(); + result = 31 * result + frameCount; + result = 31 * result + (interpolation ? 1 : 0); + return result; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimationFrame.java b/forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimationFrame.java new file mode 100644 index 00000000..1216a9a7 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimationFrame.java @@ -0,0 +1,45 @@ +package dev.notalpha.dashloader.client.sprite; + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.mixin.accessor.SpriteAnimationFrameAccessor; +import net.minecraft.client.texture.SpriteContents; + +public final class DashSpriteAnimationFrame implements DashObject { + public final int index; + public final int time; + + public DashSpriteAnimationFrame(int index, int time) { + this.index = index; + this.time = time; + } + + public DashSpriteAnimationFrame(SpriteContents.AnimationFrame animationFrame) { + SpriteAnimationFrameAccessor access = ((SpriteAnimationFrameAccessor) animationFrame); + this.index = access.getIndex(); + this.time = access.getTime(); + } + + @Override + public SpriteContents.AnimationFrame export(RegistryReader exportHandler) { + return SpriteAnimationFrameAccessor.newSpriteFrame(this.index, this.time); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DashSpriteAnimationFrame that = (DashSpriteAnimationFrame) o; + + if (index != that.index) return false; + return time == that.time; + } + + @Override + public int hashCode() { + int result = index; + result = 31 * result + time; + return result; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteContents.java b/forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteContents.java new file mode 100644 index 00000000..3ad5a9a7 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteContents.java @@ -0,0 +1,79 @@ +package dev.notalpha.dashloader.client.sprite; + +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.misc.UnsafeHelper; +import dev.notalpha.dashloader.mixin.accessor.SpriteContentsAccessor; +import dev.quantumfusion.hyphen.scan.annotations.DataNullable; +import net.minecraft.client.texture.NativeImage; +import net.minecraft.client.texture.SpriteContents; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +public final class DashSpriteContents { + public final int id; + public final int image; + @Nullable + @DataNullable + public final DashSpriteAnimation animation; + + public final int width; + public final int height; + + public DashSpriteContents(int id, int image, @Nullable DashSpriteAnimation animation, int width, int height) { + this.id = id; + this.image = image; + this.animation = animation; + this.width = width; + this.height = height; + } + + public DashSpriteContents(SpriteContents contents, RegistryWriter writer) { + var access = (SpriteContentsAccessor) contents; + this.id = writer.add(contents.getId()); + this.image = writer.add(access.getImage()); + this.width = contents.getWidth(); + this.height = contents.getHeight(); + SpriteContents.Animation animation = access.getAnimation(); + this.animation = animation == null ? null : new DashSpriteAnimation(animation); + } + + public SpriteContents export(RegistryReader reader) { + final SpriteContents out = UnsafeHelper.allocateInstance(SpriteContents.class); + var access = (SpriteContentsAccessor) out; + access.setId(reader.get(this.id)); + + NativeImage image = reader.get(this.image); + access.setImage(image); + access.setHeight(height); + access.setWidth(width); + access.setMipmapLevelsImages(new NativeImage[]{image}); + access.setAnimation(this.animation == null ? null : animation.export(out, reader)); + return out; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DashSpriteContents that = (DashSpriteContents) o; + + if (id != that.id) return false; + if (image != that.image) return false; + if (width != that.width) return false; + if (height != that.height) return false; + return Objects.equals(animation, that.animation); + } + + @Override + public int hashCode() { + int result = id; + result = 31 * result + image; + result = 31 * result + (animation != null ? animation.hashCode() : 0); + result = 31 * result + width; + result = 31 * result + height; + return result; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashStitchResult.java b/forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashStitchResult.java new file mode 100644 index 00000000..3a5034c1 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashStitchResult.java @@ -0,0 +1,85 @@ +package dev.notalpha.dashloader.client.sprite; + +import dev.notalpha.dashloader.api.collection.IntIntList; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.taski.builtin.StepTask; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.texture.SpriteLoader; +import net.minecraft.util.Identifier; + +import java.util.Map; +import java.util.concurrent.CompletableFuture; + + +public final class DashStitchResult { + public final int width; + public final int height; + public final int mipLevel; + public final int missing; + public final IntIntList regions; + + public DashStitchResult(int width, int height, int mipLevel, int missing, IntIntList regions) { + this.width = width; + this.height = height; + this.mipLevel = mipLevel; + this.missing = missing; + this.regions = regions; + } + + public DashStitchResult(SpriteLoader.StitchResult stitchResult, RegistryWriter writer, StepTask task) { + this.width = stitchResult.width(); + this.height = stitchResult.height(); + this.mipLevel = stitchResult.mipLevel(); + this.missing = writer.add(stitchResult.missing()); + + this.regions = new IntIntList(); + stitchResult.regions().forEach((identifier, sprite) -> { + this.regions.put(writer.add(identifier), writer.add(sprite)); + task.next(); + }); + } + + public SpriteLoader.StitchResult export(RegistryReader reader) { + Map regions = new Object2ObjectOpenHashMap<>(); + this.regions.forEach((key, value) -> regions.put(reader.get(key), reader.get(value))); + + return new SpriteLoader.StitchResult( + this.width, + this.height, + this.mipLevel, + reader.get(this.missing), + regions, + CompletableFuture.runAsync( + () -> { + throw new RuntimeException("Cached object not yet finalized"); + } + ) + ); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DashStitchResult that = (DashStitchResult) o; + + if (width != that.width) return false; + if (height != that.height) return false; + if (mipLevel != that.mipLevel) return false; + if (missing != that.missing) return false; + return regions.equals(that.regions); + } + + @Override + public int hashCode() { + int result = width; + result = 31 * result + height; + result = 31 * result + mipLevel; + result = 31 * result + missing; + result = 31 * result + regions.hashCode(); + return result; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashTextureSlot.java b/forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashTextureSlot.java new file mode 100644 index 00000000..bee1d428 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashTextureSlot.java @@ -0,0 +1,18 @@ +package dev.notalpha.dashloader.client.sprite; + +import net.minecraft.client.texture.TextureStitcher; + +public class DashTextureSlot { + public final int x; + public final int y; + public final int width; + public final int height; + public transient T contents; + + public DashTextureSlot(int x, int y, int width, int height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashTextureStitcher.java b/forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashTextureStitcher.java new file mode 100644 index 00000000..dee62704 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashTextureStitcher.java @@ -0,0 +1,162 @@ +package dev.notalpha.dashloader.client.sprite; + +import dev.notalpha.dashloader.DashLoader; +import dev.notalpha.dashloader.api.collection.IntObjectList; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import net.minecraft.client.texture.TextureStitcher; +import net.minecraft.util.Identifier; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; + +public class DashTextureStitcher extends TextureStitcher { + @Nullable + private ExportedData data; + private int remainingSlots; + + public DashTextureStitcher(int maxWidth, int maxHeight, int mipLevel, @Nullable ExportedData data) { + super(maxWidth, maxHeight, mipLevel); + this.data = data; + this.remainingSlots = data == null ? 0 : data.slots.size(); + } + + @Override + public int getWidth() { + if (this.data == null) { + return super.getWidth(); + } + return data.width; + } + + @Override + public int getHeight() { + if (this.data == null) { + return super.getHeight(); + } + return data.height; + } + + @Override + public void add(T info) { + if (data == null) { + super.add(info); + return; + } + + // If it starts recaching, doRecache will re-add the entries to the list. + var id = info.getId(); + var slot = data.slots.get(id); + if (slot == null) { + DashLoader.LOG.warn("Sprite {} was not cached last time.", id); + + doFallback(); + // This was never added to the slot, so it would not get added to super. + this.add(info); + return; + } + + if (slot.contents != null) { + DashLoader.LOG.warn("Sprite {} was added twice??", id); + } + + remainingSlots -= 1; + slot.contents = info; + + if (slot.width != info.getWidth() || slot.height != info.getHeight()) { + DashLoader.LOG.warn("Sprite {} had changed dimensions since last launch, falling back.", id); + doFallback(); + return; + } + } + + public void doFallback() { + if (data != null) { + DashLoader.LOG.error("Using fallback on texture stitcher."); + var slots = data.slots; + data = null; + slots.forEach((identifier, tDashTextureSlot) -> { + if (tDashTextureSlot.contents != null) { + this.add(tDashTextureSlot.contents); + } + }); + } else { + DashLoader.LOG.error("Tried to fallback stitcher twice."); + } + } + + @Override + public void stitch() { + if (data != null && remainingSlots != 0) { + DashLoader.LOG.warn("Remaining slots did not match the cached amount, Falling back."); + data.slots.forEach((identifier, tDashTextureSlot) -> { + if (tDashTextureSlot.contents == null) { + DashLoader.LOG.error("Sprite {} was not requested", identifier); + } + }); + doFallback(); + } + + if (data == null) { + super.stitch(); + } + } + + @Override + public void getStitchedSprites(SpriteConsumer consumer) { + if (data == null) { + super.getStitchedSprites(consumer); + } else { + data.slots.forEach((identifier, dashTextureSlot) -> { + consumer.load(dashTextureSlot.contents, dashTextureSlot.x, dashTextureSlot.y); + }); + } + } + + public static class Data { + public final IntObjectList> slots; + public final int width; + public final int height; + + public Data(IntObjectList> slots, int width, int height) { + this.slots = slots; + this.width = width; + this.height = height; + } + + public Data(RegistryWriter factory, TextureStitcher stitcher) { + this.slots = new IntObjectList<>(); + stitcher.getStitchedSprites((info, x, y) -> { + this.slots.put(factory.add(info.getId()), new DashTextureSlot<>(x, y, info.getWidth(), info.getHeight())); + }); + this.width = stitcher.getWidth(); + this.height = stitcher.getHeight(); + } + + public ExportedData export(RegistryReader reader) { + var output = new HashMap>(); + this.slots.forEach((key, value) -> { + output.put(reader.get(key), value); + }); + + return new ExportedData<>( + output, + width, + height + ); + } + } + + public static class ExportedData { + public final Map> slots; + public final int width; + public final int height; + + public ExportedData(Map> slots, int width, int height) { + this.slots = slots; + this.width = width; + this.height = height; + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/sprite/SpriteStitcherModule.java b/forge/src/main/java/dev/notalpha/dashloader/client/sprite/SpriteStitcherModule.java new file mode 100644 index 00000000..b9feebac --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/sprite/SpriteStitcherModule.java @@ -0,0 +1,111 @@ +package dev.notalpha.dashloader.client.sprite; + +import dev.notalpha.dashloader.DashLoader; +import dev.notalpha.dashloader.api.CachingData; +import dev.notalpha.dashloader.api.DashModule; +import dev.notalpha.dashloader.api.cache.Cache; +import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.api.collection.IntObjectList; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.config.ConfigHandler; +import dev.notalpha.dashloader.config.Option; +import dev.notalpha.taski.builtin.StepTask; +import net.minecraft.client.texture.TextureStitcher; +import net.minecraft.util.Identifier; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.*; + +public class SpriteStitcherModule implements DashModule { + //public final static CachingData> ATLASES = new CachingData<>(); + public final static CachingData>>> STITCHERS_SAVE = new CachingData<>(CacheStatus.SAVE); + public final static CachingData>> STITCHERS_LOAD = new CachingData<>(CacheStatus.LOAD); + //public final static CachingData> ATLAS_IDS = new CachingData<>(CacheStatus.SAVE); + + @Override + public void reset(Cache cache) { + // ATLASES.reset(cache, new HashMap<>()); + STITCHERS_SAVE.reset(cache, new ArrayList<>()); + STITCHERS_LOAD.reset(cache, new HashMap<>()); + //ATLAS_IDS.reset(cache, new HashMap<>()); + } + + @Override + public Data save(RegistryWriter writer, StepTask task) { + task.reset(2); + + var stitchers = new HashMap>(); + var duplicate = new HashSet(); + task.run(new StepTask("Caching Stitchers"), (stepTask) -> { + stepTask.doForEach(STITCHERS_SAVE.get(CacheStatus.SAVE), (pair) -> { + var identifier = pair.getLeft(); + var textureStitcher = pair.getRight(); + DashTextureStitcher.Data existing = stitchers.put(identifier, new DashTextureStitcher.Data<>(writer, textureStitcher)); + if (existing != null) { + duplicate.add(identifier); + } + }); + }); + duplicate.forEach(identifier -> { + DashLoader.LOG.warn("Duplicate stitcher {}", identifier); + stitchers.remove(identifier); + }); + + + var output = new IntObjectList>(); + + stitchers.forEach((identifier, data) -> { + output.put(writer.add(identifier), data); + }); + + //var results = new IntObjectList(); + //task.run(new StepTask("Caching Atlases"), (stepTask) -> { + // var map = ATLASES.get(CacheStatus.SAVE); + // stepTask.doForEach(map, (identifier, stitchResult) -> { + // StepTask atlases = new StepTask("atlas", stitchResult.regions().size()); + // task.setSubTask(atlases); + // results.put(factory.add(identifier), new DashStitchResult(stitchResult, factory, atlases)); + // }); + //}); + + return new Data(output); + } + + @Override + public void load(Data data, RegistryReader reader, StepTask task) { + //HashMap stitchResults = new HashMap<>(data.results.list().size()); + //data.results.forEach((identifier, stitchResult) -> { + // stitchResults.put(reader.get(identifier), stitchResult.export(reader)); + //}); +// + //ATLASES.set(CacheStatus.LOAD, stitchResults); + var map = new HashMap>(); + data.stitchers.forEach((key, value) -> { + map.put(reader.get(key), value.export(reader)); + }); + STITCHERS_LOAD.set(CacheStatus.LOAD, map); + } + + @Override + public Class getDataClass() { + return Data.class; + } + + @Override + public boolean isActive() { + return ConfigHandler.optionActive(Option.CACHE_SPRITES); + } + + public static final class Data { + // public final IntObjectList results; + public final IntObjectList> stitchers; + + public Data( + // IntObjectList results, + IntObjectList> stitchers) { + // this.results = results; + this.stitchers = stitchers; + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/ui/Color.java b/forge/src/main/java/dev/notalpha/dashloader/client/ui/Color.java new file mode 100644 index 00000000..82f86854 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/ui/Color.java @@ -0,0 +1,45 @@ +package dev.notalpha.dashloader.client.ui; + +public class Color { + private final int rgba; + + public Color(int rgba) { + this.rgba = rgba; + } + + public Color(int red, int green, int blue, int alpha) { + this.rgba = ((red & 0xFF) << 24) | ((green & 0xFF) << 16) | ((blue & 0xFF) << 8) | (alpha & 0xFF); + } + + public Color(int red, int green, int blue) { + this(red, green, blue, 255); + } + + public int red() { + return (rgba >>> 24) & 0xFF; + } + + public int green() { + return (rgba >>> 16) & 0xFF; + } + + public int blue() { + return (rgba >>> 8) & 0xFF; + } + + public int alpha() { + return rgba & 0xFF; + } + + public int rgb() { + return rgba >>> 8; + } + + public int rgba() { + return rgba; + } + + public int argb() { + return this.rgb() | (this.alpha() << 24); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/ui/DashToast.java b/forge/src/main/java/dev/notalpha/dashloader/client/ui/DashToast.java new file mode 100644 index 00000000..9f6d92db --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/ui/DashToast.java @@ -0,0 +1,267 @@ +package dev.notalpha.dashloader.client.ui; + +import com.mojang.blaze3d.systems.RenderSystem; +import dev.notalpha.dashloader.misc.HahaManager; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.render.*; +import net.minecraft.client.toast.Toast; +import net.minecraft.client.toast.ToastManager; +import net.minecraft.client.util.Window; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.math.MathHelper; +import org.jetbrains.annotations.Nullable; +import org.joml.Matrix4f; +import org.joml.Vector4f; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.function.BiConsumer; + +public class DashToast implements Toast { + private static final int PROGRESS_BAR_HEIGHT = 2; + private static final int PADDING = 8; + private static final int LINES = 125; + private final Random random = new Random(); + private List lines = new ArrayList<>(); + + @Nullable + private final String fact = HahaManager.getFact(); + private long oldTime = System.currentTimeMillis(); + public final DashToastState state; + + private static void drawVertex(Matrix4f m4f, BufferBuilder bb, float z, float x, float y, Color color) { + bb.vertex(m4f, x, y, z).color(color.red(), color.green(), color.blue(), color.alpha()).next(); + } + + public int getWidth() { + return 200; + } + + public int getHeight() { + return 40; + } + + public DashToast() { + this.state = new DashToastState(); + // Create lines + for (int i = 0; i < LINES; i++) { + this.lines.add(new Line()); + } + } + + + @Override + public Visibility draw(DrawContext context, ToastManager manager, long startTime) { + final int width = this.getWidth(); + final int height = this.getHeight(); + final int barY = height - PROGRESS_BAR_HEIGHT; + + // Get progress + final float progress; + final Color progressColor; + if (state.getStatus() == DashToastStatus.CRASHED) { + progress = (float) this.state.getProgress(); + progressColor = DrawerUtil.FAILED_COLOR; + } else { + progress = (float) this.state.getProgress(); + progressColor = DrawerUtil.getProgressColor(progress); + } + + // Tick progress + List newList = new ArrayList<>(); + List newListPrio = new ArrayList<>(); + long currentTime = System.currentTimeMillis(); + for (Line line : this.lines) { + if (line.tick(width, height, progress, (currentTime - this.oldTime) / 17f)) { + newListPrio.add(line); + } else { + newList.add(line); + } + } + this.oldTime = currentTime; + this.lines = newList; + this.lines.addAll(newListPrio); + + + // Setup scissor + MatrixStack matrices = context.getMatrices(); + { + Vector4f vec = new Vector4f(0.0f, 0.0f, 0.0f, 1.0f); + vec.mul(matrices.peek().getPositionMatrix()); + Window window = manager.getClient().getWindow(); + double scale = window.getScaleFactor(); + RenderSystem.enableScissor( + (int) (vec.x * scale), + (int) (window.getFramebufferHeight() - (vec.y * scale) - height * scale), + (int) (width * scale), + (int) (height * scale)); + } + + // Draw the ui + DrawerUtil.drawRect(context, 0, 0, width, height, DrawerUtil.BACKGROUND_COLOR); + + // Draw the background lines. + this.drawBatched(matrices, (matrix4f, bufferBuilder) -> { + for (Line line : lines) { + line.draw(matrix4f, bufferBuilder); + } + }); + + + TextRenderer textRenderer = manager.getClient().textRenderer; + // Draw progress text + String progressText = this.state.getProgressText(); + int progressTextY = this.fact != null ? barY - PADDING : (barY / 2) + (textRenderer.fontHeight / 2); + DrawerUtil.drawText(context, textRenderer, PADDING, progressTextY, this.state.getText(), DrawerUtil.STATUS_COLOR); + DrawerUtil.drawText(context, textRenderer, (width - PADDING) - textRenderer.getWidth(progressText), progressTextY, progressText, DrawerUtil.STATUS_COLOR); + + if (this.fact != null) { + // Draw the fun fact + DrawerUtil.drawText(context, textRenderer, PADDING, textRenderer.fontHeight + PADDING, this.fact, DrawerUtil.FOREGROUND_COLOR); + } + + // Draw progress bar + DrawerUtil.drawRect(context, 0, barY, width, PROGRESS_BAR_HEIGHT, DrawerUtil.PROGRESS_TRACK); + DrawerUtil.drawRect(context, 0, barY, (int) (width * progress), PROGRESS_BAR_HEIGHT, progressColor); + + // Epic rtx graphics. aka i slapped some glow on the things. + this.drawBatched(matrices, (matrix4f, bb) -> { + // Line glow + for (Line line : lines) { + line.drawGlow(matrix4f, bb); + } + // Progress bar glow + DrawerUtil.drawGlow(matrix4f, bb, 0, barY, (int) (width * progress), PROGRESS_BAR_HEIGHT, 0.75f, progressColor, true, true, true, true); + }); + RenderSystem.disableScissor(); + + if (state.getStatus() == DashToastStatus.CRASHED && System.currentTimeMillis() - state.getTimeDone() > 10000) { + return Visibility.HIDE; + } + + if (state.getStatus() == DashToastStatus.DONE && System.currentTimeMillis() - state.getTimeDone() > 2000) { + return Visibility.HIDE; + } + return Visibility.SHOW; + } + + private void drawBatched(MatrixStack ms, BiConsumer consumer) { + BufferBuilder bufferBuilder = Tessellator.getInstance().getBuffer(); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + RenderSystem.setShader(GameRenderer::getPositionColorProgram); + bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR); + Matrix4f matrix = ms.peek().getPositionMatrix(); + consumer.accept(matrix, bufferBuilder); + BufferRenderer.drawWithGlobalProgram(bufferBuilder.end()); + RenderSystem.disableBlend(); + } + + + private final class Line { + public ColorKind colorKind; + public float x; + public float y; + public int width; + public int height; + public float speedBoost; + private Color color; + + public Line() { + this.x = -1000; + this.y = -1000; + this.width = DashToast.this.random.nextInt(30, 50); + this.height = DashToast.this.random.nextInt(2, 5); + this.colorKind = ColorKind.Neutral; + this.color = new Color(0xFF0000FF); + } + + public boolean tick(int screenWidth, int screenHeight, float progress, float delta) { + // Move the values + this.x += (float) (speedBoost * (0.8 + (2.5 * progress))) * delta; + + + // Check if not visible + if (x > screenWidth || x + width < 0) { + // Randomize position + this.x = -width; + this.y = screenHeight * DashToast.this.random.nextFloat(); + + // Randomise color + if (state.getStatus() == DashToastStatus.CRASHED) { + if (DashToast.this.random.nextFloat() > 0.9 || this.colorKind == ColorKind.Progress) { + this.colorKind = ColorKind.Crashed; + } + } else { + if (DashToast.this.random.nextFloat() > 0.95) { + this.colorKind = ColorKind.Progress; + } else { + this.colorKind = ColorKind.Neutral; + } + } + + // Randomise speed based on some values. + // Weight (the size of the line), 0.2 deviation + float weight = 1f - getWeight(); + float weightSpeed = (float) (0.7 + (weight * 0.6)); + + // Kind (The type of line), + float kindSpeed; + if (this.colorKind == ColorKind.Neutral) { + kindSpeed = (float) (1.0 + (DashToast.this.random.nextFloat() * 0.2f)); + } else { + kindSpeed = (float) (1.0 + (DashToast.this.random.nextFloat() * 0.8f)); + } + + this.speedBoost = kindSpeed * weightSpeed; + return this.colorKind != ColorKind.Neutral; + } + this.color = getColor(progress); + + return false; + } + + public void draw(Matrix4f b4, BufferBuilder bb) { + Color end = DrawerUtil.withOpacity(color, 0f); + drawVertex(b4, bb, 0f, x + width, y, color); // right top + drawVertex(b4, bb, 0f, x, y, end); // left top + drawVertex(b4, bb, 0f, x, y + height, end); // left bottom + drawVertex(b4, bb, 0f, x + width, y + height, color); // right bottom + } + + + public void drawGlow(Matrix4f b4, BufferBuilder bb) { + if (this.colorKind != ColorKind.Neutral) { + DrawerUtil.drawGlow(b4, bb, x, y, width, height, (getWeight() + 2.0f) / 3.0f, this.color, false, true, false, true); + } + } + + public Color getColor(double progress) { + Color color = switch (this.colorKind) { + case Neutral -> DrawerUtil.NEUTRAL_LINE; + case Progress -> { + if (state.getStatus() == DashToastStatus.CRASHED) { + yield DrawerUtil.FAILED_COLOR; + } + + yield DrawerUtil.getProgressColor(progress); + } + case Crashed -> DrawerUtil.FAILED_COLOR; + }; + + return DrawerUtil.withOpacity(color, MathHelper.clamp(((this.x) / (this.width)), 0.0f, 1.0f)); + } + + public float getWeight() { + return ((this.width * (float) this.height) - 60f) / 190f; + } + } + + public enum ColorKind { + Neutral, + Progress, + Crashed, + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/ui/DashToastState.java b/forge/src/main/java/dev/notalpha/dashloader/client/ui/DashToastState.java new file mode 100644 index 00000000..cb58d51a --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/ui/DashToastState.java @@ -0,0 +1,126 @@ +package dev.notalpha.dashloader.client.ui; + +import dev.notalpha.dashloader.DashLoader; +import dev.notalpha.taski.ParentTask; +import dev.notalpha.taski.Task; +import dev.notalpha.taski.builtin.AbstractTask; +import dev.notalpha.taski.builtin.StaticTask; +import net.minecraft.client.MinecraftClient; +import net.minecraft.util.Language; + +import java.util.HashMap; + +public final class DashToastState { + public Task task = new StaticTask("Idle", 0); + private final HashMap translations; + private String overwriteText; + private DashToastStatus status; + private double currentProgress = 0; + private long lastUpdate = System.currentTimeMillis(); + private long timeDone = System.currentTimeMillis(); + + + public DashToastState() { + var langCode = MinecraftClient.getInstance().getLanguageManager().getLanguage(); + DashLoader.LOG.info(langCode); + var stream = this.getClass().getClassLoader().getResourceAsStream("dashloader/lang/" + langCode + ".json"); + this.translations = new HashMap<>(); + if (stream != null) { + DashLoader.LOG.info("Found translations"); + Language.load(stream, this.translations::put); + } else { + var en_stream = this.getClass().getClassLoader().getResourceAsStream("dashloader/lang/en_us.json"); + if (en_stream != null) { + Language.load(en_stream, this.translations::put); + } + } + } + + private void tickProgress() { + if (Double.isNaN(this.currentProgress)) { + this.currentProgress = 0.0; + } + final double actualProgress = task.getProgress(); + final double divisionSpeed = (actualProgress < this.currentProgress) ? 3 : 30; + double currentProgress1 = (actualProgress - this.currentProgress) / divisionSpeed; + this.currentProgress += currentProgress1; + } + + public double getProgress() { + final long currentTime = System.currentTimeMillis(); + while (currentTime > this.lastUpdate) { + this.tickProgress(); + this.lastUpdate += 10; // ~100ups + } + return this.currentProgress; + } + + public String getText() { + if (this.overwriteText != null) { + return this.overwriteText; + } + + String text = concatTask(3, task); + return this.translations.getOrDefault(text, text); + } + + public String getProgressText() { + return this.getProgressText(3, task); + } + + private String concatTask(int depth, Task task) { + String name = null; + if (task instanceof AbstractTask abstractTask) { + name = abstractTask.getName(); + } + + if (task instanceof ParentTask stepTask) { + Task subTask = stepTask.getChild(); + if (depth > 1) { + String subName = concatTask(depth - 1, subTask); + if (subName != null) { + return name + "." + subName; + } + } + } + + return name; + } + + private String getProgressText(int depth, Task task) { + if (task instanceof ParentTask stepTask) { + Task subTask = stepTask.getChild(); + if (depth > 1) { + String subName = getProgressText(depth - 1, subTask); + if (subName != null) { + return subName; + } + } + } + + if (task instanceof AbstractTask abstractTask) { + return abstractTask.getProgressText(); + } + return null; + } + + public void setOverwriteText(String overwriteText) { + this.overwriteText = this.translations.getOrDefault(overwriteText, overwriteText); + } + + public DashToastStatus getStatus() { + return status; + } + + public void setStatus(DashToastStatus status) { + this.status = status; + } + + public long getTimeDone() { + return timeDone; + } + + public void setDone() { + this.timeDone = System.currentTimeMillis(); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/ui/DashToastStatus.java b/forge/src/main/java/dev/notalpha/dashloader/client/ui/DashToastStatus.java new file mode 100644 index 00000000..dea81b66 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/ui/DashToastStatus.java @@ -0,0 +1,7 @@ +package dev.notalpha.dashloader.client.ui; + +public enum DashToastStatus { + PROGRESS, + CRASHED, + DONE +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/client/ui/DrawerUtil.java b/forge/src/main/java/dev/notalpha/dashloader/client/ui/DrawerUtil.java new file mode 100644 index 00000000..b70c810b --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/client/ui/DrawerUtil.java @@ -0,0 +1,157 @@ +package dev.notalpha.dashloader.client.ui; + +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.render.BufferBuilder; +import net.minecraft.text.Text; +import org.joml.Matrix4f; + + +public class DrawerUtil { + public static final float GLOW_SIZE = 30f; + public static final float GLOW_STRENGTH = 0.1f; + public static final Color FAILED_COLOR = new Color(250, 68, 51); + public static final Color BACKGROUND_COLOR = new Color(34, 31, 34); + public static final Color FOREGROUND_COLOR = new Color(252, 252, 250); + public static final Color STATUS_COLOR = new Color(180, 180, 180); + public static final Color NEUTRAL_LINE = new Color(45, 42, 46); + public static final Color PROGRESS_TRACK = new Color(25, 25, 25); + private static final Color[] PROGRESS_COLORS = new Color[]{ + new Color(0xff, 0x61, 0x88), + new Color(0xfc, 0x98, 0x67), + new Color(0xff, 0xd8, 0x66), + new Color(0xa9, 0xdc, 0x76) + }; + + + public static void drawRect(DrawContext context, int x, int y, int width, int height, Color color) { + final int x2 = width + x; + final int y2 = height + y; + context.fill(x, y, x2, y2, color.argb()); + } + + public static void drawText(DrawContext context, TextRenderer textRenderer, int x, int y, String text, Color color) { + context.drawTextWithShadow(textRenderer, Text.of(text), x, y - (textRenderer.fontHeight), color.argb()); + } + + private static void drawVertex(Matrix4f m4f, BufferBuilder bb, float x, float y, Color color) { + bb.vertex(m4f, x, y, 0f).color(color.red(), color.green(), color.blue(), color.alpha()).next(); + } + + public static void drawGlow(Matrix4f b4, BufferBuilder bb, float x, float y, float width, float height, float strength, Color color, boolean topLeft, boolean topRight, boolean bottomLeft, boolean bottomRight) { + Color end = withOpacity(color, 0); + Color glow = withOpacity(color, GLOW_STRENGTH * strength); + + Color tl = topLeft ? glow : end; + Color tr = topRight ? glow : end; + Color bl = bottomLeft ? glow : end; + Color br = bottomRight ? glow : end; + + Color tlEnd = new Color(tl.red(), tl.green(), tl.blue(), 0); + Color trEnd = new Color(tr.red(), tr.green(), tr.blue(), 0); + Color blEnd = new Color(bl.red(), bl.green(), bl.blue(), 0); + Color brEnd = new Color(br.red(), br.green(), br.blue(), 0); + + float x2 = x + width; + float y2 = y + height; + + // Inside + drawVertex(b4, bb, x, y2, bl); // left bottom + drawVertex(b4, bb, x2, y2, br); // right bottom + drawVertex(b4, bb, x2, y, tr); // right top + drawVertex(b4, bb, x, y, tl); // left top + + // Top + drawVertex(b4, bb, x, y, tl); // left bottom + drawVertex(b4, bb, x2, y, tr); // right bottom + drawVertex(b4, bb, x2, y - GLOW_SIZE, trEnd); // right top + drawVertex(b4, bb, x, y - GLOW_SIZE, tlEnd); // left top + + // Top Right + drawVertex(b4, bb, x2, y - GLOW_SIZE, trEnd); // left top + drawVertex(b4, bb, x2, y, tr); // left bottom + drawVertex(b4, bb, x2 + GLOW_SIZE, y, trEnd); // right bottom + drawVertex(b4, bb, x2 + GLOW_SIZE, y - GLOW_SIZE, trEnd); // right top + + // Top Left + drawVertex(b4, bb, x, y - GLOW_SIZE, tlEnd); // right top + drawVertex(b4, bb, x - GLOW_SIZE, y - GLOW_SIZE, tlEnd); // left top + drawVertex(b4, bb, x - GLOW_SIZE, y, tlEnd); // left bottom + drawVertex(b4, bb, x, y, tl); // right bottom + + // Bottom + drawVertex(b4, bb, x2, y2 + GLOW_SIZE, brEnd); // right bottom + drawVertex(b4, bb, x2, y2, br); // right top + drawVertex(b4, bb, x, y2, bl); // left top + drawVertex(b4, bb, x, y2 + GLOW_SIZE, blEnd); // left bottom + + // Bottom Right + drawVertex(b4, bb, x2 + GLOW_SIZE, y2, brEnd); // right top + drawVertex(b4, bb, x2, y2, br); // left top + drawVertex(b4, bb, x2, y2 + GLOW_SIZE, brEnd); // left bottom + drawVertex(b4, bb, x2 + GLOW_SIZE, y2 + GLOW_SIZE, brEnd); // right bottom + + // Bottom Left + drawVertex(b4, bb, x - GLOW_SIZE, y2, blEnd); // left top + drawVertex(b4, bb, x - GLOW_SIZE, y2 + GLOW_SIZE, blEnd); // left bottom + drawVertex(b4, bb, x, y2 + GLOW_SIZE, blEnd); // right bottom + drawVertex(b4, bb, x, y2, bl); // right top + + // Right + drawVertex(b4, bb, x2, y, tr); // left top + drawVertex(b4, bb, x2, y2, br); // left bottom + drawVertex(b4, bb, x2 + GLOW_SIZE, y2, brEnd); // right bottom + drawVertex(b4, bb, x2 + GLOW_SIZE, y, trEnd); // right top + + // Left + drawVertex(b4, bb, x - GLOW_SIZE, y2, blEnd); // left bottom + drawVertex(b4, bb, x, y2, bl); // right bottom + drawVertex(b4, bb, x, y, tl); // right top + drawVertex(b4, bb, x - GLOW_SIZE, y, tlEnd); // left top + } + + public static int convertColor(Color color) { + return color.rgb() | color.alpha() << 24; + } + + public static Color withOpacity(Color color, float opacity) { + float currentOpacity = color.alpha() / 255f; + return new Color(color.red(), color.green(), color.blue(), (int) ((opacity * currentOpacity) * 255)); + } + + + public static Color getProgressColor(double progress) { + return mix(progress, PROGRESS_COLORS); + } + + private static Color mix(double pos, Color... colors) { + if (colors.length == 1) { + return colors[0]; + } + pos = Math.min(1, Math.max(0, pos)); + int breaks = colors.length - 1; + if (pos == 1) { + return colors[breaks]; + } + int colorPos = (int) Math.floor(pos * (breaks)); + final double step = 1d / (breaks); + double localRatio = (pos % step) * breaks; + return blend(colors[colorPos], colors[colorPos + 1], localRatio); + } + + private static Color blend(Color i1, Color i2, double ratio) { + if (ratio > 1f) { + ratio = 1f; + } else if (ratio < 0f) { + ratio = 0f; + } + double iRatio = 1.0f - ratio; + + int a = (int) ((i1.alpha() * iRatio) + (i2.alpha() * ratio)); + int r = (int) ((i1.red() * iRatio) + (i2.red() * ratio)); + int g = (int) ((i1.green() * iRatio) + (i2.green() * ratio)); + int b = (int) ((i1.blue() * iRatio) + (i2.blue() * ratio)); + + return new Color(r, g, b, a); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/config/Config.java b/forge/src/main/java/dev/notalpha/dashloader/config/Config.java new file mode 100644 index 00000000..27476949 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/config/Config.java @@ -0,0 +1,17 @@ +package dev.notalpha.dashloader.config; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +@SuppressWarnings("CanBeFinal") +public class Config { + public Map options = new LinkedHashMap<>(); + public byte compression = 3; + public int maxCaches = 5; + public List customSplashLines = new ArrayList<>(); + public boolean addDefaultSplashLines = true; + public boolean singleThreadedReading = false; + public boolean showCachingToast = true; +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/config/ConfigHandler.java b/forge/src/main/java/dev/notalpha/dashloader/config/ConfigHandler.java new file mode 100644 index 00000000..97921412 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/config/ConfigHandler.java @@ -0,0 +1,101 @@ +package dev.notalpha.dashloader.config; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import dev.notalpha.dashloader.DashLoader; +import net.minecraftforge.fml.ModList; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.EnumMap; + +public class ConfigHandler { + private static final EnumMap OPTION_ACTIVE = new EnumMap<>(Option.class); + + static { + for (Option value : Option.values()) { + OPTION_ACTIVE.put(value, true); + } + } + + private static final String DISABLE_OPTION_TAG = "dashloader:disableoption"; + public static final ConfigHandler INSTANCE = new ConfigHandler(new File("config/dashloader.json").toPath()); + private final Gson gson = new GsonBuilder().setLenient().setPrettyPrinting().create(); + private final Path configPath; + public Config config = new Config(); + + public ConfigHandler(Path configPath) { + this.configPath = configPath; + this.reloadConfig(); + this.config.options.forEach((s, aBoolean) -> { + try { + var option = Option.valueOf(s.toUpperCase()); + OPTION_ACTIVE.put(option, false); + DashLoader.LOG.warn("Disabled Optional Feature {} from DashLoader config.", s); + } catch (IllegalArgumentException illegalArgumentException) { + DashLoader.LOG.error("Could not disable Optional Feature {} as it does not exist.", s); + } + }); + + /*for (var modContainer : ModList.get().getMods()) { + var mod = modContainer; + if (mod.containsCustomValue(DISABLE_OPTION_TAG)) { + for (var value : mod.getCustomValue(DISABLE_OPTION_TAG).getAsArray()) { + final String feature = value.getAsString(); + try { + var option = Option.valueOf(feature.toUpperCase()); + OPTION_ACTIVE.put(option, false); + DashLoader.LOG.warn("Disabled Optional Feature {} from {} config. {}", feature, mod.getId(), mod.getName()); + } catch (IllegalArgumentException illegalArgumentException) { + DashLoader.LOG.error("Could not disable Optional Feature {} as it does not exist.", feature); + } + } + } + }*/ + } + + + public void reloadConfig() { + try { + if (Files.exists(this.configPath)) { + final BufferedReader json = Files.newBufferedReader(this.configPath); + this.config = this.gson.fromJson(json, Config.class); + json.close(); + } + } catch (Throwable err) { + DashLoader.LOG.info("Config corrupted creating a new one.", err); + } + + this.saveConfig(); + } + + public void saveConfig() { + try { + Files.createDirectories(this.configPath.getParent()); + Files.deleteIfExists(this.configPath); + final BufferedWriter writer = Files.newBufferedWriter(this.configPath, StandardOpenOption.CREATE); + this.gson.toJson(this.config, writer); + writer.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static boolean shouldApplyMixin(String name) { + for (Option value : Option.values()) { + if (name.contains(value.mixinContains)) { + return OPTION_ACTIVE.get(value); + } + } + return true; + } + + public static boolean optionActive(Option option) { + return OPTION_ACTIVE.get(option); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/config/Option.java b/forge/src/main/java/dev/notalpha/dashloader/config/Option.java new file mode 100644 index 00000000..7b6348ef --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/config/Option.java @@ -0,0 +1,33 @@ +package dev.notalpha.dashloader.config; + +public enum Option { + CACHE_MODEL_LOADER( + "cache.model", + "Caches BakedModels which allows the game to load extremely fast"), + CACHE_SPRITES( + "cache.sprite", + "Caches Sprite/Atlases which allows the game to load textures extremely fast"), + CACHE_FONT( + "cache.font", + "Caches all of the fonts and their images."), + CACHE_SPLASH_TEXT( + "cache.SplashTextResourceSupplierMixin", + "Caches the splash texts from the main screen."), + CACHE_SHADER( + "cache.shader", + "Caches the GL Shaders."), + FAST_MODEL_IDENTIFIER_EQUALS( + "misc.ModelIdentifierMixin", + "Use a much faster .equals() on the ModelIdentifiers"), + FAST_WALL_BLOCK( + "WallBlockMixin", + "Caches the 2 most common blockstates for wall blocks."); + + public final String mixinContains; + public final String description; + + Option(String mixinContains, String description) { + this.mixinContains = mixinContains; + this.description = description; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/io/IOHelper.java b/forge/src/main/java/dev/notalpha/dashloader/io/IOHelper.java new file mode 100644 index 00000000..ced56ee7 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/io/IOHelper.java @@ -0,0 +1,139 @@ +package dev.notalpha.dashloader.io; + +import com.github.luben.zstd.Zstd; +import dev.notalpha.taski.builtin.StepTask; +import dev.quantumfusion.hyphen.io.ByteBufferIO; +import org.apache.commons.io.IOUtils; +import org.lwjgl.system.MemoryUtil; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.nio.channels.FileChannel; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; + +public final class IOHelper { + + public static int[] toArray(IntBuffer buffer) { + if (buffer == null) { + return null; + } + buffer.rewind(); + int[] foo = new int[buffer.remaining()]; + buffer.get(foo); + return foo; + } + + public static float[] toArray(FloatBuffer buffer) { + if (buffer == null) { + return null; + } + + buffer.rewind(); + float[] foo = new float[buffer.remaining()]; + buffer.get(foo); + return foo; + } + + public static IntBuffer fromArray(int[] arr) { + if (arr == null) { + return null; + } + + var buffer = MemoryUtil.memAllocInt(arr.length); + buffer.put(arr); + buffer.rewind(); + return buffer; + } + + public static FloatBuffer fromArray(float[] arr) { + if (arr == null) { + return null; + } + + var buffer = MemoryUtil.memAllocFloat(arr.length); + buffer.put(arr); + buffer.rewind(); + return buffer; + } + + public static void save(Path path, StepTask task, ByteBufferIO io, int fileSize, byte compressionLevel) throws IOException { + io.rewind(); + io.byteBuffer.limit(fileSize); + try (FileChannel channel = createFile(path)) { + if (compressionLevel > 0) { + task.reset(4); + // Allocate + final long maxSize = Zstd.compressBound(fileSize); + final var dst = ByteBufferIO.createDirect((int) maxSize); + task.next(); + + // Compress + final long size = Zstd.compress(dst.byteBuffer, io.byteBuffer, compressionLevel); + task.next(); + + // Write + dst.rewind(); + dst.byteBuffer.limit((int) size); + final var map = channel.map(FileChannel.MapMode.READ_WRITE, 0, size + 5).order(ByteOrder.LITTLE_ENDIAN); + task.next(); + + map.put(compressionLevel); + map.putInt(fileSize); + map.put(dst.byteBuffer); + io.close(); + dst.close(); + } else { + task.reset(2); + final var map = channel.map(FileChannel.MapMode.READ_WRITE, 0, fileSize + 1).order(ByteOrder.LITTLE_ENDIAN); + task.next(); + ByteBufferIO file = ByteBufferIO.wrap(map); + file.putByte(compressionLevel); + file.putByteBuffer(io.byteBuffer, fileSize); + task.next(); + } + } + } + + public static ByteBufferIO load(Path path) throws IOException { + try (FileChannel channel = openFile(path)) { + var buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size()).order(ByteOrder.LITTLE_ENDIAN); + // Check compression + if (buffer.get() > 0) { + final int size = buffer.getInt(); + final var dst = ByteBufferIO.createDirect(size); + Zstd.decompress(dst.byteBuffer, buffer); + dst.rewind(); + return dst; + } else { + return ByteBufferIO.wrap(buffer); + } + } + } + + public static FileChannel createFile(Path path) throws IOException { + Files.createDirectories(path.getParent()); + Files.deleteIfExists(path); + return FileChannel.open(path, StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.READ); + } + + public static FileChannel openFile(Path path) throws IOException { + return FileChannel.open(path, StandardOpenOption.READ); + } + + public static byte[] streamToArray(InputStream inputStream) throws IOException { + final ByteArrayOutputStream output = new ByteArrayOutputStream() { + @Override + public synchronized byte[] toByteArray() { + return this.buf; + } + }; + IOUtils.copy(inputStream, output); + return output.toByteArray(); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/io/MappingSerializer.java b/forge/src/main/java/dev/notalpha/dashloader/io/MappingSerializer.java new file mode 100644 index 00000000..a29b8ab6 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/io/MappingSerializer.java @@ -0,0 +1,124 @@ +package dev.notalpha.dashloader.io; + +import dev.notalpha.dashloader.DashLoader; +import dev.notalpha.dashloader.api.DashModule; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.config.ConfigHandler; +import dev.notalpha.taski.Task; +import dev.notalpha.taski.builtin.StepTask; +import dev.notalpha.taski.builtin.WeightedStageTask; +import dev.quantumfusion.hyphen.io.ByteBufferIO; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +public class MappingSerializer { + private final Object2ObjectMap, Serializer> serializers; + + public MappingSerializer(List> cacheHandlers) { + this.serializers = new Object2ObjectOpenHashMap<>(); + + cacheHandlers.forEach(handler -> { + Class dataClass = handler.getDataClass(); + this.serializers.put(dataClass, new Serializer<>(dataClass)); + }); + } + + + @SuppressWarnings({"unchecked", "rawtypes"}) + public void save(Path dir, RegistryWriter factory, List> handlers, StepTask parent) { + List tasks = new ArrayList<>(); + for (DashModule value : handlers) { + tasks.add(new WeightedStageTask.WeightedStage(value.taskWeight(), new StepTask(value.getDataClass().getSimpleName(), 1))); + } + WeightedStageTask stageTask = new WeightedStageTask("Mapping", tasks); + parent.setSubTask(stageTask); + + + List objects = new ArrayList<>(); + int i = 0; + for (DashModule handler : handlers) { + Task task = stageTask.getStages().get(i).task; + if (handler.isActive()) { + Object object = handler.save(factory, (StepTask) task); + Class dataClass = handler.getDataClass(); + if (object.getClass() != dataClass) { + throw new RuntimeException("Handler DataClass does not match the output of saveMappings on " + handler.getClass()); + } + objects.add(object); + } else { + objects.add(null); + } + //noinspection DataFlowIssue + task.finish(); + i++; + } + + Path path = dir.resolve("mapping.bin"); + + int measure = 0; + for (Object object : objects) { + measure += 1; + if (object != null) { + Class aClass = object.getClass(); + Serializer serializer = this.serializers.get(aClass); + + if (serializer == null) { + throw new RuntimeException("Could not find mapping serializer for " + aClass); + } + + measure += serializer.measure(object); + } + } + + ByteBufferIO io = ByteBufferIO.createDirect(measure); + for (Object object : objects) { + if (object == null) { + io.putByte((byte) 0); + } else { + io.putByte((byte) 1); + Serializer serializer = this.serializers.get(object.getClass()); + serializer.put(io, object); + } + } + + try { + io.rewind(); + IOHelper.save(path, new StepTask(""), io, measure, ConfigHandler.INSTANCE.config.compression); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + public boolean load(Path dir, RegistryReader reader, List> handlers) { + try { + ByteBufferIO io = IOHelper.load(dir.resolve("mapping.bin")); + for (DashModule handler : handlers) { + if (io.getByte() == 0 && handler.isActive()) { + DashLoader.LOG.info("Recaching as " + handler.getClass().getSimpleName() + " is now active."); + return false; + } else { + Class dataClass = handler.getDataClass(); + Serializer serializer = this.serializers.get(dataClass); + Object object = serializer.get(io); + + if (handler.isActive()) { + handler.load(object, reader, new StepTask("")); + } + } + } + + return true; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/io/RegistrySerializer.java b/forge/src/main/java/dev/notalpha/dashloader/io/RegistrySerializer.java new file mode 100644 index 00000000..33868af7 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/io/RegistrySerializer.java @@ -0,0 +1,225 @@ +package dev.notalpha.dashloader.io; + +import dev.notalpha.dashloader.DashLoader; +import dev.notalpha.dashloader.DashObjectClass; +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.config.ConfigHandler; +import dev.notalpha.dashloader.io.data.CacheInfo; +import dev.notalpha.dashloader.io.data.ChunkInfo; +import dev.notalpha.dashloader.io.data.fragment.CacheFragment; +import dev.notalpha.dashloader.io.data.fragment.ChunkFragment; +import dev.notalpha.dashloader.io.data.fragment.StageFragment; +import dev.notalpha.dashloader.io.fragment.Fragment; +import dev.notalpha.dashloader.io.fragment.SimplePiece; +import dev.notalpha.dashloader.io.fragment.SizePiece; +import dev.notalpha.dashloader.registry.RegistryWriterImpl; +import dev.notalpha.dashloader.registry.data.ChunkData; +import dev.notalpha.dashloader.registry.data.ChunkFactory; +import dev.notalpha.dashloader.registry.data.StageData; +import dev.notalpha.dashloader.thread.ThreadHandler; +import dev.notalpha.taski.Task; +import dev.notalpha.taski.builtin.StepTask; +import dev.quantumfusion.hyphen.io.ByteBufferIO; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +@SuppressWarnings({"rawtypes", "unchecked"}) +public class RegistrySerializer { + // 20MB + private static final int MIN_PER_THREAD_FRAGMENT_SIZE = 1024 * 1024 * 20; + // 1GB + private static final int MAX_FRAGMENT_SIZE = 1024 * 1024 * 1024; + private final Object2ObjectMap, Serializer> serializers; + private final int compressionLevel; + + public RegistrySerializer(List> dashObjects) { + this.compressionLevel = ConfigHandler.INSTANCE.config.compression; + this.serializers = new Object2ObjectOpenHashMap<>(); + for (DashObjectClass dashObject : dashObjects) { + Class dashClass = dashObject.getDashClass(); + this.serializers.put(dashClass, new Serializer<>(dashClass)); + } + } + + public > Serializer getSerializer(DashObjectClass dashObject) { + return (Serializer) this.serializers.get(dashObject.getDashClass()); + } + + public CacheInfo serialize(Path dir, RegistryWriterImpl factory, Consumer taskConsumer) throws IOException { + StageData[] stages = factory.export(); + + SimplePiece[] value = new SimplePiece[stages.length]; + for (int i = 0; i < stages.length; i++) { + StageData stage = stages[i]; + SimplePiece[] value2 = new SimplePiece[stage.chunks.length]; + for (int i1 = 0; i1 < stage.chunks.length; i1++) { + ChunkData chunk = stage.chunks[i1]; + Serializer serializer = getSerializer(chunk.dashObject); + SizePiece[] value3 = new SizePiece[chunk.dashables.length]; + for (int i2 = 0; i2 < chunk.dashables.length; i2++) { + value3[i2] = new SizePiece(serializer.measure(chunk.dashables[i2].data) + 4); + } + + value2[i1] = new SimplePiece(value3); + } + + value[i] = new SimplePiece(value2); + } + SimplePiece piece = new SimplePiece(value); + + int[][] stageSizes = new int[stages.length][]; + for (int i = 0; i < stages.length; i++) { + StageData stage = stages[i]; + int[] chunkSizes = new int[stage.chunks.length]; + for (int i1 = 0; i1 < stage.chunks.length; i1++) { + chunkSizes[i1] = stage.chunks[i1].dashables.length; + } + stageSizes[i] = chunkSizes; + } + + + // Calculate amount of fragments required + int minFragments = (int) (piece.size / MAX_FRAGMENT_SIZE); + int maxFragments = (int) (piece.size / MIN_PER_THREAD_FRAGMENT_SIZE); + int fragmentCount = Integer.max(Integer.max(Integer.min(ThreadHandler.THREADS, maxFragments), minFragments), 1); + long remainingSize = piece.size; + + List fragments = new ArrayList<>(); + for (int i = 0; i < fragmentCount; i++) { + long fragmentSize = remainingSize / (fragmentCount - i); + if (i == fragmentCount - 1) { + fragmentSize = Long.MAX_VALUE; + } + Fragment fragment = piece.fragment(fragmentSize); + remainingSize -= fragment.size; + fragments.add(new CacheFragment(fragment)); + } + + + StepTask task = new StepTask("fragment", fragments.size() * 2); + taskConsumer.accept(task); + // Serialize + for (int k = 0; k < fragments.size(); k++) { + DashLoader.LOG.info("Serializing fragment " + k); + CacheFragment fragment = fragments.get(k); + List stageFragmentMetadata = fragment.stages; + ByteBufferIO io = ByteBufferIO.createDirect((int) fragment.info.fileSize); + + + int taskSize = 0; + for (var stage : stageFragmentMetadata) { + for (var chunk : stage.chunks) { + taskSize += chunk.info.rangeEnd - chunk.info.rangeStart; + } + } + + StepTask stageTask = new StepTask("stage", taskSize); + task.setSubTask(stageTask); + for (int i = 0; i < stageFragmentMetadata.size(); i++) { + StageFragment stage = stageFragmentMetadata.get(i); + StageData data = stages[i + fragment.info.rangeStart]; + + List chunks = stage.chunks; + for (int j = 0; j < chunks.size(); j++) { + ChunkFragment chunk = chunks.get(j); + ChunkData chunkData = data.chunks[j + stage.info.rangeStart]; + Serializer serializer = serializers.get(chunkData.dashObject.getDashClass()); + for (int i1 = chunk.info.rangeStart; i1 < chunk.info.rangeEnd; i1++) { + ChunkData.Entry dashable = chunkData.dashables[i1]; + io.putInt(dashable.pos); + serializer.put(io, dashable.data); + stageTask.next(); + } + } + } + task.next(); + + StepTask serializingTask = new StepTask("Serializing"); + task.setSubTask(serializingTask); + + int fileSize = (int) fragment.info.fileSize; + IOHelper.save(fragmentFilePath(dir, k), serializingTask, io, fileSize, (byte) compressionLevel); + task.next(); + } + + List chunks = new ArrayList<>(); + for (ChunkFactory chunk : factory.chunks) { + chunks.add(new ChunkInfo(chunk)); + } + + return new CacheInfo(fragments, chunks, stageSizes); + } + + public StageData[] deserialize(Path dir, CacheInfo metadata, List> objects) { + StageData[] out = new StageData[metadata.stageSizes.length]; + for (int i = 0; i < metadata.stageSizes.length; i++) { + int[] chunkSizes = metadata.stageSizes[i]; + ChunkData[] chunks = new ChunkData[chunkSizes.length]; + for (int j = 0; j < chunks.length; j++) { + ChunkInfo chunkInfo = metadata.chunks.get(j); + chunks[j] = new ChunkData( + (byte) j, + chunkInfo.name, + objects.get(chunkInfo.dashObjectId), + new ChunkData.Entry[chunkSizes[j]] + ); + } + + out[i] = new StageData(chunks); + } + + + List fragments = metadata.fragments; + List runnables = new ArrayList<>(); + for (int j = 0; j < fragments.size(); j++) { + CacheFragment fragment = fragments.get(j); + int finalJ = j; + runnables.add(() -> { + try { + ByteBufferIO io = IOHelper.load(fragmentFilePath(dir, finalJ)); + deserialize(out, io, fragment); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } + + if (ConfigHandler.INSTANCE.config.singleThreadedReading) { + for (Runnable runnable : runnables) { + runnable.run(); + } + } else { + ThreadHandler.INSTANCE.parallelRunnable(runnables); + } + + return out; + } + + + private void deserialize(StageData[] data, ByteBufferIO io, CacheFragment fragment) { + for (int i = 0; i < fragment.stages.size(); i++) { + StageFragment stageFragment = fragment.stages.get(i); + StageData stage = data[fragment.info.rangeStart + i]; + for (int i1 = 0; i1 < stageFragment.chunks.size(); i1++) { + ChunkFragment chunkFragment = stageFragment.chunks.get(i1); + ChunkData chunkData = stage.chunks[stageFragment.info.rangeStart + i1]; + Serializer serializer = getSerializer(chunkData.dashObject); + for (int i2 = chunkFragment.info.rangeStart; i2 < chunkFragment.info.rangeEnd; i2++) { + int pos = io.getInt(); + Object out = serializer.get(io); + chunkData.dashables[i2] = new ChunkData.Entry<>(out, pos); + } + } + } + } + + private Path fragmentFilePath(Path dir, int fragment) { + return dir.resolve("fragment-" + fragment + ".bin"); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/io/Serializer.java b/forge/src/main/java/dev/notalpha/dashloader/io/Serializer.java new file mode 100644 index 00000000..2d5da226 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/io/Serializer.java @@ -0,0 +1,72 @@ +package dev.notalpha.dashloader.io; + +import dev.notalpha.dashloader.config.ConfigHandler; +import dev.notalpha.dashloader.io.def.NativeImageData; +import dev.notalpha.dashloader.io.def.NativeImageDataDef; +import dev.notalpha.dashloader.registry.data.ChunkData; +import dev.notalpha.taski.builtin.StepTask; +import dev.quantumfusion.hyphen.HyphenSerializer; +import dev.quantumfusion.hyphen.SerializerFactory; +import dev.quantumfusion.hyphen.io.ByteBufferIO; +import dev.quantumfusion.hyphen.scan.annotations.DataSubclasses; +import net.minecraft.client.font.UnihexFont; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.nio.file.Path; + +public class Serializer { + private final HyphenSerializer serializer; + + public Serializer(Class aClass) { + var factory = SerializerFactory.createDebug(ByteBufferIO.class, aClass); + factory.addGlobalAnnotation(ChunkData.class, DataSubclasses.class, new Class[]{ChunkData.class}); + factory.setClassName(getSerializerClassName(aClass)); + factory.addGlobalAnnotation(UnihexFont.BitmapGlyph.class, DataSubclasses.class, new Class[]{ + UnihexFont.FontImage32x16.class, + UnihexFont.FontImage16x16.class, + UnihexFont.FontImage8x16.class, + }); + factory.addDynamicDef(NativeImageData.class, (clazz, serializerHandler) -> new NativeImageDataDef(serializerHandler, clazz)); + this.serializer = factory.build(); + } + + public O get(ByteBufferIO io) { + return this.serializer.get(io); + } + + public void put(ByteBufferIO io, O data) { + this.serializer.put(io, data); + } + + public long measure(O data) { + return this.serializer.measure(data); + } + + public void save(Path path, StepTask task, O data) { + var measure = (int) this.serializer.measure(data); + var io = ByteBufferIO.createDirect(measure); + this.serializer.put(io, data); + io.rewind(); + try { + + IOHelper.save(path, task, io, measure, ConfigHandler.INSTANCE.config.compression); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public O load(Path path) { + try { + ByteBufferIO io = IOHelper.load(path); + return this.serializer.get(io); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @NotNull + private static String getSerializerClassName(Class holderClass) { + return holderClass.getSimpleName().toLowerCase() + "-serializer"; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/io/data/CacheInfo.java b/forge/src/main/java/dev/notalpha/dashloader/io/data/CacheInfo.java new file mode 100644 index 00000000..d1dae4b3 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/io/data/CacheInfo.java @@ -0,0 +1,30 @@ +package dev.notalpha.dashloader.io.data; + + +import dev.notalpha.dashloader.io.data.fragment.CacheFragment; + +import java.util.List; + +public class CacheInfo { + /** + * Information about the different file fragments the cache contains. + */ + public final List fragments; + /** + * Information about the output chunks. + */ + public final List chunks; + + /** + * A two dimensional array containing the sizes of the stages and chunks. + * The first index is the stage index which will yield an array of the chunk sizes, + * The size of this array is the amount of chunks in that stage. + */ + public final int[][] stageSizes; + + public CacheInfo(List fragments, List chunks, int[][] stageSizes) { + this.fragments = fragments; + this.chunks = chunks; + this.stageSizes = stageSizes; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/io/data/ChunkInfo.java b/forge/src/main/java/dev/notalpha/dashloader/io/data/ChunkInfo.java new file mode 100644 index 00000000..63dc08e7 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/io/data/ChunkInfo.java @@ -0,0 +1,21 @@ +package dev.notalpha.dashloader.io.data; + +import dev.notalpha.dashloader.registry.data.ChunkFactory; + +public class ChunkInfo { + public final int dashObjectId; + public final int size; + public final String name; + + public ChunkInfo(int dashObjectId, int size, String name) { + this.dashObjectId = dashObjectId; + this.size = size; + this.name = name; + } + + public ChunkInfo(ChunkFactory chunk) { + this.dashObjectId = chunk.dashObject.getDashObjectId(); + this.size = chunk.list.size(); + this.name = chunk.name; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/io/data/fragment/CacheFragment.java b/forge/src/main/java/dev/notalpha/dashloader/io/data/fragment/CacheFragment.java new file mode 100644 index 00000000..03628dae --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/io/data/fragment/CacheFragment.java @@ -0,0 +1,24 @@ +package dev.notalpha.dashloader.io.data.fragment; + +import dev.notalpha.dashloader.io.fragment.Fragment; + +import java.util.ArrayList; +import java.util.List; + +public class CacheFragment { + public final List stages; + public final FragmentSlice info; + + public CacheFragment(List stages, FragmentSlice info) { + this.stages = stages; + this.info = info; + } + + public CacheFragment(Fragment fragment) { + this.info = new FragmentSlice(fragment); + this.stages = new ArrayList<>(); + for (Fragment inner : fragment.inner) { + this.stages.add(new StageFragment(inner)); + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/io/data/fragment/ChunkFragment.java b/forge/src/main/java/dev/notalpha/dashloader/io/data/fragment/ChunkFragment.java new file mode 100644 index 00000000..46b46e2d --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/io/data/fragment/ChunkFragment.java @@ -0,0 +1,15 @@ +package dev.notalpha.dashloader.io.data.fragment; + +import dev.notalpha.dashloader.io.fragment.Fragment; + +public final class ChunkFragment { + public final FragmentSlice info; + + public ChunkFragment(FragmentSlice info) { + this.info = info; + } + + public ChunkFragment(Fragment fragment) { + this.info = new FragmentSlice(fragment); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/io/data/fragment/FragmentSlice.java b/forge/src/main/java/dev/notalpha/dashloader/io/data/fragment/FragmentSlice.java new file mode 100644 index 00000000..1c8ddcab --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/io/data/fragment/FragmentSlice.java @@ -0,0 +1,21 @@ +package dev.notalpha.dashloader.io.data.fragment; + +import dev.notalpha.dashloader.io.fragment.Fragment; + +public class FragmentSlice { + public final int rangeStart; + public final int rangeEnd; + public final long fileSize; + + public FragmentSlice(int rangeStart, int rangeEnd, long fileSize) { + this.rangeStart = rangeStart; + this.rangeEnd = rangeEnd; + this.fileSize = fileSize; + } + + public FragmentSlice(Fragment fragment) { + this.rangeStart = fragment.startIndex; + this.rangeEnd = fragment.endIndex; + this.fileSize = fragment.size; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/io/data/fragment/StageFragment.java b/forge/src/main/java/dev/notalpha/dashloader/io/data/fragment/StageFragment.java new file mode 100644 index 00000000..110bd111 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/io/data/fragment/StageFragment.java @@ -0,0 +1,24 @@ +package dev.notalpha.dashloader.io.data.fragment; + +import dev.notalpha.dashloader.io.fragment.Fragment; + +import java.util.ArrayList; +import java.util.List; + +public class StageFragment { + public final List chunks; + public final FragmentSlice info; + + public StageFragment(List chunks, FragmentSlice info) { + this.chunks = chunks; + this.info = info; + } + + public StageFragment(Fragment fragment) { + this.info = new FragmentSlice(fragment); + this.chunks = new ArrayList<>(); + for (Fragment inner : fragment.inner) { + this.chunks.add(new ChunkFragment(inner)); + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/io/def/DataUnsafeByteBuffer.java b/forge/src/main/java/dev/notalpha/dashloader/io/def/DataUnsafeByteBuffer.java new file mode 100644 index 00000000..9c469e2a --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/io/def/DataUnsafeByteBuffer.java @@ -0,0 +1,14 @@ +package dev.notalpha.dashloader.io.def; + +import dev.quantumfusion.hyphen.scan.annotations.HyphenAnnotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@HyphenAnnotation +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE_USE}) +public @interface DataUnsafeByteBuffer { +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/io/def/NativeImageData.java b/forge/src/main/java/dev/notalpha/dashloader/io/def/NativeImageData.java new file mode 100644 index 00000000..4420f147 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/io/def/NativeImageData.java @@ -0,0 +1,15 @@ +package dev.notalpha.dashloader.io.def; + +import java.nio.ByteBuffer; + +public class NativeImageData { + public final ByteBuffer buffer; + public final boolean stb; + + public NativeImageData(ByteBuffer buffer, boolean stb) { + this.buffer = buffer; + this.stb = stb; + } + + +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/io/def/NativeImageDataDef.java b/forge/src/main/java/dev/notalpha/dashloader/io/def/NativeImageDataDef.java new file mode 100644 index 00000000..59b736bf --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/io/def/NativeImageDataDef.java @@ -0,0 +1,90 @@ +package dev.notalpha.dashloader.io.def; + +import dev.quantumfusion.hyphen.SerializerHandler; +import dev.quantumfusion.hyphen.codegen.MethodHandler; +import dev.quantumfusion.hyphen.codegen.Variable; +import dev.quantumfusion.hyphen.codegen.def.BufferDef; +import dev.quantumfusion.hyphen.codegen.def.MethodDef; +import dev.quantumfusion.hyphen.codegen.statement.IfElse; +import dev.quantumfusion.hyphen.scan.type.Clazz; +import org.lwjgl.system.MemoryUtil; +import org.objectweb.asm.Opcodes; + +import java.nio.ByteBuffer; + +public class NativeImageDataDef extends MethodDef { + private ByteBufferDef bytebufferDef; + + public NativeImageDataDef(SerializerHandler handler, Clazz clazz) { + super(handler, clazz); + } + + @Override + public void scan(SerializerHandler handler, Clazz clazz) { + this.bytebufferDef = new ByteBufferDef(new Clazz(handler, ByteBuffer.class), handler); + } + + @Override + protected void writeMethodPut(MethodHandler mh, Runnable valueLoad) { + mh.loadIO(); + valueLoad.run(); + mh.visitFieldInsn(Opcodes.GETFIELD, NativeImageData.class, "stb", boolean.class); + mh.putIO(boolean.class); + + bytebufferDef.writePut(mh, () -> { + valueLoad.run(); + mh.visitFieldInsn(Opcodes.GETFIELD, NativeImageData.class, "buffer", ByteBuffer.class); + }); + } + + @Override + protected void writeMethodGet(MethodHandler mh) { + mh.typeOp(Opcodes.NEW, NativeImageData.class); + mh.op(Opcodes.DUP); + + mh.loadIO(); + mh.getIO(boolean.class); + + mh.op(Opcodes.DUP); + Variable stb = mh.addVar("stb", boolean.class); + mh.varOp(Opcodes.ISTORE, stb); + + bytebufferDef.stbVariable = stb; + bytebufferDef.writeGet(mh); + + mh.op(Opcodes.SWAP); + mh.callInst(Opcodes.INVOKESPECIAL, NativeImageData.class, "", Void.TYPE, ByteBuffer.class, boolean.class); + } + + @Override + protected void writeMethodMeasure(MethodHandler mh, Runnable valueLoad) { + bytebufferDef.writeMeasure(mh, () -> { + valueLoad.run(); + mh.visitFieldInsn(Opcodes.GETFIELD, NativeImageData.class, "buffer", ByteBuffer.class); + }); + } + + @Override + public long getStaticSize() { + return bytebufferDef.getStaticSize() + 1; + } + + private static class ByteBufferDef extends BufferDef { + private Variable stbVariable; + + public ByteBufferDef(Clazz clazz, SerializerHandler serializerHandler) { + super(clazz, serializerHandler); + } + + @Override + protected void allocateBuffer(MethodHandler mh) { + mh.varOp(Opcodes.ILOAD, stbVariable); + try (var thing = new IfElse(mh, Opcodes.IFEQ)) { + mh.op(Opcodes.ICONST_1, Opcodes.SWAP); + mh.callInst(Opcodes.INVOKESTATIC, MemoryUtil.class, "memCalloc", ByteBuffer.class, int.class, int.class); + thing.elseEnd(); + mh.callInst(Opcodes.INVOKESTATIC, MemoryUtil.class, "memAlloc", ByteBuffer.class, int.class); + } + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/io/fragment/Fragment.java b/forge/src/main/java/dev/notalpha/dashloader/io/fragment/Fragment.java new file mode 100644 index 00000000..edc2ed65 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/io/fragment/Fragment.java @@ -0,0 +1,27 @@ +package dev.notalpha.dashloader.io.fragment; + +import java.util.List; + +public class Fragment { + public final long size; + public final int startIndex; + public final int endIndex; + public final List inner; + + public Fragment(long size, int startIndex, int endIndex, List inner) { + this.size = size; + this.startIndex = startIndex; + this.endIndex = endIndex; + this.inner = inner; + } + + @Override + public String toString() { + return "Fragment{" + + "size=" + size + + ", startIndex=" + startIndex + + ", endIndex=" + endIndex + + ", inner=" + inner + + '}'; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/io/fragment/Piece.java b/forge/src/main/java/dev/notalpha/dashloader/io/fragment/Piece.java new file mode 100644 index 00000000..6a68a8bc --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/io/fragment/Piece.java @@ -0,0 +1,51 @@ +package dev.notalpha.dashloader.io.fragment; + +import java.util.ArrayList; +import java.util.List; + +public abstract class Piece { + public final long size; + + protected Piece(long size) { + this.size = size; + } + + public abstract Piece[] getInner(); + + public boolean isDone() { + Piece[] inner = this.getInner(); + return inner == null || !(elementPos < inner.length); + } + + int elementPos = 0; + + public Fragment fragment(long sizeRemaining) { + Piece[] inner = this.getInner(); + if (inner == null) { + throw new RuntimeException("Non splitting piece requested fragmentation"); + } else { + int rangeStart = elementPos; + long currentSize = 0; + + List innerOut = new ArrayList<>(); + int rangeEnd = 0; + // Add until we reach the intended size, or we hit the last element. + while ((currentSize < sizeRemaining) && elementPos < inner.length) { + var piece = inner[elementPos]; + rangeEnd = elementPos + 1; + if (piece.getInner() == null) { + currentSize += piece.size; + elementPos += 1; + } else { + Fragment fragment = piece.fragment(sizeRemaining); + innerOut.add(fragment); + currentSize += fragment.size; + if (piece.isDone()) { + elementPos += 1; + } + } + } + return new Fragment(currentSize, rangeStart, rangeEnd, innerOut); + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/io/fragment/SimplePiece.java b/forge/src/main/java/dev/notalpha/dashloader/io/fragment/SimplePiece.java new file mode 100644 index 00000000..4b612b29 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/io/fragment/SimplePiece.java @@ -0,0 +1,22 @@ +package dev.notalpha.dashloader.io.fragment; + +import java.util.Arrays; + +public class SimplePiece extends Piece { + public final Piece[] value; + + public SimplePiece(Piece[] value) { + super(Arrays.stream(value).mapToLong(dEntry -> dEntry.size).sum()); + this.value = value; + } + + @Override + public Piece[] getInner() { + return value; + } + + @Override + public String toString() { + return Arrays.toString(value); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/io/fragment/SizePiece.java b/forge/src/main/java/dev/notalpha/dashloader/io/fragment/SizePiece.java new file mode 100644 index 00000000..8d587d6a --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/io/fragment/SizePiece.java @@ -0,0 +1,17 @@ +package dev.notalpha.dashloader.io.fragment; + +public class SizePiece extends Piece { + public SizePiece(long size) { + super(size); + } + + @Override + public Piece[] getInner() { + return null; + } + + @Override + public String toString() { + return ""; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/misc/HahaManager.java b/forge/src/main/java/dev/notalpha/dashloader/misc/HahaManager.java new file mode 100644 index 00000000..ee5c9fa9 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/misc/HahaManager.java @@ -0,0 +1,80 @@ +package dev.notalpha.dashloader.misc; + +import dev.notalpha.dashloader.config.Config; +import dev.notalpha.dashloader.config.ConfigHandler; + +import java.util.ArrayList; +import java.util.List; + +public final class HahaManager { + private static final String[] FACTS = { + "Dash was for the cool kids", + "fun fact: 1 + 1 = 11", + "glisco goes around and yells", + ":froge:", + ":bigfroge:", + ":smolfroge:", + "Frog + Doge = Froge", + "Froges dad is cool", + "Rogger Rogger!", + "Yes commander!", + "I am not the swarm!", + "Get that golden strawberry!", + "Kevin is cool.", + "B-Sides are where I flex.", + "Starting an accelerated backhop", + "Gordon Freeman. I like your tie.", + "The factory must grow.", + "Not the biters.", + "Ya got more red belts?", + "I need more boilers.", + "Throughput of circuits is gud.", + "amogus", + "sus", + "imposter", + "it was red!", + "What does the vent button do?", + "We need more white wine.", + "I season my cuttingboard", + "Do as I say, not as I do", + "Colton is fired", + "Was a banger on the cord.", + "My code thinks different.", + "Make it for 300$ sell it for 1300$", + "Steve is almost chad", + "IKEA is traditional.", + "1 + 1 = 11", + "https://ko-fi.com/notequalalpha", + "USB-C is gud.", + "Modrinth gud.", + "Leocth and Alpha were first.", + "Corn on a jakob is the best.", + "Cornebb is cool.", + "Hyphen is cool.", + "DashLoader kinda banger.", + "MFOTS was a thing.", + ":tnypotat:", + "418 I'm a teapot is a real error", + "mld hrdr - leocth 2022", + // HiItsDevin + "Devin beat 7C after 5 1/2 hours", + // shedaniel + "Look at me, I am vibing up here", + "Doesn't break REI" + }; + + public static String getFact() { + Config config = ConfigHandler.INSTANCE.config; + List splashLines = new ArrayList<>(config.customSplashLines); + if (config.addDefaultSplashLines) { + splashLines.addAll(List.of(FACTS)); + } + + if (splashLines.isEmpty()) { + return null; + } + + + return splashLines.get((int) (System.currentTimeMillis() % splashLines.size())); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/misc/ObjectDumper.java b/forge/src/main/java/dev/notalpha/dashloader/misc/ObjectDumper.java new file mode 100644 index 00000000..f8610602 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/misc/ObjectDumper.java @@ -0,0 +1,146 @@ +package dev.notalpha.dashloader.misc; + +import net.minecraft.client.texture.NativeImage; +import org.apache.commons.lang3.builder.MultilineRecursiveToStringStyle; +import org.apache.commons.lang3.builder.ReflectionToStringBuilder; + +import java.lang.reflect.Field; +import java.lang.reflect.InaccessibleObjectException; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.util.*; + +public class ObjectDumper { + public static String dump(Wrapper object) { + return ReflectionToStringBuilder.toString(object, new Style()); + } + + public static class Wrapper { + public final Object data; + public Wrapper(Object data) { + this.data = data; + } + } + + private static final class Style extends MultilineRecursiveToStringStyle { + public Style() { + setFieldNameValueSeparator(": "); + setUseIdentityHashCode(false); + setUseShortClassName(true); + } + + public void appendDetail(StringBuffer buffer, String fieldName, Object value) { + try { + if (value != null) { + if (Objects.equals(fieldName, "glRef")) { + buffer.append(""); + return; + } + + if (value instanceof ThreadLocal local) { + appendDetail(buffer, fieldName, local.get()); + return; + } + + if (value instanceof HashMap map) { + appendDetail(buffer, fieldName, (Map) map); + return; + } + + if (value instanceof ArrayList list) { + appendDetail(buffer, fieldName, (List) list); + return; + } + + if (value instanceof NativeImage image) { + buffer.append("Image{ format: ").append(image.getFormat()).append(", size: ").append(image.getWidth()).append("x").append(image.getHeight()).append(" }"); + return; + } + + if (value instanceof IntBuffer buffer1) { + buffer.append("IntBuffer ["); + int limit = buffer1.limit(); + if (limit < 50) { + buffer1.rewind(); + for (int i = 0; i < limit; i++) { + float v = buffer1.get(); + buffer.append(v); + buffer.append(", "); + } + } + buffer.append("]"); + return; + } + + if (value instanceof FloatBuffer buffer1) { + buffer.append("FloatBuffer ["); + int limit = buffer1.limit(); + if (limit < 50) { + buffer1.rewind(); + for (int i = 0; i < limit; i++) { + float v = buffer1.get(); + buffer.append(v); + buffer.append(", "); + } + } + buffer.append("]"); + return; + } + + if (value instanceof Enum enumValue) { + buffer.append(enumValue.name()); + return; + } + } else { + buffer.append("null"); + return; + } + + try { + StringBuffer builder = new StringBuffer(); + super.appendDetail(builder, fieldName, value); + String s = builder.toString(); + String result = s.split("@")[0]; + buffer.append(result); + } + catch (InaccessibleObjectException e) { + throw e; + } + catch (Exception e) { + e.printStackTrace(); + + buffer.append("unknown"); + try { + Field spaces = MultilineRecursiveToStringStyle.class.getDeclaredField("spaces"); + spaces.setAccessible(true); + spaces.setInt(this, spaces.getInt(this) - 2); + } catch (IllegalAccessException | NoSuchFieldException ex) { + throw new RuntimeException(ex); + } + } + } catch (Exception e) { + throw new RuntimeException(value == null ? "null" : value.toString(), e); + } + } + + @Override + protected void appendDetail(StringBuffer buffer, String fieldName, Map map) { + buffer.append(this.getArrayStart()); + + // Sort maps to be comparible + List> entries = new ArrayList<>(map.entrySet()); + entries.sort((o1, o2) -> o1.getKey().toString().compareTo(o2.toString())); + entries.forEach((entry) -> { + buffer.append(getArraySeparator()); + this.appendDetail(buffer, String.valueOf(entry.getKey()), entry.getValue()); + }); + buffer.append(this.getArrayEnd()); + } + + @Override + protected void appendIdentityHashCode(StringBuffer buffer, Object object) { + + + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/misc/ProfilerUtil.java b/forge/src/main/java/dev/notalpha/dashloader/misc/ProfilerUtil.java new file mode 100644 index 00000000..71e5cc90 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/misc/ProfilerUtil.java @@ -0,0 +1,25 @@ +package dev.notalpha.dashloader.misc; + + +public final class ProfilerUtil { + public static long RELOAD_START = 0; + + public static String getTimeStringFromStart(long start) { + return getTimeString(System.currentTimeMillis() - start); + } + + public static String getTimeString(long ms) { + if (ms >= 60000) { // 1m + return ((int) ((ms / 60000))) + "m " + ((int) (ms % 60000) / 1000) + "s"; // [4m 42s] + } else if (ms >= 3000) // 3s + { + return printMsToSec(ms) + "s"; // 1293ms = [1.2s] + } else { + return ms + "ms"; // [400ms] + } + } + + private static float printMsToSec(long ms) { + return Math.round(ms / 100f) / 10f; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/misc/UnsafeHelper.java b/forge/src/main/java/dev/notalpha/dashloader/misc/UnsafeHelper.java new file mode 100644 index 00000000..327a387b --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/misc/UnsafeHelper.java @@ -0,0 +1,41 @@ +package dev.notalpha.dashloader.misc; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +public final class UnsafeHelper { + + public static final sun.misc.Unsafe UNSAFE = getUnsafeInstance(); + + private static sun.misc.Unsafe getUnsafeInstance() { + Class clazz = sun.misc.Unsafe.class; + for (Field field : clazz.getDeclaredFields()) { + if (!field.getType().equals(clazz)) { + continue; + } + final int modifiers = field.getModifiers(); + if (!(Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers))) { + continue; + } + try { + field.setAccessible(true); + return (sun.misc.Unsafe) field.get(null); + } catch (Exception ignored) { + } + break; + } + + throw new IllegalStateException("Unsafe is unavailable."); + } + + @SuppressWarnings("unchecked") + public static O allocateInstance(Class closs) { + try { + return (O) UNSAFE.allocateInstance(closs); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } + } + + +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/misc/UnsafeImage.java b/forge/src/main/java/dev/notalpha/dashloader/misc/UnsafeImage.java new file mode 100644 index 00000000..d7923cd8 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/misc/UnsafeImage.java @@ -0,0 +1,27 @@ +package dev.notalpha.dashloader.misc; + +import dev.notalpha.dashloader.mixin.accessor.NativeImageAccessor; +import net.minecraft.client.texture.NativeImage; +import org.lwjgl.system.MemoryUtil; + +public final class UnsafeImage { + public final NativeImage image; + public final int width; + public final int height; + public final long pointer; + + public UnsafeImage(NativeImage image) { + this.image = image; + this.width = image.getWidth(); + this.height = image.getHeight(); + this.pointer = ((NativeImageAccessor)(Object) image).getPointer(); + } + + public int get(int x, int y) { + return MemoryUtil.memGetInt(this.pointer + ((long)x + (long)y * (long)width) * 4L); + } + + public void set(int x, int y, int value) { + MemoryUtil.memPutInt(this.pointer + ((long)x + (long)y * (long)width) * 4L, value); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/MixinPlugin.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/MixinPlugin.java new file mode 100644 index 00000000..d7532817 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/MixinPlugin.java @@ -0,0 +1,47 @@ +package dev.notalpha.dashloader.mixin; + +import dev.notalpha.dashloader.config.ConfigHandler; +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; + +import java.util.List; +import java.util.Set; + +public class MixinPlugin implements IMixinConfigPlugin { + + @Override + public void onLoad(String mixinPackage) { + + } + + @Override + public String getRefMapperConfig() { + return null; + } + + @Override + public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { + return ConfigHandler.shouldApplyMixin(mixinClassName); + } + + @Override + public void acceptTargets(Set myTargets, Set otherTargets) { + + } + + @Override + public List getMixins() { + return null; + } + + @Override + public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } + + @Override + public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/AbstractTextureAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/AbstractTextureAccessor.java new file mode 100644 index 00000000..b1eb9046 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/AbstractTextureAccessor.java @@ -0,0 +1,21 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.client.texture.AbstractTexture; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(AbstractTexture.class) +public interface AbstractTextureAccessor { + + @Accessor + boolean getBilinear(); + + @Accessor + void setBilinear(boolean bilinear); + + @Accessor + boolean getMipmap(); + + @Accessor + void setMipmap(boolean mipmap); +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/AndMultipartModelSelectorAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/AndMultipartModelSelectorAccessor.java new file mode 100644 index 00000000..88c346ab --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/AndMultipartModelSelectorAccessor.java @@ -0,0 +1,14 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.client.render.model.json.AndMultipartModelSelector; +import net.minecraft.client.render.model.json.MultipartModelSelector; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(AndMultipartModelSelector.class) +public interface AndMultipartModelSelectorAccessor { + + @Accessor + Iterable getSelectors(); + +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/BasicBakedModelAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/BasicBakedModelAccessor.java new file mode 100644 index 00000000..7d44708d --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/BasicBakedModelAccessor.java @@ -0,0 +1,41 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.client.render.model.BakedQuad; +import net.minecraft.client.render.model.BasicBakedModel; +import net.minecraft.client.render.model.json.ModelOverrideList; +import net.minecraft.client.render.model.json.ModelTransformation; +import net.minecraft.client.texture.Sprite; +import net.minecraft.util.math.Direction; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.List; +import java.util.Map; + +@Mixin(BasicBakedModel.class) +public interface BasicBakedModelAccessor { + + @Accessor + List getQuads(); + + @Accessor + Map> getFaceQuads(); + + @Accessor + boolean getUsesAo(); + + @Accessor + boolean getHasDepth(); + + @Accessor + boolean getIsSideLit(); + + @Accessor + Sprite getSprite(); + + @Accessor + ModelTransformation getTransformation(); + + @Accessor + ModelOverrideList getItemPropertyOverrides(); +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontAccessor.java new file mode 100644 index 00000000..cfa6bd81 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontAccessor.java @@ -0,0 +1,25 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import net.minecraft.client.font.BitmapFont; +import net.minecraft.client.font.GlyphContainer; +import net.minecraft.client.texture.NativeImage; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(BitmapFont.class) +public interface BitmapFontAccessor { + + @Invoker("") + static BitmapFont init(NativeImage image, GlyphContainer glyphs) { + throw new AssertionError(); + } + + @Accessor + GlyphContainer getGlyphs(); + + @Accessor + NativeImage getImage(); + +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontGlyphAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontGlyphAccessor.java new file mode 100644 index 00000000..951e8862 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontGlyphAccessor.java @@ -0,0 +1,41 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.client.font.BitmapFont; +import net.minecraft.client.texture.NativeImage; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(BitmapFont.BitmapFontGlyph.class) +public interface BitmapFontGlyphAccessor { + + + @Invoker("") + static BitmapFont.BitmapFontGlyph init(float scaleFactor, NativeImage image, int x, int y, int width, int height, int advance, int ascent) { + throw new AssertionError(); + } + + @Accessor + NativeImage getImage(); + + @Accessor("x") + int getX(); + + @Accessor("y") + int getY(); + + @Accessor + float getScaleFactor(); + + @Accessor + int getWidth(); + + @Accessor + int getHeight(); + + @Accessor + int getAdvance(); + + @Accessor + int getAscent(); +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/BuiltinBakedModelAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/BuiltinBakedModelAccessor.java new file mode 100644 index 00000000..d3b31bc6 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/BuiltinBakedModelAccessor.java @@ -0,0 +1,25 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.client.render.model.BuiltinBakedModel; +import net.minecraft.client.render.model.json.ModelOverrideList; +import net.minecraft.client.render.model.json.ModelTransformation; +import net.minecraft.client.texture.Sprite; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(BuiltinBakedModel.class) +public interface BuiltinBakedModelAccessor { + + @Accessor + ModelTransformation getTransformation(); + + @Accessor + ModelOverrideList getItemPropertyOverrides(); + + @Accessor + Sprite getSprite(); + + @Accessor + boolean getSideLit(); +} + diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/EffectShaderStageAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/EffectShaderStageAccessor.java new file mode 100644 index 00000000..9e4a4e59 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/EffectShaderStageAccessor.java @@ -0,0 +1,14 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.client.gl.EffectShaderStage; +import net.minecraft.client.gl.ShaderStage; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(EffectShaderStage.class) +public interface EffectShaderStageAccessor { + @Invoker("") + static EffectShaderStage create(ShaderStage.Type shaderType, int shaderRef, String name) { + throw new AssertionError(); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontManagerProviderIndexAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontManagerProviderIndexAccessor.java new file mode 100644 index 00000000..b06d2c7b --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontManagerProviderIndexAccessor.java @@ -0,0 +1,20 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.client.font.Font; +import net.minecraft.client.font.FontManager; +import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +import java.util.List; +import java.util.Map; + +@Mixin(FontManager.ProviderIndex.class) +public interface FontManagerProviderIndexAccessor { + + @Invoker("") + static FontManager.ProviderIndex create(Map> providers, List allProviders) { + throw new AssertionError(); + } + +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontStorageAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontStorageAccessor.java new file mode 100644 index 00000000..4b272087 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontStorageAccessor.java @@ -0,0 +1,40 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.IntList; +import net.minecraft.client.font.*; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +import java.util.List; + +@Mixin(FontStorage.class) +public interface FontStorageAccessor { + @Accessor + void setBlankGlyphRenderer(GlyphRenderer renderer); + + @Accessor + void setWhiteRectangleGlyphRenderer(GlyphRenderer renderer); + + @Accessor + GlyphContainer getGlyphRendererCache(); + + @Accessor + GlyphContainer getGlyphCache(); + + @Accessor + Int2ObjectMap getCharactersByWidth(); + + @Accessor + List getFonts(); + + @Invoker + GlyphRenderer callGetGlyphRenderer(RenderableGlyph c); + + @Invoker + void callCloseFonts(); + + @Invoker + void callCloseGlyphAtlases(); +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/GlBlendStateAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/GlBlendStateAccessor.java new file mode 100644 index 00000000..c10e32c2 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/GlBlendStateAccessor.java @@ -0,0 +1,38 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.client.gl.GlBlendState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(GlBlendState.class) +public interface GlBlendStateAccessor { + + @Invoker("") + static GlBlendState create(boolean separateBlend, boolean blendDisabled, int srcRgb, int dstRgb, int srcAlpha, int dstAlpha, int mode) { + throw new AssertionError(); + } + + @Accessor + int getSrcRgb(); + + @Accessor + int getSrcAlpha(); + + @Accessor + int getDstRgb(); + + @Accessor + int getDstAlpha(); + + @Accessor + int getMode(); + + @Accessor + boolean getSeparateBlend(); + + @Accessor + boolean getBlendDisabled(); + + +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/GlUniformAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/GlUniformAccessor.java new file mode 100644 index 00000000..11062656 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/GlUniformAccessor.java @@ -0,0 +1,30 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.client.gl.GlUniform; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.nio.FloatBuffer; +import java.nio.IntBuffer; + +@Mixin(GlUniform.class) +public interface GlUniformAccessor { + @Accessor + @Mutable + void setIntData(IntBuffer intData); + + @Accessor + IntBuffer getIntData(); + + @Accessor + FloatBuffer getFloatData(); + + @Accessor + @Mutable + void setFloatData(FloatBuffer floatData); + + @Accessor + @Mutable + void setName(String name); +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/IdentifierAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/IdentifierAccessor.java new file mode 100644 index 00000000..f6812ade --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/IdentifierAccessor.java @@ -0,0 +1,15 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.util.Identifier; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(Identifier.class) +public interface IdentifierAccessor { + + @Invoker("") + static Identifier init(String namespace, String path, @Nullable Identifier.ExtraData extraData) { + throw new AssertionError(); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelIdentifierAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelIdentifierAccessor.java new file mode 100644 index 00000000..d1eb30ef --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelIdentifierAccessor.java @@ -0,0 +1,15 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.client.util.ModelIdentifier; +import net.minecraft.util.Identifier; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(ModelIdentifier.class) +public interface ModelIdentifierAccessor { + @Invoker("") + static ModelIdentifier init(String namespace, String path, String variant, @Nullable Identifier.ExtraData extraData) { + throw new AssertionError(); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelLoaderAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelLoaderAccessor.java new file mode 100644 index 00000000..d1398e13 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelLoaderAccessor.java @@ -0,0 +1,26 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import dev.quantumfusion.hyphen.thr.HyphenException; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.client.render.model.ModelLoader; +import net.minecraft.state.StateManager; +import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.Map; + +@Mixin(ModelLoader.class) +public interface ModelLoaderAccessor { + + @Accessor("ITEM_FRAME_STATE_FACTORY") + static StateManager getTheItemFrameThing() { + throw new HyphenException("froge", "your dad"); + } + + @Accessor("STATIC_DEFINITIONS") + static Map> getStaticDefinitions() { + throw new HyphenException("froge", "your dad"); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListAccessor.java new file mode 100644 index 00000000..ce7ff85e --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListAccessor.java @@ -0,0 +1,32 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.client.render.model.json.ModelOverrideList; +import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(ModelOverrideList.class) +public interface ModelOverrideListAccessor { + + + @Invoker("") + static ModelOverrideList newModelOverrideList() { + throw new AssertionError(); + } + + @Accessor + ModelOverrideList.BakedOverride[] getOverrides(); + + @Accessor + @Mutable + void setOverrides(ModelOverrideList.BakedOverride[] overrides); + + @Accessor + Identifier[] getConditionTypes(); + + @Accessor + @Mutable + void setConditionTypes(Identifier[] conditionTypes); +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListBakedOverrideAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListBakedOverrideAccessor.java new file mode 100644 index 00000000..776f66af --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListBakedOverrideAccessor.java @@ -0,0 +1,23 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.json.ModelOverrideList; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(ModelOverrideList.BakedOverride.class) +public interface ModelOverrideListBakedOverrideAccessor { + @Invoker("") + static ModelOverrideList.BakedOverride newModelOverrideListBakedOverride(ModelOverrideList.InlinedCondition[] conditions, @Nullable BakedModel model) { + throw new AssertionError(); + } + + @Accessor + ModelOverrideList.InlinedCondition[] getConditions(); + + @Accessor + BakedModel getModel(); + +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListInlinedCondition.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListInlinedCondition.java new file mode 100644 index 00000000..085af7c4 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListInlinedCondition.java @@ -0,0 +1,16 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.client.render.model.json.ModelOverrideList; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(ModelOverrideList.InlinedCondition.class) +public interface ModelOverrideListInlinedCondition { + + + @Invoker("") + static ModelOverrideList.InlinedCondition newModelOverrideListInlinedCondition(int index, float threshold) { + throw new AssertionError(); + } + +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartBakedModelAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartBakedModelAccessor.java new file mode 100644 index 00000000..db5d809a --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartBakedModelAccessor.java @@ -0,0 +1,37 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.block.BlockState; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.MultipartBakedModel; +import net.minecraft.client.texture.Sprite; +import org.apache.commons.lang3.tuple.Pair; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.BitSet; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; + +@Mixin(MultipartBakedModel.class) +public interface MultipartBakedModelAccessor { + + @Accessor + List, BakedModel>> getComponents(); + + @Accessor + @Mutable + void setComponents(List, BakedModel>> components); + + @Accessor + Map getStateCache(); + + @Accessor + @Mutable + void setStateCache(Map stateBitSetMap); + + @Accessor + @Mutable + void setSprite(Sprite sprite); +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartModelComponentAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartModelComponentAccessor.java new file mode 100644 index 00000000..84c1c4c1 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartModelComponentAccessor.java @@ -0,0 +1,13 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.client.render.model.json.MultipartModelComponent; +import net.minecraft.client.render.model.json.MultipartModelSelector; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(MultipartModelComponent.class) +public interface MultipartModelComponentAccessor { + + @Accessor() + MultipartModelSelector getSelector(); +} diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontImageAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/NativeImageAccessor.java similarity index 56% rename from src/main/java/dev/notalpha/dashloader/mixin/accessor/FontImageAccessor.java rename to forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/NativeImageAccessor.java index 2b7ad084..22ec08b3 100644 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontImageAccessor.java +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/NativeImageAccessor.java @@ -1,19 +1,22 @@ package dev.notalpha.dashloader.mixin.accessor; -import net.minecraft.client.font.UnicodeTextureFont; import net.minecraft.client.texture.NativeImage; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; import org.spongepowered.asm.mixin.gen.Invoker; -@Mixin(UnicodeTextureFont.FontImage.class) -public interface FontImageAccessor { - @Accessor - NativeImage getImage(); +@Mixin(NativeImage.class) +public interface NativeImageAccessor { + @Invoker("") - static UnicodeTextureFont.FontImage create(byte[] sizes, NativeImage image) { + static NativeImage init(NativeImage.Format format, int width, int height, boolean useStb, long pointer) { throw new AssertionError(); } + @Accessor + long getPointer(); + + @Accessor + boolean getIsStbImage(); } diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/OrMultipartModelSelectorAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/OrMultipartModelSelectorAccessor.java new file mode 100644 index 00000000..134d1a72 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/OrMultipartModelSelectorAccessor.java @@ -0,0 +1,14 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.client.render.model.json.MultipartModelSelector; +import net.minecraft.client.render.model.json.OrMultipartModelSelector; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(OrMultipartModelSelector.class) +public interface OrMultipartModelSelectorAccessor { + + @Accessor + Iterable getSelectors(); + +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderProgramAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderProgramAccessor.java new file mode 100644 index 00000000..b955690f --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderProgramAccessor.java @@ -0,0 +1,101 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.client.gl.GlBlendState; +import net.minecraft.client.gl.GlUniform; +import net.minecraft.client.gl.ShaderProgram; +import net.minecraft.client.gl.ShaderStage; +import net.minecraft.client.render.VertexFormat; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +import java.util.List; +import java.util.Map; + +@Mixin(ShaderProgram.class) +public interface ShaderProgramAccessor { + + @Accessor + Map getSamplers(); + + @Accessor + @Mutable + void setSamplers(Map samplers); + + @Accessor + GlBlendState getBlendState(); + + @Accessor + @Mutable + void setBlendState(GlBlendState blendState); + + @Accessor + List getLoadedAttributeIds(); + + + @Accessor + Map getLoadedUniforms(); + + @Accessor + List getUniforms(); + + @Accessor + @Mutable + void setLoadedAttributeIds(List loadedAttributeIds); + + @Accessor + List getAttributeNames(); + + @Accessor + @Mutable + void setAttributeNames(List attributeNames); + + @Accessor + List getSamplerNames(); + + @Accessor + @Mutable + void setSamplerNames(List samplerNames); + + @Accessor + @Mutable + void setLoadedSamplerIds(List loadedSamplerIds); + + @Accessor + @Mutable + void setUniforms(List uniforms); + + @Accessor + @Mutable + void setLoadedUniformIds(List loadedUniformIds); + + @Accessor + @Mutable + void setLoadedUniforms(Map loadedUniforms); + + @Accessor + @Mutable + void setGlRef(int glRef); + + @Accessor + @Mutable + void setName(String name); + + @Accessor + @Mutable + void setVertexShader(ShaderStage vertexShader); + + @Accessor + @Mutable + void setFragmentShader(ShaderStage fragmentShader); + + @Accessor + @Mutable + void setFormat(VertexFormat format); + + @Invoker("loadReferences") + void loadref(); +} + + diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderStageAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderStageAccessor.java new file mode 100644 index 00000000..b41a915d --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderStageAccessor.java @@ -0,0 +1,27 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.client.gl.ShaderStage; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(ShaderStage.class) +public interface ShaderStageAccessor { + @Invoker("") + static ShaderStage create(ShaderStage.Type shaderType, int shaderRef, String name) { + throw new AssertionError(); + } + + @Accessor + ShaderStage.Type getType(); + + @Accessor + int getGlRef(); + + @Mixin(ShaderStage.Type.class) + interface TypeAccessor { + @Accessor + int getGlType(); + } +} + diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/SimpleMultipartModelSelectorAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/SimpleMultipartModelSelectorAccessor.java new file mode 100644 index 00000000..51729f34 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/SimpleMultipartModelSelectorAccessor.java @@ -0,0 +1,16 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.client.render.model.json.SimpleMultipartModelSelector; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(SimpleMultipartModelSelector.class) +public interface SimpleMultipartModelSelectorAccessor { + + @Accessor + String getKey(); + + @Accessor + String getValueString(); + +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAccessor.java new file mode 100644 index 00000000..793de382 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAccessor.java @@ -0,0 +1,16 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.texture.SpriteContents; +import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(Sprite.class) +public interface SpriteAccessor { + + @Invoker("") + static Sprite init(Identifier atlasId, SpriteContents contents, int atlasWidth, int atlasHeight, int width, int height) { + throw new AssertionError(); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationAccessor.java new file mode 100644 index 00000000..26e2be5a --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationAccessor.java @@ -0,0 +1,28 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.client.texture.SpriteContents; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +import java.util.List; + +@Mixin(SpriteContents.Animation.class) +public interface SpriteAnimationAccessor { + + + @Invoker("") + static SpriteContents.Animation init(SpriteContents parent, List frames, int frameCount, boolean interpolation) { + throw new AssertionError(); + } + + @Accessor + List getFrames(); + + @Accessor + int getFrameCount(); + + @Accessor + boolean getInterpolation(); + +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationFrameAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationFrameAccessor.java new file mode 100644 index 00000000..83dc0ee8 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationFrameAccessor.java @@ -0,0 +1,21 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.client.texture.SpriteContents; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(SpriteContents.AnimationFrame.class) +public interface SpriteAnimationFrameAccessor { + + @Invoker("") + static SpriteContents.AnimationFrame newSpriteFrame(int index, int time) { + throw new AssertionError(); + } + + @Accessor + int getIndex(); + + @Accessor + int getTime(); +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteContentsAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteContentsAccessor.java new file mode 100644 index 00000000..29672892 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteContentsAccessor.java @@ -0,0 +1,46 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.client.texture.NativeImage; +import net.minecraft.client.texture.SpriteContents; +import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(SpriteContents.class) +public interface SpriteContentsAccessor { + + @Accessor + NativeImage getImage(); + + @Accessor + SpriteContents.Animation getAnimation(); + + @Accessor + NativeImage[] getMipmapLevelsImages(); + + @Accessor + @Mutable + void setId(Identifier id); + + @Accessor + @Mutable + void setWidth(int width); + + @Accessor + @Mutable + void setHeight(int height); + + @Accessor + @Mutable + void setImage(NativeImage image); + + @Accessor + @Mutable + void setMipmapLevelsImages(NativeImage[] mipmapLevelsImages); + + @Accessor + @Mutable + void setAnimation(SpriteContents.Animation animation); + +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteLoaderStitchResultAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteLoaderStitchResultAccessor.java new file mode 100644 index 00000000..6adaef58 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteLoaderStitchResultAccessor.java @@ -0,0 +1,20 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.client.texture.SpriteLoader; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(SpriteLoader.StitchResult.class) +public interface SpriteLoaderStitchResultAccessor { + + @Accessor + int getWidth(); + + @Accessor + int getHeight(); + + @Accessor + int getMipLevel(); + + +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/TrueTypeFontAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/TrueTypeFontAccessor.java new file mode 100644 index 00000000..a1706cbe --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/TrueTypeFontAccessor.java @@ -0,0 +1,68 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import it.unimi.dsi.fastutil.ints.IntSet; +import net.minecraft.client.font.TrueTypeFont; +import org.lwjgl.stb.STBTTFontinfo; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.nio.ByteBuffer; + +@Mixin(TrueTypeFont.class) +public interface TrueTypeFontAccessor { + @Accessor + @Mutable + void setBuffer(ByteBuffer thing); + + @Accessor + STBTTFontinfo getInfo(); + + @Accessor + @Mutable + void setInfo(STBTTFontinfo thing); + + @Accessor + float getOversample(); + + @Accessor + @Mutable + void setOversample(float thing); + + @Accessor + IntSet getExcludedCharacters(); + + @Accessor + @Mutable + void setExcludedCharacters(IntSet thing); + + @Accessor + float getShiftX(); + + @Accessor + @Mutable + void setShiftX(float thing); + + @Accessor + float getShiftY(); + + @Accessor + @Mutable + void setShiftY(float thing); + + @Accessor + float getScaleFactor(); + + @Accessor + @Mutable + void setScaleFactor(float thing); + + @Accessor + float getAscent(); + + @Accessor + @Mutable + void setAscent(float thing); + + +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/UnihexFontAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/UnihexFontAccessor.java new file mode 100644 index 00000000..ba5b02cf --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/UnihexFontAccessor.java @@ -0,0 +1,22 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.client.font.GlyphContainer; +import net.minecraft.client.font.UnihexFont; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(UnihexFont.class) +public interface UnihexFontAccessor { + @Invoker("") + static UnihexFont create(GlyphContainer glyphs) { + throw new AssertionError(); + } + + @Accessor + GlyphContainer getGlyphs(); + @Accessor + @Mutable + void setGlyphs(GlyphContainer glyphs); +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/VertexFormatAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/VertexFormatAccessor.java new file mode 100644 index 00000000..dc7d27a1 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/VertexFormatAccessor.java @@ -0,0 +1,14 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import com.google.common.collect.ImmutableMap; +import net.minecraft.client.render.VertexFormat; +import net.minecraft.client.render.VertexFormatElement; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(VertexFormat.class) +public interface VertexFormatAccessor { + + @Accessor + ImmutableMap getElementMap(); +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelAccessor.java new file mode 100644 index 00000000..0d1c2394 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelAccessor.java @@ -0,0 +1,16 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.WeightedBakedModel; +import net.minecraft.util.collection.Weighted; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.List; + +@Mixin(WeightedBakedModel.class) +public interface WeightedBakedModelAccessor { + + @Accessor("models") + List> getBakedModels(); +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelEntryAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelEntryAccessor.java new file mode 100644 index 00000000..2e9c2897 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelEntryAccessor.java @@ -0,0 +1,14 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.util.collection.Weight; +import net.minecraft.util.collection.Weighted; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(Weighted.Present.class) +public interface WeightedBakedModelEntryAccessor { + @Invoker("") + static Weighted.Present init(Object data, Weight weight) { + throw new AssertionError(); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ZipResourcePackAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ZipResourcePackAccessor.java new file mode 100644 index 00000000..baf957b4 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ZipResourcePackAccessor.java @@ -0,0 +1,13 @@ +package dev.notalpha.dashloader.mixin.accessor; + +import net.minecraft.resource.ZipResourcePack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.io.File; + +@Mixin(ZipResourcePack.class) +public interface ZipResourcePackAccessor { + @Accessor + File getBackingZipFile(); +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/main/BootstrapMixin.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/main/BootstrapMixin.java new file mode 100644 index 00000000..264dce93 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/main/BootstrapMixin.java @@ -0,0 +1,25 @@ +package dev.notalpha.dashloader.mixin.main; + +import dev.notalpha.dashloader.DashLoader; +import dev.notalpha.dashloader.misc.ProfilerUtil; +import net.minecraft.Bootstrap; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(value = Bootstrap.class, priority = -69) +public class BootstrapMixin { + private static long BOOTSTRAP_START = -1; + + + @Inject(method = "initialize", at = @At("HEAD")) + private static void timeStart(CallbackInfo ci) { + BOOTSTRAP_START = System.currentTimeMillis(); + } + + @Inject(method = "initialize", at = @At("TAIL")) + private static void timeStop(CallbackInfo ci) { + DashLoader.LOG.info("Minecraft bootstrap in {}", ProfilerUtil.getTimeStringFromStart(BOOTSTRAP_START)); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/main/KeyboardMixin.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/main/KeyboardMixin.java new file mode 100644 index 00000000..dd600cc0 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/main/KeyboardMixin.java @@ -0,0 +1,46 @@ +package dev.notalpha.dashloader.mixin.main; + +import dev.notalpha.dashloader.DashLoader; +import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.client.DashLoaderClient; +import net.minecraft.client.Keyboard; +import org.lwjgl.glfw.GLFW; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +/** + * Makes f3 + t reset the cache. Also makes shift + f3 + t not reset it. + */ +@Mixin(Keyboard.class) +public class KeyboardMixin { + + private boolean shiftHeld = false; + + @Inject( + method = "processF3", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/MinecraftClient;reloadResources()Ljava/util/concurrent/CompletableFuture;", + shift = At.Shift.BEFORE + ) + ) + private void f3tReloadWorld(int key, CallbackInfoReturnable cir) { + if (!this.shiftHeld) { + if (DashLoaderClient.CACHE.getStatus() == CacheStatus.IDLE) { + DashLoader.LOG.info("Clearing cache."); + DashLoaderClient.CACHE.remove(); + } + } + } + + @Inject( + method = "onKey", + at = @At("HEAD") + ) + private void keyPress(long window, int key, int scancode, int action, int modifiers, CallbackInfo ci) { + this.shiftHeld = action != 0 && modifiers == GLFW.GLFW_MOD_SHIFT; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/main/MainMixin.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/main/MainMixin.java new file mode 100644 index 00000000..5f00ecbc --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/main/MainMixin.java @@ -0,0 +1,24 @@ +package dev.notalpha.dashloader.mixin.main; + +import dev.notalpha.dashloader.DashLoader; +import net.minecraft.client.main.Main; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Main.class) +public class MainMixin { + private static boolean INITIALIZED = false; + + @Inject( + method = "main*", + at = @At(value = "HEAD") + ) + private static void main(String[] args, CallbackInfo ci) { + if (!INITIALIZED) { + DashLoader.bootstrap(); + INITIALIZED = true; + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/main/MinecraftClientMixin.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/main/MinecraftClientMixin.java new file mode 100644 index 00000000..df50f39d --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/main/MinecraftClientMixin.java @@ -0,0 +1,37 @@ +package dev.notalpha.dashloader.mixin.main; + +import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.client.DashLoaderClient; +import net.minecraft.client.MinecraftClient; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.concurrent.CompletableFuture; + +@Mixin(MinecraftClient.class) +public abstract class MinecraftClientMixin { + @Shadow + protected abstract void render(boolean tick); + + @Inject(method = "reloadResources()Ljava/util/concurrent/CompletableFuture;", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;reloadResources(Z)Ljava/util/concurrent/CompletableFuture;")) + private void requestReload(CallbackInfoReturnable> cir) { + DashLoaderClient.NEEDS_RELOAD = true; + } + + + @Inject(method = "reloadResources(Z)Ljava/util/concurrent/CompletableFuture;", at = @At(value = "RETURN")) + private void reloadComplete(boolean thing, CallbackInfoReturnable> cir) { + cir.getReturnValue().thenRun(() -> { + // If the state is SAVE, then this will reset before the caching process can initialize from the splash screen. + if (DashLoaderClient.CACHE.getStatus() != CacheStatus.SAVE) { + DashLoaderClient.CACHE.reset(); + } + }); + } + + +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/main/ReloadableResourceManagerImplMixin.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/main/ReloadableResourceManagerImplMixin.java new file mode 100644 index 00000000..4b5c0c78 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/main/ReloadableResourceManagerImplMixin.java @@ -0,0 +1,57 @@ +package dev.notalpha.dashloader.mixin.main; + +import dev.notalpha.dashloader.DashLoader; +import dev.notalpha.dashloader.client.DashLoaderClient; +import dev.notalpha.dashloader.misc.ProfilerUtil; +import dev.notalpha.dashloader.mixin.accessor.ZipResourcePackAccessor; +import net.minecraft.client.MinecraftClient; +import net.minecraft.resource.*; +import net.minecraft.util.Unit; +import org.apache.commons.codec.digest.DigestUtils; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + +@Mixin(ReloadableResourceManagerImpl.class) +public class ReloadableResourceManagerImplMixin { + + @Inject(method = "reload", + at = @At(value = "RETURN", shift = At.Shift.BEFORE)) + private void reloadDash(Executor prepareExecutor, Executor applyExecutor, CompletableFuture initialStage, List packs, CallbackInfoReturnable cir) { + ProfilerUtil.RELOAD_START = System.currentTimeMillis(); + ResourcePackManager manager = MinecraftClient.getInstance().getResourcePackManager(); + List values = new ArrayList<>(); + + // Use server resource pack display name to differentiate them across each-other + for (ResourcePack pack : packs) { + if (Objects.equals(pack.getName(), "server")) { + if (pack instanceof ZipResourcePack zipResourcePack) { + ZipResourcePackAccessor zipPack = (ZipResourcePackAccessor) zipResourcePack; + Path path = zipPack.getBackingZipFile().toPath(); + values.add(path.toString()); + } + } + } + + for (ResourcePackProfile profile : manager.getEnabledProfiles()) { + if (profile != null) { + // Skip server as we have a special case where we use its path instead which contains its hash + if (!Objects.equals(profile.getName(), "server")) { + values.add(profile.getName() + "/"); + } + } + } + + String hash = DigestUtils.md5Hex(values.toString()).toUpperCase(); + DashLoader.LOG.info("Hash changed to " + hash); + DashLoaderClient.CACHE.load(hash); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/main/SplashScreenMixin.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/main/SplashScreenMixin.java new file mode 100644 index 00000000..326a91d0 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/main/SplashScreenMixin.java @@ -0,0 +1,110 @@ +package dev.notalpha.dashloader.mixin.main; + +import dev.notalpha.dashloader.DashLoader; +import dev.notalpha.dashloader.api.cache.Cache; +import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.client.DashLoaderClient; +import dev.notalpha.dashloader.client.ui.DashToast; +import dev.notalpha.dashloader.client.ui.DashToastState; +import dev.notalpha.dashloader.client.ui.DashToastStatus; +import dev.notalpha.dashloader.config.ConfigHandler; +import dev.notalpha.dashloader.misc.ProfilerUtil; +import dev.notalpha.taski.builtin.StaticTask; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.SplashOverlay; +import net.minecraft.client.gui.screen.TitleScreen; +import net.minecraft.client.toast.Toast; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.resource.ResourceReload; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + + +@Mixin(value = SplashOverlay.class, priority = 69420) +public class SplashScreenMixin { + @Shadow + @Final + private MinecraftClient client; + + @Shadow + private long reloadCompleteTime; + + @Shadow + @Final + private ResourceReload reload; + + @Mutable + @Shadow + @Final + private boolean reloading; + + @Inject( + method = "render", + at = @At(value = "INVOKE", target = "Lnet/minecraft/util/Util;getMeasuringTimeMs()J", shift = At.Shift.BEFORE, ordinal = 1) + ) + private void done(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci) { + this.client.setOverlay(null); + if (this.client.currentScreen != null) { + if (this.client.currentScreen instanceof TitleScreen) { + this.client.currentScreen = new TitleScreen(false); + } + } + + DashLoader.LOG.info("Minecraft reloaded in {}", ProfilerUtil.getTimeStringFromStart(ProfilerUtil.RELOAD_START)); + Cache cache = DashLoaderClient.CACHE; + if (DashLoaderClient.CACHE.getStatus() == CacheStatus.SAVE && client.getToastManager().getToast(DashToast.class, Toast.TYPE) == null) { + DashToastState rawState; + if (ConfigHandler.INSTANCE.config.showCachingToast) { + DashToast toast = new DashToast(); + client.getToastManager().add(toast); + rawState = toast.state; + } else { + rawState = new DashToastState(); + } + + final Thread thread = new Thread(() -> { + DashToastState state = rawState; + DashToastState finalState = state; + state.setStatus(DashToastStatus.PROGRESS); + long start = System.currentTimeMillis(); + boolean save = cache.save(stepTask -> finalState.task = stepTask); + if (save) { + state.setOverwriteText("Created cache in " + ProfilerUtil.getTimeStringFromStart(start)); + state.setStatus(DashToastStatus.DONE); + } else { + // Only show toast on fail. + if (!ConfigHandler.INSTANCE.config.showCachingToast) { + DashToast toast = new DashToast(); + client.getToastManager().add(toast); + state = toast.state; + } + state.setOverwriteText("Internal error, Please check logs."); + state.task = new StaticTask("Crash", 0); + state.setStatus(DashToastStatus.CRASHED); + } + cache.reset(); + state.setDone(); + }); + thread.setName("dashloader-thread"); + thread.start(); + } else { + cache.reset(); + } + } + + @Inject( + method = "render", + at = @At(value = "INVOKE", target = "Lnet/minecraft/resource/ResourceReload;isComplete()Z", shift = At.Shift.BEFORE) + ) + private void removeMinimumTime(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci) { + if (this.reloadCompleteTime == -1L && this.reload.isComplete()) { + this.reloading = false; + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/option/WallBlockMixin.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/WallBlockMixin.java new file mode 100644 index 00000000..644cb630 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/WallBlockMixin.java @@ -0,0 +1,164 @@ +package dev.notalpha.dashloader.mixin.option; + +import com.google.common.collect.ImmutableMap; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.WallBlock; +import net.minecraft.block.Waterloggable; +import net.minecraft.block.enums.WallShape; +import net.minecraft.state.property.BooleanProperty; +import net.minecraft.state.property.EnumProperty; +import net.minecraft.util.shape.VoxelShape; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.Map; + +@Mixin(WallBlock.class) +public abstract class WallBlockMixin extends Block implements Waterloggable { + private static final int LENGTH = WallShape.values().length; + private static VoxelShape[][][][][] SHAPE_CACHE; + private static VoxelShape[][][][][] COLLISION_CACHE; + + + @Shadow + @Final + public static BooleanProperty UP; + + @Shadow + @Final + public static EnumProperty EAST_SHAPE; + + @Shadow + @Final + public static EnumProperty NORTH_SHAPE; + + @Shadow + @Final + public static EnumProperty WEST_SHAPE; + + @Shadow + @Final + public static EnumProperty SOUTH_SHAPE; + + @Shadow + @Final + public static BooleanProperty WATERLOGGED; + + public WallBlockMixin(Settings settings) { + super(settings); + } + + + @Inject(method = "getShapeMap", at = @At(value = "HEAD"), cancellable = true) + private void getShapeMapCache(float f, float g, float h, float i, float j, float k, CallbackInfoReturnable> cir) { + if (this.isCommon(f, g, i)) { + if (this.isShape(h, j, k)) { + if (SHAPE_CACHE != null) { + cir.setReturnValue(this.createFromCache(SHAPE_CACHE)); + } + } else if (this.isCollision(h, j, k)) { + if (COLLISION_CACHE != null) { + cir.setReturnValue(this.createFromCache(COLLISION_CACHE)); + } + } + } + } + + @Inject(method = "getShapeMap", at = @At(value = "RETURN")) + private void getShapeMapCacheCreate(float f, float g, float h, float i, float j, float k, CallbackInfoReturnable> cir) { + if (SHAPE_CACHE == null || COLLISION_CACHE == null) { + if (this.isCommon(f, g, i)) { + if (this.isShape(h, j, k)) { + if (SHAPE_CACHE == null) { + SHAPE_CACHE = new VoxelShape[2][LENGTH][LENGTH][LENGTH][LENGTH]; + this.createCache(SHAPE_CACHE, cir.getReturnValue()); + } + } else if (this.isCollision(h, j, k)) { + if (COLLISION_CACHE == null) { + COLLISION_CACHE = new VoxelShape[2][LENGTH][LENGTH][LENGTH][LENGTH]; + this.createCache(COLLISION_CACHE, cir.getReturnValue()); + } + } + } + } + } + + private ImmutableMap createFromCache(VoxelShape[][][][][] rawCache) { + ImmutableMap.Builder builder = ImmutableMap.builder(); + for (Boolean up : UP.getValues()) { + VoxelShape[][][][] cache = up ? rawCache[1] : rawCache[0]; + for (WallShape east : EAST_SHAPE.getValues()) { + for (WallShape north : NORTH_SHAPE.getValues()) { + for (WallShape west : WEST_SHAPE.getValues()) { + for (WallShape south : SOUTH_SHAPE.getValues()) { + final VoxelShape cached = this.getCached(cache, east, north, west, south); + + BlockState blockState = this.getDefaultState() + .with(UP, up) + .with(EAST_SHAPE, east) + .with(WEST_SHAPE, west) + .with(NORTH_SHAPE, north) + .with(SOUTH_SHAPE, south); + + builder.put(blockState.with(WATERLOGGED, false), cached); + builder.put(blockState.with(WATERLOGGED, true), cached); + } + } + } + } + } + return builder.build(); + } + + private void createCache(VoxelShape[][][][][] rawCache, Map map) { + for (Boolean up : UP.getValues()) { + VoxelShape[][][][] cache = up ? rawCache[1] : rawCache[0]; + for (WallShape east : EAST_SHAPE.getValues()) { + for (WallShape north : NORTH_SHAPE.getValues()) { + for (WallShape west : WEST_SHAPE.getValues()) { + for (WallShape south : SOUTH_SHAPE.getValues()) { + + BlockState blockState = this.getDefaultState() + .with(UP, up) + .with(EAST_SHAPE, east) + .with(WEST_SHAPE, west) + .with(NORTH_SHAPE, north) + .with(SOUTH_SHAPE, south) + .with(WATERLOGGED, false); + + this.setCached(cache, east, north, west, south, map.get(blockState)); + } + } + } + } + } + } + + //shape 4.0F, 3.0F, 16.0F, 0.0F, 14.0F, 16.0F + //collision 4.0F, 3.0F, 24.0F, 0.0F, 24.0F, 24.0F + private boolean isShape(float h, float j, float k) { + return h == 16.0F && j == 14.0F && k == 16.0F; + } + + private boolean isCollision(float h, float j, float k) { + return h == 24.0F && j == 24.0F && k == 24.0F; + } + + private boolean isCommon(float f, float g, float i) { + return f == 4.0F && g == 3.0F && i == 0.0F; + } + + private VoxelShape getCached(VoxelShape[][][][] cache, WallShape east, WallShape north, WallShape west, WallShape south) { + return cache[east.ordinal()][north.ordinal()][west.ordinal()][south.ordinal()]; + } + + private void setCached(VoxelShape[][][][] cache, WallShape east, WallShape north, WallShape west, WallShape south, VoxelShape shape) { + cache[east.ordinal()][north.ordinal()][west.ordinal()][south.ordinal()] = shape; + } + +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/SplashTextResourceSupplierMixin.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/SplashTextResourceSupplierMixin.java new file mode 100644 index 00000000..5d1c1646 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/SplashTextResourceSupplierMixin.java @@ -0,0 +1,37 @@ +package dev.notalpha.dashloader.mixin.option.cache; + +import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.client.splash.SplashModule; +import net.minecraft.client.resource.SplashTextResourceSupplier; +import net.minecraft.resource.ResourceManager; +import net.minecraft.util.profiler.Profiler; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.List; + +@Mixin(SplashTextResourceSupplier.class) +public class SplashTextResourceSupplierMixin { + @Inject( + method = "prepare(Lnet/minecraft/resource/ResourceManager;Lnet/minecraft/util/profiler/Profiler;)Ljava/util/List;", + at = @At(value = "HEAD"), + cancellable = true + ) + private void applySplashCache(ResourceManager resourceManager, Profiler profiler, CallbackInfoReturnable> cir) { + SplashModule.TEXTS.visit(CacheStatus.LOAD, cir::setReturnValue); + } + + + @Inject( + method = "prepare(Lnet/minecraft/resource/ResourceManager;Lnet/minecraft/util/profiler/Profiler;)Ljava/util/List;", + at = @At(value = "RETURN") + ) + private void stealSplashCache(ResourceManager resourceManager, Profiler profiler, CallbackInfoReturnable> cir) { + SplashModule.TEXTS.visit(CacheStatus.SAVE, strings -> { + strings.clear(); + strings.addAll(cir.getReturnValue()); + }); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/font/FontManagerOverride.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/font/FontManagerOverride.java new file mode 100644 index 00000000..120ed7fa --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/font/FontManagerOverride.java @@ -0,0 +1,44 @@ +package dev.notalpha.dashloader.mixin.option.cache.font; + +import dev.notalpha.dashloader.DashLoader; +import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.client.font.FontModule; +import dev.notalpha.dashloader.mixin.accessor.FontManagerProviderIndexAccessor; +import net.minecraft.client.font.FontManager; +import net.minecraft.resource.ResourceManager; +import net.minecraft.util.profiler.Profiler; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + +@Mixin(FontManager.class) +public class FontManagerOverride { + + @Inject( + method = "loadIndex", + at = @At(value = "HEAD"), + cancellable = true + ) + private void loadFonts(ResourceManager resourceManager, Executor executor, CallbackInfoReturnable> cir) { + FontModule.DATA.visit(CacheStatus.LOAD, data -> { + DashLoader.LOG.info("Providing fonts"); + cir.setReturnValue(CompletableFuture.completedFuture(FontManagerProviderIndexAccessor.create(data.providers, data.allProviders))); + }); + } + + @Inject( + method = "reload(Lnet/minecraft/client/font/FontManager$ProviderIndex;Lnet/minecraft/util/profiler/Profiler;)V", + at = @At(value = "HEAD") + ) + private void saveFonts(FontManager.ProviderIndex index, Profiler profiler, CallbackInfo ci) { + if (FontModule.DATA.active(CacheStatus.SAVE)) { + DashLoader.LOG.info("Saving fonts"); + FontModule.DATA.set(CacheStatus.SAVE, new FontModule.ProviderIndex(index.providers(), index.allProviders())); + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/font/TrueTypeFontLoaderMixin.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/font/TrueTypeFontLoaderMixin.java new file mode 100644 index 00000000..b8c59c97 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/font/TrueTypeFontLoaderMixin.java @@ -0,0 +1,33 @@ +package dev.notalpha.dashloader.mixin.option.cache.font; + +import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.client.font.FontModule; +import net.minecraft.client.font.Font; +import net.minecraft.client.font.TrueTypeFontLoader; +import net.minecraft.resource.ResourceManager; +import net.minecraft.util.Identifier; +import org.lwjgl.stb.STBTTFontinfo; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +@Mixin(TrueTypeFontLoader.class) +public abstract class TrueTypeFontLoaderMixin { + + @Shadow public abstract Identifier location(); + + @Inject( + method = "load", + at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/platform/TextureUtil;readResource(Ljava/io/InputStream;)Ljava/nio/ByteBuffer;"), + locals = LocalCapture.CAPTURE_FAILSOFT + ) + private void loadInject(ResourceManager manager, CallbackInfoReturnable cir, STBTTFontinfo sTBTTFontinfo) { + FontModule.FONT_TO_IDENT.visit(CacheStatus.SAVE, map -> { + map.put(sTBTTFontinfo, location()); + }); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/BakedModelManagerOverride.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/BakedModelManagerOverride.java new file mode 100644 index 00000000..0c31a337 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/BakedModelManagerOverride.java @@ -0,0 +1,34 @@ +package dev.notalpha.dashloader.mixin.option.cache.model; + +import dev.notalpha.dashloader.DashLoader; +import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.client.model.ModelModule; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.BakedModelManager; +import net.minecraft.util.Identifier; +import net.minecraft.util.profiler.Profiler; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Map; + +@Mixin(value = BakedModelManager.class, priority = 69420) +public abstract class BakedModelManagerOverride { + @Shadow + private Map models; + + @Inject(method = "upload", + at = @At(value = "TAIL") + ) + + private void yankAssets(BakedModelManager.BakingResult bakingResult, Profiler profiler, CallbackInfo ci) { + ModelModule.MODELS_SAVE.visit(CacheStatus.SAVE, map -> { + DashLoader.LOG.info("Yanking Minecraft Assets"); + map.putAll(this.models); + }); + } + +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/BlockModelsMixin.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/BlockModelsMixin.java new file mode 100644 index 00000000..87ec8e00 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/BlockModelsMixin.java @@ -0,0 +1,30 @@ +package dev.notalpha.dashloader.mixin.option.cache.model; + +import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.client.model.ModelModule; +import net.minecraft.block.BlockState; +import net.minecraft.client.render.block.BlockModels; +import net.minecraft.client.util.ModelIdentifier; +import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(BlockModels.class) +public class BlockModelsMixin { + + @Inject( + method = "getModelId(Lnet/minecraft/block/BlockState;)Lnet/minecraft/client/util/ModelIdentifier;", + at = @At(value = "HEAD"), + cancellable = true + ) + private static void cacheModelId(BlockState state, CallbackInfoReturnable cir) { + ModelModule.MISSING_READ.visit(CacheStatus.LOAD, map -> { + final Identifier identifier = map.get(state); + if (identifier != null) { + cir.setReturnValue((ModelIdentifier) identifier); + } + }); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/ModelLoaderMixin.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/ModelLoaderMixin.java new file mode 100644 index 00000000..9a5997e2 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/ModelLoaderMixin.java @@ -0,0 +1,155 @@ +package dev.notalpha.dashloader.mixin.option.cache.model; + +import dev.notalpha.dashloader.CacheImpl; +import dev.notalpha.dashloader.DashLoader; +import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.client.DashLoaderClient; +import dev.notalpha.dashloader.client.model.ModelModule; +import dev.notalpha.dashloader.client.model.fallback.UnbakedBakedModel; +import dev.notalpha.dashloader.misc.ObjectDumper; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import net.minecraft.block.BlockRenderType; +import net.minecraft.block.BlockState; +import net.minecraft.client.color.block.BlockColors; +import net.minecraft.client.render.model.*; +import net.minecraft.client.render.model.json.JsonUnbakedModel; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.SpriteIdentifier; +import net.minecraft.util.Identifier; +import net.minecraft.util.profiler.Profiler; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.function.BiFunction; + +@Mixin(value = ModelLoader.class, priority = 69420) +public abstract class ModelLoaderMixin { + + @Mutable + @Shadow + @Final + private Map unbakedModels; + + /*@Shadow + protected abstract void method_4716(BlockState blockState);*/ + + @Mutable + @Shadow + @Final + private Map modelsToBake; + + @Shadow @Final private Map bakedModels; + + @Shadow @Final private Object2IntMap stateLookup; + + @Inject( + method = "", + at = @At(value = "INVOKE_STRING", target = "Lnet/minecraft/util/profiler/Profiler;swap(Ljava/lang/String;)V", args = "ldc=static_definitions", shift = At.Shift.AFTER) + ) + private void injectLoadedModels(BlockColors blockColors, Profiler profiler, Map jsonUnbakedModels, Map> blockStates, CallbackInfo ci) { + ModelModule.MODELS_LOAD.visit(CacheStatus.LOAD, dashModels -> { + int total = dashModels.size(); + this.unbakedModels.keySet().forEach(dashModels::remove); + this.modelsToBake.keySet().forEach(dashModels::remove); + DashLoader.LOG.info("Injecting {}/{} Cached Models", dashModels.size(), total); + this.unbakedModels.putAll(dashModels); + this.modelsToBake.putAll(dashModels); + }); + } + + /** + * We want to not load all of the blockstate models as we have a list of them available on which ones to load to save a lot of computation + */ + @Redirect( + method = "", + at = @At(value = "INVOKE", target = "Ljava/util/Iterator;hasNext()Z", ordinal = 0) + ) + private boolean loadMissingModels(Iterator instance) { + var map = ModelModule.MISSING_READ.get(CacheStatus.LOAD); + if (map != null) { + for (BlockState blockstate : map.keySet()) { + // load thing lambda + if (blockstate.getRenderType() != BlockRenderType.MODEL) { + this.stateLookup.put(blockstate, 0); + } + //this.method_4716(blockState); + } + DashLoader.LOG.info("Loaded {} unsupported models.", map.size()); + return false; + } + return instance.hasNext(); + } + + @Inject( + method = "bake", + at = @At( + value = "HEAD" + ) + ) + private void countModels(BiFunction spriteLoader, CallbackInfo ci) { + if (ModelModule.MODELS_LOAD.active(CacheStatus.LOAD)) { + // Cache stats + int cachedModels = 0; + int fallbackModels = 0; + for (UnbakedModel value : this.modelsToBake.values()) { + if (value instanceof UnbakedBakedModel) { + cachedModels += 1; + } else { + fallbackModels += 1; + } + } + long totalModels = cachedModels + fallbackModels; + DashLoader.LOG.info("{}% Cache coverage", (int) (((cachedModels / (float) totalModels) * 100))); + DashLoader.LOG.info("with {} Fallback models", fallbackModels); + DashLoader.LOG.info("and {} Cached models", cachedModels); + } + + } + + @Inject( + method = "bake", + at = @At( + value = "TAIL" + ) + ) + private void debug(BiFunction spriteLoader, CallbackInfo ci) { +//var models = new HashMap(); +//this.bakedModels.forEach((identifier, bakedModel) -> { +// if ( +// bakedModel.getClass() == BasicBakedModel.class || +// bakedModel.getClass() == MultipartBakedModel.class || +// bakedModel.getClass() == WeightedBakedModel.class || +// bakedModel.getClass() == BuiltinBakedModel.class +// ) { +// return; +// } +// +// models.put(identifier, bakedModel); +//}); +// System.out.println(); + +// + //String dump = ObjectDumper.dump(new ObjectDumper.Wrapper(models)); + //try { + // Files.writeString(Path.of("./output." + DashLoaderClient.CACHE.getStatus()), dump); + //} catch (IOException e) { + // throw new RuntimeException(e); + //} + } + + +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/MultipartUnbakedModelMixin.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/MultipartUnbakedModelMixin.java new file mode 100644 index 00000000..447299c2 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/MultipartUnbakedModelMixin.java @@ -0,0 +1,55 @@ +package dev.notalpha.dashloader.mixin.option.cache.model; + +import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.client.model.ModelModule; +import dev.notalpha.dashloader.mixin.accessor.MultipartModelComponentAccessor; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.client.render.model.*; +import net.minecraft.client.render.model.json.MultipartModelComponent; +import net.minecraft.client.render.model.json.MultipartModelSelector; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.SpriteIdentifier; +import net.minecraft.state.StateManager; +import net.minecraft.util.Identifier; +import org.apache.commons.lang3.tuple.Pair; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +@Mixin(MultipartUnbakedModel.class) +public class MultipartUnbakedModelMixin { + @Shadow + @Final + private List components; + + @Shadow + @Final + private StateManager stateFactory; + + @Inject( + method = "bake", + at = @At(value = "RETURN"), + locals = LocalCapture.CAPTURE_FAILSOFT, + cancellable = true + ) + private void addPredicateInfo(Baker baker, Function textureGetter, ModelBakeSettings rotationContainer, Identifier modelId, CallbackInfoReturnable<@Nullable BakedModel> cir, MultipartBakedModel.Builder builder) { + ModelModule.MULTIPART_PREDICATES.visit(CacheStatus.SAVE, map -> { + var bakedModel = (MultipartBakedModel) builder.build(); + var outSelectors = new ArrayList(); + this.components.forEach(multipartModelComponent -> outSelectors.add(((MultipartModelComponentAccessor) multipartModelComponent).getSelector())); + map.put(bakedModel, Pair.of(outSelectors, this.stateFactory)); + cir.setReturnValue(bakedModel); + }); + } + +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/shader/GameRendererMixin.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/shader/GameRendererMixin.java new file mode 100644 index 00000000..f4769649 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/shader/GameRendererMixin.java @@ -0,0 +1,41 @@ +package dev.notalpha.dashloader.mixin.option.cache.shader; + +import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.client.shader.ShaderModule; +import net.minecraft.client.gl.ShaderProgram; +import net.minecraft.client.render.GameRenderer; +import net.minecraft.client.render.VertexFormat; +import net.minecraft.resource.ResourceFactory; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.io.IOException; +import java.util.HashMap; + +@Mixin(value = GameRenderer.class, priority = 69) +public abstract class GameRendererMixin { + @Redirect( + method = "loadPrograms", + at = @At( + value = "NEW", + target = "(Lnet/minecraft/resource/ResourceFactory;Ljava/lang/String;Lnet/minecraft/client/render/VertexFormat;)Lnet/minecraft/client/gl/ShaderProgram;" + ) + ) + private ShaderProgram shaderCreation(ResourceFactory factory, String name, VertexFormat format) throws IOException { + HashMap shaders = ShaderModule.SHADERS.get(CacheStatus.LOAD); + if (shaders != null) { + // If we are reading from cache load the shader and check if its cached. + var shader = shaders.get(name); + if (shader != null) { + return shader; + } + } + + ShaderProgram shader = new ShaderProgram(factory, name, format); + ShaderModule.SHADERS.visit(CacheStatus.SAVE, map -> map.put(name, shader)); + return shader; + } + + +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/shader/GlStateManagerMixin.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/shader/GlStateManagerMixin.java new file mode 100644 index 00000000..dafbf972 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/shader/GlStateManagerMixin.java @@ -0,0 +1,27 @@ +package dev.notalpha.dashloader.mixin.option.cache.shader; + +import com.mojang.blaze3d.platform.GlStateManager; +import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.client.shader.ShaderModule; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.List; + +@Mixin(GlStateManager.class) +public class GlStateManagerMixin { + + @Inject( + method = "glShaderSource", + at = @At(value = "HEAD") + ) + private static void glShaderSourceInject(int shader, List strings, CallbackInfo ci) { + ShaderModule.WRITE_PROGRAM_SOURCES.visit(CacheStatus.SAVE, map -> { + map.put(shader, strings); + }); + } + +} + diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/sprite/SpriteLoaderMixin.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/sprite/SpriteLoaderMixin.java new file mode 100644 index 00000000..6894c6c0 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/sprite/SpriteLoaderMixin.java @@ -0,0 +1,96 @@ +package dev.notalpha.dashloader.mixin.option.cache.sprite; + +import dev.notalpha.dashloader.api.cache.CacheStatus; +import dev.notalpha.dashloader.client.sprite.DashTextureStitcher; +import dev.notalpha.dashloader.client.sprite.SpriteStitcherModule; +import net.minecraft.client.texture.SpriteContents; +import net.minecraft.client.texture.SpriteLoader; +import net.minecraft.client.texture.TextureStitcher; +import net.minecraft.util.Identifier; +import org.apache.commons.lang3.tuple.Pair; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import java.util.List; +import java.util.concurrent.Executor; + +@Mixin(SpriteLoader.class) +public final class SpriteLoaderMixin { + + @Shadow + @Final + private Identifier id; + + @Redirect( + method = "stitch", + at = @At(value = "NEW", target = "(III)Lnet/minecraft/client/texture/TextureStitcher;") + ) + private TextureStitcher dashloaderStitcherLoad(int maxWidth, int maxHeight, int mipLevel) { + if (SpriteStitcherModule.STITCHERS_LOAD.active(CacheStatus.LOAD)) { + var map = SpriteStitcherModule.STITCHERS_LOAD.get(CacheStatus.LOAD); + var data = map.get(id); + if (data != null) { + return new DashTextureStitcher(maxWidth, maxHeight, mipLevel, data); + } + } + + return new TextureStitcher(maxWidth, maxHeight, mipLevel); + } + + @Inject( + method = "stitch", + at = @At(value = "RETURN"), + locals = LocalCapture.CAPTURE_FAILSOFT + ) + private void dashloaderStitcherSave(List sprites, int mipLevel, Executor executor, CallbackInfoReturnable cir, int i, TextureStitcher textureStitcher) { + SpriteStitcherModule.STITCHERS_SAVE.visit(CacheStatus.SAVE, map -> { + map.add(Pair.of(id, textureStitcher)); + }); + } + + //@Inject( + // method = "load(Lnet/minecraft/resource/ResourceManager;Lnet/minecraft/util/Identifier;ILjava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;", + // at = @At(value = "RETURN"), + // cancellable = true + // ) + // private void dashloaderWrite(ResourceManager resourceManager, Identifier identifier, int i, Executor executor, CallbackInfoReturnable> cir) { + // SpriteModule.ATLASES.visit(CacheStatus.SAVE, map -> { + // SpriteModule.ATLAS_IDS.get(CacheStatus.SAVE).put(id, identifier); + // cir.setReturnValue(cir.getReturnValue().thenApply(stitchResult -> { + // map.put(identifier, stitchResult); + // return stitchResult; + // })); + // }); + // } + // + // @Inject( + // method = "load(Lnet/minecraft/resource/ResourceManager;Lnet/minecraft/util/Identifier;ILjava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;", + // at = @At(value = "HEAD"), + // cancellable = true + // ) + // private void dashloaderRead(ResourceManager resourceManager, Identifier identifier, int m, Executor executor, CallbackInfoReturnable> cir) { + // SpriteModule.ATLASES.visit(CacheStatus.LOAD, map -> { + // SpriteLoader.StitchResult cached = map.get(identifier); + // if (cached != null) { + // int mipLevel = cached.mipLevel(); + // // Correct the executor + // CompletableFuture completableFuture = mipLevel > 0 ? CompletableFuture.runAsync(() -> cached.regions().values().forEach(sprite -> sprite.getContents().generateMipmaps(mipLevel)), executor) : CompletableFuture.completedFuture(null); + // cir.setReturnValue(CompletableFuture.completedFuture(new SpriteLoader.StitchResult( + // cached.width(), + // cached.height(), + // mipLevel, + // cached.missing(), + // cached.regions(), + // completableFuture + // ))); + // cir.cancel(); + // } + // }); + // } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/option/misc/AffineTransformationMixin.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/misc/AffineTransformationMixin.java new file mode 100644 index 00000000..1b5f73c9 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/misc/AffineTransformationMixin.java @@ -0,0 +1,31 @@ +package dev.notalpha.dashloader.mixin.option.misc; + +import net.minecraft.util.math.AffineTransformation; +import org.joml.Matrix4f; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.Objects; + +@Mixin(value = AffineTransformation.class, priority = 999) +public class AffineTransformationMixin { + @Shadow + @Final + private Matrix4f matrix; + + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof AffineTransformationMixin that)) return false; + if (!super.equals(o)) return false; + + return Objects.equals(matrix, that.matrix); + } + + @Override + public int hashCode() { + return matrix.hashCode(); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/option/misc/MipmapHelperMixin.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/misc/MipmapHelperMixin.java new file mode 100644 index 00000000..2fae3650 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/misc/MipmapHelperMixin.java @@ -0,0 +1,142 @@ +package dev.notalpha.dashloader.mixin.option.misc; + +import dev.notalpha.dashloader.misc.UnsafeImage; +import net.minecraft.client.texture.MipmapHelper; +import net.minecraft.client.texture.NativeImage; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(MipmapHelper.class) +public abstract class MipmapHelperMixin { + + @Shadow + private static int getColorComponent(int one, int two, int three, int four, int bits) { + return 0; + } + + @Shadow + private static float getColorFraction(int value) { + return 0; + } + + @Shadow + private static boolean hasAlpha(NativeImage image) { + return false; + } + + @Shadow + private static int blend(int one, int two, int three, int four, boolean checkAlpha) { + return 0; + } + + /** + * @author notalpha + * @reason fast + */ + @Overwrite + public static NativeImage[] getMipmapLevelsImages(NativeImage[] originals, int mipmap) { + if (mipmap + 1 <= originals.length) { + return originals; + } + + UnsafeImage[] images = new UnsafeImage[mipmap + 1]; + images[0] = new UnsafeImage(originals[0]); + UnsafeImage baseImage = images[0]; + boolean hasAlpha = false; + + hi: + for (int y = 0; y < baseImage.height; ++y) { + for (int x = 0; x < baseImage.width; ++x) { + if (baseImage.get(x, y) >> 24 == 0) { + hasAlpha = true; + break hi; + } + } + } + + + for (int layer = 1; layer <= mipmap; ++layer) { + if (layer < originals.length) { + images[layer] = new UnsafeImage(originals[layer]); + } else { + UnsafeImage sourceImage = images[layer - 1]; + UnsafeImage targetImage = new UnsafeImage(new NativeImage(sourceImage.width >> 1, sourceImage.height >> 1, false)); + int height = targetImage.height; + int width = targetImage.width; + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + int one = sourceImage.get(x * 2, y * 2); + int two = sourceImage.get(x * 2 + 1, y * 2); + int three = sourceImage.get(x * 2, y * 2 + 1); + int four = sourceImage.get(x * 2 + 1, y * 2 + 1); + + if (hasAlpha) { + float a = 0.0F; + float r = 0.0F; + float g = 0.0F; + float b = 0.0F; + if (one >> 24 != 0) { + a += getColorFraction(one >> 24); + r += getColorFraction(one >> 16); + g += getColorFraction(one >> 8); + b += getColorFraction(one); + } + + if (two >> 24 != 0) { + a += getColorFraction(two >> 24); + r += getColorFraction(two >> 16); + g += getColorFraction(two >> 8); + b += getColorFraction(two); + } + + if (three >> 24 != 0) { + a += getColorFraction(three >> 24); + r += getColorFraction(three >> 16); + g += getColorFraction(three >> 8); + b += getColorFraction(three); + } + + if (four >> 24 != 0) { + a += getColorFraction(four >> 24); + r += getColorFraction(four >> 16); + g += getColorFraction(four >> 8); + b += getColorFraction(four); + } + + a /= 4.0F; + r /= 4.0F; + g /= 4.0F; + b /= 4.0F; + int aI = (int) (Math.pow(a, 0.45454545454545453) * 255.0); + int rI = (int) (Math.pow(r, 0.45454545454545453) * 255.0); + int gI = (int) (Math.pow(g, 0.45454545454545453) * 255.0); + int bI = (int) (Math.pow(b, 0.45454545454545453) * 255.0); + + if (aI < 96) { + aI = 0; + } + + targetImage.set(x, y, aI << 24 | rI << 16 | gI << 8 | bI); + } else { + int a = getColorComponent(one, two, three, four, 24); + int r = getColorComponent(one, two, three, four, 16); + int g = getColorComponent(one, two, three, four, 8); + int b = getColorComponent(one, two, three, four, 0); + targetImage.set(x, y, a << 24 | r << 16 | g << 8 | b); + } + } + } + + images[layer] = targetImage; + } + } + + NativeImage[] imagesOut = new NativeImage[mipmap + 1]; + for (int i = 0; i < imagesOut.length; i++) { + imagesOut[i] = images[i].image; + } + return imagesOut; + + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelIdentifierMixin.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelIdentifierMixin.java new file mode 100644 index 00000000..1871b915 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelIdentifierMixin.java @@ -0,0 +1,35 @@ +package dev.notalpha.dashloader.mixin.option.misc; + +import net.minecraft.client.util.ModelIdentifier; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.Objects; + +@Mixin(value = ModelIdentifier.class, priority = 999) +public abstract class ModelIdentifierMixin { + @Shadow + @Final + private String variant; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || this.getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } + ModelIdentifier that = (ModelIdentifier) o; + return Objects.equals(this.variant, that.getVariant()); + } + + @Override + public int hashCode() { + return 31 * super.hashCode() + variant.hashCode(); + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelLoaderBakedModelCacheKeyMixin.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelLoaderBakedModelCacheKeyMixin.java new file mode 100644 index 00000000..eb80fb0b --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelLoaderBakedModelCacheKeyMixin.java @@ -0,0 +1,41 @@ +package dev.notalpha.dashloader.mixin.option.misc; + +import net.minecraft.client.render.model.ModelLoader; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.AffineTransformation; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(value = ModelLoader.BakedModelCacheKey.class, priority = 999) +public class ModelLoaderBakedModelCacheKeyMixin { + @Shadow + @Final + private Identifier id; + + @Shadow + @Final + private boolean isUvLocked; + + @Shadow + @Final + private AffineTransformation transformation; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ModelLoaderBakedModelCacheKeyMixin that)) return false; + + if (isUvLocked != that.isUvLocked) return false; + if (!id.equals(that.id)) return false; + return transformation.equals(that.transformation); + } + + @Override + public int hashCode() { + int result = id.hashCode(); + result = 31 * result + transformation.hashCode(); + result = 31 * result + (isUvLocked ? 1 : 0); + return result; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/registry/FactoryBinding.java b/forge/src/main/java/dev/notalpha/dashloader/registry/FactoryBinding.java new file mode 100644 index 00000000..8fc887b5 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/registry/FactoryBinding.java @@ -0,0 +1,96 @@ +package dev.notalpha.dashloader.registry; + +import dev.notalpha.dashloader.DashObjectClass; +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import org.jetbrains.annotations.Nullable; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.function.Function; + +public final class FactoryBinding> { + private final MethodHandle method; + private final FactoryFunction creator; + + public FactoryBinding(MethodHandle method, FactoryFunction creator) { + this.method = method; + this.creator = creator; + } + + public static > FactoryBinding create(DashObjectClass dashObject) { + final Class dashClass = dashObject.getDashClass(); + + var factory = tryScanCreators((look, type) -> look.findConstructor(dashClass, type.changeReturnType(void.class)), dashObject); + if (factory == null) { + factory = tryScanCreators((look, type) -> look.findStatic(dashClass, "factory", type), dashObject); + } + if (factory == null) { + factory = tryScanCreators((look, type) -> look.findStatic(dashClass, "factory", type), dashObject); + } + + if (factory == null) { + throw new RuntimeException("Could not find a way to create " + dashClass.getSimpleName() + ". Create the method and/or check if it's accessible."); + } + + return factory; + } + + public D create(R raw, RegistryWriter writer) { + try { + //noinspection unchecked + return (D) this.creator.create(this.method, raw, writer); + } catch (Throwable e) { + throw new RuntimeException("Could not create DashObject " + raw.getClass().getSimpleName(), e); + } + } + + @Nullable + private static > FactoryBinding tryScanCreators(MethodTester tester, DashObjectClass dashObject) { + for (InvokeType value : InvokeType.values()) { + final Class[] apply = value.parameters.apply(dashObject); + + try { + var method = tester.getMethod( + MethodHandles.publicLookup(), + MethodType.methodType(dashObject.getTargetClass(), apply)); + + if (method != null) { + return new FactoryBinding<>(method, value.creator); + } + } catch (Throwable ignored) { + } + } + return null; + } + + // FULL object, writer + // WRITER writer + // RAW object + // EMPTY + private enum InvokeType { + FULL((methodHandle, args, args2) -> methodHandle.invoke(args, args2), doc -> new Class[]{doc.getTargetClass(), RegistryWriter.class}), + WRITER((mh, raw, writer) -> mh.invoke(writer), doc -> new Class[]{RegistryWriter.class}), + RAW((mh, raw, writer) -> mh.invoke(raw), doc -> new Class[]{doc.getTargetClass()}), + EMPTY((mh, raw, writer) -> mh.invoke(), doc -> new Class[0]); + private final FactoryFunction creator; + private final Function, Class[]> parameters; + + InvokeType(FactoryFunction creator, Function, Class[]> parameters) { + this.creator = creator; + this.parameters = parameters; + } + } + + @FunctionalInterface + private interface FactoryFunction { + Object create(MethodHandle method, Object raw, RegistryWriter writer) throws Throwable; + } + + @FunctionalInterface + private interface MethodTester { + MethodHandle getMethod(MethodHandles.Lookup lookup, MethodType parameters) throws Throwable; + } + +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/registry/MissingHandler.java b/forge/src/main/java/dev/notalpha/dashloader/registry/MissingHandler.java new file mode 100644 index 00000000..08a423b7 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/registry/MissingHandler.java @@ -0,0 +1,16 @@ +package dev.notalpha.dashloader.registry; + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryWriter; + +import java.util.function.BiFunction; + +public class MissingHandler { + public final Class parentClass; + public final BiFunction> func; + + public MissingHandler(Class parentClass, BiFunction> func) { + this.parentClass = parentClass; + this.func = func; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/registry/RegistryReaderImpl.java b/forge/src/main/java/dev/notalpha/dashloader/registry/RegistryReaderImpl.java new file mode 100644 index 00000000..e6b9ac8d --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/registry/RegistryReaderImpl.java @@ -0,0 +1,46 @@ +package dev.notalpha.dashloader.registry; + + +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.io.data.CacheInfo; +import dev.notalpha.dashloader.registry.data.StageData; +import dev.notalpha.taski.Task; +import dev.notalpha.taski.builtin.StepTask; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Consumer; + +@SuppressWarnings("FinalMethodInFinalClass") +public final class RegistryReaderImpl implements RegistryReader { + private final StageData[] chunkData; + + // Holds an array of the exported dataChunks array values. + private final Object[][] data; + + public RegistryReaderImpl(CacheInfo metadata, StageData[] data) { + this.chunkData = data; + this.data = new Object[metadata.chunks.size()][]; + for (int i = 0; i < metadata.chunks.size(); i++) { + this.data[i] = new Object[metadata.chunks.get(i).size]; + } + } + + public final void export(@Nullable Consumer taskConsumer) { + StepTask task = new StepTask("Exporting", Integer.max(this.chunkData.length, 1)); + if (taskConsumer != null) { + taskConsumer.accept(task); + } + + for (StageData chunkData : chunkData) { + chunkData.preExport(this); + chunkData.export(data, this); + chunkData.postExport(this); + } + } + + @SuppressWarnings("unchecked") + public final R get(final int pointer) { + // inlining go brrr + return (R) this.data[pointer & 0x3f][pointer >>> 6]; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/registry/RegistryWriterImpl.java b/forge/src/main/java/dev/notalpha/dashloader/registry/RegistryWriterImpl.java new file mode 100644 index 00000000..21d94129 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/registry/RegistryWriterImpl.java @@ -0,0 +1,185 @@ +package dev.notalpha.dashloader.registry; + +import dev.notalpha.dashloader.DashObjectClass; +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryAddException; +import dev.notalpha.dashloader.api.registry.RegistryUtil; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.registry.data.ChunkData; +import dev.notalpha.dashloader.registry.data.ChunkFactory; +import dev.notalpha.dashloader.registry.data.StageData; +import it.unimi.dsi.fastutil.objects.Object2ByteMap; +import it.unimi.dsi.fastutil.objects.Object2ByteOpenHashMap; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.IdentityHashMap; +import java.util.List; + +public final class RegistryWriterImpl implements RegistryWriter { + private final IdentityHashMap dedup = new IdentityHashMap<>(); + private final Object2ByteMap> target2chunkMappings; + private final Object2ByteMap> dash2chunkMappings; + private final List> missingHandlers; + public final ChunkFactory[] chunks; + + private RegistryWriterImpl(ChunkFactory[] chunks, List> missingHandlers) { + this.target2chunkMappings = new Object2ByteOpenHashMap<>(); + this.target2chunkMappings.defaultReturnValue((byte) -1); + + this.dash2chunkMappings = new Object2ByteOpenHashMap<>(); + this.dash2chunkMappings.defaultReturnValue((byte) -1); + + this.missingHandlers = missingHandlers; + this.chunks = chunks; + } + + public static > RegistryWriterImpl create(List> missingHandlers, List> dashObjects) { + if (dashObjects.size() > 63) { + throw new RuntimeException("Hit group limit of 63. Please contact notalpha if you hit this limit!"); + } + + //noinspection unchecked + ChunkFactory[] chunks = new ChunkFactory[dashObjects.size()]; + RegistryWriterImpl writer = new RegistryWriterImpl(chunks, missingHandlers); + + + for (int i = 0; i < dashObjects.size(); i++) { + final DashObjectClass dashObject = (DashObjectClass) dashObjects.get(i); + + var dashClass = dashObject.getDashClass(); + var targetClass = dashObject.getTargetClass(); + byte old = writer.target2chunkMappings.put(targetClass, (byte) i); + if (old != -1) { + DashObjectClass conflicting = dashObjects.get(old); + throw new IllegalStateException("DashObjects \"" + dashObject.getDashClass() + "\" and \"" + conflicting.getDashClass() + "\" have the same target class \"" + targetClass + "\"."); + } + + writer.dash2chunkMappings.put(dashClass, (byte) i); + var factory = FactoryBinding.create(dashObject); + var name = dashClass.getSimpleName(); + chunks[i] = new ChunkFactory<>((byte) i, name, factory, dashObject); + } + + return writer; + } + + public int add(R object) { + return this.addObject(object); + } + + @SuppressWarnings("unchecked") + private > int addObject(R object) { + if (this.dedup.containsKey(object)) { + return this.dedup.get(object); + } + + if (object == null) { + throw new NullPointerException("Registry add argument is null"); + } + + var targetClass = object.getClass(); + Integer pointer = null; + // If we have a dashObject supporting the target we create using its factory constructor + { + byte chunkPos = this.target2chunkMappings.getByte(targetClass); + if (chunkPos != -1) { + var chunk = (ChunkFactory) this.chunks[chunkPos]; + var entry = TrackingRegistryWriterImpl.create(this, writer -> { + return chunk.create(object, writer); + }); + pointer = chunk.add(entry, this); + } + } + + // If we cannot find a target matching we go through the missing handlers + if (pointer == null) { + for (MissingHandler missingHandler : this.missingHandlers) { + if (missingHandler.parentClass.isAssignableFrom(targetClass)) { + var entry = TrackingRegistryWriterImpl.create(this, writer -> { + return (D) missingHandler.func.apply(object, writer); + }); + if (entry.data != null) { + var dashClass = entry.data.getClass(); + byte chunkPos = this.dash2chunkMappings.getByte(dashClass); + if (chunkPos == -1) { + throw new RuntimeException("Could not find a ChunkWriter for DashClass " + dashClass); + } + var chunk = (ChunkFactory) this.chunks[chunkPos]; + pointer = chunk.add(entry, this); + break; + } + } + } + } + + if (pointer == null) { + throw new RegistryAddException(targetClass, object); + } + + ((IdentityHashMap) this.dedup).put(object, pointer); + return pointer; + } + + public ChunkFactory.Entry get(int id) { + return (ChunkFactory.Entry) this.chunks[RegistryUtil.getChunkId(id)].list.get(RegistryUtil.getObjectId(id)); + } + + public StageData[] export() { + // Create a queue with the elements with no references + var exposedQueue = new ArrayDeque>(); + for (ChunkFactory chunk : chunks) { + for (ChunkFactory.Entry entry : chunk.list) { + if (entry.references == 0) { + entry.stage = 0; + exposedQueue.offer(entry); + } + } + } + + // This sets the correct stage for every element + int stages = 1; + // Go through the exposed nodes (ones without edges) + while (!exposedQueue.isEmpty()) { + // Remove the element from the exposed queue. + var element = exposedQueue.poll(); + for (var dependencyId : element.dependencies) { + // Make dependencies a stage above + ChunkFactory.Entry dependency = get(dependencyId); + if (dependency.stage <= element.stage) { + dependency.stage = element.stage + 1; + if (dependency.stage >= stages) { + stages = dependency.stage + 1; + } + } + // Remove the edge, if the dependency no longer has references, add it to the queue. + if (--dependency.references == 0) { + exposedQueue.offer(dependency); + } + } + } + + // Create the output + StageData[] out = new StageData[stages]; + for (int i = 0; i < stages; i++) { + ChunkData[] chunksOut = new ChunkData[this.chunks.length]; + + for (int j = 0; j < this.chunks.length; j++) { + ChunkFactory chunk = this.chunks[j]; + List> dashablesOut = new ArrayList<>(); + for (int k = 0; k < chunk.list.size(); k++) { + ChunkFactory.Entry entry = chunk.list.get(k); + if (entry.stage == i) { + dashablesOut.add(new ChunkData.Entry<>(entry.data, k)); + } + } + + chunksOut[j] = new ChunkData<>(chunk.chunkId, chunk.name, chunk.dashObject, dashablesOut.toArray(ChunkData.Entry[]::new)); + } + + out[stages - (i + 1)] = new StageData(chunksOut); + } + + return out; + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/registry/TrackingRegistryWriterImpl.java b/forge/src/main/java/dev/notalpha/dashloader/registry/TrackingRegistryWriterImpl.java new file mode 100644 index 00000000..8a0bff30 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/registry/TrackingRegistryWriterImpl.java @@ -0,0 +1,36 @@ +package dev.notalpha.dashloader.registry; + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.registry.data.ChunkFactory; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; + +import java.util.function.Function; + +/** + * The Writers job is to allow dashObject to add dependencies by adding them to the registry and allowing parallelization. + * The logic is actually in RegistryFactory, but we need to be able to track what added what so the writer gets issued on the invocation of the creator. + */ +public final class TrackingRegistryWriterImpl implements RegistryWriter { + private final RegistryWriterImpl factory; + private final IntList dependencies = new IntArrayList(); + + private TrackingRegistryWriterImpl(RegistryWriterImpl factory) { + this.factory = factory; + } + + public int add(R object) { + int value = factory.add(object); + dependencies.add(value); + return value; + } + + static > ChunkFactory.Entry create(RegistryWriterImpl factory, Function function) { + TrackingRegistryWriterImpl writer = new TrackingRegistryWriterImpl(factory); + D data = function.apply(writer); + int[] dependencies = writer.dependencies.toIntArray(); + return new ChunkFactory.Entry<>(data, dependencies); + } + +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/registry/data/ChunkData.java b/forge/src/main/java/dev/notalpha/dashloader/registry/data/ChunkData.java new file mode 100644 index 00000000..fbe05aa5 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/registry/data/ChunkData.java @@ -0,0 +1,50 @@ +package dev.notalpha.dashloader.registry.data; + +import dev.notalpha.dashloader.DashObjectClass; +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.thread.ThreadHandler; + +public class ChunkData> { + public final byte chunkId; + public final String name; + public final DashObjectClass dashObject; + public final Entry[] dashables; + + public ChunkData(byte chunkId, String name, DashObjectClass dashObject, Entry[] dashables) { + this.chunkId = chunkId; + this.name = name; + this.dashObject = dashObject; + this.dashables = dashables; + } + + public void preExport(RegistryReader reader) { + for (Entry entry : this.dashables) { + entry.data.preExport(reader); + } + } + + public void export(Object[] data, RegistryReader registry) { + ThreadHandler.INSTANCE.parallelExport(this.dashables, data, registry); + } + + public void postExport(RegistryReader reader) { + for (Entry entry : this.dashables) { + entry.data.postExport(reader); + } + } + + public int getSize() { + return this.dashables.length; + } + + public static final class Entry { + public final D data; + public final int pos; + + public Entry(D data, int pos) { + this.data = data; + this.pos = pos; + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/registry/data/ChunkFactory.java b/forge/src/main/java/dev/notalpha/dashloader/registry/data/ChunkFactory.java new file mode 100644 index 00000000..0eaf757b --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/registry/data/ChunkFactory.java @@ -0,0 +1,67 @@ +package dev.notalpha.dashloader.registry.data; + +import dev.notalpha.dashloader.DashObjectClass; +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryUtil; +import dev.notalpha.dashloader.api.registry.RegistryWriter; +import dev.notalpha.dashloader.registry.FactoryBinding; +import dev.notalpha.dashloader.registry.RegistryWriterImpl; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; + +import java.util.ArrayList; +import java.util.List; + +public class ChunkFactory> { + public final byte chunkId; + public final String name; + public final DashObjectClass dashObject; + public final List> list = new ArrayList<>(); + public final Object2IntMap deduplication = new Object2IntOpenHashMap<>(); + private final FactoryBinding factory; + + public ChunkFactory(byte chunkId, String name, FactoryBinding factory, DashObjectClass dashObject) { + this.chunkId = chunkId; + this.name = name; + this.factory = factory; + this.dashObject = dashObject; + } + + public D create(R raw, RegistryWriter writer) { + return this.factory.create(raw, writer); + } + + public int add(Entry entry, RegistryWriterImpl factory) { + int existing = deduplication.getOrDefault(entry.data, -1); + if (existing != -1) { + return RegistryUtil.createId(existing, chunkId); + } + + final int pos = this.list.size(); + this.list.add(entry); + + // Add to deduplication + deduplication.put(entry.data, pos); + + // Increment dependencies + for (int dependency : entry.dependencies) { + ChunkFactory chunk = factory.chunks[RegistryUtil.getChunkId(dependency)]; + Entry dependencyEntry = chunk.list.get(RegistryUtil.getObjectId(dependency)); + dependencyEntry.references++; + } + + return RegistryUtil.createId(pos, chunkId); + } + + public static final class Entry { + public final D data; + public final int[] dependencies; + public int references = 0; + public int stage = -1; + + public Entry(D data, int[] dependencies) { + this.data = data; + this.dependencies = dependencies; + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/registry/data/StageData.java b/forge/src/main/java/dev/notalpha/dashloader/registry/data/StageData.java new file mode 100644 index 00000000..d5e9e06c --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/registry/data/StageData.java @@ -0,0 +1,31 @@ +package dev.notalpha.dashloader.registry.data; + +import dev.notalpha.dashloader.api.registry.RegistryReader; + +public class StageData { + public final ChunkData[] chunks; + + public StageData(ChunkData[] chunks) { + this.chunks = chunks; + } + + public void preExport(RegistryReader reader) { + for (ChunkData chunk : chunks) { + chunk.preExport(reader); + + } + } + + public void export(Object[][] data, RegistryReader registry) { + for (int i = 0; i < chunks.length; i++) { + ChunkData chunk = chunks[i]; + chunk.export(data[i], registry); + } + } + + public void postExport(RegistryReader reader) { + for (ChunkData chunk : chunks) { + chunk.postExport(reader); + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/thread/IndexedArrayMapTask.java b/forge/src/main/java/dev/notalpha/dashloader/thread/IndexedArrayMapTask.java new file mode 100644 index 00000000..70311194 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/thread/IndexedArrayMapTask.java @@ -0,0 +1,48 @@ +package dev.notalpha.dashloader.thread; + +import dev.notalpha.dashloader.registry.data.ChunkData; + +import java.util.concurrent.RecursiveAction; +import java.util.function.Function; + +public final class IndexedArrayMapTask extends RecursiveAction { + private final int threshold; + private final int start; + private final int stop; + private final ChunkData.Entry[] inArray; + private final O[] outArray; + private final Function function; + + private IndexedArrayMapTask(ChunkData.Entry[] inArray, O[] outArray, Function function, int threshold, int start, int stop) { + this.threshold = threshold; + this.start = start; + this.stop = stop; + this.inArray = inArray; + this.outArray = outArray; + this.function = function; + } + + public IndexedArrayMapTask(ChunkData.Entry[] inArray, O[] outArray, Function function) { + this.start = 0; + this.stop = inArray.length; + this.threshold = ThreadHandler.calcThreshold(this.stop); + this.inArray = inArray; + this.outArray = outArray; + this.function = function; + } + + @Override + protected void compute() { + final int size = this.stop - this.start; + if (size < this.threshold) { + for (int i = this.start; i < this.stop; i++) { + var entry = this.inArray[i]; + this.outArray[entry.pos] = this.function.apply(entry.data); + } + } else { + final int middle = this.start + (size / 2); + invokeAll(new IndexedArrayMapTask<>(this.inArray, this.outArray, this.function, this.threshold, this.start, middle), + new IndexedArrayMapTask<>(this.inArray, this.outArray, this.function, this.threshold, middle, this.stop)); + } + } +} diff --git a/forge/src/main/java/dev/notalpha/dashloader/thread/ThreadHandler.java b/forge/src/main/java/dev/notalpha/dashloader/thread/ThreadHandler.java new file mode 100644 index 00000000..bcfe6d30 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/thread/ThreadHandler.java @@ -0,0 +1,81 @@ +package dev.notalpha.dashloader.thread; + +import dev.notalpha.dashloader.api.DashObject; +import dev.notalpha.dashloader.api.registry.RegistryReader; +import dev.notalpha.dashloader.registry.data.ChunkData; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.IntFunction; + +public final class ThreadHandler { + public static final int THREADS = Runtime.getRuntime().availableProcessors(); + public static final ThreadHandler INSTANCE = new ThreadHandler(); + + private final ForkJoinPool threadPool = new ForkJoinPool(THREADS, new ForkJoinPool.ForkJoinWorkerThreadFactory() { + private final AtomicInteger threadNumber = new AtomicInteger(0); + + @Override + public ForkJoinWorkerThread newThread(ForkJoinPool pool) { + final ForkJoinWorkerThread dashThread = ForkJoinPool.defaultForkJoinWorkerThreadFactory.newThread(pool); + dashThread.setDaemon(true); + dashThread.setName("dlc-thread-" + this.threadNumber.getAndIncrement()); + return dashThread; + } + }, null, true); + + private ThreadHandler() { + } + + public static int calcThreshold(final int tasks) { + return Math.max(tasks / (THREADS * 8), 4); + } + + // Fork Join Methods + public > void parallelExport(ChunkData.Entry[] in, R[] out, RegistryReader reader) { + this.threadPool.invoke(new IndexedArrayMapTask<>(in, out, d -> d.export(reader))); + } + + // Basic Methods + public void parallelRunnable(Runnable... runnables) { + this.parallelRunnable(List.of(runnables)); + } + + public void parallelRunnable(Collection runnables) { + for (Future future : this.threadPool.invokeAll(runnables.stream().map(Executors::callable).toList())) { + this.acquire(future); + } + } + + @SafeVarargs + public final O[] parallelCallable(IntFunction creator, Callable... callables) { + O[] out = creator.apply(callables.length); + var futures = this.threadPool.invokeAll(List.of(callables)); + for (int i = 0, futuresSize = futures.size(); i < futuresSize; i++) { + out[i] = (this.acquire(futures.get(i))); + } + return out; + } + + public Collection parallelCallable(Collection> callables) { + List out = new ArrayList<>(); + var futures = this.threadPool.invokeAll(callables); + for (Future future : futures) { + out.add(this.acquire(future)); + } + return out; + } + + private O acquire(Future future) { + try { + return future.get(); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + } + + +} diff --git a/forge/src/main/resources/META-INF/mods.toml b/forge/src/main/resources/META-INF/mods.toml new file mode 100644 index 00000000..bf9233f2 --- /dev/null +++ b/forge/src/main/resources/META-INF/mods.toml @@ -0,0 +1,35 @@ +modLoader = "javafml" +loaderVersion = "[47,)" +#issueTrackerURL = "" +license = "GNU LGPL 3.0" + +[[mods]] +modId = "dashloader" +version = "${version}" +displayName = "DashLoaderForge" +authors = "KSmc_brigade" +description = ''' + +''' +#logoFile = "" + +[[dependencies.dashloader]] +modId = "forge" +mandatory = true +versionRange = "[47,)" +ordering = "NONE" +side = "BOTH" + +[[dependencies.dashloader]] +modId = "minecraft" +mandatory = true +versionRange = "[1.20.1,)" +ordering = "NONE" +side = "BOTH" + +[[dependencies.dashloader]] +modId = "architectury" +mandatory = true +versionRange = "[9.2.14,)" +ordering = "AFTER" +side = "BOTH" diff --git a/forge/src/main/resources/dashloader.accesswidener b/forge/src/main/resources/dashloader.accesswidener new file mode 100644 index 00000000..abad3b9a --- /dev/null +++ b/forge/src/main/resources/dashloader.accesswidener @@ -0,0 +1,37 @@ +accessWidener v1 named +accessible class net/minecraft/client/texture/SpriteContents$Interpolation +accessible class net/minecraft/client/texture/SpriteContents$Animation +accessible class net/minecraft/client/texture/SpriteContents$AnimationFrame +accessible class net/minecraft/client/particle/ParticleManager$SimpleSpriteProvider +accessible class net/minecraft/client/font/BitmapFont$BitmapFontGlyph +accessible class net/minecraft/client/render/model/json/ModelOverrideList$BakedOverride +accessible class net/minecraft/client/render/model/json/ModelOverrideList$InlinedCondition +accessible class net/minecraft/client/render/model/BakedModelManager$BakingResult +accessible class net/minecraft/client/render/model/ModelLoader$BakedModelCacheKey +accessible class net/minecraft/client/font/UnihexFont$UnicodeTextureGlyph +accessible class net/minecraft/client/font/UnihexFont$FontImage16x16 +accessible class net/minecraft/client/font/UnihexFont$FontImage8x16 +accessible class net/minecraft/client/font/UnihexFont$FontImage32x16 +accessible class net/minecraft/client/font/FontStorage$GlyphPair +accessible class net/minecraft/util/Identifier$ExtraData +accessible class net/minecraft/client/font/FontStorage$GlyphPair +accessible class net/minecraft/client/font/FontManager$ProviderIndex +accessible method net/minecraft/client/font/UnihexFont$FontImage8x16 ([B)V +accessible method net/minecraft/client/font/UnihexFont$FontImage16x16 ([S)V +accessible method net/minecraft/client/font/UnihexFont$FontImage32x16 ([II)V +accessible method net/minecraft/client/font/UnihexFont$UnicodeTextureGlyph (Lnet/minecraft/client/font/UnihexFont$BitmapGlyph;II)V +mutable field net/minecraft/client/gl/ShaderProgram modelViewMat Lnet/minecraft/client/gl/GlUniform; +mutable field net/minecraft/client/gl/ShaderProgram projectionMat Lnet/minecraft/client/gl/GlUniform; +mutable field net/minecraft/client/gl/ShaderProgram viewRotationMat Lnet/minecraft/client/gl/GlUniform; +mutable field net/minecraft/client/gl/ShaderProgram textureMat Lnet/minecraft/client/gl/GlUniform; +mutable field net/minecraft/client/gl/ShaderProgram screenSize Lnet/minecraft/client/gl/GlUniform; +mutable field net/minecraft/client/gl/ShaderProgram colorModulator Lnet/minecraft/client/gl/GlUniform; +mutable field net/minecraft/client/gl/ShaderProgram light0Direction Lnet/minecraft/client/gl/GlUniform; +mutable field net/minecraft/client/gl/ShaderProgram light1Direction Lnet/minecraft/client/gl/GlUniform; +mutable field net/minecraft/client/gl/ShaderProgram fogStart Lnet/minecraft/client/gl/GlUniform; +mutable field net/minecraft/client/gl/ShaderProgram fogEnd Lnet/minecraft/client/gl/GlUniform; +mutable field net/minecraft/client/gl/ShaderProgram fogColor Lnet/minecraft/client/gl/GlUniform; +mutable field net/minecraft/client/gl/ShaderProgram fogShape Lnet/minecraft/client/gl/GlUniform; +mutable field net/minecraft/client/gl/ShaderProgram lineWidth Lnet/minecraft/client/gl/GlUniform; +mutable field net/minecraft/client/gl/ShaderProgram gameTime Lnet/minecraft/client/gl/GlUniform; +mutable field net/minecraft/client/gl/ShaderProgram chunkOffset Lnet/minecraft/client/gl/GlUniform; diff --git a/forge/src/main/resources/dashloader.mixins.json b/forge/src/main/resources/dashloader.mixins.json new file mode 100644 index 00000000..9676a0b2 --- /dev/null +++ b/forge/src/main/resources/dashloader.mixins.json @@ -0,0 +1,72 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "dev.notalpha.dashloader.mixin", + "plugin": "dev.notalpha.dashloader.mixin.MixinPlugin", + "compatibilityLevel": "JAVA_16", + "mixins": [ + "accessor.AbstractTextureAccessor", + "accessor.AndMultipartModelSelectorAccessor", + "accessor.BasicBakedModelAccessor", + "accessor.BitmapFontAccessor", + "accessor.BitmapFontGlyphAccessor", + "accessor.BuiltinBakedModelAccessor", + "accessor.EffectShaderStageAccessor", + "accessor.FontManagerProviderIndexAccessor", + "accessor.FontStorageAccessor", + "accessor.GlBlendStateAccessor", + "accessor.GlUniformAccessor", + "accessor.IdentifierAccessor", + "accessor.ModelLoaderAccessor", + "accessor.ModelOverrideListAccessor", + "accessor.ModelOverrideListBakedOverrideAccessor", + "accessor.ModelOverrideListInlinedCondition", + "accessor.MultipartBakedModelAccessor", + "accessor.MultipartModelComponentAccessor", + "accessor.NativeImageAccessor", + "accessor.OrMultipartModelSelectorAccessor", + "accessor.ShaderProgramAccessor", + "accessor.ShaderStageAccessor", + "accessor.ShaderStageAccessor$TypeAccessor", + "accessor.SimpleMultipartModelSelectorAccessor", + "accessor.SpriteAccessor", + "accessor.SpriteAnimationAccessor", + "accessor.SpriteAnimationFrameAccessor", + "accessor.SpriteLoaderStitchResultAccessor", + "accessor.TrueTypeFontAccessor", + "accessor.UnihexFontAccessor", + "accessor.WeightedBakedModelAccessor", + "accessor.WeightedBakedModelEntryAccessor", + "accessor.ZipResourcePackAccessor", + "main.BootstrapMixin", + "main.KeyboardMixin", + "main.MainMixin", + "main.MinecraftClientMixin", + "main.ReloadableResourceManagerImplMixin", + "main.SplashScreenMixin", + "option.WallBlockMixin", + "option.cache.SplashTextResourceSupplierMixin", + "option.cache.font.FontManagerOverride", + "option.cache.font.TrueTypeFontLoaderMixin", + "option.cache.model.BakedModelManagerOverride", + "option.cache.model.BlockModelsMixin", + "option.cache.model.ModelLoaderMixin", + "option.cache.model.MultipartUnbakedModelMixin", + "option.cache.shader.GameRendererMixin", + "option.cache.shader.GlStateManagerMixin", + "option.cache.sprite.SpriteLoaderMixin", + "option.misc.AffineTransformationMixin", + "option.misc.ModelIdentifierMixin" + ], + "injectors": { + "defaultRequire": 1 + }, + "client": [ + "accessor.ModelIdentifierAccessor", + "accessor.ShaderStageAccessor$TypeAccessor", + "accessor.SpriteContentsAccessor", + "accessor.VertexFormatAccessor", + "option.misc.MipmapHelperMixin", + "option.misc.ModelLoaderBakedModelCacheKeyMixin" + ] +} diff --git a/forge/src/main/resources/dashloader/lang/en_us.json b/forge/src/main/resources/dashloader/lang/en_us.json new file mode 100644 index 00000000..a92a3f75 --- /dev/null +++ b/forge/src/main/resources/dashloader/lang/en_us.json @@ -0,0 +1,11 @@ +{ + "debug": "Debug Mode is active in config.", + "save": "Initializing", + "save.cache": "Caching", + "save.cache.model": "Caching models", + "save.cache.image": "Caching images", + "save.cache.misc": "Caching miscellaneous", + "save.serialize": "Serializing", + "save.serialize.fragment": "Serializing fragments", + "save.serialize.mapping": "Serializing mappings" +} \ No newline at end of file diff --git a/forge/src/main/resources/dashloader/lang/lol_us.json b/forge/src/main/resources/dashloader/lang/lol_us.json new file mode 100644 index 00000000..7d404ff2 --- /dev/null +++ b/forge/src/main/resources/dashloader/lang/lol_us.json @@ -0,0 +1,11 @@ +{ + "debug": "eyo debug is on! Check the cribby config.", + "save": "wakin up!", + "save.cache": "owoifying", + "save.cache.model": "uwufying anime", + "save.cache.image": "saving anime", + "save.cache.misc": "savin' stuff", + "save.serialize": "sending dms", + "save.serialize.fragment": "sending hot sha256 keys", + "save.serialize.mapping": "sending private key" +} \ No newline at end of file diff --git a/forge/src/main/resources/dashloader/lang/sv_se.json b/forge/src/main/resources/dashloader/lang/sv_se.json new file mode 100644 index 00000000..cf2da4a0 --- /dev/null +++ b/forge/src/main/resources/dashloader/lang/sv_se.json @@ -0,0 +1,11 @@ +{ + "debug": "Debug läge är på i konfigurations filen.", + "save": "Påbörjar", + "save.cache": "Laddar", + "save.cache.model": "Laddar modeler", + "save.cache.image": "Laddar bilder", + "save.cache.misc": "Laddar blandat", + "save.serialize": "Sparar", + "save.serialize.fragment": "Sparar fragment", + "save.serialize.mapping": "Sparar mappningar" +} \ No newline at end of file diff --git a/forge/src/main/resources/dashloader/textures/icon.png b/forge/src/main/resources/dashloader/textures/icon.png new file mode 100644 index 00000000..5f8fc5f8 Binary files /dev/null and b/forge/src/main/resources/dashloader/textures/icon.png differ diff --git a/forge/src/main/resources/pack.mcmeta b/forge/src/main/resources/pack.mcmeta new file mode 100644 index 00000000..cbf2eae1 --- /dev/null +++ b/forge/src/main/resources/pack.mcmeta @@ -0,0 +1,6 @@ +{ + "pack": { + "description": "dashloader resources", + "pack_format": 15 + } +} diff --git a/gradle.properties b/gradle.properties index 37777fb7..be73f3e3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,12 +1,16 @@ -# Hello this is Froge. I like QuantumFusion and anyone who uses DashLoader. :heart: from !alpha, Froge and the QuantumFusion team. -# Current Minecraft Properties -org.gradle.jvmargs=-Xmx2560m - -minecraft_version=1.19.3 -yarn_mappings=1.19.3+build.4 -loader_version=0.14.12 - -# Mod Properties -mod_version=5.0.0-alpha.14+1.19.3 -maven_group=dev.notalpha -archives_base_name=dashloader +# Done to increase the memory available to Gradle. +org.gradle.jvmargs=-Xmx2G +org.gradle.parallel=true +# Mod properties +mod_version=5.0.0-beta.3+1.20.0 +maven_group=cn.ksmcbrigade +archives_name=dashloader +enabled_platforms=neoforge +# Minecraft properties +minecraft_version=1.20.1 +# Dependencies +architectury_api_version=9.2.14 +fabric_loader_version=0.14.22 +fabric_api_version=0.83.0+1.20.1 +forge_version=1.20.1-47.3.0 +yarn_mappings=1.20.1+build.10 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar old mode 100755 new mode 100644 index 7454180f..a4b76b95 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e750102e..e18bc253 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 744e882e..f3b75f3b 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,69 +15,103 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MSYS* | MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,88 +132,120 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 107acd32..9b42019c 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,89 +1,94 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle index 8a88f8db..95bc2b21 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,12 +1,14 @@ pluginManagement { repositories { - mavenCentral() + maven { url "https://maven.fabricmc.net/" } + maven { url "https://maven.architectury.dev/" } + maven { url "https://files.minecraftforge.net/maven/" } gradlePluginPortal() - maven { - name "Fabric" - url "https://maven.fabricmc.net" - } } } rootProject.name = 'dashloader' + +include 'common' +//include 'fabric' +include 'forge' diff --git a/src/main/java/dev/notalpha/dashloader/api/DashEntrypoint.java b/src/main/java/dev/notalpha/dashloader/api/DashEntrypoint.java deleted file mode 100644 index 4c5bb379..00000000 --- a/src/main/java/dev/notalpha/dashloader/api/DashEntrypoint.java +++ /dev/null @@ -1,7 +0,0 @@ -package dev.notalpha.dashloader.api; - -import dev.notalpha.dashloader.api.cache.DashCacheFactory; - -public interface DashEntrypoint { - void onDashLoaderInit(DashCacheFactory factory); -} diff --git a/src/main/java/dev/notalpha/dashloader/api/DashObject.java b/src/main/java/dev/notalpha/dashloader/api/DashObject.java deleted file mode 100644 index 7e745e36..00000000 --- a/src/main/java/dev/notalpha/dashloader/api/DashObject.java +++ /dev/null @@ -1,29 +0,0 @@ -package dev.notalpha.dashloader.api; - -/** - * The Exportable interface is the interface to implement when adding DashLoader cache support to a registry object. - * - * @param Raw Object. - */ -@SuppressWarnings("unused") -public interface DashObject { - /** - * Runs before {@link DashObject#export(RegistryReader)} on the main thread. - */ - @SuppressWarnings("unused") - default void preExport(RegistryReader reader) { - } - - /** - * Runs in parallel returning the target object. - */ - @SuppressWarnings("unused") - R export(RegistryReader reader); - - /** - * Runs after {@link DashObject#export(RegistryReader)} on the main thread. - */ - @SuppressWarnings("unused") - default void postExport(RegistryReader reader) { - } -} diff --git a/src/main/java/dev/notalpha/dashloader/api/RegistryReader.java b/src/main/java/dev/notalpha/dashloader/api/RegistryReader.java deleted file mode 100644 index 703d0dc5..00000000 --- a/src/main/java/dev/notalpha/dashloader/api/RegistryReader.java +++ /dev/null @@ -1,12 +0,0 @@ -package dev.notalpha.dashloader.api; - -public interface RegistryReader { - /** - * Gets an object back from the registry. - * This is used in conjunction with {@link RegistryWriter#add(Object)} to save and load objects from the registry. - * @param id A registry id which points to the object. - * @return Object which was registered by the id. - * @param Object Type - */ - R get(final int id); -} diff --git a/src/main/java/dev/notalpha/dashloader/api/RegistryWriter.java b/src/main/java/dev/notalpha/dashloader/api/RegistryWriter.java deleted file mode 100644 index ee3403dc..00000000 --- a/src/main/java/dev/notalpha/dashloader/api/RegistryWriter.java +++ /dev/null @@ -1,11 +0,0 @@ -package dev.notalpha.dashloader.api; - -public interface RegistryWriter { - /** - * Adds an entry to the DashRegistry. - * @param object The object to add to the registry. - * @return An id to the registry entry, this is used to get back the original object on the cache read. - */ - int add(final R object); - -} diff --git a/src/main/java/dev/notalpha/dashloader/api/cache/CacheStatus.java b/src/main/java/dev/notalpha/dashloader/api/cache/CacheStatus.java deleted file mode 100644 index 2e7b4046..00000000 --- a/src/main/java/dev/notalpha/dashloader/api/cache/CacheStatus.java +++ /dev/null @@ -1,16 +0,0 @@ -package dev.notalpha.dashloader.api.cache; - -public enum CacheStatus { - /** - * The cache manager is doing nothing. - */ - IDLE, - /** - * The cache manager is in the process of loading a cache. - */ - LOAD, - /** - * The cache manager is creating a cache. - */ - SAVE, -} diff --git a/src/main/java/dev/notalpha/dashloader/api/cache/DashCache.java b/src/main/java/dev/notalpha/dashloader/api/cache/DashCache.java deleted file mode 100644 index 4bd125d1..00000000 --- a/src/main/java/dev/notalpha/dashloader/api/cache/DashCache.java +++ /dev/null @@ -1,8 +0,0 @@ -package dev.notalpha.dashloader.api.cache; - -import java.nio.file.Path; - -public interface DashCache { - CacheStatus getStatus(); - Path getDir(); -} diff --git a/src/main/java/dev/notalpha/dashloader/api/cache/DashCacheFactory.java b/src/main/java/dev/notalpha/dashloader/api/cache/DashCacheFactory.java deleted file mode 100644 index dee8eeaa..00000000 --- a/src/main/java/dev/notalpha/dashloader/api/cache/DashCacheFactory.java +++ /dev/null @@ -1,14 +0,0 @@ -package dev.notalpha.dashloader.api.cache; - -import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryWriter; - -import java.util.function.BiFunction; - -public interface DashCacheFactory { - void addDashObject(Class> dashClass); - - void addModule(DashModule handler); - - void addMissingHandler(Class parentClass, BiFunction> func); -} diff --git a/src/main/java/dev/notalpha/dashloader/api/cache/DashModule.java b/src/main/java/dev/notalpha/dashloader/api/cache/DashModule.java deleted file mode 100644 index 19d37982..00000000 --- a/src/main/java/dev/notalpha/dashloader/api/cache/DashModule.java +++ /dev/null @@ -1,23 +0,0 @@ -package dev.notalpha.dashloader.api.cache; - -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.api.RegistryWriter; -import dev.notalpha.taski.builtin.StepTask; - -public interface DashModule { - void reset(DashCache cacheManager); - - M save(RegistryWriter writer, StepTask task); - - void load(M mappings, RegistryReader reader, StepTask task); - - Class getDataClass(); - - default boolean isActive() { - return true; - } - - default float taskWeight() { - return 100; - } -} diff --git a/src/main/java/dev/notalpha/dashloader/client/font/DashUnicodeFont.java b/src/main/java/dev/notalpha/dashloader/client/font/DashUnicodeFont.java deleted file mode 100644 index 4c2cce93..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/font/DashUnicodeFont.java +++ /dev/null @@ -1,50 +0,0 @@ -package dev.notalpha.dashloader.client.font; - -import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.api.RegistryWriter; -import dev.notalpha.dashloader.misc.UnsafeHelper; -import dev.notalpha.dashloader.mixin.accessor.FontImageAccessor; -import dev.notalpha.dashloader.mixin.accessor.UnicodeTextureFontAccessor; -import dev.notalpha.hyphen.scan.annotations.DataFixedArraySize; -import dev.notalpha.hyphen.scan.annotations.DataNullable; -import net.minecraft.client.font.UnicodeTextureFont; - -public final class DashUnicodeFont implements DashObject { - - - public final @DataNullable Integer @DataFixedArraySize(256) [] images; - public final byte[] sizes; - - public DashUnicodeFont(Integer[] images, byte[] sizes) { - this.images = images; - this.sizes = sizes; - } - - public DashUnicodeFont(UnicodeTextureFont rawFont, RegistryWriter writer) { - this.images = new Integer[256]; - UnicodeTextureFontAccessor font = ((UnicodeTextureFontAccessor) rawFont); - UnicodeTextureFont.FontImage[] fontImages = font.getFontImages(); - for (int i = 0; i < fontImages.length; i++) { - UnicodeTextureFont.FontImage fontImage = fontImages[i]; - this.images[i] = fontImage == null ? null : writer.add(((FontImageAccessor) fontImage).getImage()); - } - this.sizes = font.getSizes(); - } - - - public UnicodeTextureFont export(RegistryReader handler) { - UnicodeTextureFont font = UnsafeHelper.allocateInstance(UnicodeTextureFont.class); - UnicodeTextureFontAccessor accessor = ((UnicodeTextureFontAccessor) font); - accessor.setSizes(this.sizes); - UnicodeTextureFont.FontImage[] fontImages = new UnicodeTextureFont.FontImage[256]; - - - for (int i = 0; i < images.length; i++) { - Integer image = images[i]; - fontImages[i] = image == null ? null : FontImageAccessor.create(this.sizes, handler.get(image)); - } - accessor.setFontImages(fontImages); - return font; - } -} diff --git a/src/main/java/dev/notalpha/dashloader/client/font/FontModule.java b/src/main/java/dev/notalpha/dashloader/client/font/FontModule.java deleted file mode 100644 index d5eb687c..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/font/FontModule.java +++ /dev/null @@ -1,101 +0,0 @@ -package dev.notalpha.dashloader.client.font; - -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.api.RegistryWriter; -import dev.notalpha.dashloader.api.cache.CacheStatus; -import dev.notalpha.dashloader.api.cache.CachingData; -import dev.notalpha.dashloader.api.cache.DashCache; -import dev.notalpha.dashloader.api.cache.DashModule; -import dev.notalpha.dashloader.api.collection.IntObjectList; -import dev.notalpha.dashloader.config.ConfigHandler; -import dev.notalpha.dashloader.config.Option; -import dev.notalpha.taski.builtin.StepTask; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.ints.IntArrayList; -import it.unimi.dsi.fastutil.ints.IntList; -import it.unimi.dsi.fastutil.objects.Object2ObjectMap; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import net.minecraft.client.font.Font; -import net.minecraft.client.font.FontManager; -import net.minecraft.util.Identifier; -import org.apache.commons.lang3.tuple.Pair; -import org.lwjgl.stb.STBTTFontinfo; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class FontModule implements DashModule { - public static FontManager FONTMANAGER; - public static final CachingData, List>>> DATA = new CachingData<>(); - public static final CachingData> FONT_TO_IDENT = new CachingData<>(); - - @Override - public void reset(DashCache cacheManager) { - DATA.reset(cacheManager, new Object2ObjectOpenHashMap<>()); - FONT_TO_IDENT.reset(cacheManager, new HashMap<>()); - } - - @Override - public Data save(RegistryWriter writer, StepTask task) { - var fontMap = new IntObjectList(); - Object2ObjectMap, List>> identifierPairObject2ObjectMap = DATA.get(CacheStatus.SAVE); - identifierPairObject2ObjectMap.forEach((identifier, fontList) -> { - List fontsOut = new ArrayList<>(); - for (Font font : fontList.getValue()) { - fontsOut.add(writer.add(font)); - } - IntObjectList> charactersByWidth = new IntObjectList<>(); - fontList.getKey().forEach(charactersByWidth::put); - fontMap.put(writer.add(identifier), new DashFontStorage(charactersByWidth, fontsOut)); - task.next(); - }); - - return new Data(fontMap); - } - - @Override - public void load(Data mappings, RegistryReader reader, StepTask task) { - Object2ObjectMap, List>> out = new Object2ObjectOpenHashMap<>(); - mappings.fontMap.forEach((key, value) -> { - List fontsOut = new ArrayList<>(); - value.fonts.forEach(fontPointer -> fontsOut.add(reader.get(fontPointer))); - - Int2ObjectMap charactersByWidth = new Int2ObjectOpenHashMap<>(); - value.charactersByWidth.forEach((key1, value1) -> charactersByWidth.put(key1, new IntArrayList(value1))); - out.put(reader.get(key), Pair.of(charactersByWidth, fontsOut)); - }); - - DATA.set(CacheStatus.LOAD, out); - } - - @Override - public Class getDataClass() { - return Data.class; - } - - @Override - public boolean isActive() { - return ConfigHandler.optionActive(Option.CACHE_FONT); - } - - public static final class Data { - public final IntObjectList fontMap; - - public Data(IntObjectList fontMap) { - this.fontMap = fontMap; - } - } - - public static final class DashFontStorage { - public final IntObjectList> charactersByWidth; - public final List fonts; - - public DashFontStorage(IntObjectList> charactersByWidth, List fonts) { - this.charactersByWidth = charactersByWidth; - this.fonts = fonts; - } - } -} diff --git a/src/main/java/dev/notalpha/dashloader/client/sprite/DashSprite.java b/src/main/java/dev/notalpha/dashloader/client/sprite/DashSprite.java deleted file mode 100644 index 2c79c7bc..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/sprite/DashSprite.java +++ /dev/null @@ -1,73 +0,0 @@ -package dev.notalpha.dashloader.client.sprite; - -import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.api.RegistryWriter; -import dev.notalpha.dashloader.api.cache.CacheStatus; -import dev.notalpha.dashloader.mixin.accessor.SpriteAccessor; -import net.minecraft.client.texture.Sprite; -import net.minecraft.client.texture.SpriteLoader; -import net.minecraft.util.Identifier; - -public class DashSprite implements DashObject { - public final int atlasId; - public final DashSpriteContents contents; - - public final int x; - public final int y; - - public final int atlasWidth; - public final int atlasHeight; - - public DashSprite(int atlasId, DashSpriteContents contents, int x, int y, int atlasWidth, int atlasHeight) { - this.atlasId = atlasId; - this.contents = contents; - this.x = x; - this.y = y; - this.atlasWidth = atlasWidth; - this.atlasHeight = atlasHeight; - } - - public DashSprite(Sprite sprite, RegistryWriter writer) { - this.atlasId = writer.add(sprite.getAtlasId()); - this.contents = new DashSpriteContents(sprite.getContents(), writer); - - Identifier identifier = SpriteModule.ATLAS_IDS.get(CacheStatus.SAVE).get(sprite.getAtlasId()); - SpriteLoader.StitchResult atlas = SpriteModule.ATLASES.get(CacheStatus.SAVE).get(identifier); - this.x = sprite.getX(); - this.y = sprite.getY(); - this.atlasWidth = atlas.width(); - this.atlasHeight = atlas.height(); - } - - @Override - public Sprite export(final RegistryReader registry) { - return SpriteAccessor.init(registry.get(this.atlasId), this.contents.export(registry), this.atlasWidth, this.atlasHeight, this.x, this.y); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - DashSprite that = (DashSprite) o; - - if (atlasId != that.atlasId) return false; - if (x != that.x) return false; - if (y != that.y) return false; - if (atlasWidth != that.atlasWidth) return false; - if (atlasHeight != that.atlasHeight) return false; - return contents.equals(that.contents); - } - - @Override - public int hashCode() { - int result = atlasId; - result = 31 * result + contents.hashCode(); - result = 31 * result + x; - result = 31 * result + y; - result = 31 * result + atlasWidth; - result = 31 * result + atlasHeight; - return result; - } -} diff --git a/src/main/java/dev/notalpha/dashloader/client/sprite/SpriteModule.java b/src/main/java/dev/notalpha/dashloader/client/sprite/SpriteModule.java deleted file mode 100644 index 82bccdf7..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/sprite/SpriteModule.java +++ /dev/null @@ -1,69 +0,0 @@ -package dev.notalpha.dashloader.client.sprite; - -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.api.RegistryWriter; -import dev.notalpha.dashloader.api.cache.CacheStatus; -import dev.notalpha.dashloader.api.cache.CachingData; -import dev.notalpha.dashloader.api.cache.DashCache; -import dev.notalpha.dashloader.api.cache.DashModule; -import dev.notalpha.dashloader.api.collection.IntObjectList; -import dev.notalpha.dashloader.config.ConfigHandler; -import dev.notalpha.dashloader.config.Option; -import dev.notalpha.taski.builtin.StepTask; -import net.minecraft.client.texture.SpriteLoader; -import net.minecraft.util.Identifier; - -import java.util.HashMap; - -public class SpriteModule implements DashModule { - public final static CachingData> ATLASES = new CachingData<>(); - public final static CachingData> ATLAS_IDS = new CachingData<>(CacheStatus.SAVE); - - @Override - public void reset(DashCache cacheManager) { - ATLASES.reset(cacheManager, new HashMap<>()); - ATLAS_IDS.reset(cacheManager, new HashMap<>()); - } - - @Override - public Data save(RegistryWriter writer, StepTask task) { - var results = new IntObjectList(); - - var map = ATLASES.get(CacheStatus.SAVE); - task.doForEach(map, (identifier, stitchResult) -> { - StepTask atlases = new StepTask("atlas", stitchResult.regions().size()); - task.setSubTask(atlases); - results.put(writer.add(identifier), new DashStitchResult(stitchResult, writer, atlases)); - }); - - return new Data(results); - } - - @Override - public void load(Data mappings, RegistryReader reader, StepTask task) { - HashMap stitchResults = new HashMap<>(mappings.results.list().size()); - mappings.results.forEach((identifier, stitchResult) -> { - stitchResults.put(reader.get(identifier), stitchResult.export(reader)); - }); - - ATLASES.set(CacheStatus.LOAD, stitchResults); - } - - @Override - public Class getDataClass() { - return Data.class; - } - - @Override - public boolean isActive() { - return ConfigHandler.optionActive(Option.CACHE_SPRITES); - } - - public static final class Data { - public final IntObjectList results; - - public Data(IntObjectList results) { - this.results = results; - } - } -} diff --git a/src/main/java/dev/notalpha/dashloader/misc/ObjectDumper.java b/src/main/java/dev/notalpha/dashloader/misc/ObjectDumper.java deleted file mode 100644 index 2c242a56..00000000 --- a/src/main/java/dev/notalpha/dashloader/misc/ObjectDumper.java +++ /dev/null @@ -1,117 +0,0 @@ -package dev.notalpha.dashloader.misc; - -import net.minecraft.client.texture.NativeImage; -import org.apache.commons.lang3.builder.MultilineRecursiveToStringStyle; -import org.apache.commons.lang3.builder.ReflectionToStringBuilder; - -import java.lang.reflect.Field; -import java.nio.FloatBuffer; -import java.nio.IntBuffer; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -public class ObjectDumper { - public static String dump(Object object) { - return ReflectionToStringBuilder.toString(object, new Style()); - } - - private static final class Style extends MultilineRecursiveToStringStyle { - public Style() { - setFieldNameValueSeparator(": "); - setUseIdentityHashCode(false); - setUseShortClassName(true); - } - - public void appendDetail(StringBuffer buffer, String fieldName, Object value) { - if (value != null) { - if (Objects.equals(fieldName, "glRef")) { - buffer.append(""); - return; - } - if (value instanceof NativeImage image) { - buffer.append("Image{ format: ").append(image.getFormat()).append(", size: ").append(image.getWidth()).append("x").append(image.getHeight()).append(" }"); - return; - } - - if (value instanceof IntBuffer buffer1) { - buffer.append("IntBuffer ["); - int limit = buffer1.limit(); - if (limit < 50) { - buffer1.rewind(); - for (int i = 0; i < limit; i++) { - float v = buffer1.get(); - buffer.append(v); - buffer.append(", "); - } - } - buffer.append("]"); - return; - } - - if (value instanceof FloatBuffer buffer1) { - buffer.append("FloatBuffer ["); - int limit = buffer1.limit(); - if (limit < 50) { - buffer1.rewind(); - for (int i = 0; i < limit; i++) { - float v = buffer1.get(); - buffer.append(v); - buffer.append(", "); - } - } - buffer.append("]"); - return; - } - - if (value instanceof Enum enumValue) { - buffer.append(enumValue.name()); - return; - } - } else { - buffer.append("null"); - return; - } - - try { - StringBuffer builder = new StringBuffer(); - super.appendDetail(builder, fieldName, value); - String s = builder.toString(); - String result = s.split("@")[0]; - buffer.append(result); - } catch (Exception e) { - e.printStackTrace(); - - buffer.append("unknown"); - try { - Field spaces = MultilineRecursiveToStringStyle.class.getDeclaredField("spaces"); - spaces.setAccessible(true); - spaces.setInt(this, spaces.getInt(this) - 2); - } catch (IllegalAccessException | NoSuchFieldException ex) { - throw new RuntimeException(ex); - } - } - } - - @Override - protected void appendDetail(StringBuffer buffer, String fieldName, Map map) { - buffer.append(this.getArrayStart()); - - // Sort maps to be comparible - List> entries = new ArrayList<>(map.entrySet()); - entries.sort((o1, o2) -> o1.getKey().toString().compareTo(o2.toString())); - entries.forEach((entry) -> { - buffer.append(getArraySeparator()); - this.appendDetail(buffer, String.valueOf(entry.getKey()), entry.getValue()); - }); - buffer.append(this.getArrayEnd()); - } - - @Override - protected void appendIdentityHashCode(StringBuffer buffer, Object object) { - - - } - } -} diff --git a/src/main/java/dev/notalpha/dashloader/misc/RegistryUtil.java b/src/main/java/dev/notalpha/dashloader/misc/RegistryUtil.java deleted file mode 100644 index 08203e2c..00000000 --- a/src/main/java/dev/notalpha/dashloader/misc/RegistryUtil.java +++ /dev/null @@ -1,21 +0,0 @@ -package dev.notalpha.dashloader.misc; - -public class RegistryUtil { - public static int createId(int objectPos, byte chunkPos) { - if (chunkPos > 0b111111) { - throw new IllegalStateException("Chunk pos is too big. " + chunkPos + " > " + 0x3f); - } - if (objectPos > 0x3ffffff) { - throw new IllegalStateException("Object pos is too big. " + objectPos + " > " + 0x3ffffff); - } - return objectPos << 6 | (chunkPos & 0x3f); - } - - public static byte getChunkId(int id) { - return (byte) (id & 0x3f); - } - - public static int getObjectId(int id) { - return id >>> 6; - } -} diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontManagerAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontManagerAccessor.java deleted file mode 100644 index 7a60ccc9..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontManagerAccessor.java +++ /dev/null @@ -1,21 +0,0 @@ -package dev.notalpha.dashloader.mixin.accessor; - -import net.minecraft.client.font.FontManager; -import net.minecraft.client.font.FontStorage; -import net.minecraft.client.texture.TextureManager; -import net.minecraft.util.Identifier; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -import java.util.Map; - -@Mixin(FontManager.class) -public interface FontManagerAccessor { - - @Accessor - TextureManager getTextureManager(); - - @Accessor - Map getFontStorages(); - -} diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/UnicodeTextureFontAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/UnicodeTextureFontAccessor.java deleted file mode 100644 index 7f854bb9..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/UnicodeTextureFontAccessor.java +++ /dev/null @@ -1,24 +0,0 @@ -package dev.notalpha.dashloader.mixin.accessor; - -import net.minecraft.client.font.UnicodeTextureFont; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Mutable; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Mixin(UnicodeTextureFont.class) -public interface UnicodeTextureFontAccessor { - - @Accessor - byte[] getSizes(); - - @Accessor - UnicodeTextureFont.FontImage[] getFontImages(); - - @Mutable - @Accessor - void setSizes(byte[] sizes); - - @Accessor - @Mutable - void setFontImages(UnicodeTextureFont.FontImage[] fontImages); -} diff --git a/src/main/java/dev/notalpha/dashloader/mixin/option/cache/font/FontManagerOverride.java b/src/main/java/dev/notalpha/dashloader/mixin/option/cache/font/FontManagerOverride.java deleted file mode 100644 index adf926c6..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/option/cache/font/FontManagerOverride.java +++ /dev/null @@ -1,109 +0,0 @@ -package dev.notalpha.dashloader.mixin.option.cache.font; - -import dev.notalpha.dashloader.DashLoader; -import dev.notalpha.dashloader.api.cache.CacheStatus; -import dev.notalpha.dashloader.client.font.FontModule; -import dev.notalpha.dashloader.mixin.accessor.FontManagerAccessor; -import dev.notalpha.dashloader.mixin.accessor.FontStorageAccessor; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import net.minecraft.client.font.BuiltinEmptyGlyph; -import net.minecraft.client.font.Font; -import net.minecraft.client.font.FontManager; -import net.minecraft.client.font.FontStorage; -import net.minecraft.client.texture.TextureManager; -import net.minecraft.resource.ResourceManager; -import net.minecraft.util.Identifier; -import net.minecraft.util.profiler.Profiler; -import org.apache.commons.lang3.tuple.Pair; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import java.util.List; -import java.util.Map; - -@Mixin(targets = "net/minecraft/client/font/FontManager$1") -public class FontManagerOverride { - - @SuppressWarnings("UnresolvedMixinReference") - @Inject( - method = {"method_18638", "prepare*"}, - at = @At(value = "HEAD"), - cancellable = true - ) - private void overridePrepare(ResourceManager resourceManager, Profiler profiler, CallbackInfoReturnable>> cir) { - FontModule.DATA.visit(CacheStatus.LOAD, data -> { - DashLoader.LOG.info("Preparing fonts"); - Map> out = new Object2ObjectOpenHashMap<>(); - data.forEach( - (identifier, int2ObjectMapListPair) -> out.put(identifier, int2ObjectMapListPair.getValue()) - ); - cir.setReturnValue(out); - }); - } - - @SuppressWarnings("UnresolvedMixinReference") - @Inject( - method = {"method_18635", "apply*"}, - at = @At(value = "HEAD"), - cancellable = true - ) - private void overrideApply(Map> map, ResourceManager resourceManager, Profiler profiler, CallbackInfo ci) { - FontModule.DATA.visit(CacheStatus.LOAD, data -> { - profiler.startTick(); - profiler.push("closing"); - final FontManagerAccessor fontManagerAccessor = (FontManagerAccessor) FontModule.FONTMANAGER; - final Map fontStorages = fontManagerAccessor.getFontStorages(); - - fontStorages.values().forEach(FontStorage::close); - fontStorages.clear(); - - DashLoader.LOG.info("Applying fonts off-thread"); - profiler.swap("reloading"); - data.forEach((identifier, entry) -> { - FontStorage fontStorage = new FontStorage(fontManagerAccessor.getTextureManager(), identifier); - FontStorageAccessor access = (FontStorageAccessor) fontStorage; - access.callCloseFonts(); - access.callCloseGlyphAtlases(); - access.getGlyphRendererCache().clear(); - access.getGlyphCache().clear(); - access.getCharactersByWidth().clear(); - access.setBlankGlyphRenderer(BuiltinEmptyGlyph.MISSING.bake(access::callGetGlyphRenderer)); - access.setWhiteRectangleGlyphRenderer(BuiltinEmptyGlyph.WHITE.bake(access::callGetGlyphRenderer)); - - access.getCharactersByWidth().putAll(entry.getKey()); - access.getFonts().addAll(entry.getValue()); - fontStorages.put(identifier, fontStorage); - }); - - profiler.pop(); - profiler.endTick(); - ci.cancel(); - }); - } - - @SuppressWarnings("UnresolvedMixinReference") - @Inject(method = {"method_18635", "apply*"}, at = @At(value = "TAIL")) - private void applyInject(Map> map, ResourceManager resourceManager, Profiler profiler, CallbackInfo ci) { - FontModule.DATA.visit(CacheStatus.SAVE, data -> { - data.clear(); - final FontManagerAccessor fontManagerAccessor = (FontManagerAccessor) FontModule.FONTMANAGER; - final Map fontStorages = fontManagerAccessor.getFontStorages(); - fontStorages.forEach((identifier, fontStorage) -> { - var access = ((FontStorageAccessor) fontStorage); - data.put(identifier, Pair.of(access.getCharactersByWidth(), access.getFonts())); - }); - }); - } - - @Mixin(FontManager.class) - private static class LeoFontSolution { - @Inject(method = "", at = @At(value = "TAIL")) - private void initInject(TextureManager manager, CallbackInfo ci) { - FontModule.FONTMANAGER = ((FontManager) (Object) this); - } - } - -} diff --git a/src/main/java/dev/notalpha/dashloader/mixin/option/cache/sprite/SpriteLoaderMixin.java b/src/main/java/dev/notalpha/dashloader/mixin/option/cache/sprite/SpriteLoaderMixin.java deleted file mode 100644 index a23bac3a..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/option/cache/sprite/SpriteLoaderMixin.java +++ /dev/null @@ -1,62 +0,0 @@ -package dev.notalpha.dashloader.mixin.option.cache.sprite; - -import dev.notalpha.dashloader.api.cache.CacheStatus; -import dev.notalpha.dashloader.client.sprite.SpriteModule; -import net.minecraft.client.texture.SpriteLoader; -import net.minecraft.resource.ResourceManager; -import net.minecraft.util.Identifier; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; - -@Mixin(SpriteLoader.class) -public final class SpriteLoaderMixin { - - @Shadow @Final private Identifier id; - - @Inject( - method = "method_47661", - at = @At(value = "RETURN"), - cancellable = true - ) - private void dashloaderWrite(ResourceManager resourceManager, Identifier identifier, int i, Executor executor, CallbackInfoReturnable> cir) { - SpriteModule.ATLASES.visit(CacheStatus.SAVE, map -> { - SpriteModule.ATLAS_IDS.get(CacheStatus.SAVE).put(id, identifier); - cir.setReturnValue(cir.getReturnValue().thenApply(stitchResult -> { - map.put(identifier, stitchResult); - return stitchResult; - })); - }); - } - - @Inject( - method = "method_47661", - at = @At(value = "HEAD"), - cancellable = true - ) - private void dashloaderRead(ResourceManager resourceManager, Identifier identifier, int m, Executor executor, CallbackInfoReturnable> cir) { - SpriteModule.ATLASES.visit(CacheStatus.LOAD, map -> { - SpriteLoader.StitchResult cached = map.get(identifier); - if (cached != null) { - int mipLevel = cached.mipLevel(); - // Correct the executor - CompletableFuture completableFuture = mipLevel > 0 ? CompletableFuture.runAsync(() -> cached.regions().values().forEach(sprite -> sprite.getContents().generateMipmaps(mipLevel)), executor) : CompletableFuture.completedFuture(null); - cir.setReturnValue(CompletableFuture.completedFuture(new SpriteLoader.StitchResult( - cached.width(), - cached.height(), - mipLevel, - cached.missing(), - cached.regions(), - completableFuture - ))); - cir.cancel(); - } - }); - } -} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json deleted file mode 100644 index e531c95d..00000000 --- a/src/main/resources/fabric.mod.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "schemaVersion" : 1, - "id" : "dashloader", - "version" : "${version}", - "name" : "DashLoader", - "description" : "Launch at the speed of Light.", - "authors" : [ - "!alpha", - "leocth" - ], - "contact" : { - "homepage" : "https://discord.gg/VeFTrtCkrb", - "sources" : "https://github.com/QuantumFusionMC/DashLoader-Definition" - }, - "entrypoints": { - "dashloader": [ - "dev.notalpha.dashloader.client.DashLoaderClient" - ] - }, - "license" : "LGPL-3.0-only", - "icon" : "dashloader/textures/icon.png", - "environment" : "client", - "accessWidener" : "dashloader.accesswidener", - "mixins" : [ - "dashloader.mixins.json" - ], - "depends" : { - "fabricloader" : ">=0.11.3", - "minecraft" : "1.19.x", - "java" : ">=17" - }, - "custom": { - "dashloader:disableoption": [ - ] - }, - "breaks" : { - "sodium" : "<=0.1.0", - "fabric-api" : "<0.81.0" - } -} \ No newline at end of file