From 7be0ec9d4910d9deb121fadf5e143ef5d7419f44 Mon Sep 17 00:00:00 2001 From: ShuyanMC <1149461164@qq.com> Date: Thu, 31 Jul 2025 23:38:28 +0800 Subject: [PATCH 01/17] Delete .github directory --- .github/FUNDING.yml | 12 ------- .github/ISSUE_TEMPLATE/LAUNCH_ISSUE.yaml | 46 ------------------------ .github/ISSUE_TEMPLATE/bug_report.md | 31 ---------------- 3 files changed, 89 deletions(-) delete mode 100644 .github/FUNDING.yml delete mode 100644 .github/ISSUE_TEMPLATE/LAUNCH_ISSUE.yaml delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md 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. From ab05e98b9a12a5f153ca1bd1453cbe34d0dc2fdc Mon Sep 17 00:00:00 2001 From: ShuyanMC <1149461164@qq.com> Date: Thu, 31 Jul 2025 23:38:40 +0800 Subject: [PATCH 02/17] Delete gradle directory --- gradle/wrapper/gradle-wrapper.jar | Bin 59536 -> 0 bytes gradle/wrapper/gradle-wrapper.properties | 5 ----- 2 files changed, 5 deletions(-) delete mode 100755 gradle/wrapper/gradle-wrapper.jar delete mode 100644 gradle/wrapper/gradle-wrapper.properties diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar deleted file mode 100755 index 7454180f2ae8848c63b8b4dea2cb829da983f2fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59536 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 QuEJmfE|#`Dqx|px0L@K;Y5)KL diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index e750102e..00000000 --- a/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists From d3a54fc9318b69685006dc0e53aa51e7c1bd7cf3 Mon Sep 17 00:00:00 2001 From: ShuyanMC <1149461164@qq.com> Date: Thu, 31 Jul 2025 23:38:49 +0800 Subject: [PATCH 03/17] Delete src directory --- .../java/dev/notalpha/dashloader/Cache.java | 221 --------------- .../dev/notalpha/dashloader/CacheFactory.java | 67 ----- .../dev/notalpha/dashloader/DashLoader.java | 55 ---- .../notalpha/dashloader/DashObjectClass.java | 80 ------ .../dashloader/api/DashEntrypoint.java | 7 - .../notalpha/dashloader/api/DashObject.java | 29 -- .../dashloader/api/RegistryReader.java | 12 - .../dashloader/api/RegistryWriter.java | 11 - .../dashloader/api/cache/CacheStatus.java | 16 -- .../dashloader/api/cache/CachingData.java | 75 ----- .../dashloader/api/cache/DashCache.java | 8 - .../api/cache/DashCacheFactory.java | 14 - .../dashloader/api/cache/DashModule.java | 23 -- .../dashloader/api/collection/IntIntList.java | 26 -- .../api/collection/IntObjectList.java | 26 -- .../api/collection/ObjectIntList.java | 26 -- .../api/collection/ObjectObjectList.java | 22 -- .../dashloader/client/DashLoaderClient.java | 113 -------- .../client/blockstate/DashBlockState.java | 86 ------ .../client/font/DashBitmapFont.java | 36 --- .../client/font/DashBitmapFontGlyph.java | 44 --- .../dashloader/client/font/DashBlankFont.java | 12 - .../dashloader/client/font/DashSpaceFont.java | 38 --- .../client/font/DashTrueTypeFont.java | 90 ------ .../client/font/DashUnicodeFont.java | 50 ---- .../dashloader/client/font/FontModule.java | 101 ------- .../client/identifier/DashIdentifier.java | 44 --- .../identifier/DashModelIdentifier.java | 50 ---- .../client/model/DashBasicBakedModel.java | 115 -------- .../client/model/DashBuiltinBakedModel.java | 68 ----- .../client/model/DashMultipartBakedModel.java | 113 -------- .../client/model/DashWeightedBakedModel.java | 52 ---- .../dashloader/client/model/ModelModule.java | 146 ---------- .../model/components/BakedQuadCollection.java | 13 - .../model/components/DashBakedQuad.java | 58 ---- .../components/DashBakedQuadCollection.java | 48 ---- .../client/model/components/DashMesh.java | 85 ------ .../components/DashModelOverrideList.java | 73 ----- .../DashModelOverrideListBakedOverride.java | 62 ---- ...DashModelOverrideListInlinedCondition.java | 40 --- .../components/DashModelTransformation.java | 134 --------- .../components/DashWeightedModelEntry.java | 46 --- .../model/fallback/UnbakedBakedModel.java | 43 --- .../model/predicates/BooleanSelector.java | 25 -- .../model/predicates/DashAndPredicate.java | 61 ---- .../model/predicates/DashOrPredicate.java | 62 ---- .../model/predicates/DashSimplePredicate.java | 46 --- .../model/predicates/DashStaticPredicate.java | 36 --- .../client/shader/DashGlBlendState.java | 45 --- .../client/shader/DashGlUniform.java | 44 --- .../dashloader/client/shader/DashShader.java | 154 ---------- .../client/shader/DashShaderStage.java | 54 ---- .../client/shader/DashVertexFormat.java | 80 ------ .../shader/DashVertexFormatElement.java | 78 ----- .../client/shader/ShaderModule.java | 71 ----- .../client/splash/SplashModule.java | 57 ---- .../dashloader/client/sprite/DashImage.java | 55 ---- .../dashloader/client/sprite/DashSprite.java | 73 ----- .../client/sprite/DashSpriteAnimation.java | 69 ----- .../sprite/DashSpriteAnimationFrame.java | 45 --- .../client/sprite/DashSpriteContents.java | 79 ------ .../client/sprite/DashStitchResult.java | 87 ------ .../client/sprite/SpriteModule.java | 69 ----- .../notalpha/dashloader/client/ui/Color.java | 45 --- .../dashloader/client/ui/DashToast.java | 267 ------------------ .../dashloader/client/ui/DashToastState.java | 126 --------- .../dashloader/client/ui/DashToastStatus.java | 7 - .../dashloader/client/ui/DrawerUtil.java | 157 ---------- .../notalpha/dashloader/config/Config.java | 17 -- .../dashloader/config/ConfigHandler.java | 99 ------- .../notalpha/dashloader/config/Option.java | 33 --- .../dev/notalpha/dashloader/io/IOHelper.java | 139 --------- .../dashloader/io/MappingSerializer.java | 130 --------- .../dashloader/io/RegistrySerializer.java | 223 --------------- .../notalpha/dashloader/io/Serializer.java | 77 ----- .../dashloader/io/data/CacheInfo.java | 30 -- .../dashloader/io/data/ChunkInfo.java | 21 -- .../io/data/fragment/CacheFragment.java | 24 -- .../io/data/fragment/ChunkFragment.java | 15 - .../io/data/fragment/FragmentSlice.java | 21 -- .../io/data/fragment/StageFragment.java | 24 -- .../io/def/DataUnsafeByteBuffer.java | 14 - .../dashloader/io/def/NativeImageData.java | 15 - .../dashloader/io/def/NativeImageDataDef.java | 93 ------ .../dashloader/io/fragment/Fragment.java | 27 -- .../dashloader/io/fragment/Piece.java | 51 ---- .../dashloader/io/fragment/SimplePiece.java | 22 -- .../dashloader/io/fragment/SizePiece.java | 17 -- .../notalpha/dashloader/misc/HahaManager.java | 80 ------ .../dashloader/misc/ObjectDumper.java | 117 -------- .../dashloader/misc/ProfilerUtil.java | 25 -- .../dashloader/misc/RegistryUtil.java | 21 -- .../dashloader/misc/UnsafeHelper.java | 41 --- .../notalpha/dashloader/misc/UnsafeImage.java | 27 -- .../dashloader/mixin/MixinPlugin.java | 47 --- .../accessor/AbstractTextureAccessor.java | 21 -- .../AndMultipartModelSelectorAccessor.java | 14 - .../accessor/BasicBakedModelAccessor.java | 41 --- .../mixin/accessor/BitmapFontAccessor.java | 24 -- .../accessor/BitmapFontGlyphAccessor.java | 41 --- .../accessor/BuiltinBakedModelAccessor.java | 25 -- .../accessor/EffectShaderStageAccessor.java | 14 - .../mixin/accessor/FontImageAccessor.java | 19 -- .../mixin/accessor/FontManagerAccessor.java | 21 -- .../mixin/accessor/FontStorageAccessor.java | 40 --- .../mixin/accessor/GlBlendStateAccessor.java | 38 --- .../mixin/accessor/GlUniformAccessor.java | 30 -- .../mixin/accessor/IdentifierAccessor.java | 15 - .../accessor/ModelIdentifierAccessor.java | 15 - .../mixin/accessor/ModelLoaderAccessor.java | 26 -- .../accessor/ModelOverrideListAccessor.java | 32 --- ...odelOverrideListBakedOverrideAccessor.java | 23 -- .../ModelOverrideListInlinedCondition.java | 16 -- .../accessor/MultipartBakedModelAccessor.java | 37 --- .../MultipartModelComponentAccessor.java | 13 - .../mixin/accessor/NativeImageAccessor.java | 22 -- .../OrMultipartModelSelectorAccessor.java | 14 - .../mixin/accessor/ShaderProgramAccessor.java | 101 ------- .../mixin/accessor/ShaderStageAccessor.java | 27 -- .../SimpleMultipartModelSelectorAccessor.java | 16 -- .../mixin/accessor/SpriteAccessor.java | 16 -- .../accessor/SpriteAnimationAccessor.java | 28 -- .../SpriteAnimationFrameAccessor.java | 21 -- .../accessor/SpriteContentsAccessor.java | 46 --- .../SpriteLoaderStitchResultAccessor.java | 20 -- .../mixin/accessor/TrueTypeFontAccessor.java | 68 ----- .../accessor/UnicodeTextureFontAccessor.java | 24 -- .../mixin/accessor/VertexFormatAccessor.java | 14 - .../accessor/WeightedBakedModelAccessor.java | 16 -- .../WeightedBakedModelEntryAccessor.java | 14 - .../accessor/ZipResourcePackAccessor.java | 13 - .../dashloader/mixin/main/BootstrapMixin.java | 25 -- .../dashloader/mixin/main/KeyboardMixin.java | 43 --- .../dashloader/mixin/main/MainMixin.java | 24 -- .../mixin/main/MinecraftClientMixin.java | 37 --- .../ReloadableResourceManagerImplMixin.java | 55 ---- .../mixin/main/SplashScreenMixin.java | 110 -------- .../mixin/option/WallBlockMixin.java | 164 ----------- .../SplashTextResourceSupplierMixin.java | 37 --- .../cache/font/FontManagerOverride.java | 109 ------- .../cache/font/TrueTypeFontLoaderMixin.java | 34 --- .../model/BakedModelManagerOverride.java | 34 --- .../option/cache/model/BlockModelsMixin.java | 30 -- .../option/cache/model/ModelLoaderMixin.java | 111 -------- .../model/MultipartUnbakedModelMixin.java | 55 ---- .../cache/shader/GameRendererMixin.java | 41 --- .../cache/shader/GlStateManagerMixin.java | 27 -- .../cache/sprite/SpriteLoaderMixin.java | 62 ---- .../misc/AffineTransformationMixin.java | 31 -- .../mixin/option/misc/MipmapHelperMixin.java | 142 ---------- .../option/misc/ModelIdentifierMixin.java | 35 --- .../ModelLoaderBakedModelCacheKeyMixin.java | 41 --- .../dashloader/registry/FactoryBinding.java | 96 ------- .../dashloader/registry/MissingHandler.java | 16 -- .../registry/RegistryAddException.java | 17 -- .../dashloader/registry/RegistryFactory.java | 170 ----------- .../registry/RegistryReaderImpl.java | 46 --- .../registry/TrackedRegistryFactory.java | 38 --- .../dashloader/registry/data/ChunkData.java | 50 ---- .../registry/data/ChunkFactory.java | 67 ----- .../dashloader/registry/data/StageData.java | 32 --- .../thread/IndexedArrayMapTask.java | 48 ---- .../dashloader/thread/ThreadHandler.java | 52 ---- src/main/resources/dashloader.accesswidener | 27 -- src/main/resources/dashloader.mixins.json | 74 ----- src/main/resources/dashloader/lang/en_us.json | 11 - .../resources/dashloader/lang/lol_us.json | 11 - src/main/resources/dashloader/lang/sv_se.json | 11 - .../resources/dashloader/textures/icon.png | Bin 18600 -> 0 bytes src/main/resources/fabric.mod.json | 40 --- 170 files changed, 8838 deletions(-) delete mode 100644 src/main/java/dev/notalpha/dashloader/Cache.java delete mode 100644 src/main/java/dev/notalpha/dashloader/CacheFactory.java delete mode 100644 src/main/java/dev/notalpha/dashloader/DashLoader.java delete mode 100644 src/main/java/dev/notalpha/dashloader/DashObjectClass.java delete mode 100644 src/main/java/dev/notalpha/dashloader/api/DashEntrypoint.java delete mode 100644 src/main/java/dev/notalpha/dashloader/api/DashObject.java delete mode 100644 src/main/java/dev/notalpha/dashloader/api/RegistryReader.java delete mode 100644 src/main/java/dev/notalpha/dashloader/api/RegistryWriter.java delete mode 100644 src/main/java/dev/notalpha/dashloader/api/cache/CacheStatus.java delete mode 100644 src/main/java/dev/notalpha/dashloader/api/cache/CachingData.java delete mode 100644 src/main/java/dev/notalpha/dashloader/api/cache/DashCache.java delete mode 100644 src/main/java/dev/notalpha/dashloader/api/cache/DashCacheFactory.java delete mode 100644 src/main/java/dev/notalpha/dashloader/api/cache/DashModule.java delete mode 100644 src/main/java/dev/notalpha/dashloader/api/collection/IntIntList.java delete mode 100644 src/main/java/dev/notalpha/dashloader/api/collection/IntObjectList.java delete mode 100644 src/main/java/dev/notalpha/dashloader/api/collection/ObjectIntList.java delete mode 100644 src/main/java/dev/notalpha/dashloader/api/collection/ObjectObjectList.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/DashLoaderClient.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/blockstate/DashBlockState.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFont.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFontGlyph.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/font/DashBlankFont.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/font/DashSpaceFont.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/font/DashTrueTypeFont.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/font/DashUnicodeFont.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/font/FontModule.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/identifier/DashIdentifier.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/identifier/DashModelIdentifier.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/model/DashBasicBakedModel.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/model/DashBuiltinBakedModel.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/model/DashMultipartBakedModel.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/model/DashWeightedBakedModel.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/model/ModelModule.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/model/components/BakedQuadCollection.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuad.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuadCollection.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/model/components/DashMesh.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideList.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListBakedOverride.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListInlinedCondition.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/model/components/DashModelTransformation.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/model/components/DashWeightedModelEntry.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/model/fallback/UnbakedBakedModel.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/model/predicates/BooleanSelector.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/model/predicates/DashAndPredicate.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/model/predicates/DashOrPredicate.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/model/predicates/DashSimplePredicate.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/model/predicates/DashStaticPredicate.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/shader/DashGlBlendState.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/shader/DashGlUniform.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/shader/DashShader.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/shader/DashShaderStage.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormat.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormatElement.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/shader/ShaderModule.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/splash/SplashModule.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/sprite/DashImage.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/sprite/DashSprite.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimation.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimationFrame.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteContents.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/sprite/DashStitchResult.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/sprite/SpriteModule.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/ui/Color.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/ui/DashToast.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/ui/DashToastState.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/ui/DashToastStatus.java delete mode 100644 src/main/java/dev/notalpha/dashloader/client/ui/DrawerUtil.java delete mode 100644 src/main/java/dev/notalpha/dashloader/config/Config.java delete mode 100644 src/main/java/dev/notalpha/dashloader/config/ConfigHandler.java delete mode 100644 src/main/java/dev/notalpha/dashloader/config/Option.java delete mode 100644 src/main/java/dev/notalpha/dashloader/io/IOHelper.java delete mode 100644 src/main/java/dev/notalpha/dashloader/io/MappingSerializer.java delete mode 100644 src/main/java/dev/notalpha/dashloader/io/RegistrySerializer.java delete mode 100644 src/main/java/dev/notalpha/dashloader/io/Serializer.java delete mode 100644 src/main/java/dev/notalpha/dashloader/io/data/CacheInfo.java delete mode 100644 src/main/java/dev/notalpha/dashloader/io/data/ChunkInfo.java delete mode 100644 src/main/java/dev/notalpha/dashloader/io/data/fragment/CacheFragment.java delete mode 100644 src/main/java/dev/notalpha/dashloader/io/data/fragment/ChunkFragment.java delete mode 100644 src/main/java/dev/notalpha/dashloader/io/data/fragment/FragmentSlice.java delete mode 100644 src/main/java/dev/notalpha/dashloader/io/data/fragment/StageFragment.java delete mode 100644 src/main/java/dev/notalpha/dashloader/io/def/DataUnsafeByteBuffer.java delete mode 100644 src/main/java/dev/notalpha/dashloader/io/def/NativeImageData.java delete mode 100644 src/main/java/dev/notalpha/dashloader/io/def/NativeImageDataDef.java delete mode 100644 src/main/java/dev/notalpha/dashloader/io/fragment/Fragment.java delete mode 100644 src/main/java/dev/notalpha/dashloader/io/fragment/Piece.java delete mode 100644 src/main/java/dev/notalpha/dashloader/io/fragment/SimplePiece.java delete mode 100644 src/main/java/dev/notalpha/dashloader/io/fragment/SizePiece.java delete mode 100644 src/main/java/dev/notalpha/dashloader/misc/HahaManager.java delete mode 100644 src/main/java/dev/notalpha/dashloader/misc/ObjectDumper.java delete mode 100644 src/main/java/dev/notalpha/dashloader/misc/ProfilerUtil.java delete mode 100644 src/main/java/dev/notalpha/dashloader/misc/RegistryUtil.java delete mode 100644 src/main/java/dev/notalpha/dashloader/misc/UnsafeHelper.java delete mode 100644 src/main/java/dev/notalpha/dashloader/misc/UnsafeImage.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/MixinPlugin.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/AbstractTextureAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/AndMultipartModelSelectorAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/BasicBakedModelAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontGlyphAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/BuiltinBakedModelAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/EffectShaderStageAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/FontImageAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/FontManagerAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/FontStorageAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/GlBlendStateAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/GlUniformAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/IdentifierAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelIdentifierAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelLoaderAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListBakedOverrideAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListInlinedCondition.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartBakedModelAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartModelComponentAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/NativeImageAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/OrMultipartModelSelectorAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderProgramAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderStageAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/SimpleMultipartModelSelectorAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationFrameAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteContentsAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteLoaderStitchResultAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/TrueTypeFontAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/UnicodeTextureFontAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/VertexFormatAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelEntryAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/accessor/ZipResourcePackAccessor.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/main/BootstrapMixin.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/main/KeyboardMixin.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/main/MainMixin.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/main/MinecraftClientMixin.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/main/ReloadableResourceManagerImplMixin.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/main/SplashScreenMixin.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/option/WallBlockMixin.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/option/cache/SplashTextResourceSupplierMixin.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/option/cache/font/FontManagerOverride.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/option/cache/font/TrueTypeFontLoaderMixin.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/BakedModelManagerOverride.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/BlockModelsMixin.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/ModelLoaderMixin.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/MultipartUnbakedModelMixin.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/option/cache/shader/GameRendererMixin.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/option/cache/shader/GlStateManagerMixin.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/option/cache/sprite/SpriteLoaderMixin.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/option/misc/AffineTransformationMixin.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/option/misc/MipmapHelperMixin.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelIdentifierMixin.java delete mode 100644 src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelLoaderBakedModelCacheKeyMixin.java delete mode 100644 src/main/java/dev/notalpha/dashloader/registry/FactoryBinding.java delete mode 100644 src/main/java/dev/notalpha/dashloader/registry/MissingHandler.java delete mode 100644 src/main/java/dev/notalpha/dashloader/registry/RegistryAddException.java delete mode 100644 src/main/java/dev/notalpha/dashloader/registry/RegistryFactory.java delete mode 100644 src/main/java/dev/notalpha/dashloader/registry/RegistryReaderImpl.java delete mode 100644 src/main/java/dev/notalpha/dashloader/registry/TrackedRegistryFactory.java delete mode 100644 src/main/java/dev/notalpha/dashloader/registry/data/ChunkData.java delete mode 100644 src/main/java/dev/notalpha/dashloader/registry/data/ChunkFactory.java delete mode 100644 src/main/java/dev/notalpha/dashloader/registry/data/StageData.java delete mode 100644 src/main/java/dev/notalpha/dashloader/thread/IndexedArrayMapTask.java delete mode 100644 src/main/java/dev/notalpha/dashloader/thread/ThreadHandler.java delete mode 100644 src/main/resources/dashloader.accesswidener delete mode 100644 src/main/resources/dashloader.mixins.json delete mode 100644 src/main/resources/dashloader/lang/en_us.json delete mode 100644 src/main/resources/dashloader/lang/lol_us.json delete mode 100644 src/main/resources/dashloader/lang/sv_se.json delete mode 100644 src/main/resources/dashloader/textures/icon.png delete mode 100644 src/main/resources/fabric.mod.json diff --git a/src/main/java/dev/notalpha/dashloader/Cache.java b/src/main/java/dev/notalpha/dashloader/Cache.java deleted file mode 100644 index 82ccfec9..00000000 --- a/src/main/java/dev/notalpha/dashloader/Cache.java +++ /dev/null @@ -1,221 +0,0 @@ -package dev.notalpha.dashloader; - -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.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 Cache implements DashCache { - 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; - - Cache(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 start() { - if (this.exists()) { - this.setStatus(CacheStatus.LOAD); - this.load(); - } else { - this.setStatus(CacheStatus.SAVE); - } - } - - public boolean save(@Nullable Consumer taskConsumer) { - DashLoader.LOG.info("Starting DashLoader Caching"); - try { - if (status != CacheStatus.SAVE) { - throw new RuntimeException("Status is not SAVE"); - } - - 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); - } - - RegistryFactory factory = RegistryFactory.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.clear(); - return false; - } - } - - public void load() { - this.status = CacheStatus.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.clear(); - 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.clear(); - } - } - - 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() { - try { - FileUtils.deleteDirectory(this.getDir().toFile()); - } catch (IOException e) { - e.printStackTrace(); - } - } - - public Path getDir() { - if (hash == null) { - throw new RuntimeException("Cache hash has not been set."); - } - return cacheDir.resolve(hash + "/"); - } - - - public 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/CacheFactory.java b/src/main/java/dev/notalpha/dashloader/CacheFactory.java deleted file mode 100644 index 869a2145..00000000 --- a/src/main/java/dev/notalpha/dashloader/CacheFactory.java +++ /dev/null @@ -1,67 +0,0 @@ -package dev.notalpha.dashloader; - -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 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 CacheFactory implements DashCacheFactory { - private static final Logger LOGGER = LogManager.getLogger("CacherFactory"); - private final List> dashObjects; - private final List> modules; - private final List> missingHandlers; - private boolean failed = false; - - public CacheFactory() { - this.dashObjects = new ArrayList<>(); - this.modules = new ArrayList<>(); - this.missingHandlers = new ArrayList<>(); - } - - 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)); - } - - public void addModule(DashModule handler) { - this.modules.add(handler); - } - - @Override - public void addMissingHandler(Class parentClass, BiFunction> func) { - this.missingHandlers.add(new MissingHandler<>(parentClass, func)); - } - - 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())); - 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; - } - - return new Cache(cacheDir.resolve(DashLoader.MOD_HASH + "/"), modules, dashObjects, missingHandlers); - - } -} \ No newline at end of file diff --git a/src/main/java/dev/notalpha/dashloader/DashLoader.java b/src/main/java/dev/notalpha/dashloader/DashLoader.java deleted file mode 100644 index bb0fc536..00000000 --- a/src/main/java/dev/notalpha/dashloader/DashLoader.java +++ /dev/null @@ -1,55 +0,0 @@ -package dev.notalpha.dashloader; - -import dev.notalpha.dashloader.io.Serializer; -import dev.notalpha.dashloader.io.data.CacheInfo; -import net.fabricmc.loader.api.FabricLoader; -import net.fabricmc.loader.api.ModContainer; -import net.fabricmc.loader.api.metadata.ModMetadata; -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 class DashLoader { - private static final String VERSION = FabricLoader.getInstance() - .getModContainer("dashloader") - .orElseThrow(() -> new IllegalStateException("DashLoader not found... apparently! WTF?")) - .getMetadata() - .getVersion() - .getFriendlyString(); - 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/src/main/java/dev/notalpha/dashloader/DashObjectClass.java b/src/main/java/dev/notalpha/dashloader/DashObjectClass.java deleted file mode 100644 index e194a8c2..00000000 --- a/src/main/java/dev/notalpha/dashloader/DashObjectClass.java +++ /dev/null @@ -1,80 +0,0 @@ -package dev.notalpha.dashloader; - -import dev.notalpha.dashloader.api.DashObject; -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; - Class[] interfaces = this.dashClass.getInterfaces(); - for (int i = 0; i < interfaces.length; i++) { - if (interfaces[i] == 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 { - throw new RuntimeException(this.dashClass + " has a non resolvable DashObject parameter"); - } - } 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/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/CachingData.java b/src/main/java/dev/notalpha/dashloader/api/cache/CachingData.java deleted file mode 100644 index 35e4f279..00000000 --- a/src/main/java/dev/notalpha/dashloader/api/cache/CachingData.java +++ /dev/null @@ -1,75 +0,0 @@ -package dev.notalpha.dashloader.api.cache; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.function.Consumer; - -public class CachingData { - @Nullable - private D data; - - private DashCache cache; - - @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(DashCache cache, @NotNull D data) { - this.cache = cache; - set(cache.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 (cache == null) { - throw new RuntimeException("cacheManager is null. This OptionData has never been reset in its handler."); - } - - CacheStatus currentStatus = cache.getStatus(); - if (status == currentStatus) { - this.dataStatus = status; - this.data = data; - } - } - - public boolean active(CacheStatus status) { - return status == this.dataStatus && status == cache.getStatus() && this.data != null && (onlyOn == null || onlyOn == status); - } -} 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/api/collection/IntIntList.java b/src/main/java/dev/notalpha/dashloader/api/collection/IntIntList.java deleted file mode 100644 index 6a82ada4..00000000 --- a/src/main/java/dev/notalpha/dashloader/api/collection/IntIntList.java +++ /dev/null @@ -1,26 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/api/collection/IntObjectList.java b/src/main/java/dev/notalpha/dashloader/api/collection/IntObjectList.java deleted file mode 100644 index 46f7104c..00000000 --- a/src/main/java/dev/notalpha/dashloader/api/collection/IntObjectList.java +++ /dev/null @@ -1,26 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/api/collection/ObjectIntList.java b/src/main/java/dev/notalpha/dashloader/api/collection/ObjectIntList.java deleted file mode 100644 index 2b1c0b41..00000000 --- a/src/main/java/dev/notalpha/dashloader/api/collection/ObjectIntList.java +++ /dev/null @@ -1,26 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/api/collection/ObjectObjectList.java b/src/main/java/dev/notalpha/dashloader/api/collection/ObjectObjectList.java deleted file mode 100644 index d9c0a48d..00000000 --- a/src/main/java/dev/notalpha/dashloader/api/collection/ObjectObjectList.java +++ /dev/null @@ -1,22 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/client/DashLoaderClient.java b/src/main/java/dev/notalpha/dashloader/client/DashLoaderClient.java deleted file mode 100644 index 96e548ab..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/DashLoaderClient.java +++ /dev/null @@ -1,113 +0,0 @@ -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.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.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.SpriteModule; -import net.fabricmc.loader.api.FabricLoader; -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.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); - for (DashEntrypoint entryPoint : entryPoints) { - entryPoint.onDashLoaderInit(cacheManagerFactory); - } - - CACHE = cacheManagerFactory.build(Path.of("./dashloader-cache/client/")); - } - - @Override - public void onDashLoaderInit(DashCacheFactory factory) { - factory.addModule(new FontModule()); - factory.addModule(new ModelModule()); - factory.addModule(new ShaderModule()); - factory.addModule(new SplashModule()); - factory.addModule(new SpriteModule()); - - 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) -> { - if (identifier instanceof ModelIdentifier m) { - return new DashModelIdentifier(m); - } else { - return new DashIdentifier(identifier); - } - } - ); - 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"); - } - } - ); - } -} diff --git a/src/main/java/dev/notalpha/dashloader/client/blockstate/DashBlockState.java b/src/main/java/dev/notalpha/dashloader/client/blockstate/DashBlockState.java deleted file mode 100644 index 2c04b8c8..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/blockstate/DashBlockState.java +++ /dev/null @@ -1,86 +0,0 @@ -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.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/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFont.java b/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFont.java deleted file mode 100644 index fe1386e2..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFont.java +++ /dev/null @@ -1,36 +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.api.collection.IntObjectList; -import dev.notalpha.dashloader.mixin.accessor.BitmapFontAccessor; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import net.minecraft.client.font.BitmapFont; - -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().forEach((integer, bitmapFontGlyph) -> this.glyphs.put(integer, new DashBitmapFontGlyph(bitmapFontGlyph, writer))); - } - - public BitmapFont export(RegistryReader reader) { - Int2ObjectOpenHashMap out = new Int2ObjectOpenHashMap<>(); - 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/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFontGlyph.java deleted file mode 100644 index 21e4be84..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFontGlyph.java +++ /dev/null @@ -1,44 +0,0 @@ -package dev.notalpha.dashloader.client.font; - -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.api.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/src/main/java/dev/notalpha/dashloader/client/font/DashBlankFont.java b/src/main/java/dev/notalpha/dashloader/client/font/DashBlankFont.java deleted file mode 100644 index d537e255..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/font/DashBlankFont.java +++ /dev/null @@ -1,12 +0,0 @@ -package dev.notalpha.dashloader.client.font; - -import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.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/src/main/java/dev/notalpha/dashloader/client/font/DashSpaceFont.java b/src/main/java/dev/notalpha/dashloader/client/font/DashSpaceFont.java deleted file mode 100644 index bb2432ab..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/font/DashSpaceFont.java +++ /dev/null @@ -1,38 +0,0 @@ -package dev.notalpha.dashloader.client.font; - -import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.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/src/main/java/dev/notalpha/dashloader/client/font/DashTrueTypeFont.java b/src/main/java/dev/notalpha/dashloader/client/font/DashTrueTypeFont.java deleted file mode 100644 index 5e9bbd28..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/font/DashTrueTypeFont.java +++ /dev/null @@ -1,90 +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.cache.CacheStatus; -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/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/identifier/DashIdentifier.java b/src/main/java/dev/notalpha/dashloader/client/identifier/DashIdentifier.java deleted file mode 100644 index f1d6bcbd..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/identifier/DashIdentifier.java +++ /dev/null @@ -1,44 +0,0 @@ -package dev.notalpha.dashloader.client.identifier; - -import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.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/src/main/java/dev/notalpha/dashloader/client/identifier/DashModelIdentifier.java b/src/main/java/dev/notalpha/dashloader/client/identifier/DashModelIdentifier.java deleted file mode 100644 index f046d3e2..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/identifier/DashModelIdentifier.java +++ /dev/null @@ -1,50 +0,0 @@ -package dev.notalpha.dashloader.client.identifier; - - -import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.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/src/main/java/dev/notalpha/dashloader/client/model/DashBasicBakedModel.java b/src/main/java/dev/notalpha/dashloader/client/model/DashBasicBakedModel.java deleted file mode 100644 index 4c82acda..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/model/DashBasicBakedModel.java +++ /dev/null @@ -1,115 +0,0 @@ -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.client.model.components.BakedQuadCollection; -import dev.notalpha.dashloader.client.model.components.DashModelOverrideList; -import dev.notalpha.dashloader.client.model.components.DashModelTransformation; -import dev.notalpha.dashloader.mixin.accessor.BasicBakedModelAccessor; -import dev.notalpha.hyphen.scan.annotations.DataNullable; -import net.minecraft.client.render.model.BakedQuad; -import net.minecraft.client.render.model.BasicBakedModel; -import net.minecraft.client.texture.Sprite; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.random.Random; - -import java.util.HashMap; -import java.util.List; -import java.util.Objects; - -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); - basicBakedModel.getQuads(null, null, Random.create()); - this.quads = writer.add(new BakedQuadCollection(access.getQuads())); - - this.faceQuads = new ObjectObjectList<>(); - access.getFaceQuads().forEach((direction, bakedQuads) -> { - this.faceQuads.put(direction, writer.add(new BakedQuadCollection(bakedQuads))); - }); - - 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 BasicBakedModel export(final RegistryReader reader) { - final Sprite sprite = reader.get(this.spritePointer); - - BakedQuadCollection collection = reader.get(this.quads); - var quadsOut = collection.quads; - - var faceQuadsOut = new HashMap>(); - for (var entry : this.faceQuads.list()) { - BakedQuadCollection collectionEntry = reader.get(entry.value()); - faceQuadsOut.put(entry.key(), collectionEntry.quads); - } - - return new BasicBakedModel(quadsOut, faceQuadsOut, this.usesAo, this.isSideLit, this.hasDepth, sprite, DashModelTransformation.exportOrDefault(this.transformation), this.itemPropertyOverrides.export(reader)); - } - - @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; - } -} diff --git a/src/main/java/dev/notalpha/dashloader/client/model/DashBuiltinBakedModel.java b/src/main/java/dev/notalpha/dashloader/client/model/DashBuiltinBakedModel.java deleted file mode 100644 index 0c450454..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/model/DashBuiltinBakedModel.java +++ /dev/null @@ -1,68 +0,0 @@ -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.client.model.components.DashModelOverrideList; -import dev.notalpha.dashloader.client.model.components.DashModelTransformation; -import dev.notalpha.dashloader.mixin.accessor.BuiltinBakedModelAccessor; -import dev.notalpha.hyphen.scan.annotations.DataNullable; -import net.minecraft.client.render.model.BuiltinBakedModel; -import net.minecraft.client.render.model.json.ModelTransformation; -import net.minecraft.client.texture.Sprite; - -import java.util.Objects; - -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 BuiltinBakedModel export(RegistryReader reader) { - Sprite sprite = reader.get(this.spritePointer); - return new BuiltinBakedModel(DashModelTransformation.exportOrDefault(this.transformation), this.itemPropertyOverrides.export(reader), 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; - } -} diff --git a/src/main/java/dev/notalpha/dashloader/client/model/DashMultipartBakedModel.java b/src/main/java/dev/notalpha/dashloader/client/model/DashMultipartBakedModel.java deleted file mode 100644 index 4b4ee118..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/model/DashMultipartBakedModel.java +++ /dev/null @@ -1,113 +0,0 @@ -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.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.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.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 MultipartBakedModel export(RegistryReader reader) { - List, BakedModel>> componentsOut = new ArrayList<>(this.components.size()); - this.components.forEach(component -> { - BakedModel 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)); - }); - - 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 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(); - } -} - diff --git a/src/main/java/dev/notalpha/dashloader/client/model/DashWeightedBakedModel.java b/src/main/java/dev/notalpha/dashloader/client/model/DashWeightedBakedModel.java deleted file mode 100644 index ef40e3e4..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/model/DashWeightedBakedModel.java +++ /dev/null @@ -1,52 +0,0 @@ -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.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 java.util.ArrayList; -import java.util.List; - -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 WeightedBakedModel export(RegistryReader reader) { - var modelsOut = new ArrayList>(); - for (DashWeightedModelEntry model : this.models) { - modelsOut.add(model.export(reader)); - } - return new WeightedBakedModel(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(); - } -} diff --git a/src/main/java/dev/notalpha/dashloader/client/model/ModelModule.java b/src/main/java/dev/notalpha/dashloader/client/model/ModelModule.java deleted file mode 100644 index b5ad45a6..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/model/ModelModule.java +++ /dev/null @@ -1,146 +0,0 @@ -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.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.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; -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(DashCache 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 writer, 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 = writer.add(bakedModel); - outModels.put(writer.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(writer.add(blockState), writer.add(modelId)); - } - }); - } - - return new Data(outModels, missingModels); - } - } - - @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); - Identifier identifier = reader.get(key); - out.put(identifier, new UnbakedBakedModel(model, identifier)); - }); - - var missingModelsRead = new HashMap(); - mappings.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/src/main/java/dev/notalpha/dashloader/client/model/components/BakedQuadCollection.java b/src/main/java/dev/notalpha/dashloader/client/model/components/BakedQuadCollection.java deleted file mode 100644 index 71266611..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/model/components/BakedQuadCollection.java +++ /dev/null @@ -1,13 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuad.java b/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuad.java deleted file mode 100644 index 1d0c7f9b..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuad.java +++ /dev/null @@ -1,58 +0,0 @@ -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 net.minecraft.client.render.model.BakedQuad; -import net.minecraft.util.math.Direction; - -import java.util.Arrays; - -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 BakedQuad export(RegistryReader handler) { - return new BakedQuad(this.vertexData, this.colorIndex, this.face, handler.get(this.sprite), this.shade); - } - - @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; - } -} diff --git a/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuadCollection.java b/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuadCollection.java deleted file mode 100644 index ee566fb4..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuadCollection.java +++ /dev/null @@ -1,48 +0,0 @@ -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 net.minecraft.client.render.model.BakedQuad; - -import java.util.ArrayList; -import java.util.List; - -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 BakedQuadCollection export(RegistryReader reader) { - var out = new ArrayList(this.quads.size()); - for (Integer quad : this.quads) { - out.add(reader.get(quad)); - } - return new BakedQuadCollection(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(); - } -} diff --git a/src/main/java/dev/notalpha/dashloader/client/model/components/DashMesh.java b/src/main/java/dev/notalpha/dashloader/client/model/components/DashMesh.java deleted file mode 100644 index 03025ffe..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/model/components/DashMesh.java +++ /dev/null @@ -1,85 +0,0 @@ -package dev.notalpha.dashloader.client.model.components; - -import dev.notalpha.dashloader.misc.UnsafeHelper; -import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh; - -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/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideList.java b/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideList.java deleted file mode 100644 index bb34f91d..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideList.java +++ /dev/null @@ -1,73 +0,0 @@ -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.ModelOverrideListAccessor; -import net.minecraft.client.render.model.json.ModelOverrideList; -import net.minecraft.util.Identifier; - -import java.util.Arrays; - -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 ModelOverrideList export(RegistryReader reader) { - var out = ModelOverrideListAccessor.newModelOverrideList(); - ModelOverrideListAccessor access = (ModelOverrideListAccessor) out; - - 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]; - for (int i = 0; i < this.overrides.length; i++) { - overridesOut[i] = this.overrides[i].export(reader); - } - - access.setConditionTypes(conditionTypesOut); - access.setOverrides(overridesOut); - return out; - } - - @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; - } -} diff --git a/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListBakedOverride.java b/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListBakedOverride.java deleted file mode 100644 index 00137154..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListBakedOverride.java +++ /dev/null @@ -1,62 +0,0 @@ -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.ModelOverrideListBakedOverrideAccessor; -import dev.notalpha.hyphen.scan.annotations.DataNullable; -import net.minecraft.client.render.model.BakedModel; -import net.minecraft.client.render.model.json.ModelOverrideList; -import org.jetbrains.annotations.Nullable; - -import java.util.Arrays; -import java.util.Objects; - -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 ModelOverrideList.BakedOverride 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)); - } - - @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; - } -} diff --git a/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListInlinedCondition.java b/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListInlinedCondition.java deleted file mode 100644 index 88ca2f05..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListInlinedCondition.java +++ /dev/null @@ -1,40 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelTransformation.java b/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelTransformation.java deleted file mode 100644 index cde1017c..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelTransformation.java +++ /dev/null @@ -1,134 +0,0 @@ -package dev.notalpha.dashloader.client.model.components; - -import dev.notalpha.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; - -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; - - 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/src/main/java/dev/notalpha/dashloader/client/model/components/DashWeightedModelEntry.java b/src/main/java/dev/notalpha/dashloader/client/model/components/DashWeightedModelEntry.java deleted file mode 100644 index da2bec08..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/model/components/DashWeightedModelEntry.java +++ /dev/null @@ -1,46 +0,0 @@ -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 net.minecraft.client.render.model.BakedModel; -import net.minecraft.util.collection.Weight; -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 Weighted.Present export(RegistryReader handler) { - //noinspection unchecked - return WeightedBakedModelEntryAccessor.init(handler.get(this.model), Weight.of(this.weight)); - } - - @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/src/main/java/dev/notalpha/dashloader/client/model/fallback/UnbakedBakedModel.java b/src/main/java/dev/notalpha/dashloader/client/model/fallback/UnbakedBakedModel.java deleted file mode 100644 index 04de939f..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/model/fallback/UnbakedBakedModel.java +++ /dev/null @@ -1,43 +0,0 @@ -package dev.notalpha.dashloader.client.model.fallback; - -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 extends JsonUnbakedModel implements UnbakedModel { - private final BakedModel 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(); - 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; - } -} diff --git a/src/main/java/dev/notalpha/dashloader/client/model/predicates/BooleanSelector.java b/src/main/java/dev/notalpha/dashloader/client/model/predicates/BooleanSelector.java deleted file mode 100644 index c699e8c8..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/model/predicates/BooleanSelector.java +++ /dev/null @@ -1,25 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashAndPredicate.java b/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashAndPredicate.java deleted file mode 100644 index 05797de3..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashAndPredicate.java +++ /dev/null @@ -1,61 +0,0 @@ -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.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/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashOrPredicate.java b/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashOrPredicate.java deleted file mode 100644 index f1f13920..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashOrPredicate.java +++ /dev/null @@ -1,62 +0,0 @@ -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.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/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashSimplePredicate.java b/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashSimplePredicate.java deleted file mode 100644 index cf72e8d5..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashSimplePredicate.java +++ /dev/null @@ -1,46 +0,0 @@ -package dev.notalpha.dashloader.client.model.predicates; - -import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.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/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashStaticPredicate.java b/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashStaticPredicate.java deleted file mode 100644 index c5681d36..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashStaticPredicate.java +++ /dev/null @@ -1,36 +0,0 @@ -package dev.notalpha.dashloader.client.model.predicates; - -import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.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/src/main/java/dev/notalpha/dashloader/client/shader/DashGlBlendState.java b/src/main/java/dev/notalpha/dashloader/client/shader/DashGlBlendState.java deleted file mode 100644 index 4f26f7ca..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/shader/DashGlBlendState.java +++ /dev/null @@ -1,45 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/client/shader/DashGlUniform.java b/src/main/java/dev/notalpha/dashloader/client/shader/DashGlUniform.java deleted file mode 100644 index 6b3c2a35..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/shader/DashGlUniform.java +++ /dev/null @@ -1,44 +0,0 @@ -package dev.notalpha.dashloader.client.shader; - -import dev.notalpha.dashloader.io.IOHelper; -import dev.notalpha.dashloader.mixin.accessor.GlUniformAccessor; -import dev.notalpha.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/src/main/java/dev/notalpha/dashloader/client/shader/DashShader.java b/src/main/java/dev/notalpha/dashloader/client/shader/DashShader.java deleted file mode 100644 index 4abdb133..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/shader/DashShader.java +++ /dev/null @@ -1,154 +0,0 @@ -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.RegistryReader; -import dev.notalpha.dashloader.api.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 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/src/main/java/dev/notalpha/dashloader/client/shader/DashShaderStage.java b/src/main/java/dev/notalpha/dashloader/client/shader/DashShaderStage.java deleted file mode 100644 index fc008626..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/shader/DashShaderStage.java +++ /dev/null @@ -1,54 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormat.java b/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormat.java deleted file mode 100644 index 2655f910..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormat.java +++ /dev/null @@ -1,80 +0,0 @@ -package dev.notalpha.dashloader.client.shader; - -import com.google.common.collect.ImmutableMap; -import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.mixin.accessor.VertexFormatAccessor; -import dev.notalpha.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/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormatElement.java b/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormatElement.java deleted file mode 100644 index 0adf9bce..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormatElement.java +++ /dev/null @@ -1,78 +0,0 @@ -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 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/src/main/java/dev/notalpha/dashloader/client/shader/ShaderModule.java b/src/main/java/dev/notalpha/dashloader/client/shader/ShaderModule.java deleted file mode 100644 index 350f8141..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/shader/ShaderModule.java +++ /dev/null @@ -1,71 +0,0 @@ -package dev.notalpha.dashloader.client.shader; - -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.ObjectIntList; -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(DashCache cacheManager) { - SHADERS.reset(cacheManager, new HashMap<>()); - WRITE_PROGRAM_SOURCES.reset(cacheManager, new Int2ObjectOpenHashMap<>()); - } - - @Override - public Data save(RegistryWriter writer, 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)); - }); - - return new Data(shaders); - } - - @Override - public void load(Data mappings, RegistryReader reader, StepTask task) { - HashMap out = new HashMap<>(); - mappings.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/src/main/java/dev/notalpha/dashloader/client/splash/SplashModule.java b/src/main/java/dev/notalpha/dashloader/client/splash/SplashModule.java deleted file mode 100644 index 6535dd8a..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/splash/SplashModule.java +++ /dev/null @@ -1,57 +0,0 @@ -package dev.notalpha.dashloader.client.splash; - -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.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(DashCache cacheManager) { - TEXTS.reset(cacheManager, new ArrayList<>()); - } - - @Override - public Data save(RegistryWriter writer, StepTask task) { - return new Data(TEXTS.get(CacheStatus.SAVE)); - } - - @Override - public void load(Data mappings, RegistryReader reader, StepTask task) { - TEXTS.set(CacheStatus.LOAD, mappings.splashList); - } - - @Override - public Class getDataClass() { - return SplashModule.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/src/main/java/dev/notalpha/dashloader/client/sprite/DashImage.java b/src/main/java/dev/notalpha/dashloader/client/sprite/DashImage.java deleted file mode 100644 index 517d3cec..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/sprite/DashImage.java +++ /dev/null @@ -1,55 +0,0 @@ -package dev.notalpha.dashloader.client.sprite; - -import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.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/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/DashSpriteAnimation.java b/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimation.java deleted file mode 100644 index aa165640..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimation.java +++ /dev/null @@ -1,69 +0,0 @@ -package dev.notalpha.dashloader.client.sprite; - -import dev.notalpha.dashloader.api.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/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimationFrame.java b/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimationFrame.java deleted file mode 100644 index 4179b6e3..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimationFrame.java +++ /dev/null @@ -1,45 +0,0 @@ -package dev.notalpha.dashloader.client.sprite; - -import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.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/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteContents.java b/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteContents.java deleted file mode 100644 index db90db14..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteContents.java +++ /dev/null @@ -1,79 +0,0 @@ -package dev.notalpha.dashloader.client.sprite; - -import dev.notalpha.dashloader.api.RegistryReader; -import dev.notalpha.dashloader.api.RegistryWriter; -import dev.notalpha.dashloader.misc.UnsafeHelper; -import dev.notalpha.dashloader.mixin.accessor.SpriteContentsAccessor; -import dev.notalpha.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/src/main/java/dev/notalpha/dashloader/client/sprite/DashStitchResult.java b/src/main/java/dev/notalpha/dashloader/client/sprite/DashStitchResult.java deleted file mode 100644 index 02f15c1f..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/sprite/DashStitchResult.java +++ /dev/null @@ -1,87 +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.collection.IntIntList; -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/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/client/ui/Color.java b/src/main/java/dev/notalpha/dashloader/client/ui/Color.java deleted file mode 100644 index 09b3a945..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/ui/Color.java +++ /dev/null @@ -1,45 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/client/ui/DashToast.java b/src/main/java/dev/notalpha/dashloader/client/ui/DashToast.java deleted file mode 100644 index ab3ee673..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/ui/DashToast.java +++ /dev/null @@ -1,267 +0,0 @@ -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.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(MatrixStack matrices, 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 matrixStack = RenderSystem.getModelViewStack(); - Vector4f vec = new Vector4f(0.0f, 0.0f, 0.0f, 1.0f); - vec.mul(matrixStack.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(matrices, 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(matrices, textRenderer, PADDING, progressTextY, this.state.getText(), DrawerUtil.STATUS_COLOR); - DrawerUtil.drawText(matrices, 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); - } - - // 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); - - // 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.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(); - } - - - 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/src/main/java/dev/notalpha/dashloader/client/ui/DashToastState.java b/src/main/java/dev/notalpha/dashloader/client/ui/DashToastState.java deleted file mode 100644 index 7a8db073..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/ui/DashToastState.java +++ /dev/null @@ -1,126 +0,0 @@ -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().getCode(); - 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/src/main/java/dev/notalpha/dashloader/client/ui/DashToastStatus.java b/src/main/java/dev/notalpha/dashloader/client/ui/DashToastStatus.java deleted file mode 100644 index dea81b66..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/ui/DashToastStatus.java +++ /dev/null @@ -1,7 +0,0 @@ -package dev.notalpha.dashloader.client.ui; - -public enum DashToastStatus { - PROGRESS, - CRASHED, - DONE -} diff --git a/src/main/java/dev/notalpha/dashloader/client/ui/DrawerUtil.java b/src/main/java/dev/notalpha/dashloader/client/ui/DrawerUtil.java deleted file mode 100644 index 434c1df7..00000000 --- a/src/main/java/dev/notalpha/dashloader/client/ui/DrawerUtil.java +++ /dev/null @@ -1,157 +0,0 @@ -package dev.notalpha.dashloader.client.ui; - -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.DrawableHelper; -import net.minecraft.client.render.BufferBuilder; -import net.minecraft.client.util.math.MatrixStack; -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(MatrixStack matrixStack, 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)); - } - - 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()); - } - - 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/src/main/java/dev/notalpha/dashloader/config/Config.java b/src/main/java/dev/notalpha/dashloader/config/Config.java deleted file mode 100644 index 27476949..00000000 --- a/src/main/java/dev/notalpha/dashloader/config/Config.java +++ /dev/null @@ -1,17 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/config/ConfigHandler.java b/src/main/java/dev/notalpha/dashloader/config/ConfigHandler.java deleted file mode 100644 index 5b9e5602..00000000 --- a/src/main/java/dev/notalpha/dashloader/config/ConfigHandler.java +++ /dev/null @@ -1,99 +0,0 @@ -package dev.notalpha.dashloader.config; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import dev.notalpha.dashloader.DashLoader; -import net.fabricmc.loader.api.FabricLoader; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -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(FabricLoader.getInstance().getConfigDir().normalize().resolve("dashloader.json")); - 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 : FabricLoader.getInstance().getAllMods()) { - var mod = modContainer.getMetadata(); - 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/src/main/java/dev/notalpha/dashloader/config/Option.java b/src/main/java/dev/notalpha/dashloader/config/Option.java deleted file mode 100644 index 7b6348ef..00000000 --- a/src/main/java/dev/notalpha/dashloader/config/Option.java +++ /dev/null @@ -1,33 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/io/IOHelper.java b/src/main/java/dev/notalpha/dashloader/io/IOHelper.java deleted file mode 100644 index 5ba76b45..00000000 --- a/src/main/java/dev/notalpha/dashloader/io/IOHelper.java +++ /dev/null @@ -1,139 +0,0 @@ -package dev.notalpha.dashloader.io; - -import com.github.luben.zstd.Zstd; -import dev.notalpha.hyphen.io.ByteBufferIO; -import dev.notalpha.taski.builtin.StepTask; -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 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/src/main/java/dev/notalpha/dashloader/io/MappingSerializer.java b/src/main/java/dev/notalpha/dashloader/io/MappingSerializer.java deleted file mode 100644 index b04be9ac..00000000 --- a/src/main/java/dev/notalpha/dashloader/io/MappingSerializer.java +++ /dev/null @@ -1,130 +0,0 @@ -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.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 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 writer, 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(writer, (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); - } - 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.putBoolean(false); - } else { - io.putBoolean(true); - 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) { - boolean moduleActive = io.getBoolean(); - if (moduleActive) { - if (!handler.isActive()) { - DashLoader.LOG.info("Recaching as " + handler.getClass().getSimpleName() + " is now inactive."); - return false; - } - - 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; - } - } - } - - return true; - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - -} diff --git a/src/main/java/dev/notalpha/dashloader/io/RegistrySerializer.java b/src/main/java/dev/notalpha/dashloader/io/RegistrySerializer.java deleted file mode 100644 index 866c92c6..00000000 --- a/src/main/java/dev/notalpha/dashloader/io/RegistrySerializer.java +++ /dev/null @@ -1,223 +0,0 @@ -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.RegistryFactory; -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 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; - -public class RegistrySerializer { - 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, RegistryFactory 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/src/main/java/dev/notalpha/dashloader/io/Serializer.java b/src/main/java/dev/notalpha/dashloader/io/Serializer.java deleted file mode 100644 index b224958b..00000000 --- a/src/main/java/dev/notalpha/dashloader/io/Serializer.java +++ /dev/null @@ -1,77 +0,0 @@ -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.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 org.jetbrains.annotations.NotNull; - -import java.io.IOException; -import java.lang.annotation.Annotation; -import java.nio.file.Path; - -public class Serializer { - private final HyphenSerializer 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.setClassName(getSerializerClassName(aClass)); - factory.addDynamicDef(NativeImageData.class, NativeImageDataDef::new); - 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/src/main/java/dev/notalpha/dashloader/io/data/CacheInfo.java b/src/main/java/dev/notalpha/dashloader/io/data/CacheInfo.java deleted file mode 100644 index d1dae4b3..00000000 --- a/src/main/java/dev/notalpha/dashloader/io/data/CacheInfo.java +++ /dev/null @@ -1,30 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/io/data/ChunkInfo.java b/src/main/java/dev/notalpha/dashloader/io/data/ChunkInfo.java deleted file mode 100644 index 63dc08e7..00000000 --- a/src/main/java/dev/notalpha/dashloader/io/data/ChunkInfo.java +++ /dev/null @@ -1,21 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/io/data/fragment/CacheFragment.java b/src/main/java/dev/notalpha/dashloader/io/data/fragment/CacheFragment.java deleted file mode 100644 index 03628dae..00000000 --- a/src/main/java/dev/notalpha/dashloader/io/data/fragment/CacheFragment.java +++ /dev/null @@ -1,24 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/io/data/fragment/ChunkFragment.java b/src/main/java/dev/notalpha/dashloader/io/data/fragment/ChunkFragment.java deleted file mode 100644 index 46b46e2d..00000000 --- a/src/main/java/dev/notalpha/dashloader/io/data/fragment/ChunkFragment.java +++ /dev/null @@ -1,15 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/io/data/fragment/FragmentSlice.java b/src/main/java/dev/notalpha/dashloader/io/data/fragment/FragmentSlice.java deleted file mode 100644 index 1c8ddcab..00000000 --- a/src/main/java/dev/notalpha/dashloader/io/data/fragment/FragmentSlice.java +++ /dev/null @@ -1,21 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/io/data/fragment/StageFragment.java b/src/main/java/dev/notalpha/dashloader/io/data/fragment/StageFragment.java deleted file mode 100644 index 110bd111..00000000 --- a/src/main/java/dev/notalpha/dashloader/io/data/fragment/StageFragment.java +++ /dev/null @@ -1,24 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/io/def/DataUnsafeByteBuffer.java b/src/main/java/dev/notalpha/dashloader/io/def/DataUnsafeByteBuffer.java deleted file mode 100644 index 28f269b4..00000000 --- a/src/main/java/dev/notalpha/dashloader/io/def/DataUnsafeByteBuffer.java +++ /dev/null @@ -1,14 +0,0 @@ -package dev.notalpha.dashloader.io.def; - -import dev.notalpha.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/src/main/java/dev/notalpha/dashloader/io/def/NativeImageData.java b/src/main/java/dev/notalpha/dashloader/io/def/NativeImageData.java deleted file mode 100644 index 4420f147..00000000 --- a/src/main/java/dev/notalpha/dashloader/io/def/NativeImageData.java +++ /dev/null @@ -1,15 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/io/def/NativeImageDataDef.java b/src/main/java/dev/notalpha/dashloader/io/def/NativeImageDataDef.java deleted file mode 100644 index d864a507..00000000 --- a/src/main/java/dev/notalpha/dashloader/io/def/NativeImageDataDef.java +++ /dev/null @@ -1,93 +0,0 @@ -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 org.lwjgl.system.MemoryUtil; -import org.objectweb.asm.Opcodes; - -import java.nio.ByteBuffer; - -public class NativeImageDataDef extends MethodDef { - private ByteBufferDef bytebufferDef; - - public NativeImageDataDef(Struct clazz) { - super(clazz); - } - - @Override - public void scan(SerializerGenerator handler) { - this.bytebufferDef = new ByteBufferDef(new ClassStruct(ByteBuffer.class)); - this.bytebufferDef.scan(handler); - super.scan(handler); - } - - @Override - protected void writeMethodPut(MethodWriter 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(MethodWriter 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(MethodWriter 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(Struct clazz) { - super(clazz); - } - - @Override - protected void allocateBuffer(MethodWriter 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/src/main/java/dev/notalpha/dashloader/io/fragment/Fragment.java b/src/main/java/dev/notalpha/dashloader/io/fragment/Fragment.java deleted file mode 100644 index edc2ed65..00000000 --- a/src/main/java/dev/notalpha/dashloader/io/fragment/Fragment.java +++ /dev/null @@ -1,27 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/io/fragment/Piece.java b/src/main/java/dev/notalpha/dashloader/io/fragment/Piece.java deleted file mode 100644 index 6a68a8bc..00000000 --- a/src/main/java/dev/notalpha/dashloader/io/fragment/Piece.java +++ /dev/null @@ -1,51 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/io/fragment/SimplePiece.java b/src/main/java/dev/notalpha/dashloader/io/fragment/SimplePiece.java deleted file mode 100644 index 4b612b29..00000000 --- a/src/main/java/dev/notalpha/dashloader/io/fragment/SimplePiece.java +++ /dev/null @@ -1,22 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/io/fragment/SizePiece.java b/src/main/java/dev/notalpha/dashloader/io/fragment/SizePiece.java deleted file mode 100644 index 8d587d6a..00000000 --- a/src/main/java/dev/notalpha/dashloader/io/fragment/SizePiece.java +++ /dev/null @@ -1,17 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/misc/HahaManager.java b/src/main/java/dev/notalpha/dashloader/misc/HahaManager.java deleted file mode 100644 index c73d7321..00000000 --- a/src/main/java/dev/notalpha/dashloader/misc/HahaManager.java +++ /dev/null @@ -1,80 +0,0 @@ -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 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/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/ProfilerUtil.java b/src/main/java/dev/notalpha/dashloader/misc/ProfilerUtil.java deleted file mode 100644 index bbffce9b..00000000 --- a/src/main/java/dev/notalpha/dashloader/misc/ProfilerUtil.java +++ /dev/null @@ -1,25 +0,0 @@ -package dev.notalpha.dashloader.misc; - - -public 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/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/misc/UnsafeHelper.java b/src/main/java/dev/notalpha/dashloader/misc/UnsafeHelper.java deleted file mode 100644 index ec639038..00000000 --- a/src/main/java/dev/notalpha/dashloader/misc/UnsafeHelper.java +++ /dev/null @@ -1,41 +0,0 @@ -package dev.notalpha.dashloader.misc; - -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; - -public 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/src/main/java/dev/notalpha/dashloader/misc/UnsafeImage.java b/src/main/java/dev/notalpha/dashloader/misc/UnsafeImage.java deleted file mode 100644 index d7923cd8..00000000 --- a/src/main/java/dev/notalpha/dashloader/misc/UnsafeImage.java +++ /dev/null @@ -1,27 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/MixinPlugin.java b/src/main/java/dev/notalpha/dashloader/mixin/MixinPlugin.java deleted file mode 100644 index d7532817..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/MixinPlugin.java +++ /dev/null @@ -1,47 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/accessor/AbstractTextureAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/AbstractTextureAccessor.java deleted file mode 100644 index b1eb9046..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/AbstractTextureAccessor.java +++ /dev/null @@ -1,21 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/accessor/AndMultipartModelSelectorAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/AndMultipartModelSelectorAccessor.java deleted file mode 100644 index 88c346ab..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/AndMultipartModelSelectorAccessor.java +++ /dev/null @@ -1,14 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/accessor/BasicBakedModelAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/BasicBakedModelAccessor.java deleted file mode 100644 index 7d44708d..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/BasicBakedModelAccessor.java +++ /dev/null @@ -1,41 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontAccessor.java deleted file mode 100644 index 5f724d4d..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontAccessor.java +++ /dev/null @@ -1,24 +0,0 @@ -package dev.notalpha.dashloader.mixin.accessor; - -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -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.class) -public interface BitmapFontAccessor { - - @Invoker("") - static BitmapFont init(NativeImage image, Int2ObjectMap glyphs) { - throw new AssertionError(); - } - - @Accessor - Int2ObjectMap getGlyphs(); - - @Accessor - NativeImage getImage(); - -} diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontGlyphAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontGlyphAccessor.java deleted file mode 100644 index 951e8862..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontGlyphAccessor.java +++ /dev/null @@ -1,41 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/accessor/BuiltinBakedModelAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/BuiltinBakedModelAccessor.java deleted file mode 100644 index d3b31bc6..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/BuiltinBakedModelAccessor.java +++ /dev/null @@ -1,25 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/accessor/EffectShaderStageAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/EffectShaderStageAccessor.java deleted file mode 100644 index 9e4a4e59..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/EffectShaderStageAccessor.java +++ /dev/null @@ -1,14 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontImageAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontImageAccessor.java deleted file mode 100644 index 2b7ad084..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontImageAccessor.java +++ /dev/null @@ -1,19 +0,0 @@ -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(); - - @Invoker("") - static UnicodeTextureFont.FontImage create(byte[] sizes, NativeImage image) { - throw new AssertionError(); - } - -} 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/FontStorageAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontStorageAccessor.java deleted file mode 100644 index d24f6ebd..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontStorageAccessor.java +++ /dev/null @@ -1,40 +0,0 @@ -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 - Int2ObjectMap getGlyphRendererCache(); - - @Accessor - Int2ObjectMap getGlyphCache(); - - @Accessor - Int2ObjectMap getCharactersByWidth(); - - @Accessor - List getFonts(); - - @Invoker - GlyphRenderer callGetGlyphRenderer(RenderableGlyph c); - - @Invoker - void callCloseFonts(); - - @Invoker - void callCloseGlyphAtlases(); -} diff --git a/src/main/java/dev/notalpha/dashloader/mixin/accessor/GlBlendStateAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/GlBlendStateAccessor.java deleted file mode 100644 index c10e32c2..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/GlBlendStateAccessor.java +++ /dev/null @@ -1,38 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/accessor/GlUniformAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/GlUniformAccessor.java deleted file mode 100644 index 11062656..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/GlUniformAccessor.java +++ /dev/null @@ -1,30 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/accessor/IdentifierAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/IdentifierAccessor.java deleted file mode 100644 index f6812ade..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/IdentifierAccessor.java +++ /dev/null @@ -1,15 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelIdentifierAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelIdentifierAccessor.java deleted file mode 100644 index d1eb30ef..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelIdentifierAccessor.java +++ /dev/null @@ -1,15 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelLoaderAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelLoaderAccessor.java deleted file mode 100644 index d0dedac6..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelLoaderAccessor.java +++ /dev/null @@ -1,26 +0,0 @@ -package dev.notalpha.dashloader.mixin.accessor; - -import dev.notalpha.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/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListAccessor.java deleted file mode 100644 index ce7ff85e..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListAccessor.java +++ /dev/null @@ -1,32 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListBakedOverrideAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListBakedOverrideAccessor.java deleted file mode 100644 index 776f66af..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListBakedOverrideAccessor.java +++ /dev/null @@ -1,23 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListInlinedCondition.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListInlinedCondition.java deleted file mode 100644 index 085af7c4..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListInlinedCondition.java +++ /dev/null @@ -1,16 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartBakedModelAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartBakedModelAccessor.java deleted file mode 100644 index db5d809a..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartBakedModelAccessor.java +++ /dev/null @@ -1,37 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartModelComponentAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartModelComponentAccessor.java deleted file mode 100644 index 84c1c4c1..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartModelComponentAccessor.java +++ /dev/null @@ -1,13 +0,0 @@ -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/NativeImageAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/NativeImageAccessor.java deleted file mode 100644 index 22ec08b3..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/NativeImageAccessor.java +++ /dev/null @@ -1,22 +0,0 @@ -package dev.notalpha.dashloader.mixin.accessor; - -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(NativeImage.class) -public interface NativeImageAccessor { - - - @Invoker("") - 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/src/main/java/dev/notalpha/dashloader/mixin/accessor/OrMultipartModelSelectorAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/OrMultipartModelSelectorAccessor.java deleted file mode 100644 index 134d1a72..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/OrMultipartModelSelectorAccessor.java +++ /dev/null @@ -1,14 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderProgramAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderProgramAccessor.java deleted file mode 100644 index b955690f..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderProgramAccessor.java +++ /dev/null @@ -1,101 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderStageAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderStageAccessor.java deleted file mode 100644 index b41a915d..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderStageAccessor.java +++ /dev/null @@ -1,27 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/accessor/SimpleMultipartModelSelectorAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/SimpleMultipartModelSelectorAccessor.java deleted file mode 100644 index 51729f34..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/SimpleMultipartModelSelectorAccessor.java +++ /dev/null @@ -1,16 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAccessor.java deleted file mode 100644 index 793de382..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAccessor.java +++ /dev/null @@ -1,16 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationAccessor.java deleted file mode 100644 index 26e2be5a..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationAccessor.java +++ /dev/null @@ -1,28 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationFrameAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationFrameAccessor.java deleted file mode 100644 index 83dc0ee8..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationFrameAccessor.java +++ /dev/null @@ -1,21 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteContentsAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteContentsAccessor.java deleted file mode 100644 index 29672892..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteContentsAccessor.java +++ /dev/null @@ -1,46 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteLoaderStitchResultAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteLoaderStitchResultAccessor.java deleted file mode 100644 index 6adaef58..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteLoaderStitchResultAccessor.java +++ /dev/null @@ -1,20 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/accessor/TrueTypeFontAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/TrueTypeFontAccessor.java deleted file mode 100644 index a1706cbe..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/TrueTypeFontAccessor.java +++ /dev/null @@ -1,68 +0,0 @@ -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/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/accessor/VertexFormatAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/VertexFormatAccessor.java deleted file mode 100644 index dc7d27a1..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/VertexFormatAccessor.java +++ /dev/null @@ -1,14 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelAccessor.java deleted file mode 100644 index 0d1c2394..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelAccessor.java +++ /dev/null @@ -1,16 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelEntryAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelEntryAccessor.java deleted file mode 100644 index 2e9c2897..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelEntryAccessor.java +++ /dev/null @@ -1,14 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/accessor/ZipResourcePackAccessor.java b/src/main/java/dev/notalpha/dashloader/mixin/accessor/ZipResourcePackAccessor.java deleted file mode 100644 index baf957b4..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/accessor/ZipResourcePackAccessor.java +++ /dev/null @@ -1,13 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/main/BootstrapMixin.java b/src/main/java/dev/notalpha/dashloader/mixin/main/BootstrapMixin.java deleted file mode 100644 index 264dce93..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/main/BootstrapMixin.java +++ /dev/null @@ -1,25 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/main/KeyboardMixin.java b/src/main/java/dev/notalpha/dashloader/mixin/main/KeyboardMixin.java deleted file mode 100644 index 07c207d1..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/main/KeyboardMixin.java +++ /dev/null @@ -1,43 +0,0 @@ -package dev.notalpha.dashloader.mixin.main; - -import dev.notalpha.dashloader.DashLoader; -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) { - DashLoader.LOG.info("Clearing cache."); - DashLoaderClient.CACHE.clear(); - } - } - - @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/src/main/java/dev/notalpha/dashloader/mixin/main/MainMixin.java b/src/main/java/dev/notalpha/dashloader/mixin/main/MainMixin.java deleted file mode 100644 index 5f00ecbc..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/main/MainMixin.java +++ /dev/null @@ -1,24 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/main/MinecraftClientMixin.java b/src/main/java/dev/notalpha/dashloader/mixin/main/MinecraftClientMixin.java deleted file mode 100644 index 864c0272..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/main/MinecraftClientMixin.java +++ /dev/null @@ -1,37 +0,0 @@ -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(() -> { - // Reset the manager - if (DashLoaderClient.CACHE.getStatus() == CacheStatus.LOAD) { - DashLoaderClient.CACHE.setStatus(CacheStatus.IDLE); - } - }); - } - - -} diff --git a/src/main/java/dev/notalpha/dashloader/mixin/main/ReloadableResourceManagerImplMixin.java b/src/main/java/dev/notalpha/dashloader/mixin/main/ReloadableResourceManagerImplMixin.java deleted file mode 100644 index 96e3760e..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/main/ReloadableResourceManagerImplMixin.java +++ /dev/null @@ -1,55 +0,0 @@ -package dev.notalpha.dashloader.mixin.main; - -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() + "/"); - } - } - } - - DashLoaderClient.CACHE.setHash(DigestUtils.md5Hex(values.toString()).toUpperCase()); - DashLoaderClient.CACHE.start(); - } -} diff --git a/src/main/java/dev/notalpha/dashloader/mixin/main/SplashScreenMixin.java b/src/main/java/dev/notalpha/dashloader/mixin/main/SplashScreenMixin.java deleted file mode 100644 index 73eb1fc9..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/main/SplashScreenMixin.java +++ /dev/null @@ -1,110 +0,0 @@ -package dev.notalpha.dashloader.mixin.main; - -import dev.notalpha.dashloader.Cache; -import dev.notalpha.dashloader.DashLoader; -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.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(Lnet/minecraft/client/util/math/MatrixStack;IIF)V", - 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) { - 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)); - 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(); - 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.setStatus(CacheStatus.IDLE); - state.setDone(); - }); - thread.setName("dashloader-thread"); - thread.start(); - } else { - DashLoaderClient.CACHE.setStatus(CacheStatus.IDLE); - } - } - - @Inject( - method = "render(Lnet/minecraft/client/util/math/MatrixStack;IIF)V", - 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) { - if (this.reloadCompleteTime == -1L && this.reload.isComplete()) { - this.reloading = false; - } - } -} diff --git a/src/main/java/dev/notalpha/dashloader/mixin/option/WallBlockMixin.java b/src/main/java/dev/notalpha/dashloader/mixin/option/WallBlockMixin.java deleted file mode 100644 index 644cb630..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/option/WallBlockMixin.java +++ /dev/null @@ -1,164 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/option/cache/SplashTextResourceSupplierMixin.java b/src/main/java/dev/notalpha/dashloader/mixin/option/cache/SplashTextResourceSupplierMixin.java deleted file mode 100644 index 5d1c1646..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/option/cache/SplashTextResourceSupplierMixin.java +++ /dev/null @@ -1,37 +0,0 @@ -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/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/font/TrueTypeFontLoaderMixin.java b/src/main/java/dev/notalpha/dashloader/mixin/option/cache/font/TrueTypeFontLoaderMixin.java deleted file mode 100644 index d3760dee..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/option/cache/font/TrueTypeFontLoaderMixin.java +++ /dev/null @@ -1,34 +0,0 @@ -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 class TrueTypeFontLoaderMixin { - @Shadow - @Final - private Identifier filename; - - @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, this.filename); - }); - } -} diff --git a/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/BakedModelManagerOverride.java b/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/BakedModelManagerOverride.java deleted file mode 100644 index 0c31a337..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/BakedModelManagerOverride.java +++ /dev/null @@ -1,34 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/BlockModelsMixin.java b/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/BlockModelsMixin.java deleted file mode 100644 index 87ec8e00..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/BlockModelsMixin.java +++ /dev/null @@ -1,30 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/ModelLoaderMixin.java b/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/ModelLoaderMixin.java deleted file mode 100644 index 3eb0d72f..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/ModelLoaderMixin.java +++ /dev/null @@ -1,111 +0,0 @@ -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 dev.notalpha.dashloader.client.model.fallback.UnbakedBakedModel; -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.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.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; - - @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)); - - this.unbakedModels.putAll(dashModels); - this.unbakedModels.putAll(oldUnbakedModels); - this.modelsToBake.putAll(dashModels); - this.modelsToBake.putAll(oldModelsToBake); - }); - } - - /** - * 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 - 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); - } - - } -} diff --git a/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/MultipartUnbakedModelMixin.java b/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/MultipartUnbakedModelMixin.java deleted file mode 100644 index 447299c2..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/MultipartUnbakedModelMixin.java +++ /dev/null @@ -1,55 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/option/cache/shader/GameRendererMixin.java b/src/main/java/dev/notalpha/dashloader/mixin/option/cache/shader/GameRendererMixin.java deleted file mode 100644 index f4769649..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/option/cache/shader/GameRendererMixin.java +++ /dev/null @@ -1,41 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/option/cache/shader/GlStateManagerMixin.java b/src/main/java/dev/notalpha/dashloader/mixin/option/cache/shader/GlStateManagerMixin.java deleted file mode 100644 index dafbf972..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/option/cache/shader/GlStateManagerMixin.java +++ /dev/null @@ -1,27 +0,0 @@ -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/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/java/dev/notalpha/dashloader/mixin/option/misc/AffineTransformationMixin.java b/src/main/java/dev/notalpha/dashloader/mixin/option/misc/AffineTransformationMixin.java deleted file mode 100644 index 1b5f73c9..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/option/misc/AffineTransformationMixin.java +++ /dev/null @@ -1,31 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/option/misc/MipmapHelperMixin.java b/src/main/java/dev/notalpha/dashloader/mixin/option/misc/MipmapHelperMixin.java deleted file mode 100644 index b16b1c40..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/option/misc/MipmapHelperMixin.java +++ /dev/null @@ -1,142 +0,0 @@ -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 - protected static boolean hasAlpha(NativeImage image) { - return false; - } - - @Shadow - protected static int blend(int one, int two, int three, int four, boolean checkAlpha) { - return 0; - } - - /** - * @author - * @reason - */ - @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/src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelIdentifierMixin.java b/src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelIdentifierMixin.java deleted file mode 100644 index 1871b915..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelIdentifierMixin.java +++ /dev/null @@ -1,35 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelLoaderBakedModelCacheKeyMixin.java b/src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelLoaderBakedModelCacheKeyMixin.java deleted file mode 100644 index eb80fb0b..00000000 --- a/src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelLoaderBakedModelCacheKeyMixin.java +++ /dev/null @@ -1,41 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/registry/FactoryBinding.java b/src/main/java/dev/notalpha/dashloader/registry/FactoryBinding.java deleted file mode 100644 index ff808baf..00000000 --- a/src/main/java/dev/notalpha/dashloader/registry/FactoryBinding.java +++ /dev/null @@ -1,96 +0,0 @@ -package dev.notalpha.dashloader.registry; - -import dev.notalpha.dashloader.DashObjectClass; -import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.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/src/main/java/dev/notalpha/dashloader/registry/MissingHandler.java b/src/main/java/dev/notalpha/dashloader/registry/MissingHandler.java deleted file mode 100644 index ad1f40e8..00000000 --- a/src/main/java/dev/notalpha/dashloader/registry/MissingHandler.java +++ /dev/null @@ -1,16 +0,0 @@ -package dev.notalpha.dashloader.registry; - -import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.api.RegistryWriter; - -import java.util.function.BiFunction; - -public final 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/src/main/java/dev/notalpha/dashloader/registry/RegistryAddException.java b/src/main/java/dev/notalpha/dashloader/registry/RegistryAddException.java deleted file mode 100644 index 8521a268..00000000 --- a/src/main/java/dev/notalpha/dashloader/registry/RegistryAddException.java +++ /dev/null @@ -1,17 +0,0 @@ -package dev.notalpha.dashloader.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/src/main/java/dev/notalpha/dashloader/registry/RegistryFactory.java b/src/main/java/dev/notalpha/dashloader/registry/RegistryFactory.java deleted file mode 100644 index 639bcbf5..00000000 --- a/src/main/java/dev/notalpha/dashloader/registry/RegistryFactory.java +++ /dev/null @@ -1,170 +0,0 @@ -package dev.notalpha.dashloader.registry; - -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.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 RegistryFactory 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) { - this.target2chunkMappings = new Object2ByteOpenHashMap<>(); - this.dash2chunkMappings = new Object2ByteOpenHashMap<>(); - this.missingHandlers = missingHandlers; - this.chunks = chunks; - } - - public static > RegistryFactory create(List> missingHandlers, List> dashObjects) { - - //noinspection unchecked - ChunkFactory[] chunks = new ChunkFactory[dashObjects.size()]; - RegistryFactory writer = new RegistryFactory(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); - - writer.target2chunkMappings.put(dashObject.getTargetClass(), (byte) i); - writer.dash2chunkMappings.put(dashClass, (byte) i); - } - - return writer; - } - - @SuppressWarnings("unchecked") - public int add(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.getOrDefault(targetClass, (byte) -1); - if (chunkPos != -1) { - var chunk = (ChunkFactory) this.chunks[chunkPos]; - var entry = TrackedRegistryFactory.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 = TrackedRegistryFactory.create(this, writer -> { - return missingHandler.func.apply(object, writer); - }); - if (entry.data != null) { - var dashClass = entry.data.getClass(); - byte chunkPos = this.dash2chunkMappings.getOrDefault(dashClass, (byte) -1); - 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/src/main/java/dev/notalpha/dashloader/registry/RegistryReaderImpl.java b/src/main/java/dev/notalpha/dashloader/registry/RegistryReaderImpl.java deleted file mode 100644 index e88fea27..00000000 --- a/src/main/java/dev/notalpha/dashloader/registry/RegistryReaderImpl.java +++ /dev/null @@ -1,46 +0,0 @@ -package dev.notalpha.dashloader.registry; - - -import dev.notalpha.dashloader.api.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 id) { - // inlining go brrr - return (R) this.data[id & 0x3f][id >>> 6]; - } -} diff --git a/src/main/java/dev/notalpha/dashloader/registry/TrackedRegistryFactory.java b/src/main/java/dev/notalpha/dashloader/registry/TrackedRegistryFactory.java deleted file mode 100644 index 4e50a16f..00000000 --- a/src/main/java/dev/notalpha/dashloader/registry/TrackedRegistryFactory.java +++ /dev/null @@ -1,38 +0,0 @@ -package dev.notalpha.dashloader.registry; - -import dev.notalpha.dashloader.api.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. - */ -class TrackedRegistryFactory implements RegistryWriter { - private final RegistryFactory factory; - private final IntList dependencies = new IntArrayList(); - - private TrackedRegistryFactory(RegistryFactory 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); - 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/src/main/java/dev/notalpha/dashloader/registry/data/ChunkData.java deleted file mode 100644 index 73255c0e..00000000 --- a/src/main/java/dev/notalpha/dashloader/registry/data/ChunkData.java +++ /dev/null @@ -1,50 +0,0 @@ -package dev.notalpha.dashloader.registry.data; - -import dev.notalpha.dashloader.DashObjectClass; -import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.registry.RegistryReaderImpl; -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(RegistryReaderImpl reader) { - for (Entry entry : this.dashables) { - entry.data.preExport(reader); - } - } - - public void export(Object[] data, RegistryReaderImpl registry) { - ThreadHandler.INSTANCE.parallelExport(this.dashables, data, registry); - } - - public void postExport(RegistryReaderImpl 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/src/main/java/dev/notalpha/dashloader/registry/data/ChunkFactory.java b/src/main/java/dev/notalpha/dashloader/registry/data/ChunkFactory.java deleted file mode 100644 index 73478947..00000000 --- a/src/main/java/dev/notalpha/dashloader/registry/data/ChunkFactory.java +++ /dev/null @@ -1,67 +0,0 @@ -package dev.notalpha.dashloader.registry.data; - -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.registry.FactoryBinding; -import dev.notalpha.dashloader.registry.RegistryFactory; -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, RegistryFactory 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)]; - ChunkFactory.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/src/main/java/dev/notalpha/dashloader/registry/data/StageData.java b/src/main/java/dev/notalpha/dashloader/registry/data/StageData.java deleted file mode 100644 index 13e646d2..00000000 --- a/src/main/java/dev/notalpha/dashloader/registry/data/StageData.java +++ /dev/null @@ -1,32 +0,0 @@ -package dev.notalpha.dashloader.registry.data; - - -import dev.notalpha.dashloader.registry.RegistryReaderImpl; - -public class StageData { - public final ChunkData[] chunks; - - public StageData(ChunkData[] chunks) { - this.chunks = chunks; - } - - public void preExport(RegistryReaderImpl reader) { - for (ChunkData chunk : chunks) { - chunk.preExport(reader); - - } - } - - public void export(Object[][] data, RegistryReaderImpl registry) { - for (int i = 0; i < chunks.length; i++) { - ChunkData chunk = chunks[i]; - chunk.export(data[i], registry); - } - } - - public void postExport(RegistryReaderImpl reader) { - for (ChunkData chunk : chunks) { - chunk.postExport(reader); - } - } -} diff --git a/src/main/java/dev/notalpha/dashloader/thread/IndexedArrayMapTask.java b/src/main/java/dev/notalpha/dashloader/thread/IndexedArrayMapTask.java deleted file mode 100644 index 70311194..00000000 --- a/src/main/java/dev/notalpha/dashloader/thread/IndexedArrayMapTask.java +++ /dev/null @@ -1,48 +0,0 @@ -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/src/main/java/dev/notalpha/dashloader/thread/ThreadHandler.java b/src/main/java/dev/notalpha/dashloader/thread/ThreadHandler.java deleted file mode 100644 index 39308754..00000000 --- a/src/main/java/dev/notalpha/dashloader/thread/ThreadHandler.java +++ /dev/null @@ -1,52 +0,0 @@ -package dev.notalpha.dashloader.thread; - -import dev.notalpha.dashloader.api.DashObject; -import dev.notalpha.dashloader.registry.RegistryReaderImpl; -import dev.notalpha.dashloader.registry.data.ChunkData; - -import java.util.Collection; -import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicInteger; - -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); - } - - public > void parallelExport(ChunkData.Entry[] in, R[] out, RegistryReaderImpl reader) { - this.threadPool.invoke(new IndexedArrayMapTask<>(in, out, d -> d.export(reader))); - } - public void parallelRunnable(Collection runnables) { - for (Future future : this.threadPool.invokeAll(runnables.stream().map(Executors::callable).toList())) { - this.acquire(future); - } - } - - private O acquire(Future future) { - try { - return future.get(); - } catch (InterruptedException | ExecutionException e) { - throw new RuntimeException(e); - } - } - - -} diff --git a/src/main/resources/dashloader.accesswidener b/src/main/resources/dashloader.accesswidener deleted file mode 100644 index f78416c2..00000000 --- a/src/main/resources/dashloader.accesswidener +++ /dev/null @@ -1,27 +0,0 @@ -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/UnicodeTextureFont$FontImage -accessible class net/minecraft/util/Identifier$ExtraData -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/src/main/resources/dashloader.mixins.json b/src/main/resources/dashloader.mixins.json deleted file mode 100644 index ba5803ad..00000000 --- a/src/main/resources/dashloader.mixins.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "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.FontManagerAccessor", - "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.UnicodeTextureFontAccessor", - "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.FontManagerOverride$LeoFontSolution", - "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.FontImageAccessor", - "accessor.ModelIdentifierAccessor", - "accessor.ShaderStageAccessor$TypeAccessor", - "accessor.SpriteContentsAccessor", - "accessor.VertexFormatAccessor", - "option.misc.MipmapHelperMixin", - "option.misc.ModelLoaderBakedModelCacheKeyMixin" - ] -} diff --git a/src/main/resources/dashloader/lang/en_us.json b/src/main/resources/dashloader/lang/en_us.json deleted file mode 100644 index a92a3f75..00000000 --- a/src/main/resources/dashloader/lang/en_us.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "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/src/main/resources/dashloader/lang/lol_us.json b/src/main/resources/dashloader/lang/lol_us.json deleted file mode 100644 index 7d404ff2..00000000 --- a/src/main/resources/dashloader/lang/lol_us.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "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/src/main/resources/dashloader/lang/sv_se.json b/src/main/resources/dashloader/lang/sv_se.json deleted file mode 100644 index cf2da4a0..00000000 --- a/src/main/resources/dashloader/lang/sv_se.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "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/src/main/resources/dashloader/textures/icon.png b/src/main/resources/dashloader/textures/icon.png deleted file mode 100644 index 5f8fc5f83d46ff6d5a739a94be0e4d86e53ec5d6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18600 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 (-jmicAB8X3EDp^o|{IMLnh(D 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∈4HgYwx)#=>0Z^);fB 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 N13lvlW#^p2{|_Z5?N|T+ 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 From ea1af447c3dc90890c7d13e880768f4ac24b538e Mon Sep 17 00:00:00 2001 From: ShuyanMC <1149461164@qq.com> Date: Thu, 31 Jul 2025 23:39:09 +0800 Subject: [PATCH 04/17] Delete build.gradle --- build.gradle | 154 --------------------------------------------------- 1 file changed, 154 deletions(-) delete mode 100644 build.gradle diff --git a/build.gradle b/build.gradle deleted file mode 100644 index ae74c8bd..00000000 --- a/build.gradle +++ /dev/null @@ -1,154 +0,0 @@ -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' -} - -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' - } -} - -loom { - accessWidenerPath = file("src/main/resources/dashloader.accesswidener") -} - -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" - - 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" - } -} - -processResources { - inputs.property "version", project.version - - filesMatching("fabric.mod.json") { - expand "version": project.version - } -} - -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}" } - } -} - -// 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'] -} - -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 - } -} - -tasks.register("publishMod") { - dependsOn 'modrinth' - dependsOn 'curseforge' -} - -tasks.register("getVersion") { - print("$project.version") -} - -publishing { - repositories { - maven { - name = "notalpha" - url = "https://notalpha.dev/maven/releases" - credentials(PasswordCredentials) - authentication { - basic(BasicAuthentication) - } - } - } - publications { - maven(MavenPublication) { - from components.java - } - } -} \ No newline at end of file From 450accea176ef85508dc54357fc2b7cd3ec709b8 Mon Sep 17 00:00:00 2001 From: ShuyanMC <1149461164@qq.com> Date: Thu, 31 Jul 2025 23:39:21 +0800 Subject: [PATCH 05/17] Delete gradle.properties --- gradle.properties | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 gradle.properties diff --git a/gradle.properties b/gradle.properties deleted file mode 100644 index 37777fb7..00000000 --- a/gradle.properties +++ /dev/null @@ -1,12 +0,0 @@ -# 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 From 1d7109bb8ec29f99ddb6e7e26b32808c6fd9ba11 Mon Sep 17 00:00:00 2001 From: ShuyanMC <1149461164@qq.com> Date: Thu, 31 Jul 2025 23:39:31 +0800 Subject: [PATCH 06/17] Delete settings.gradle --- settings.gradle | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 settings.gradle diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index 8a88f8db..00000000 --- a/settings.gradle +++ /dev/null @@ -1,12 +0,0 @@ -pluginManagement { - repositories { - mavenCentral() - gradlePluginPortal() - maven { - name "Fabric" - url "https://maven.fabricmc.net" - } - } -} - -rootProject.name = 'dashloader' From f6887785affdcf4437c06be933da2138248765d0 Mon Sep 17 00:00:00 2001 From: ShuyanMC <1149461164@qq.com> Date: Thu, 31 Jul 2025 23:42:32 +0800 Subject: [PATCH 07/17] Add files via upload --- LICENSE.txt | 857 +++++++++++++++++++++++ build.gradle | 70 ++ gradle.properties | 16 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43583 bytes gradle/wrapper/gradle-wrapper.properties | 7 + gradlew | 284 +++++--- gradlew.bat | 183 ++--- settings.gradle | 14 + 8 files changed, 1233 insertions(+), 198 deletions(-) create mode 100644 LICENSE.txt create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 settings.gradle diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 00000000..b622450a --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,857 @@ +Copyright (c) 2025 KSmc_brigade + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +and a copy of GNU General Public License along with this program. If not, see + + + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + {project} Copyright (C) {year} {fullname} + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. + diff --git a/build.gradle b/build.gradle new file mode 100644 index 00000000..8d77b323 --- /dev/null +++ b/build.gradle @@ -0,0 +1,70 @@ +plugins { + 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 +} + +architectury { + minecraft = project.minecraft_version +} + +allprojects { + group = rootProject.maven_group + version = rootProject.mod_version +} + +subprojects { + apply plugin: 'dev.architectury.loom' + apply plugin: 'architectury-plugin' + apply plugin: 'maven-publish' + + base { + // Set up a suffixed format for the mod jar names, e.g. `example-fabric`. + archivesName = "$rootProject.archives_name-$project.name" + } + + 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. + } + + dependencies { + minecraft "net.minecraft:minecraft:$rootProject.minecraft_version" + mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" + } + + 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() + + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + tasks.withType(JavaCompile).configureEach { + it.options.release = 17 + } + + // Configure Maven publishing. + publishing { + publications { + mavenJava(MavenPublication) { + artifactId = base.archivesName.get() + 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. + } + } +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 00000000..be73f3e3 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,16 @@ +# 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 new file mode 100644 index 0000000000000000000000000000000000000000..a4b76b9530d66f5e68d973ea569d8e19de379189 GIT binary patch literal 43583 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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 GZ~q4|mN%#X literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..e18bc253 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +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 new file mode 100644 index 00000000..95bc2b21 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,14 @@ +pluginManagement { + repositories { + maven { url "https://maven.fabricmc.net/" } + maven { url "https://maven.architectury.dev/" } + maven { url "https://files.minecraftforge.net/maven/" } + gradlePluginPortal() + } +} + +rootProject.name = 'dashloader' + +include 'common' +//include 'fabric' +include 'forge' From bcd446294784c6fc208eba3e94763be23ab5a09c Mon Sep 17 00:00:00 2001 From: ShuyanMC <1149461164@qq.com> Date: Thu, 31 Jul 2025 23:45:04 +0800 Subject: [PATCH 08/17] Add files via upload --- common/build.gradle | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 common/build.gradle 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") +} From d02d9cb13f4a116a692ac16b866dd70eea85d8eb Mon Sep 17 00:00:00 2001 From: ShuyanMC <1149461164@qq.com> Date: Thu, 31 Jul 2025 23:46:02 +0800 Subject: [PATCH 09/17] Add files via upload --- .../cn/ksmcbrigade/dashloader/Dashloader.java | 12 +++ .../main/resources/dashloader.accesswidener | 37 +++++++++ .../src/main/resources/dashloader.mixins.json | 72 ++++++++++++++++++ .../main/resources/dashloader/lang/en_us.json | 11 +++ .../resources/dashloader/lang/lol_us.json | 11 +++ .../main/resources/dashloader/lang/sv_se.json | 11 +++ .../resources/dashloader/textures/icon.png | Bin 0 -> 18600 bytes 7 files changed, 154 insertions(+) create mode 100644 common/src/main/java/cn/ksmcbrigade/dashloader/Dashloader.java create mode 100644 common/src/main/resources/dashloader.accesswidener create mode 100644 common/src/main/resources/dashloader.mixins.json create mode 100644 common/src/main/resources/dashloader/lang/en_us.json create mode 100644 common/src/main/resources/dashloader/lang/lol_us.json create mode 100644 common/src/main/resources/dashloader/lang/sv_se.json create mode 100644 common/src/main/resources/dashloader/textures/icon.png 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/common/src/main/resources/dashloader.accesswidener b/common/src/main/resources/dashloader.accesswidener new file mode 100644 index 00000000..abad3b9a --- /dev/null +++ b/common/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/common/src/main/resources/dashloader.mixins.json b/common/src/main/resources/dashloader.mixins.json new file mode 100644 index 00000000..9676a0b2 --- /dev/null +++ b/common/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/common/src/main/resources/dashloader/lang/en_us.json b/common/src/main/resources/dashloader/lang/en_us.json new file mode 100644 index 00000000..a92a3f75 --- /dev/null +++ b/common/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/common/src/main/resources/dashloader/lang/lol_us.json b/common/src/main/resources/dashloader/lang/lol_us.json new file mode 100644 index 00000000..7d404ff2 --- /dev/null +++ b/common/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/common/src/main/resources/dashloader/lang/sv_se.json b/common/src/main/resources/dashloader/lang/sv_se.json new file mode 100644 index 00000000..cf2da4a0 --- /dev/null +++ b/common/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/common/src/main/resources/dashloader/textures/icon.png b/common/src/main/resources/dashloader/textures/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..5f8fc5f83d46ff6d5a739a94be0e4d86e53ec5d6 GIT binary patch literal 18600 zcmb_^c{r47A8^Z&Q$h}sgj0$lvdi8kNp_O#OF4*1V;f^AlCtDTW$b0&r$`KAgzST| zW}B&GXe@&<#@Ob&pQ+A!-ap>!yRPs0uIuU4nde@9`*#2C=aH$gKKGu3d$w)c#%*xv zg88;>+n1p~zwZLSbPkfD!C$*?U$TL3+wOQD`m=rIT{JiNQP@xKnx6&ireC1*og3Q% z0|Vtee7xYU&bM#K!S1-H&TAdqw(ZYt1{cm+293;(d;Fc#ikf0L-qf~21@;WUop1MS zLnCi5?fdEEoodfH+H~3Z*b4KGWMrhV>$*z9sl3UHvWo3RYVobf z_M9(EqQ|(%PCVfG4g7bw1-JepLLL3{LA0FZgvH;rrpADGgc^{|_5kSX-;gL~i>DQ;Uo|Ny9{y>%V@`F;SiS zuOHM+RJ;ED15D0jKjHhKpI~Kd)|5LLPyJkyHaql;1FpgO6C3yXvXkgO^>;t;)LQqy z(U8`?{U-&6F)}|X2mSDW`M=Z}T=-A2P6(picm5)gJ8lQfjpk;NX#JCB&=0rn{-ScM zwG%O2YZyNz_>AOXMsq_x|KD3@Y7LkD@2weNYp?&k_4l?!BQ4BNGDENoZ~G-O5Ek}`@<)^Z z6RmtDleZK9n`C}d?QhfnC)^ovS~fq)na|yzwT}AmZ`z09%Kr_NIOgO}ZbJlFY5j+( zfc6=iiyi-;rn2z=wQK!er-jV`S;?_ z6&(3r{-Y9UH67CAI*wm_1;Er^-D~(uo8T1bQ8eS1y$LUjb!&&UtGjk*^y^8%O`K{6mujalwQh_^Z;czF< zynXqMIXcbq`}5H&i+Q#Jv*S{lIxibn-`AMLl5g5;DP`ZLq!dk&OzCmr*oEF>kbE%q z!3}mpMvZv(PV`}k%d zG7@zOnh>TTQQscu3le>k;u!NLDu1OOSz+1;;kKSsC=J%gbOHbj*+9%r^$ zVv{maBlfHA;sG)7VdIr3&3nKMBOK*n;y^`cbLNLlgVxPNMDZ$C76e(Li4HxXjnB=W zEIYbTeCSWP=UIK!PxfI{-A+HO`_^*be4~D-#N#r%?Qr@0O~r5o5>gFV;@9!@D?vjB zGrOXmM!7W>g%3GKb0zh_L@FO|&XQE4Sj_tJhI|50w(QzYpL-2YpAv2`6 zZZoz1P%9S=5ax|zv;s`_91v*I5$wIQky72mK_S+1X11k`xq8nWLNrvlDvY084ixL_ z65o{24BD_P>$DHu6s)7iusm=ZOEEl6f%GCbrml1O{# zvkqfvCX*lMb{XAqE{I`mVp=W2R?Rpem-)TX?#Z6Wm!BoTzhzx@5Fae#*Q1#D%#9a5 z>$zcnPS{|NwO=cK&Aau+?2yNzZT!9MfOFCEBr#|!S#!V7uXa<_U2l|zTwd2*R;rn- z--11DH3}=uNyrSsm>tUJ@&`)Zqd+>y2JHx~ZrvzoqlC^~sm-gKWy{(+g@|Wr^v8Yt zs>a&27YM7xU4$zXpj0)6xKu$DsBH_`7^|z97-A*Fx=#}M=z(?ltO6)DV(w>?Dq-yN zi^d9GL4nmuzFP|mMj9(7tmN5u+rsm?p}plvJJ?%4ku3;bJ3I5>L0t+=ZZG%uviJ>N zX~fcB*YixlAb`smXsl#ptMNz>H778pHE@HX+dus%@nO1ZKLDs9gzH0872*~*p{`Yn zh1@am56*DXEd3u(mnC9#GwaN1HpMrJ9{AL8r}y1wM+WY{`^lSFO+AzfNL}cjAR1Lt zgBK2quGO-3OXu%qV+E5Q)>1u<4op$WUih?|dIZk@o5qskhV@@*rYRfrFc+z?iOiJc zm9qer4W|sA4-H!W=@P`Sw(0~0>KPIvQM~`%y`7iR_OnsbI{zX9v8EBFum`418Mmwz zJ@DbB<7(~i|9&m4sgGm*?R&n7__BiWkx^WYR9nm2&W5FD-?UT4NH?DtexSZ8{y_Go z_?k_>(M}3vFES2;tt-(TzTpE9|F1ER? zcSYnstIl^jb45$?25|<EW`R|C$ih2B2^J*vuc-C7J@*1%&4x0X6b~(? zWL#pqL5sZ_X!k7m1tf2f`Z#{3A?oi+QUR+;;3Wi+8KIUJyv~Ln$PVh!p`NMQ8F5e> zvB&Bxn5soX2MYPg_gtBJ*cvFzv1L>hpRUs-GH?cZCxi~<1@A1UZu5tV6(|Px_#Wi| zpwjG|h@t>XczRQ-b2b!30xHDlso!Yd&T`VO1n^89o^H9$P4blrUyFq-@nd#R8YfC(Fy<0oWkFh$qA(}DYYpH|fD$<+cVuRJkb%MVA?zt8X&Eioo0gk-K zZ)#z&%kznH(84~KwTI9PV+AS*_DgrmW2{gh z_3Y(LNJ@Lu$#cNvV!t0MJN^0CzJ^Z+F0X}yb+DZ1DozdbR5ARTj5xpMm^MU`F@AzA z$TMg|>RKG*+k&^uzygfl;mKEl42J~pOicb!6D#|tYXNp)Yac&5Wn^{pwK|0F zvzC4WZ$sbc51Xqh$yx2FU(FN++fdPJ&^ER3pglFkSC4KFUNK{}UcIyUENpQU*ugP( zLf|e@0-U6NMIdwK-jHG0Y_$1{anp307aYRlN>a>Rwp3L!NN} zZV=%6u`}JdbE*d^(4c`Sucju2^>ttYiW`oH0E(y37(leTCc7tuB^U4fT6a#u$;>dr z&^ggd2pglu0#*lXFps3h7D!T!w7`S#_`BFl^iT^T|F5MNW*+Z~nKss?p49C4BKg_& z8CUy@N9e!xEog={9&mlLTG|RsWnDq>Ip@=>zoU`S%#Lfi8aKy2-4Em{lW2YHIZaO8 zJYLd%DTgT7U%J1Z&JCn=Y{)7LsQHR~(ow;fXolzl&vNg)_Ca0bAm-fqfx`NUar&iA z5kM?#sZ8N;wqt`I)u=!gB$GBcj&Rfd(R?WU$ zJYxNA>4B@eYZgzLlh|^cG4e_RNUS*8(A?~0;i2l`TL0y0^MMR~u|@vnwQ-k?;4Ah` z)S#*ah3mmzQz2MAo8AHq+i;RI$gRFrjO1yn@?dlf6pyU8Nl3>AY0UXt-TG4gch_%b zVb(}UCG)GfM}g^}MPiR~aM%d$*(0@raKA3En)eYopHS~{%$yU_=#y2>odDb|dB^SA z*BmUF?_`PT2d(izW{JA=v%)jo~G+d45dK|m5&sXDBOM^%#5`%0Z5nZ)#MH0 zeqA6BUN=fg?THs&+L@XwQ--bwpVlnCx4Ew3*C~4!Pxk42zl;pG!QES{0z#)W@W3{l zhrH$Fz-iBcoRA1-dRR&Fb_(ubKHcwtv|1-J9^QKWa7rd2c)zJhH9Thzgt;;Bt@ZMb z%!e;t9emPWeeLaaGyk6Ln2qSp8+x5L;xe^&lD+2fBkOj(VL54V$=7(rjnA5KC2KJd zZc;BIut{h`#mc4|gCWnH4_`<6a+%qn1v=-QAydpt&qgkJ?GfDV0 z34(_yjEtqaOqS&b}Dm-s85uzb)ld{Dcx<=r|EM;y$qfTehO7y zvA4G>6VxG0{6)$DnxU?825(;sq|X;49=ZxXCtD38KNOFX7MIGUtudZM5ey{bN~n_B zjS&fd;UT+PmEpHdymi_5ysZnQRt|tTL|{PQ3TM|bijld)lLU+D;Tfx>p3EfCL;YvY`Nb_w?B)>Um&Wo#Z6iONS3s9p-@dIh5u1)GuURd`x_K zZ!_@>elb)*I62fr-rs)>GF^g@Vk=+}4w`+am@7~7%8nl#%?)yD6R%F|BP5!5%=Q}y z2F~qR;#PZHIFw-Gp<>SJ=GPVx0t`j&1eSOQZ6HiVjR)-^Fei{-R#1b?w5A#bIu|5M zWe&baF{BTOHY~=e#V+#EqdXJV0`c6yji!Y7?*dcz(4MiX2j0|LB6aHgHp`1@SK0*) ziF-f$VoQeeGr;UA%LBr@mf{M4f!4K*@2?-P^xY0JB{cvtj{+vHeblJd@W~^IQ)cnc zpDSDOnG4yOfIW{KZCZbC%|`ISSrk8|C0Cq&zd~)}T||qp$9GK<$T_Hp zj4OtG8fauV0#yQU;oum~ljEjbsdwk|PYiJ{dFgYI%|<=Kfbz7{ydc@D_1n!XKhv9coX3&lwH5O@NJ8daWp1jrgA^}|5?cR7JGbvOEZ z(yu!I*8ix#R-h2FT!Fj&Ra0GpNs`90 z07J>xPm{aLL&lHaPk%XYSrgi9(Vsc+9-H_AuQ04Z5s~muEb~45eRl77Sf)ZtzylzH zafn99I;y=qDmB`&Tx-K$h>Tqu?xQmbMYc*d6s|roU@apX6V^VUL;*XAt{Hy=%rj=H7OJB z#&=fMTaq)Mt;-m*hN%X4_|0iNGA?$YH_=2=NA)i7Y$n@4@&i|SwARhBC`=#D&+J7a@R?3!l4dacpP|`XCktTk`Ws)>=?;4TdTFXAs@3~8 zJouw-e@~jr8miC8jC4HdS(E!8;izfiF33$vfhaNp0r#L^z&Ed1rIxk5PI&HVC^-VfSld zuN=y)IVBmoN~oLi^rDz(a{xom1F24XPM#TTq3T8V7p2rEl}`+UveOLkus|tu7{~+G zV-WmM4l9)!Z~>JXPZy=XR+0*$Q(D&B`%T3B%sP}(run@O)-Z0(UBKpN?1Ia~ph6x^ zF3vm7RL$tIltcDbi1(UkzuE;#Wom1VFum*o#of!jUYD*6)F}X3J5b%pCMLKz{%Z-! zSbJesole!wU+jB9T*c4zrUdtn>$EqycLV1$sRA75`lBC7HA7NeN?lm+Rz47qM8!V} z17D_ck0S@$KB<~<(r`{hh|M&jq$zb9y-$iFG8r^Up@^rx (-jmicAB8X3EDp^o|{IMLnh(D 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∈4HgYwx)#=>0Z^);fB z6S3*X;XIg+7SXcJ*sl>U=^!FgHBrJXlh9_&Rk0)CwOXN;XH z+prYyt}ye-H?}GDoE=EAyymd9hfX2bp|Z#P@MDR#>eYWng?$~-d?2!sF1rhe%ddUV zq=)@+T*ajqDV6SHp0y;$Wgfso2Uy4kTpekwUC$Tn?QS==S}zm>O_GLsN@(8{hEgus zm;3H}A24ND%G%CuT4vxgeer%|xZI4UWsFAGciXh7kp$G@0s=mA|tiH}c z6RU!4gN`W1n{ev=RqsNU?na^O9VgtWlyjFxhZZUWYOcEs8M;ULi;NJS$p9!NcLTX> zz}2ELdgJZyo3koL?He2kx-S-$0w*Qq9c8aKZV$e$S@Lm>>g-ea^&PIt=npnn44`Me zx9kq2oIYOtppP1(?_-6yQ-3FaVp8*HB6n6#^=TFoVvllc{%fu}jN3_FG?NutQyW@us1ccH+I)hjr10 z^eM=FH;gSWFPR;+juVJr?jfto-JCV=Rk#AHaolumoEd7swYvVrMnCUVQoO{(xf5k$ z0Woxb8e{TKSBQmK_NyMg;6^iMfM~-wI)Il{^Q~7?^&2nTBkITExY{Jg8s>ifwOA}K zlEY4S=mYX0bL2==LSxJjV2JBqe@C4I$h-5=I=rhsEquQB=B=N#g19Eix-8?$XnD2V zbC)5`ZlgfCp$liz5{srzwdpzUX??KaLbUw>Jd(h>v4K{9|mSed?oroy*-XYv%wIKzDtRlvw zV*Lj8%Aw8+X1udTL$ZQftKND;?&gZBt3cQw{{v1C6R?hG@eQWFa)5^Zsp}rOtIjvz zSlYp77=z9pEo!fV>S`qR`$5RII~lue!Q=ahDdY`s-Y`2-6<3<`zW4~r-*#)h!imU9 zIOZKh0_QFu8QcyxQG1uJBkh>@$Tj)&QrXy-c#?V0R`_@7r_WO4%UVCIfC?I^(X|Dq z76Ld^Z&iMsB)tDRL7JIM+m6NU3kc%&hyM&)hfP4d!Chtq3RBLelc{!nsNDJ zI<}G9FR+Qn^J6{IiF34IKg$z_9UBui+&HpFi(o zj3Ic-mDV4f>UbtIqpLbk{jJ7MbxuQ zgfETpFbDWM7&9v3jo=OtdTpY`Uw>&ZV2K&6CkJ}WeiL2VI!mh@_?ouIForl_prukg zY_b_O-?jHH!dCZCP9d8S4+&D6u>=$1qt7Bw;?XjXl{a6Tw9ESFT#$Us{}~iEw!UnG zWZpK8u-O>G>cQD&OHu!JO+jgsJ3AGf2Ws#1gi;KP@LLyMXVQJ!A9FhqJ9s%E5*xeW zMai!DK0;pPnZ(koRs|=K*7MCUt-{=TX7}?jYSz)#UGgw`)J}+eQi`yLOcP8=^3GKa zLQ_$AvmUjhZezAHg*9=?Ck{K~bp8-pYN-jd7^tK9lhxj*jnAeQOYX6{c737DK^n7l zsX~1Hjoll%l85iDcewZ;IV7a1`J}?viB%P;DA$4a3E`25V2~_#gdnIleM>2DI!8D^jcQgmkAFM+Wsh6yqXZ9_8-78#uX8W8W10* zUu)VRsez*=Ju|MEDJNoO2*>wXJ&0^XC4%mZJjd4Y%eN?GgF0BHfzIbBvb2=FN-CgSuTWl;ndN!#-M+azJ<+j*r}| zL3Yq1!yNjTLDqbXFqu=3JPi`H=NP}cY&EKD+Q@$wVn`6udcRQ`ld?5#^7a8XM_yU8 zKAMAoOgY8w!OUT&)S$1Pu^XE^Ik=XP*ht~&Ne6vFO9SjYas2@nmVo{E&7>~-0U*8;KAI_I z+iF)?xZ+*RMOc51+4>1w^Tw+8H6F5>JWF@9N$YU{+7s+ZE@nW*j|c>>Lf9qO)<*;p zSDmR7ghv=yh&qWquR>hlCRik5*!dfKxd>j*<<(Lnu`iQC zFdQrYVB%>fMX+q((S7PM+Gjs~WFQPEy%ipL3QoaBhCjLs0tZ zKBzKeydK$~FuW~^hp;Y|>^Qhg4a@T;6gy?86KdJT2&lxAH>_r5RLxIj;;b60n;P(}tQfXXBr+{0uBh`2#jjdV>#)8}rd z0+~fN8EH&w(^^MM{Up}`n(c?$V+0y9)h}E<0ih#r0`({XTt&&ci293Ee5B2a5jslK zDWhi(SC3=way|1<0(J^5#jZm+%In^0ia>56mFJ|W#YPp`U`m!jQGmHO=j1GYN=}`Rav@8$kZkUmr~Z|Lmy~MeAS@qc8zrdv~+_ zIIb04ag%tEELVl9e!!gaLRX>Hqk8S<|RO3f;RunFTBwa}eSA zAHsPq`wT)7S-YKff2h*}?THS1DN8t(p~TouBmW2hh|XJEa3^Ac=T)_L%_2ToAww2H zTjhDWEAHN|-7!};-r+!($RWadIP>tSOeGRytAefqH;1FAG)rCZd&y3Ccm|YS`MJz{ zxpfcErWQ#?Q$#+8#1JrltxY)oZ7WwrUw4`pB9B7Nmq2P;)86bPhmIWt|DOAHf*m*O zxNc3W$Bp@4c-)3NOuqi?1j`J2G!o|ckpvcLIAwc4r_KaxcPqL_h48_%57P)Bx^H(gGRGfriFzicm&A9G#!6h{CpvJ z5;e4zhsFYPh-P>IKM<9juV7j1rP!GnTfLF z*`g&tf($R9E>(q|gMevi<{NbhxePYS1FPXr) zNM&ID6hr_Zdrpv%B;>`WR-doRLq_N!p14Jdyr@M}2yiwyL*|~fj6lGPF_+Nm5`m(U zko0SRj(Qe6e`cikXfg|w$?PkWmzh~1<{)J zO^r;~)Wt#ci3v%D4495{=!XZKj37oDlgP;EZ+m^-B?WbU;J%p4e9m;ERoB*NJ?JO} z6~-rSfFHFH*!TqIiMT_xyXzY4%(-d8kX|^;(f{gz_Gh4V@0d&I+bDtYHq{kr0`}E; z$zh;Vkf=#O{sCpB$b0Gu>S(WHiV$nG$@cM(5W?e`NMnz0(}$1HE~0z7I*$6L6=V6B zdD@XeWgcV_3yQ|HTXF0r%PDbM;z9KQ(_43Ewv&Y~sSsFu0F6$e1Hln2yBaX1Eu|7N zyYH#mJKSko&2E*1n)XW^Q9>9Gh?eo_Kn`%8#tjGY&nPW}{{q=ok6Zy)%&0r~_5m{q zQiy28S8ym6k6sr_9vUQU5AiOiw*kap)e}us7|#`c$LF?XKxP?&vA4@JWvi6*X6BwNeG05NKKGTM>@}i;yKPjF zxhf4<u*6WJEx>L!M`i-^$S!=u3Pql!Q$or&OF zb)J{J_~}*Qm~WdVfs>c|v5fO^79+1s%hI=HCqeC%hyxCi%FBdY9^>ep0Fc1uGn1}r zHp2BcMapnSGRtKyS+6$? zRQ?Ul=(HVGsyi+nQS50$%+AP%t=HUStrp*b%%h(R5!9vT`N&U-qE^sfUeFEym-Qo$#uP@t%FN z(Gx59uWr*?D{%?Tv3&e4fI=|A78JKPL8oa^mAEp#G_~`I*jnETc)06+y=4Vutw*HRFCyK(L9VS>P3m|3x_&fofkz+nA`<`Z40HQ1+ZoaE$| z5PrZA1@e=u@$44vr?`k)t1A)GdzsermF*8+Uhac~j-%8gK)d*pBM@@(j=-g_$6+mz zmRkge?Olh_4J!CNk!J|5Tu~@n9@)bQFhJrjn{k44_p!v(niKXwSGR0mvX<` zV6V#j88P)5WArf>z(Ah40s>ec`J^0>6aehBCt6zjK0bhDK8?*xsnYJsSR6fyyKPU) zM8&p&r6ZZ1fc&6UW?--fb-{a~&Eb^$s8{XqRL-Z$(D)nG_$)(<6jmbaO(Zr^zzP5Z zx}1ToGsNJ6C7v)#+R1aGCkx*U)w?=a2Ub)?ARbuwd0dBQqDtmGR{jPXSi~~pK$97u zo4K;8o10Sbbb!=HW&>z?r44wjTvg~|sz9grC5U=1`Ysc$Z~T>*oC zUow9aB;EB|rPv-+#heNp8n}b}9i;i|=3wC8@fpQ$U}GXZMh85cg0JQcaNicjWG*cE z$tuEJQ_=wh755P}pxY5YV5Oz_+5W!Io{P=)O%4~PW%_1Ysw#$0fxImOtA@_!^pmIB z+GEZCv|gCEKe^{(6rAs#Du43SF53S2&FS7ZoQJ*5DfHo$!q+XzY&`B+PR?Da_;mH0Zwd`TVMG4 zl&txXkbIMqR^mc*1Px$<{*%%7lK6t1Up*cDecbZ=vyfQADHE?P8tLmtWqHOQv@K9h zFD#U?KH1iq-8<{_C-!s{dde-OuG!*yR;N;>3hf3U4uhWth1P{dGD53WhmD`yI??8s zOgVMEotxa{65@NAmKhe#ecNeXgCM{rB0H+z%-4SVX1ZddoN)6jA7cpM-UzyFORCTB5jRb#5l zN{a3P$_AV`0P-fK!?Hq`K6W){sO9wwk4J#Gu!+uXz~fCFf)|Qd%sXWi)+j#v(5bh4 zG8{jlT+7!t%l!w$u$|;~eb5Mk1#gQ&u6#VFZowS)P0`Lb(U@t`Ox^2$g) z&X$!oan%ENm!yQ#?qNx2!zbyEOLs)IOJ9tBFd;M<_KBu<;U|?rhy!&1gI1iWqO#f9 zEZSoF^kht5q0HMtAGj*ATY?s#_HOPpgwFhS@*EH)Y_SY~i}Xo1_n|@uro%>1 zqaG`1u0QrF7phFY1$6Lo#$}6&B?Z~7>C28fRbRkXL!HO+hJop+eFo*K_@#=S78T`U zc$D{IRMKRy-TZ^TSxJ_E7aJVL(hV@uTHkO=`L_3E{4wjeH>*vZ+RZp;H-I)Uji8Q3 z%>uzl$lNJzyUgc{3%3|dYq>VP@l%ZFeY5H&KZfW!f+2QK(u(T}-(QvBwo6~(S^n$g z7`<}YsBc!RBnfkYoQ_lBhJ-t{wg5z;n0uiUEM9xOB!BRMTwT_4yQGdfkCgFMvwVA` z*Fh*_hk>jJBq$d@7zubyFR3t}XXQqd9r1s!`l}gLfPOTozFFW9L6^uT1RgFl!GGt} z=VvDbpLcHQeLscIJ>F2&Q<{2{;TDZLrbu;5Ne5cYLoRjf2cluvOGe!`mVntW%`cx8 zYED5c>9^~XTQW7=c7lFpMA*^|THj|UBA=TNZQH?$hzD|0QjEOl-dC+z}X%;2q9 zTbg?0Wcfv6^`9j3$u(SF{d&{$BeY&iQFuJ0kKkrYTT+(~Sp6&CTE~l#&+y9?w1YK% z1DgFwp?-Q?nAwdRH|^c#&47xq)ldr?Gja>MQNiISrCvqnR=lJg(tU5!bs+uK()Isk||LV)*0BTl$le zMf=6W%$`jVr)Rm?IVocWPXRUdj5#d>#f#G1)!`lzVcpkdP38xezGdt!E7b%B;N!xi zm!h+mJ2v%R)-G|aqI*hJ?lA9h^=Fyuub*cG>G@!L&(6Kx4lXv}#JxX3H$`Y@%(r5v zRMH~xcysd^L(Y{#91^#}eR#6)bk&P5T-KHamKrt2&Mwy?s5Sbz*-^cYKGvxYj=>vx zdP7s1bpq__T_JZO@V@W}rt}>>cdp3pJ0eNZ*Hgx_JLVUc^=7*Vx{K;V>Q;(A{WhBW z3Te5MA#U}(tm%8qr*w3N|MX*heERYV-#+>B_b`b78kvW>+ zE_BUGvgHj9WZs<-V{1MYLXZTA$GJ7VfDWd2~Y@wn~UbW?{5nt1#++oDCn`BG7 zYfr8k2hUig9?1Uu+2`3~QS-&_2<_1`Q_p3JwpPofF?FR2amC)EJm=k@jA&l<3Umub zg)CEe;I!@UBgfD3*Yk1jEzr=&x$Sr1%jXwg%@y6nlI6``Nr##~-L~y_QRuq>Z%TmM z2*>JiOqQ#@c3rcciqxKvCgMyQx{!jiq+?22e;@e#G1tSY$I*h`1!&VvTwQwdO^8E6 zFAZ{d8INsi!Ns&OE`qgr;ZZMd8fW(#+nYiHp09WX1i^iZ7(MK}4vu?YxxE%7AK%En zCK>G}V>Nua;9O-^;~krTe5F>4LCFBOGm)rTw?OV&wgXC#O~8?JDN7N~``7a4rN`}g6KeQ9det!eBiY*{69&i?Q_EnYO{?6{S*WPrUaOhX~Cn3YI0 zcsM_%bkQuC4NocY6H#CXfp(vHy}$T|Ubh6{SmAXuyF&Eo*G3aIXqDUMl_jUix1hkT z|83@6C|EKcO*%7Pa9!2xkd$CWUSQprdZD@M>zKG=RI-BEtj5W}UGjn5{VPW7f>P0F zPe2tw$DJ^APUyMOp~#lpqNP7@c8A)nJX5z@cTQW94(+e9nSW#QTBN=C&cF>lIUiLP zK+=hbS*aM8`3=2(m#HyU6kROHpPvQIJkViP9H+K@Q1y3do?_W64eoA9r~@h0*NIu$ zzz2htsyTP?cjC#5hlH&iR1>^Tcp7~tS6wR_yeSs2@#GJ^I|G;b4S8+QF7cB^H~3oz zWIJ|1Uaas|JxG(ZurB?W&#}@snj^!nnED0GaODRIAq6^Ab~4F-jrVtmDjyGABV`p; z*PO?)cdMKe0(eSAGiwS4s*kIh?K|zYv+B!jte=aRp2`P};RZ3iJHBpN=gi)k7KkUN zE}d98eJg7W!Y_le!Uaxmjns5M7&s5SmsFM(aP{I+l#E2TzV>yt>c+YS%wT3uJUo|u zuJ%;r_p{Lx8sB_1{Xt0(NPs5*u@o zyT$sJUmWe}s6r!zhIBfcTbhl#v0JKEhdP^|9V~k56kDk{s3Dv>J3g6~7893s$=Fu} zb{>R;;96a!BUA?CC5TMONeQ=~wsDP(wP+aJ^2izaT04GtkN+Jx{5_jlKUXWQ$T=bX z$~%~lh}Umda&P9AwDfzrb>eD+u~stfO?RXQ-?QmTX47>&j(IbO@@IR2sx}T07J{M% z&9Q24Rb>t@G?QCmJO>bL{*8&i!hKMG0KKc~9jQvk##Uv1zxm^h4D6Pg&TjB!fEC02 zw5Q^|5k)yY#|@_^emqM)3pbFwYQ>WTN*!T;CH$m? z{uw{(LKK^}l>3PuIB8RKzRr=}@ei>~M9HOk)0RHbG3-NFfPfCT#lX9J8BG1B_r(9?U3g9lIs+(gF+Wfj@rA*iEQ<{GreeigJF?YA@OIz<-T6 zK~U2Na6!hH{kZec=wQ)*zE6^2K!Dvfp8V$%67KtH2mg&noKee28XOW&hbKb`E?)hV}2cM{FuXt$&eB>8-msyAtrv^hY-b z)@*+53_fQdPC!BzGJatac&vC3^ACYrRyLf8n(UL1AN0c&gVp~5P3i5F5Dkjn{#jkS zy{IejAG}?WTMAUMe}mpva{b^hP6%Vl;}A>#2HmmT)8qC}qPycdRDWC^__aK$t0=eO z2NN687Qv@3*k3yM1$h3E;z7o)9}MG!w-lGS64{4oKS9eVD%oQF_3)%O>WHr~_{z{W N13lvlW#^p2{|_Z5?N|T+ literal 0 HcmV?d00001 From 1eca09bf37ac88fc354d3f405345d91dbd3128d6 Mon Sep 17 00:00:00 2001 From: ShuyanMC <1149461164@qq.com> Date: Thu, 31 Jul 2025 23:47:33 +0800 Subject: [PATCH 10/17] Add files via upload --- .../thread/IndexedArrayMapTask.java | 48 +++++++++++ .../dashloader/thread/ThreadHandler.java | 81 +++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 common/src/main/java/dev/notalpha/dashloader/thread/IndexedArrayMapTask.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/thread/ThreadHandler.java diff --git a/common/src/main/java/dev/notalpha/dashloader/thread/IndexedArrayMapTask.java b/common/src/main/java/dev/notalpha/dashloader/thread/IndexedArrayMapTask.java new file mode 100644 index 00000000..70311194 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/thread/ThreadHandler.java b/common/src/main/java/dev/notalpha/dashloader/thread/ThreadHandler.java new file mode 100644 index 00000000..bcfe6d30 --- /dev/null +++ b/common/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); + } + } + + +} From 60af8128196c50f055110382c8280b55f9152672 Mon Sep 17 00:00:00 2001 From: ShuyanMC <1149461164@qq.com> Date: Thu, 31 Jul 2025 23:50:18 +0800 Subject: [PATCH 11/17] Add files via upload --- .../notalpha/dashloader/CacheFactoryImpl.java | 77 +++++ .../dev/notalpha/dashloader/CacheImpl.java | 224 +++++++++++++++ .../dev/notalpha/dashloader/DashLoader.java | 50 ++++ .../notalpha/dashloader/DashObjectClass.java | 80 ++++++ .../notalpha/dashloader/api/CachingData.java | 77 +++++ .../dashloader/api/DashEntrypoint.java | 18 ++ .../notalpha/dashloader/api/DashModule.java | 68 +++++ .../notalpha/dashloader/api/DashObject.java | 38 +++ .../notalpha/dashloader/api/cache/Cache.java | 52 ++++ .../dashloader/api/cache/CacheFactory.java | 54 ++++ .../dashloader/api/cache/CacheStatus.java | 19 ++ .../dashloader/api/collection/IntIntList.java | 26 ++ .../api/collection/IntObjectList.java | 26 ++ .../api/collection/ObjectIntList.java | 26 ++ .../api/collection/ObjectObjectList.java | 22 ++ .../api/registry/RegistryAddException.java | 17 ++ .../api/registry/RegistryReader.java | 18 ++ .../dashloader/api/registry/RegistryUtil.java | 43 +++ .../api/registry/RegistryWriter.java | 19 ++ .../dashloader/client/DashLoaderClient.java | 122 ++++++++ .../dev/notalpha/dashloader/client/Dazy.java | 23 ++ .../client/blockstate/DashBlockState.java | 86 ++++++ .../client/font/DashBitmapFont.java | 39 +++ .../client/font/DashBitmapFontGlyph.java | 44 +++ .../dashloader/client/font/DashBlankFont.java | 12 + .../dashloader/client/font/DashSpaceFont.java | 38 +++ .../client/font/DashTrueTypeFont.java | 90 ++++++ .../client/font/DashUnihexFont.java | 54 ++++ .../dashloader/client/font/FontModule.java | 127 +++++++++ .../client/identifier/DashIdentifier.java | 44 +++ .../identifier/DashModelIdentifier.java | 50 ++++ .../identifier/DashSpriteIdentifier.java | 27 ++ .../client/model/DashBasicBakedModel.java | 172 +++++++++++ .../client/model/DashBuiltinBakedModel.java | 95 +++++++ .../client/model/DashMultipartBakedModel.java | 148 ++++++++++ .../client/model/DashWeightedBakedModel.java | 84 ++++++ .../dashloader/client/model/ModelModule.java | 148 ++++++++++ .../model/components/BakedQuadCollection.java | 13 + .../model/components/DashBakedQuad.java | 85 ++++++ .../components/DashBakedQuadCollection.java | 71 +++++ .../client/model/components/DashMesh.java | 85 ++++++ .../components/DashModelOverrideList.java | 96 +++++++ .../DashModelOverrideListBakedOverride.java | 84 ++++++ ...DashModelOverrideListInlinedCondition.java | 40 +++ .../components/DashModelTransformation.java | 127 +++++++++ .../components/DashWeightedModelEntry.java | 44 +++ .../model/fallback/UnbakedBakedModel.java | 42 +++ .../model/predicates/BooleanSelector.java | 25 ++ .../model/predicates/DashAndPredicate.java | 61 ++++ .../model/predicates/DashOrPredicate.java | 62 ++++ .../model/predicates/DashSimplePredicate.java | 46 +++ .../model/predicates/DashStaticPredicate.java | 36 +++ .../client/shader/DashGlBlendState.java | 45 +++ .../client/shader/DashGlUniform.java | 43 +++ .../dashloader/client/shader/DashShader.java | 154 ++++++++++ .../client/shader/DashShaderStage.java | 54 ++++ .../client/shader/DashVertexFormat.java | 80 ++++++ .../shader/DashVertexFormatElement.java | 78 +++++ .../client/shader/ShaderModule.java | 69 +++++ .../client/splash/SplashModule.java | 57 ++++ .../dashloader/client/sprite/DashImage.java | 55 ++++ .../dashloader/client/sprite/DashSprite.java | 54 ++++ .../client/sprite/DashSpriteAnimation.java | 69 +++++ .../sprite/DashSpriteAnimationFrame.java | 45 +++ .../client/sprite/DashSpriteContents.java | 79 ++++++ .../client/sprite/DashStitchResult.java | 85 ++++++ .../client/sprite/DashTextureSlot.java | 18 ++ .../client/sprite/DashTextureStitcher.java | 162 +++++++++++ .../client/sprite/SpriteStitcherModule.java | 111 ++++++++ .../notalpha/dashloader/client/ui/Color.java | 45 +++ .../dashloader/client/ui/DashToast.java | 267 ++++++++++++++++++ .../dashloader/client/ui/DashToastState.java | 126 +++++++++ .../dashloader/client/ui/DashToastStatus.java | 7 + .../dashloader/client/ui/DrawerUtil.java | 157 ++++++++++ .../notalpha/dashloader/config/Config.java | 17 ++ .../dashloader/config/ConfigHandler.java | 100 +++++++ .../notalpha/dashloader/config/Option.java | 33 +++ .../dev/notalpha/dashloader/io/IOHelper.java | 139 +++++++++ .../dashloader/io/MappingSerializer.java | 124 ++++++++ .../dashloader/io/RegistrySerializer.java | 225 +++++++++++++++ .../notalpha/dashloader/io/Serializer.java | 72 +++++ .../dashloader/io/data/CacheInfo.java | 30 ++ .../dashloader/io/data/ChunkInfo.java | 21 ++ .../io/data/fragment/CacheFragment.java | 24 ++ .../io/data/fragment/ChunkFragment.java | 15 + .../io/data/fragment/FragmentSlice.java | 21 ++ .../io/data/fragment/StageFragment.java | 24 ++ .../io/def/DataUnsafeByteBuffer.java | 14 + .../dashloader/io/def/NativeImageData.java | 15 + .../dashloader/io/def/NativeImageDataDef.java | 90 ++++++ .../dashloader/io/fragment/Fragment.java | 27 ++ .../dashloader/io/fragment/Piece.java | 51 ++++ .../dashloader/io/fragment/SimplePiece.java | 22 ++ .../dashloader/io/fragment/SizePiece.java | 17 ++ .../notalpha/dashloader/misc/HahaManager.java | 80 ++++++ .../dashloader/misc/ObjectDumper.java | 146 ++++++++++ .../dashloader/misc/ProfilerUtil.java | 25 ++ .../dashloader/misc/UnsafeHelper.java | 41 +++ .../notalpha/dashloader/misc/UnsafeImage.java | 27 ++ 99 files changed, 6534 insertions(+) create mode 100644 common/src/main/java/dev/notalpha/dashloader/CacheFactoryImpl.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/CacheImpl.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/DashLoader.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/DashObjectClass.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/api/CachingData.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/api/DashEntrypoint.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/api/DashModule.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/api/DashObject.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/api/cache/Cache.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/api/cache/CacheFactory.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/api/cache/CacheStatus.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/api/collection/IntIntList.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/api/collection/IntObjectList.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/api/collection/ObjectIntList.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/api/collection/ObjectObjectList.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/api/registry/RegistryAddException.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/api/registry/RegistryReader.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/api/registry/RegistryUtil.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/api/registry/RegistryWriter.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/DashLoaderClient.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/Dazy.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/blockstate/DashBlockState.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFont.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFontGlyph.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/font/DashBlankFont.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/font/DashSpaceFont.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/font/DashTrueTypeFont.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/font/DashUnihexFont.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/font/FontModule.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/identifier/DashIdentifier.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/identifier/DashModelIdentifier.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/identifier/DashSpriteIdentifier.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/model/DashBasicBakedModel.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/model/DashBuiltinBakedModel.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/model/DashMultipartBakedModel.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/model/DashWeightedBakedModel.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/model/ModelModule.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/model/components/BakedQuadCollection.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuad.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuadCollection.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/model/components/DashMesh.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideList.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListBakedOverride.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListInlinedCondition.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelTransformation.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/model/components/DashWeightedModelEntry.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/model/fallback/UnbakedBakedModel.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/model/predicates/BooleanSelector.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashAndPredicate.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashOrPredicate.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashSimplePredicate.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashStaticPredicate.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/shader/DashGlBlendState.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/shader/DashGlUniform.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/shader/DashShader.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/shader/DashShaderStage.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormat.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormatElement.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/shader/ShaderModule.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/splash/SplashModule.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/sprite/DashImage.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/sprite/DashSprite.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimation.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimationFrame.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteContents.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/sprite/DashStitchResult.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/sprite/DashTextureSlot.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/sprite/DashTextureStitcher.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/sprite/SpriteStitcherModule.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/ui/Color.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/ui/DashToast.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/ui/DashToastState.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/ui/DashToastStatus.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/client/ui/DrawerUtil.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/config/Config.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/config/ConfigHandler.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/config/Option.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/io/IOHelper.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/io/MappingSerializer.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/io/RegistrySerializer.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/io/Serializer.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/io/data/CacheInfo.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/io/data/ChunkInfo.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/io/data/fragment/CacheFragment.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/io/data/fragment/ChunkFragment.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/io/data/fragment/FragmentSlice.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/io/data/fragment/StageFragment.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/io/def/DataUnsafeByteBuffer.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/io/def/NativeImageData.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/io/def/NativeImageDataDef.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/io/fragment/Fragment.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/io/fragment/Piece.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/io/fragment/SimplePiece.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/io/fragment/SizePiece.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/misc/HahaManager.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/misc/ObjectDumper.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/misc/ProfilerUtil.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/misc/UnsafeHelper.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/misc/UnsafeImage.java diff --git a/common/src/main/java/dev/notalpha/dashloader/CacheFactoryImpl.java b/common/src/main/java/dev/notalpha/dashloader/CacheFactoryImpl.java new file mode 100644 index 00000000..2b83261a --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/CacheImpl.java b/common/src/main/java/dev/notalpha/dashloader/CacheImpl.java new file mode 100644 index 00000000..50e6fa33 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/DashLoader.java b/common/src/main/java/dev/notalpha/dashloader/DashLoader.java new file mode 100644 index 00000000..6c8e64f7 --- /dev/null +++ b/common/src/main/java/dev/notalpha/dashloader/DashLoader.java @@ -0,0 +1,50 @@ +package dev.notalpha.dashloader; + +import dev.notalpha.dashloader.io.Serializer; +import dev.notalpha.dashloader.io.data.CacheInfo; +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.ModContainer; +import net.fabricmc.loader.api.metadata.ModMetadata; +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/common/src/main/java/dev/notalpha/dashloader/DashObjectClass.java b/common/src/main/java/dev/notalpha/dashloader/DashObjectClass.java new file mode 100644 index 00000000..d9f57bbf --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/api/CachingData.java b/common/src/main/java/dev/notalpha/dashloader/api/CachingData.java new file mode 100644 index 00000000..44324625 --- /dev/null +++ b/common/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/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/common/src/main/java/dev/notalpha/dashloader/api/collection/IntIntList.java b/common/src/main/java/dev/notalpha/dashloader/api/collection/IntIntList.java new file mode 100644 index 00000000..6a82ada4 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/api/collection/IntObjectList.java b/common/src/main/java/dev/notalpha/dashloader/api/collection/IntObjectList.java new file mode 100644 index 00000000..46f7104c --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/api/collection/ObjectIntList.java b/common/src/main/java/dev/notalpha/dashloader/api/collection/ObjectIntList.java new file mode 100644 index 00000000..2b1c0b41 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/api/collection/ObjectObjectList.java b/common/src/main/java/dev/notalpha/dashloader/api/collection/ObjectObjectList.java new file mode 100644 index 00000000..d9c0a48d --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/api/registry/RegistryAddException.java b/common/src/main/java/dev/notalpha/dashloader/api/registry/RegistryAddException.java new file mode 100644 index 00000000..30fc972f --- /dev/null +++ b/common/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/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/common/src/main/java/dev/notalpha/dashloader/client/DashLoaderClient.java b/common/src/main/java/dev/notalpha/dashloader/client/DashLoaderClient.java new file mode 100644 index 00000000..a05ee11f --- /dev/null +++ b/common/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/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/common/src/main/java/dev/notalpha/dashloader/client/blockstate/DashBlockState.java b/common/src/main/java/dev/notalpha/dashloader/client/blockstate/DashBlockState.java new file mode 100644 index 00000000..68d62fbd --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFont.java b/common/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFont.java new file mode 100644 index 00000000..247f6541 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFontGlyph.java b/common/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFontGlyph.java new file mode 100644 index 00000000..3aa4ee29 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/font/DashBlankFont.java b/common/src/main/java/dev/notalpha/dashloader/client/font/DashBlankFont.java new file mode 100644 index 00000000..24414c1d --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/font/DashSpaceFont.java b/common/src/main/java/dev/notalpha/dashloader/client/font/DashSpaceFont.java new file mode 100644 index 00000000..720dae61 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/font/DashTrueTypeFont.java b/common/src/main/java/dev/notalpha/dashloader/client/font/DashTrueTypeFont.java new file mode 100644 index 00000000..97181696 --- /dev/null +++ b/common/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/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/common/src/main/java/dev/notalpha/dashloader/client/identifier/DashIdentifier.java b/common/src/main/java/dev/notalpha/dashloader/client/identifier/DashIdentifier.java new file mode 100644 index 00000000..6e194119 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/identifier/DashModelIdentifier.java b/common/src/main/java/dev/notalpha/dashloader/client/identifier/DashModelIdentifier.java new file mode 100644 index 00000000..8eaaa499 --- /dev/null +++ b/common/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/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/common/src/main/java/dev/notalpha/dashloader/client/model/DashBasicBakedModel.java b/common/src/main/java/dev/notalpha/dashloader/client/model/DashBasicBakedModel.java new file mode 100644 index 00000000..d62680de --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/model/DashBuiltinBakedModel.java b/common/src/main/java/dev/notalpha/dashloader/client/model/DashBuiltinBakedModel.java new file mode 100644 index 00000000..8efca594 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/model/DashMultipartBakedModel.java b/common/src/main/java/dev/notalpha/dashloader/client/model/DashMultipartBakedModel.java new file mode 100644 index 00000000..a05463de --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/model/DashWeightedBakedModel.java b/common/src/main/java/dev/notalpha/dashloader/client/model/DashWeightedBakedModel.java new file mode 100644 index 00000000..49d759ab --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/model/ModelModule.java b/common/src/main/java/dev/notalpha/dashloader/client/model/ModelModule.java new file mode 100644 index 00000000..bc6588ee --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/model/components/BakedQuadCollection.java b/common/src/main/java/dev/notalpha/dashloader/client/model/components/BakedQuadCollection.java new file mode 100644 index 00000000..71266611 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuad.java b/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuad.java new file mode 100644 index 00000000..97be8df4 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuadCollection.java b/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuadCollection.java new file mode 100644 index 00000000..9dd82cb8 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashMesh.java b/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashMesh.java new file mode 100644 index 00000000..03025ffe --- /dev/null +++ b/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashMesh.java @@ -0,0 +1,85 @@ +package dev.notalpha.dashloader.client.model.components; + +import dev.notalpha.dashloader.misc.UnsafeHelper; +import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh; + +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/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideList.java b/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideList.java new file mode 100644 index 00000000..0e13f458 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListBakedOverride.java b/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListBakedOverride.java new file mode 100644 index 00000000..84b11e43 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListInlinedCondition.java b/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListInlinedCondition.java new file mode 100644 index 00000000..88ca2f05 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelTransformation.java b/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelTransformation.java new file mode 100644 index 00000000..21c9a51a --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashWeightedModelEntry.java b/common/src/main/java/dev/notalpha/dashloader/client/model/components/DashWeightedModelEntry.java new file mode 100644 index 00000000..f7dcd5db --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/model/fallback/UnbakedBakedModel.java b/common/src/main/java/dev/notalpha/dashloader/client/model/fallback/UnbakedBakedModel.java new file mode 100644 index 00000000..903a7876 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/model/predicates/BooleanSelector.java b/common/src/main/java/dev/notalpha/dashloader/client/model/predicates/BooleanSelector.java new file mode 100644 index 00000000..c699e8c8 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashAndPredicate.java b/common/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashAndPredicate.java new file mode 100644 index 00000000..45377653 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashOrPredicate.java b/common/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashOrPredicate.java new file mode 100644 index 00000000..9a208f5a --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashSimplePredicate.java b/common/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashSimplePredicate.java new file mode 100644 index 00000000..9395653b --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashStaticPredicate.java b/common/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashStaticPredicate.java new file mode 100644 index 00000000..f4419be8 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/shader/DashGlBlendState.java b/common/src/main/java/dev/notalpha/dashloader/client/shader/DashGlBlendState.java new file mode 100644 index 00000000..4f26f7ca --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/shader/DashGlUniform.java b/common/src/main/java/dev/notalpha/dashloader/client/shader/DashGlUniform.java new file mode 100644 index 00000000..d563c837 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/shader/DashShader.java b/common/src/main/java/dev/notalpha/dashloader/client/shader/DashShader.java new file mode 100644 index 00000000..8aecd44f --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/shader/DashShaderStage.java b/common/src/main/java/dev/notalpha/dashloader/client/shader/DashShaderStage.java new file mode 100644 index 00000000..fc008626 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormat.java b/common/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormat.java new file mode 100644 index 00000000..f98a073c --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormatElement.java b/common/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormatElement.java new file mode 100644 index 00000000..f37b0a4a --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/shader/ShaderModule.java b/common/src/main/java/dev/notalpha/dashloader/client/shader/ShaderModule.java new file mode 100644 index 00000000..0136eddb --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/splash/SplashModule.java b/common/src/main/java/dev/notalpha/dashloader/client/splash/SplashModule.java new file mode 100644 index 00000000..c5da26e9 --- /dev/null +++ b/common/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 SplashModule.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/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashImage.java b/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashImage.java new file mode 100644 index 00000000..7ad960c6 --- /dev/null +++ b/common/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/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/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimation.java b/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimation.java new file mode 100644 index 00000000..ec3ef01e --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimationFrame.java b/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimationFrame.java new file mode 100644 index 00000000..1216a9a7 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteContents.java b/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteContents.java new file mode 100644 index 00000000..3ad5a9a7 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashStitchResult.java b/common/src/main/java/dev/notalpha/dashloader/client/sprite/DashStitchResult.java new file mode 100644 index 00000000..3a5034c1 --- /dev/null +++ b/common/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/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/common/src/main/java/dev/notalpha/dashloader/client/ui/Color.java b/common/src/main/java/dev/notalpha/dashloader/client/ui/Color.java new file mode 100644 index 00000000..82f86854 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/ui/DashToast.java b/common/src/main/java/dev/notalpha/dashloader/client/ui/DashToast.java new file mode 100644 index 00000000..9f6d92db --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/ui/DashToastState.java b/common/src/main/java/dev/notalpha/dashloader/client/ui/DashToastState.java new file mode 100644 index 00000000..cb58d51a --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/ui/DashToastStatus.java b/common/src/main/java/dev/notalpha/dashloader/client/ui/DashToastStatus.java new file mode 100644 index 00000000..dea81b66 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/client/ui/DrawerUtil.java b/common/src/main/java/dev/notalpha/dashloader/client/ui/DrawerUtil.java new file mode 100644 index 00000000..b70c810b --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/config/Config.java b/common/src/main/java/dev/notalpha/dashloader/config/Config.java new file mode 100644 index 00000000..27476949 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/config/ConfigHandler.java b/common/src/main/java/dev/notalpha/dashloader/config/ConfigHandler.java new file mode 100644 index 00000000..73451fb2 --- /dev/null +++ b/common/src/main/java/dev/notalpha/dashloader/config/ConfigHandler.java @@ -0,0 +1,100 @@ +package dev.notalpha.dashloader.config; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import dev.notalpha.dashloader.DashLoader; +import net.fabricmc.loader.api.FabricLoader; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +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(FabricLoader.getInstance().getConfigDir().normalize().resolve("dashloader.json")); + 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 : FabricLoader.getInstance().getAllMods()) { + var mod = modContainer.getMetadata(); + 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/common/src/main/java/dev/notalpha/dashloader/config/Option.java b/common/src/main/java/dev/notalpha/dashloader/config/Option.java new file mode 100644 index 00000000..7b6348ef --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/io/IOHelper.java b/common/src/main/java/dev/notalpha/dashloader/io/IOHelper.java new file mode 100644 index 00000000..ced56ee7 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/io/MappingSerializer.java b/common/src/main/java/dev/notalpha/dashloader/io/MappingSerializer.java new file mode 100644 index 00000000..a29b8ab6 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/io/RegistrySerializer.java b/common/src/main/java/dev/notalpha/dashloader/io/RegistrySerializer.java new file mode 100644 index 00000000..33868af7 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/io/Serializer.java b/common/src/main/java/dev/notalpha/dashloader/io/Serializer.java new file mode 100644 index 00000000..2d5da226 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/io/data/CacheInfo.java b/common/src/main/java/dev/notalpha/dashloader/io/data/CacheInfo.java new file mode 100644 index 00000000..d1dae4b3 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/io/data/ChunkInfo.java b/common/src/main/java/dev/notalpha/dashloader/io/data/ChunkInfo.java new file mode 100644 index 00000000..63dc08e7 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/io/data/fragment/CacheFragment.java b/common/src/main/java/dev/notalpha/dashloader/io/data/fragment/CacheFragment.java new file mode 100644 index 00000000..03628dae --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/io/data/fragment/ChunkFragment.java b/common/src/main/java/dev/notalpha/dashloader/io/data/fragment/ChunkFragment.java new file mode 100644 index 00000000..46b46e2d --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/io/data/fragment/FragmentSlice.java b/common/src/main/java/dev/notalpha/dashloader/io/data/fragment/FragmentSlice.java new file mode 100644 index 00000000..1c8ddcab --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/io/data/fragment/StageFragment.java b/common/src/main/java/dev/notalpha/dashloader/io/data/fragment/StageFragment.java new file mode 100644 index 00000000..110bd111 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/io/def/DataUnsafeByteBuffer.java b/common/src/main/java/dev/notalpha/dashloader/io/def/DataUnsafeByteBuffer.java new file mode 100644 index 00000000..9c469e2a --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/io/def/NativeImageData.java b/common/src/main/java/dev/notalpha/dashloader/io/def/NativeImageData.java new file mode 100644 index 00000000..4420f147 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/io/def/NativeImageDataDef.java b/common/src/main/java/dev/notalpha/dashloader/io/def/NativeImageDataDef.java new file mode 100644 index 00000000..59b736bf --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/io/fragment/Fragment.java b/common/src/main/java/dev/notalpha/dashloader/io/fragment/Fragment.java new file mode 100644 index 00000000..edc2ed65 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/io/fragment/Piece.java b/common/src/main/java/dev/notalpha/dashloader/io/fragment/Piece.java new file mode 100644 index 00000000..6a68a8bc --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/io/fragment/SimplePiece.java b/common/src/main/java/dev/notalpha/dashloader/io/fragment/SimplePiece.java new file mode 100644 index 00000000..4b612b29 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/io/fragment/SizePiece.java b/common/src/main/java/dev/notalpha/dashloader/io/fragment/SizePiece.java new file mode 100644 index 00000000..8d587d6a --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/misc/HahaManager.java b/common/src/main/java/dev/notalpha/dashloader/misc/HahaManager.java new file mode 100644 index 00000000..ee5c9fa9 --- /dev/null +++ b/common/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/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/common/src/main/java/dev/notalpha/dashloader/misc/ProfilerUtil.java b/common/src/main/java/dev/notalpha/dashloader/misc/ProfilerUtil.java new file mode 100644 index 00000000..71e5cc90 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/misc/UnsafeHelper.java b/common/src/main/java/dev/notalpha/dashloader/misc/UnsafeHelper.java new file mode 100644 index 00000000..327a387b --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/misc/UnsafeImage.java b/common/src/main/java/dev/notalpha/dashloader/misc/UnsafeImage.java new file mode 100644 index 00000000..d7923cd8 --- /dev/null +++ b/common/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); + } +} From dcd7f7cd008eec5d8884b72081494c17d46bbf08 Mon Sep 17 00:00:00 2001 From: ShuyanMC <1149461164@qq.com> Date: Thu, 31 Jul 2025 23:52:18 +0800 Subject: [PATCH 12/17] Add files via upload --- .../dashloader/mixin/MixinPlugin.java | 47 +++++ .../accessor/AbstractTextureAccessor.java | 21 ++ .../AndMultipartModelSelectorAccessor.java | 14 ++ .../accessor/BasicBakedModelAccessor.java | 41 ++++ .../mixin/accessor/BitmapFontAccessor.java | 25 +++ .../accessor/BitmapFontGlyphAccessor.java | 41 ++++ .../accessor/BuiltinBakedModelAccessor.java | 25 +++ .../accessor/EffectShaderStageAccessor.java | 14 ++ .../FontManagerProviderIndexAccessor.java | 20 ++ .../mixin/accessor/FontStorageAccessor.java | 40 ++++ .../mixin/accessor/GlBlendStateAccessor.java | 38 ++++ .../mixin/accessor/GlUniformAccessor.java | 30 +++ .../mixin/accessor/IdentifierAccessor.java | 15 ++ .../accessor/ModelIdentifierAccessor.java | 15 ++ .../mixin/accessor/ModelLoaderAccessor.java | 26 +++ .../accessor/ModelOverrideListAccessor.java | 32 +++ ...odelOverrideListBakedOverrideAccessor.java | 23 +++ .../ModelOverrideListInlinedCondition.java | 16 ++ .../accessor/MultipartBakedModelAccessor.java | 37 ++++ .../MultipartModelComponentAccessor.java | 13 ++ .../mixin/accessor/NativeImageAccessor.java | 22 +++ .../OrMultipartModelSelectorAccessor.java | 14 ++ .../mixin/accessor/ShaderProgramAccessor.java | 101 ++++++++++ .../mixin/accessor/ShaderStageAccessor.java | 27 +++ .../SimpleMultipartModelSelectorAccessor.java | 16 ++ .../mixin/accessor/SpriteAccessor.java | 16 ++ .../accessor/SpriteAnimationAccessor.java | 28 +++ .../SpriteAnimationFrameAccessor.java | 21 ++ .../accessor/SpriteContentsAccessor.java | 46 +++++ .../SpriteLoaderStitchResultAccessor.java | 20 ++ .../mixin/accessor/TrueTypeFontAccessor.java | 68 +++++++ .../mixin/accessor/UnihexFontAccessor.java | 22 +++ .../mixin/accessor/VertexFormatAccessor.java | 14 ++ .../accessor/WeightedBakedModelAccessor.java | 16 ++ .../WeightedBakedModelEntryAccessor.java | 14 ++ .../accessor/ZipResourcePackAccessor.java | 13 ++ .../dashloader/mixin/main/BootstrapMixin.java | 25 +++ .../dashloader/mixin/main/KeyboardMixin.java | 46 +++++ .../dashloader/mixin/main/MainMixin.java | 24 +++ .../mixin/main/MinecraftClientMixin.java | 37 ++++ .../ReloadableResourceManagerImplMixin.java | 57 ++++++ .../mixin/main/SplashScreenMixin.java | 110 +++++++++++ .../mixin/option/WallBlockMixin.java | 164 ++++++++++++++++ .../SplashTextResourceSupplierMixin.java | 37 ++++ .../cache/font/FontManagerOverride.java | 44 +++++ .../cache/font/TrueTypeFontLoaderMixin.java | 33 ++++ .../model/BakedModelManagerOverride.java | 34 ++++ .../option/cache/model/BlockModelsMixin.java | 30 +++ .../option/cache/model/ModelLoaderMixin.java | 148 ++++++++++++++ .../model/MultipartUnbakedModelMixin.java | 55 ++++++ .../cache/shader/GameRendererMixin.java | 41 ++++ .../cache/shader/GlStateManagerMixin.java | 27 +++ .../cache/sprite/SpriteLoaderMixin.java | 96 +++++++++ .../misc/AffineTransformationMixin.java | 31 +++ .../mixin/option/misc/MipmapHelperMixin.java | 142 ++++++++++++++ .../option/misc/ModelIdentifierMixin.java | 35 ++++ .../ModelLoaderBakedModelCacheKeyMixin.java | 41 ++++ .../dashloader/registry/FactoryBinding.java | 96 +++++++++ .../dashloader/registry/MissingHandler.java | 16 ++ .../registry/RegistryReaderImpl.java | 46 +++++ .../registry/RegistryWriterImpl.java | 185 ++++++++++++++++++ .../registry/TrackingRegistryWriterImpl.java | 36 ++++ .../dashloader/registry/data/ChunkData.java | 50 +++++ .../registry/data/ChunkFactory.java | 67 +++++++ .../dashloader/registry/data/StageData.java | 31 +++ 65 files changed, 2775 insertions(+) create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/MixinPlugin.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/AbstractTextureAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/AndMultipartModelSelectorAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/BasicBakedModelAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontGlyphAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/BuiltinBakedModelAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/EffectShaderStageAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontManagerProviderIndexAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontStorageAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/GlBlendStateAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/GlUniformAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/IdentifierAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelIdentifierAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelLoaderAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListBakedOverrideAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListInlinedCondition.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartBakedModelAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartModelComponentAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/NativeImageAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/OrMultipartModelSelectorAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderProgramAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderStageAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SimpleMultipartModelSelectorAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationFrameAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteContentsAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteLoaderStitchResultAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/TrueTypeFontAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/UnihexFontAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/VertexFormatAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelEntryAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ZipResourcePackAccessor.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/main/BootstrapMixin.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/main/KeyboardMixin.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/main/MainMixin.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/main/MinecraftClientMixin.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/main/ReloadableResourceManagerImplMixin.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/main/SplashScreenMixin.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/option/WallBlockMixin.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/SplashTextResourceSupplierMixin.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/font/FontManagerOverride.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/font/TrueTypeFontLoaderMixin.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/BakedModelManagerOverride.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/BlockModelsMixin.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/ModelLoaderMixin.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/MultipartUnbakedModelMixin.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/shader/GameRendererMixin.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/shader/GlStateManagerMixin.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/sprite/SpriteLoaderMixin.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/option/misc/AffineTransformationMixin.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/option/misc/MipmapHelperMixin.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelIdentifierMixin.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelLoaderBakedModelCacheKeyMixin.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/registry/FactoryBinding.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/registry/MissingHandler.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/registry/RegistryReaderImpl.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/registry/RegistryWriterImpl.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/registry/TrackingRegistryWriterImpl.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/registry/data/ChunkData.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/registry/data/ChunkFactory.java create mode 100644 common/src/main/java/dev/notalpha/dashloader/registry/data/StageData.java diff --git a/common/src/main/java/dev/notalpha/dashloader/mixin/MixinPlugin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/MixinPlugin.java new file mode 100644 index 00000000..d7532817 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/AbstractTextureAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/AbstractTextureAccessor.java new file mode 100644 index 00000000..b1eb9046 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/AndMultipartModelSelectorAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/AndMultipartModelSelectorAccessor.java new file mode 100644 index 00000000..88c346ab --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/BasicBakedModelAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/BasicBakedModelAccessor.java new file mode 100644 index 00000000..7d44708d --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontAccessor.java new file mode 100644 index 00000000..cfa6bd81 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontGlyphAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontGlyphAccessor.java new file mode 100644 index 00000000..951e8862 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/BuiltinBakedModelAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/BuiltinBakedModelAccessor.java new file mode 100644 index 00000000..d3b31bc6 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/EffectShaderStageAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/EffectShaderStageAccessor.java new file mode 100644 index 00000000..9e4a4e59 --- /dev/null +++ b/common/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/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontStorageAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontStorageAccessor.java new file mode 100644 index 00000000..4b272087 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/GlBlendStateAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/GlBlendStateAccessor.java new file mode 100644 index 00000000..c10e32c2 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/GlUniformAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/GlUniformAccessor.java new file mode 100644 index 00000000..11062656 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/IdentifierAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/IdentifierAccessor.java new file mode 100644 index 00000000..f6812ade --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelIdentifierAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelIdentifierAccessor.java new file mode 100644 index 00000000..d1eb30ef --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelLoaderAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelLoaderAccessor.java new file mode 100644 index 00000000..d1398e13 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListAccessor.java new file mode 100644 index 00000000..ce7ff85e --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListBakedOverrideAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListBakedOverrideAccessor.java new file mode 100644 index 00000000..776f66af --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListInlinedCondition.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListInlinedCondition.java new file mode 100644 index 00000000..085af7c4 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartBakedModelAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartBakedModelAccessor.java new file mode 100644 index 00000000..db5d809a --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartModelComponentAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartModelComponentAccessor.java new file mode 100644 index 00000000..84c1c4c1 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/NativeImageAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/NativeImageAccessor.java new file mode 100644 index 00000000..22ec08b3 --- /dev/null +++ b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/NativeImageAccessor.java @@ -0,0 +1,22 @@ +package dev.notalpha.dashloader.mixin.accessor; + +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(NativeImage.class) +public interface NativeImageAccessor { + + + @Invoker("") + 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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/OrMultipartModelSelectorAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/OrMultipartModelSelectorAccessor.java new file mode 100644 index 00000000..134d1a72 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderProgramAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderProgramAccessor.java new file mode 100644 index 00000000..b955690f --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderStageAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderStageAccessor.java new file mode 100644 index 00000000..b41a915d --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SimpleMultipartModelSelectorAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SimpleMultipartModelSelectorAccessor.java new file mode 100644 index 00000000..51729f34 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAccessor.java new file mode 100644 index 00000000..793de382 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationAccessor.java new file mode 100644 index 00000000..26e2be5a --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationFrameAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationFrameAccessor.java new file mode 100644 index 00000000..83dc0ee8 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteContentsAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteContentsAccessor.java new file mode 100644 index 00000000..29672892 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteLoaderStitchResultAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteLoaderStitchResultAccessor.java new file mode 100644 index 00000000..6adaef58 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/TrueTypeFontAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/TrueTypeFontAccessor.java new file mode 100644 index 00000000..a1706cbe --- /dev/null +++ b/common/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/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/VertexFormatAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/VertexFormatAccessor.java new file mode 100644 index 00000000..dc7d27a1 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelAccessor.java new file mode 100644 index 00000000..0d1c2394 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelEntryAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelEntryAccessor.java new file mode 100644 index 00000000..2e9c2897 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ZipResourcePackAccessor.java b/common/src/main/java/dev/notalpha/dashloader/mixin/accessor/ZipResourcePackAccessor.java new file mode 100644 index 00000000..baf957b4 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/main/BootstrapMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/main/BootstrapMixin.java new file mode 100644 index 00000000..264dce93 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/main/KeyboardMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/main/KeyboardMixin.java new file mode 100644 index 00000000..dd600cc0 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/main/MainMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/main/MainMixin.java new file mode 100644 index 00000000..5f00ecbc --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/main/MinecraftClientMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/main/MinecraftClientMixin.java new file mode 100644 index 00000000..df50f39d --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/main/ReloadableResourceManagerImplMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/main/ReloadableResourceManagerImplMixin.java new file mode 100644 index 00000000..4b5c0c78 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/main/SplashScreenMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/main/SplashScreenMixin.java new file mode 100644 index 00000000..326a91d0 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/option/WallBlockMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/option/WallBlockMixin.java new file mode 100644 index 00000000..644cb630 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/SplashTextResourceSupplierMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/SplashTextResourceSupplierMixin.java new file mode 100644 index 00000000..5d1c1646 --- /dev/null +++ b/common/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/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/common/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 new file mode 100644 index 00000000..b8c59c97 --- /dev/null +++ b/common/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/common/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 new file mode 100644 index 00000000..0c31a337 --- /dev/null +++ b/common/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/common/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 new file mode 100644 index 00000000..87ec8e00 --- /dev/null +++ b/common/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/common/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 new file mode 100644 index 00000000..59d40293 --- /dev/null +++ b/common/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/ModelLoaderMixin.java @@ -0,0 +1,148 @@ +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.*; +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; + + @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 + 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/common/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 new file mode 100644 index 00000000..447299c2 --- /dev/null +++ b/common/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/common/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 new file mode 100644 index 00000000..f4769649 --- /dev/null +++ b/common/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/common/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 new file mode 100644 index 00000000..dafbf972 --- /dev/null +++ b/common/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/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/common/src/main/java/dev/notalpha/dashloader/mixin/option/misc/AffineTransformationMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/option/misc/AffineTransformationMixin.java new file mode 100644 index 00000000..1b5f73c9 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/option/misc/MipmapHelperMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/option/misc/MipmapHelperMixin.java new file mode 100644 index 00000000..2fae3650 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelIdentifierMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelIdentifierMixin.java new file mode 100644 index 00000000..1871b915 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelLoaderBakedModelCacheKeyMixin.java b/common/src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelLoaderBakedModelCacheKeyMixin.java new file mode 100644 index 00000000..eb80fb0b --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/registry/FactoryBinding.java b/common/src/main/java/dev/notalpha/dashloader/registry/FactoryBinding.java new file mode 100644 index 00000000..8fc887b5 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/registry/MissingHandler.java b/common/src/main/java/dev/notalpha/dashloader/registry/MissingHandler.java new file mode 100644 index 00000000..08a423b7 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/registry/RegistryReaderImpl.java b/common/src/main/java/dev/notalpha/dashloader/registry/RegistryReaderImpl.java new file mode 100644 index 00000000..e6b9ac8d --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/registry/RegistryWriterImpl.java b/common/src/main/java/dev/notalpha/dashloader/registry/RegistryWriterImpl.java new file mode 100644 index 00000000..21d94129 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/registry/TrackingRegistryWriterImpl.java b/common/src/main/java/dev/notalpha/dashloader/registry/TrackingRegistryWriterImpl.java new file mode 100644 index 00000000..8a0bff30 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/registry/data/ChunkData.java b/common/src/main/java/dev/notalpha/dashloader/registry/data/ChunkData.java new file mode 100644 index 00000000..fbe05aa5 --- /dev/null +++ b/common/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/common/src/main/java/dev/notalpha/dashloader/registry/data/ChunkFactory.java b/common/src/main/java/dev/notalpha/dashloader/registry/data/ChunkFactory.java new file mode 100644 index 00000000..dd712d55 --- /dev/null +++ b/common/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)]; + ChunkFactory.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/common/src/main/java/dev/notalpha/dashloader/registry/data/StageData.java b/common/src/main/java/dev/notalpha/dashloader/registry/data/StageData.java new file mode 100644 index 00000000..d5e9e06c --- /dev/null +++ b/common/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); + } + } +} From b14e45625984647849cd70083880abeb5e94241f Mon Sep 17 00:00:00 2001 From: ShuyanMC <1149461164@qq.com> Date: Thu, 31 Jul 2025 23:52:53 +0800 Subject: [PATCH 13/17] Delete LICENSE.txt --- LICENSE.txt | 857 ---------------------------------------------------- 1 file changed, 857 deletions(-) delete mode 100644 LICENSE.txt diff --git a/LICENSE.txt b/LICENSE.txt deleted file mode 100644 index b622450a..00000000 --- a/LICENSE.txt +++ /dev/null @@ -1,857 +0,0 @@ -Copyright (c) 2025 KSmc_brigade - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -and a copy of GNU General Public License along with this program. If not, see - - - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. - - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - {one line to give the program's name and a brief idea of what it does.} - Copyright (C) {year} {name of author} - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - {project} Copyright (C) {year} {fullname} - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. - From 483b5ecd56bbb2c478b22eb0840685ae4566baf5 Mon Sep 17 00:00:00 2001 From: ShuyanMC <1149461164@qq.com> Date: Thu, 31 Jul 2025 23:54:25 +0800 Subject: [PATCH 14/17] Add files via upload --- forge/build.gradle | 92 +++++++++++++++++++++++++++++++++++++++++ forge/gradle.properties | 1 + 2 files changed, 93 insertions(+) create mode 100644 forge/build.gradle create mode 100644 forge/gradle.properties 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 From 25164cfb41c36d535718a775ac868d0b7e8e47de Mon Sep 17 00:00:00 2001 From: ShuyanMC <1149461164@qq.com> Date: Thu, 31 Jul 2025 23:56:13 +0800 Subject: [PATCH 15/17] Add files via upload --- .../dashloader/forge/DashloaderForge.java | 14 ++++ forge/src/main/resources/META-INF/mods.toml | 35 +++++++++ .../main/resources/dashloader.accesswidener | 37 +++++++++ .../src/main/resources/dashloader.mixins.json | 72 ++++++++++++++++++ .../main/resources/dashloader/lang/en_us.json | 11 +++ .../resources/dashloader/lang/lol_us.json | 11 +++ .../main/resources/dashloader/lang/sv_se.json | 11 +++ .../resources/dashloader/textures/icon.png | Bin 0 -> 18600 bytes forge/src/main/resources/pack.mcmeta | 6 ++ 9 files changed, 197 insertions(+) create mode 100644 forge/src/main/java/cn/ksmcbrigade/dashloader/forge/DashloaderForge.java create mode 100644 forge/src/main/resources/META-INF/mods.toml create mode 100644 forge/src/main/resources/dashloader.accesswidener create mode 100644 forge/src/main/resources/dashloader.mixins.json create mode 100644 forge/src/main/resources/dashloader/lang/en_us.json create mode 100644 forge/src/main/resources/dashloader/lang/lol_us.json create mode 100644 forge/src/main/resources/dashloader/lang/sv_se.json create mode 100644 forge/src/main/resources/dashloader/textures/icon.png create mode 100644 forge/src/main/resources/pack.mcmeta 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/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 0000000000000000000000000000000000000000..5f8fc5f83d46ff6d5a739a94be0e4d86e53ec5d6 GIT binary patch literal 18600 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 (-jmicAB8X3EDp^o|{IMLnh(D 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∈4HgYwx)#=>0Z^);fB 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 N13lvlW#^p2{|_Z5?N|T+ literal 0 HcmV?d00001 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 + } +} From 0a70c729648588e94eebfc6c0def96f18a0361f6 Mon Sep 17 00:00:00 2001 From: ShuyanMC <1149461164@qq.com> Date: Fri, 1 Aug 2025 00:00:19 +0800 Subject: [PATCH 16/17] Add files via upload --- .../notalpha/dashloader/CacheFactoryImpl.java | 77 +++++ .../dev/notalpha/dashloader/CacheImpl.java | 224 +++++++++++++++ .../dev/notalpha/dashloader/DashLoader.java | 47 +++ .../notalpha/dashloader/DashObjectClass.java | 80 ++++++ .../notalpha/dashloader/api/CachingData.java | 77 +++++ .../dashloader/api/DashEntrypoint.java | 18 ++ .../notalpha/dashloader/api/DashModule.java | 68 +++++ .../notalpha/dashloader/api/DashObject.java | 38 +++ .../notalpha/dashloader/api/cache/Cache.java | 52 ++++ .../dashloader/api/cache/CacheFactory.java | 54 ++++ .../dashloader/api/cache/CacheStatus.java | 19 ++ .../dashloader/api/collection/IntIntList.java | 26 ++ .../api/collection/IntObjectList.java | 26 ++ .../api/collection/ObjectIntList.java | 26 ++ .../api/collection/ObjectObjectList.java | 22 ++ .../api/registry/RegistryAddException.java | 17 ++ .../api/registry/RegistryReader.java | 18 ++ .../dashloader/api/registry/RegistryUtil.java | 43 +++ .../api/registry/RegistryWriter.java | 19 ++ .../dashloader/client/DashLoaderClient.java | 122 ++++++++ .../dev/notalpha/dashloader/client/Dazy.java | 23 ++ .../client/blockstate/DashBlockState.java | 86 ++++++ .../client/font/DashBitmapFont.java | 39 +++ .../client/font/DashBitmapFontGlyph.java | 44 +++ .../dashloader/client/font/DashBlankFont.java | 12 + .../dashloader/client/font/DashSpaceFont.java | 38 +++ .../client/font/DashTrueTypeFont.java | 90 ++++++ .../client/font/DashUnihexFont.java | 54 ++++ .../dashloader/client/font/FontModule.java | 127 +++++++++ .../client/identifier/DashIdentifier.java | 44 +++ .../identifier/DashModelIdentifier.java | 50 ++++ .../identifier/DashSpriteIdentifier.java | 27 ++ .../client/model/DashBasicBakedModel.java | 172 +++++++++++ .../client/model/DashBuiltinBakedModel.java | 95 +++++++ .../client/model/DashMultipartBakedModel.java | 148 ++++++++++ .../client/model/DashWeightedBakedModel.java | 84 ++++++ .../dashloader/client/model/ModelModule.java | 148 ++++++++++ .../model/components/BakedQuadCollection.java | 13 + .../model/components/DashBakedQuad.java | 85 ++++++ .../components/DashBakedQuadCollection.java | 71 +++++ .../client/model/components/DashMesh.java | 84 ++++++ .../components/DashModelOverrideList.java | 96 +++++++ .../DashModelOverrideListBakedOverride.java | 84 ++++++ ...DashModelOverrideListInlinedCondition.java | 40 +++ .../components/DashModelTransformation.java | 127 +++++++++ .../components/DashWeightedModelEntry.java | 44 +++ .../model/fallback/UnbakedBakedModel.java | 42 +++ .../model/predicates/BooleanSelector.java | 25 ++ .../model/predicates/DashAndPredicate.java | 61 ++++ .../model/predicates/DashOrPredicate.java | 62 ++++ .../model/predicates/DashSimplePredicate.java | 46 +++ .../model/predicates/DashStaticPredicate.java | 36 +++ .../client/shader/DashGlBlendState.java | 45 +++ .../client/shader/DashGlUniform.java | 43 +++ .../dashloader/client/shader/DashShader.java | 154 ++++++++++ .../client/shader/DashShaderStage.java | 54 ++++ .../client/shader/DashVertexFormat.java | 80 ++++++ .../shader/DashVertexFormatElement.java | 78 +++++ .../client/shader/ShaderModule.java | 69 +++++ .../client/splash/SplashModule.java | 57 ++++ .../dashloader/client/sprite/DashImage.java | 55 ++++ .../dashloader/client/sprite/DashSprite.java | 54 ++++ .../client/sprite/DashSpriteAnimation.java | 69 +++++ .../sprite/DashSpriteAnimationFrame.java | 45 +++ .../client/sprite/DashSpriteContents.java | 79 ++++++ .../client/sprite/DashStitchResult.java | 85 ++++++ .../client/sprite/DashTextureSlot.java | 18 ++ .../client/sprite/DashTextureStitcher.java | 162 +++++++++++ .../client/sprite/SpriteStitcherModule.java | 111 ++++++++ .../notalpha/dashloader/client/ui/Color.java | 45 +++ .../dashloader/client/ui/DashToast.java | 267 ++++++++++++++++++ .../dashloader/client/ui/DashToastState.java | 126 +++++++++ .../dashloader/client/ui/DashToastStatus.java | 7 + .../dashloader/client/ui/DrawerUtil.java | 157 ++++++++++ .../notalpha/dashloader/config/Config.java | 17 ++ .../dashloader/config/ConfigHandler.java | 101 +++++++ .../notalpha/dashloader/config/Option.java | 33 +++ .../dev/notalpha/dashloader/io/IOHelper.java | 139 +++++++++ .../dashloader/io/MappingSerializer.java | 124 ++++++++ .../dashloader/io/RegistrySerializer.java | 225 +++++++++++++++ .../notalpha/dashloader/io/Serializer.java | 72 +++++ .../dashloader/io/data/CacheInfo.java | 30 ++ .../dashloader/io/data/ChunkInfo.java | 21 ++ .../io/data/fragment/CacheFragment.java | 24 ++ .../io/data/fragment/ChunkFragment.java | 15 + .../io/data/fragment/FragmentSlice.java | 21 ++ .../io/data/fragment/StageFragment.java | 24 ++ .../io/def/DataUnsafeByteBuffer.java | 14 + .../dashloader/io/def/NativeImageData.java | 15 + .../dashloader/io/def/NativeImageDataDef.java | 90 ++++++ .../dashloader/io/fragment/Fragment.java | 27 ++ .../dashloader/io/fragment/Piece.java | 51 ++++ .../dashloader/io/fragment/SimplePiece.java | 22 ++ .../dashloader/io/fragment/SizePiece.java | 17 ++ .../notalpha/dashloader/misc/HahaManager.java | 80 ++++++ .../dashloader/misc/ObjectDumper.java | 146 ++++++++++ .../dashloader/misc/ProfilerUtil.java | 25 ++ .../dashloader/misc/UnsafeHelper.java | 41 +++ .../notalpha/dashloader/misc/UnsafeImage.java | 27 ++ 99 files changed, 6531 insertions(+) create mode 100644 forge/src/main/java/dev/notalpha/dashloader/CacheFactoryImpl.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/CacheImpl.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/DashLoader.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/DashObjectClass.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/api/CachingData.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/api/DashEntrypoint.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/api/DashModule.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/api/DashObject.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/api/cache/Cache.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/api/cache/CacheFactory.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/api/cache/CacheStatus.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/api/collection/IntIntList.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/api/collection/IntObjectList.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/api/collection/ObjectIntList.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/api/collection/ObjectObjectList.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/api/registry/RegistryAddException.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/api/registry/RegistryReader.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/api/registry/RegistryUtil.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/api/registry/RegistryWriter.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/DashLoaderClient.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/Dazy.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/blockstate/DashBlockState.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFont.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/font/DashBitmapFontGlyph.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/font/DashBlankFont.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/font/DashSpaceFont.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/font/DashTrueTypeFont.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/font/DashUnihexFont.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/font/FontModule.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/identifier/DashIdentifier.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/identifier/DashModelIdentifier.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/identifier/DashSpriteIdentifier.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/model/DashBasicBakedModel.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/model/DashBuiltinBakedModel.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/model/DashMultipartBakedModel.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/model/DashWeightedBakedModel.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/model/ModelModule.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/model/components/BakedQuadCollection.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuad.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashBakedQuadCollection.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashMesh.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideList.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListBakedOverride.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelOverrideListInlinedCondition.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashModelTransformation.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/model/components/DashWeightedModelEntry.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/model/fallback/UnbakedBakedModel.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/model/predicates/BooleanSelector.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashAndPredicate.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashOrPredicate.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashSimplePredicate.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/model/predicates/DashStaticPredicate.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/shader/DashGlBlendState.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/shader/DashGlUniform.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/shader/DashShader.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/shader/DashShaderStage.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormat.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/shader/DashVertexFormatElement.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/shader/ShaderModule.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/splash/SplashModule.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashImage.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashSprite.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimation.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteAnimationFrame.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashSpriteContents.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashStitchResult.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashTextureSlot.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/sprite/DashTextureStitcher.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/sprite/SpriteStitcherModule.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/ui/Color.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/ui/DashToast.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/ui/DashToastState.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/ui/DashToastStatus.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/client/ui/DrawerUtil.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/config/Config.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/config/ConfigHandler.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/config/Option.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/io/IOHelper.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/io/MappingSerializer.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/io/RegistrySerializer.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/io/Serializer.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/io/data/CacheInfo.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/io/data/ChunkInfo.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/io/data/fragment/CacheFragment.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/io/data/fragment/ChunkFragment.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/io/data/fragment/FragmentSlice.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/io/data/fragment/StageFragment.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/io/def/DataUnsafeByteBuffer.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/io/def/NativeImageData.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/io/def/NativeImageDataDef.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/io/fragment/Fragment.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/io/fragment/Piece.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/io/fragment/SimplePiece.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/io/fragment/SizePiece.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/misc/HahaManager.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/misc/ObjectDumper.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/misc/ProfilerUtil.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/misc/UnsafeHelper.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/misc/UnsafeImage.java 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); + } +} From 26134171ebed7cfdb8af07208dbdb4efedf71af0 Mon Sep 17 00:00:00 2001 From: ShuyanMC <1149461164@qq.com> Date: Fri, 1 Aug 2025 00:02:51 +0800 Subject: [PATCH 17/17] Add files via upload --- .../dashloader/mixin/MixinPlugin.java | 47 +++++ .../accessor/AbstractTextureAccessor.java | 21 ++ .../AndMultipartModelSelectorAccessor.java | 14 ++ .../accessor/BasicBakedModelAccessor.java | 41 ++++ .../mixin/accessor/BitmapFontAccessor.java | 25 +++ .../accessor/BitmapFontGlyphAccessor.java | 41 ++++ .../accessor/BuiltinBakedModelAccessor.java | 25 +++ .../accessor/EffectShaderStageAccessor.java | 14 ++ .../FontManagerProviderIndexAccessor.java | 20 ++ .../mixin/accessor/FontStorageAccessor.java | 40 ++++ .../mixin/accessor/GlBlendStateAccessor.java | 38 ++++ .../mixin/accessor/GlUniformAccessor.java | 30 +++ .../mixin/accessor/IdentifierAccessor.java | 15 ++ .../accessor/ModelIdentifierAccessor.java | 15 ++ .../mixin/accessor/ModelLoaderAccessor.java | 26 +++ .../accessor/ModelOverrideListAccessor.java | 32 +++ ...odelOverrideListBakedOverrideAccessor.java | 23 +++ .../ModelOverrideListInlinedCondition.java | 16 ++ .../accessor/MultipartBakedModelAccessor.java | 37 ++++ .../MultipartModelComponentAccessor.java | 13 ++ .../mixin/accessor/NativeImageAccessor.java | 22 +++ .../OrMultipartModelSelectorAccessor.java | 14 ++ .../mixin/accessor/ShaderProgramAccessor.java | 101 ++++++++++ .../mixin/accessor/ShaderStageAccessor.java | 27 +++ .../SimpleMultipartModelSelectorAccessor.java | 16 ++ .../mixin/accessor/SpriteAccessor.java | 16 ++ .../accessor/SpriteAnimationAccessor.java | 28 +++ .../SpriteAnimationFrameAccessor.java | 21 ++ .../accessor/SpriteContentsAccessor.java | 46 +++++ .../SpriteLoaderStitchResultAccessor.java | 20 ++ .../mixin/accessor/TrueTypeFontAccessor.java | 68 +++++++ .../mixin/accessor/UnihexFontAccessor.java | 22 +++ .../mixin/accessor/VertexFormatAccessor.java | 14 ++ .../accessor/WeightedBakedModelAccessor.java | 16 ++ .../WeightedBakedModelEntryAccessor.java | 14 ++ .../accessor/ZipResourcePackAccessor.java | 13 ++ .../dashloader/mixin/main/BootstrapMixin.java | 25 +++ .../dashloader/mixin/main/KeyboardMixin.java | 46 +++++ .../dashloader/mixin/main/MainMixin.java | 24 +++ .../mixin/main/MinecraftClientMixin.java | 37 ++++ .../ReloadableResourceManagerImplMixin.java | 57 ++++++ .../mixin/main/SplashScreenMixin.java | 110 +++++++++++ .../mixin/option/WallBlockMixin.java | 164 ++++++++++++++++ .../SplashTextResourceSupplierMixin.java | 37 ++++ .../cache/font/FontManagerOverride.java | 44 +++++ .../cache/font/TrueTypeFontLoaderMixin.java | 33 ++++ .../model/BakedModelManagerOverride.java | 34 ++++ .../option/cache/model/BlockModelsMixin.java | 30 +++ .../option/cache/model/ModelLoaderMixin.java | 155 +++++++++++++++ .../model/MultipartUnbakedModelMixin.java | 55 ++++++ .../cache/shader/GameRendererMixin.java | 41 ++++ .../cache/shader/GlStateManagerMixin.java | 27 +++ .../cache/sprite/SpriteLoaderMixin.java | 96 +++++++++ .../misc/AffineTransformationMixin.java | 31 +++ .../mixin/option/misc/MipmapHelperMixin.java | 142 ++++++++++++++ .../option/misc/ModelIdentifierMixin.java | 35 ++++ .../ModelLoaderBakedModelCacheKeyMixin.java | 41 ++++ .../dashloader/registry/FactoryBinding.java | 96 +++++++++ .../dashloader/registry/MissingHandler.java | 16 ++ .../registry/RegistryReaderImpl.java | 46 +++++ .../registry/RegistryWriterImpl.java | 185 ++++++++++++++++++ .../registry/TrackingRegistryWriterImpl.java | 36 ++++ .../dashloader/registry/data/ChunkData.java | 50 +++++ .../registry/data/ChunkFactory.java | 67 +++++++ .../dashloader/registry/data/StageData.java | 31 +++ .../thread/IndexedArrayMapTask.java | 48 +++++ .../dashloader/thread/ThreadHandler.java | 81 ++++++++ 67 files changed, 2911 insertions(+) create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/MixinPlugin.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/AbstractTextureAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/AndMultipartModelSelectorAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/BasicBakedModelAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/BitmapFontGlyphAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/BuiltinBakedModelAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/EffectShaderStageAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontManagerProviderIndexAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/FontStorageAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/GlBlendStateAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/GlUniformAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/IdentifierAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelIdentifierAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelLoaderAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListBakedOverrideAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ModelOverrideListInlinedCondition.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartBakedModelAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/MultipartModelComponentAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/NativeImageAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/OrMultipartModelSelectorAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderProgramAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ShaderStageAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/SimpleMultipartModelSelectorAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteAnimationFrameAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteContentsAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/SpriteLoaderStitchResultAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/TrueTypeFontAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/UnihexFontAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/VertexFormatAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/WeightedBakedModelEntryAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/ZipResourcePackAccessor.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/main/BootstrapMixin.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/main/KeyboardMixin.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/main/MainMixin.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/main/MinecraftClientMixin.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/main/ReloadableResourceManagerImplMixin.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/main/SplashScreenMixin.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/option/WallBlockMixin.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/SplashTextResourceSupplierMixin.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/font/FontManagerOverride.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/font/TrueTypeFontLoaderMixin.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/BakedModelManagerOverride.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/BlockModelsMixin.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/ModelLoaderMixin.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/model/MultipartUnbakedModelMixin.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/shader/GameRendererMixin.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/shader/GlStateManagerMixin.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/option/cache/sprite/SpriteLoaderMixin.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/option/misc/AffineTransformationMixin.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/option/misc/MipmapHelperMixin.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelIdentifierMixin.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/mixin/option/misc/ModelLoaderBakedModelCacheKeyMixin.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/registry/FactoryBinding.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/registry/MissingHandler.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/registry/RegistryReaderImpl.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/registry/RegistryWriterImpl.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/registry/TrackingRegistryWriterImpl.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/registry/data/ChunkData.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/registry/data/ChunkFactory.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/registry/data/StageData.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/thread/IndexedArrayMapTask.java create mode 100644 forge/src/main/java/dev/notalpha/dashloader/thread/ThreadHandler.java 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/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/NativeImageAccessor.java b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/NativeImageAccessor.java new file mode 100644 index 00000000..22ec08b3 --- /dev/null +++ b/forge/src/main/java/dev/notalpha/dashloader/mixin/accessor/NativeImageAccessor.java @@ -0,0 +1,22 @@ +package dev.notalpha.dashloader.mixin.accessor; + +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(NativeImage.class) +public interface NativeImageAccessor { + + + @Invoker("") + 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); + } + } + + +}