diff options
70 files changed, 1432 insertions, 1549 deletions
| diff --git a/build.gradle.kts b/build.gradle.kts index 64d80fe..70f20f6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -21,7 +21,9 @@ plugins {  	alias(libs.plugins.kotlin.plugin.serialization)  	alias(libs.plugins.kotlin.plugin.powerassert)  	alias(libs.plugins.kotlin.plugin.ksp) -	alias(libs.plugins.loom) +	//	alias(libs.plugins.loom) +	// TODO: use arch loom once they update to 1.8 +	id("fabric-loom") version "1.8.9"  	id("com.github.johnrengelman.shadow") version "8.1.1"  	id("moe.nea.licenseextractificator")  	id("moe.nea.mc-auto-translations") version "0.0.1" @@ -113,7 +115,7 @@ fun innerJarsOf(name: String, dependency: Dependency): Provider<FileTree> {  		})  	}  	unpackAllJars { dependsOn(task) } -	println("Constructed innerJars task: ${project.files(task).asFileTree.toList().map {it to it.exists()}}") +	println("Constructed innerJars task: ${project.files(task).asFileTree.toList().map { it to it.exists() }}")  	return project.provider {  		project.files(task).asFileTree  	} @@ -125,15 +127,32 @@ val collectTranslations by tasks.registering(CollectTranslations::class) {  }  val compatSourceSets: MutableSet<SourceSet> = mutableSetOf() -fun createIsolatedSourceSet(name: String, path: String = "compat/$name"): SourceSet { +fun createIsolatedSourceSet(name: String, path: String = "compat/$name", isEnabled: Boolean = true): SourceSet {  	val ss = sourceSets.create(name) { -		this.java.setSrcDirs(listOf(layout.projectDirectory.dir("src/$path/java"))) -		this.kotlin.setSrcDirs(listOf(layout.projectDirectory.dir("src/$path/java"))) +		if (isEnabled) { +			this.java.setSrcDirs(listOf(layout.projectDirectory.dir("src/$path/java"))) +			this.kotlin.setSrcDirs(listOf(layout.projectDirectory.dir("src/$path/java"))) +		} else { +			this.java.setSrcDirs(listOf<File>()) +			this.kotlin.setSrcDirs(listOf<File>()) +		}  	} -	compatSourceSets.add(ss) -	loom.createRemapConfigurations(ss)  	val mainSS = sourceSets.main.get()  	val upperName = ss.name.capitalizeN() +	afterEvaluate { +		tasks.named("ksp${upperName}Kotlin", KspTaskJvm::class) { +			this.options.add(SubpluginOption("apoption", "firmament.sourceset=${ss.name}")) +		} +		tasks.named("compile${upperName}Kotlin", KotlinCompile::class) { +			this.enabled = isEnabled +		} +		tasks.named("compile${upperName}Java", JavaCompile::class) { +			this.enabled = isEnabled +		} +	} +	compatSourceSets.add(ss) +	loom.createRemapConfigurations(ss) +	if (!isEnabled) return ss  	configurations {  		(ss.implementationConfigurationName) {  			extendsFrom(getByName(mainSS.compileClasspathConfigurationName)) @@ -148,11 +167,6 @@ fun createIsolatedSourceSet(name: String, path: String = "compat/$name"): Source  			extendsFrom(ksp.get())  		}  	} -	afterEvaluate { -		tasks.named("ksp${upperName}Kotlin", KspTaskJvm::class) { -			this.options.add(SubpluginOption("apoption", "firmament.sourceset=${ss.name}")) -		} -	}  	dependencies {  		runtimeOnly(ss.output)  		(ss.implementationConfigurationName)(sourceSets.main.get().output) @@ -195,14 +209,16 @@ val nonModImplentation by configurations.creating {  } -val configuredSourceSet = createIsolatedSourceSet("configured") +val configuredSourceSet = createIsolatedSourceSet("configured", +                                                  isEnabled = false) // Wait for update (also low prio, because configured sucks)  val sodiumSourceSet = createIsolatedSourceSet("sodium") -val citResewnSourceSet = createIsolatedSourceSet("citresewn") +val citResewnSourceSet = createIsolatedSourceSet("citresewn", isEnabled = false) // TODO: Wait for update  val yaclSourceSet = createIsolatedSourceSet("yacl") -val explosiveEnhancementSourceSet = createIsolatedSourceSet("explosiveEnhancement") -val wildfireGenderSourceSet = createIsolatedSourceSet("wildfireGender") +val explosiveEnhancementSourceSet = createIsolatedSourceSet("explosiveEnhancement", isEnabled = false) // TODO: wait for their port +val wildfireGenderSourceSet = createIsolatedSourceSet("wildfireGender", isEnabled = false) // TODO: wait on their port  val modmenuSourceSet = createIsolatedSourceSet("modmenu") -val reiSourceSet = createIsolatedSourceSet("rei") +val reiSourceSet = +	createIsolatedSourceSet("rei", isEnabled = false) // TODO: read through https://hackmd.io/@shedaniel/rei17_primer  dependencies {  	// Minecraft dependencies @@ -299,7 +315,7 @@ loom {  			         compatSourceSets.joinToString(File.pathSeparator) {  				         File(it.output.classesDirs.asPath).absolutePath  			         }) -			property("mixin.debug", "true") +			property("mixin.debug.export", "true")  			parseEnvFile(file(".env")).forEach { (t, u) ->  				environmentVariable(t, u) @@ -360,7 +376,7 @@ tasks.shadowJar {  }  tasks.remapJar { -	injectAccessWidener.set(true) +//	injectAccessWidener.set(true)  	inputFile.set(tasks.shadowJar.flatMap { it.archiveFile })  	dependsOn(tasks.shadowJar)  	archiveClassifier.set("") diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c11d939..b25717e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,36 +3,36 @@  # SPDX-License-Identifier: CC0-1.0  [versions] -minecraft = "1.21" +minecraft = "1.21.3"  # Update from https://kotlinlang.org/ -kotlin = "2.0.20" +kotlin = "2.0.21"  # Update from https://github.com/google/ksp/releases -kotlin_ksp = "2.0.20-1.0.24" +kotlin_ksp = "2.0.21-1.0.26"  # Update from https://linkie.shedaniel.me/dependencies?loader=fabric -fabric_loader = "0.16.3" -fabric_api = "0.100.4+1.21" -fabric_kotlin = "1.11.0+kotlin.2.0.0" -yarn = "1.21+build.7" -rei = "16.0.729" -modmenu = "11.0.1" -architectury = "13.0.3" +fabric_loader = "0.16.9" +fabric_api = "0.107.0+1.21.3" +fabric_kotlin = "1.12.3+kotlin.2.0.21" +yarn = "1.21.3+build.2" +rei = "17.0.789" +modmenu = "12.0.0-beta.1" +architectury = "14.0.4"  # Update from https://maven.architectury.dev/dev/architectury/loom/dev.architectury.loom.gradle.plugin/ -loom = "1.7.412" +loom = "1.7.414"  # Update from https://modrinth.com/mod/qolify/versions?l=fabric  qolify = "1.6.0-1.21.1"  # Update from https://modrinth.com/mod/sodium/versions?l=fabric -sodium = "mc1.21-0.5.11" +sodium = "mc1.21.3-0.6.0-beta.4-fabric"  # Update from https://modrinth.com/mod/freecam/versions?l=fabric  freecammod = "vomskVK3"  # Update from https://modrinth.com/mod/no-chat-reports/versions?l=fabric -ncr = "Fabric-1.21-v2.8.0" +ncr = "Fabric-1.21.3-v2.10.0"  # Update from https://modrinth.com/mod/female-gender/versions?l=fabric  femalegender = "kJmjQvAS" @@ -49,7 +49,7 @@ citresewn = "1.2.0+1.21"  devauth = "1.2.0"  # Update from https://ktor.io/ -ktor = "2.3.12" +ktor = "3.0.1"  # Update from https://repo.nea.moe/#/releases/moe/nea/neurepoparser  neurepoparser = "1.6.0" @@ -58,10 +58,10 @@ neurepoparser = "1.6.0"  hotswap_agent = "1.4.2-SNAPSHOT"  # Update from https://github.com/LlamaLad7/MixinExtras/tags -mixinextras = "0.3.5" +mixinextras = "0.4.1"  jarvis = "1.1.3" -nealisp = "1.0.0" +nealisp = "1.1.0"  # Update from https://github.com/NotEnoughUpdates/MoulConfig/tags  moulconfig = "3.0.0-beta.15" @@ -77,7 +77,7 @@ hypixelmodapi_fabric = "1.0.1+build.1+mc1.21"  manninghamMills = "2.4.1"  # Update from https://docs.isxander.dev/yet-another-config-lib/installing-yacl -yacl = "3.5.0+1.21-fabric" +yacl = "3.6.1+1.21.2-fabric"  # Update from https://maven.shedaniel.me/me/shedaniel/cloth/basic-math/0.6.1/  basicMath = "0.6.1" @@ -120,10 +120,8 @@ basicMath = { module = "me.shedaniel.cloth:basic-math", version.ref = "basicMath  [bundles]  runtime_required = [ -	"architectury_fabric", -	"rei_fabric", -	"notenoughanimations", -	"femalegender", +#	"rei_fabric", +#	"notenoughanimations",  	"hypixelmodapi_fabric",  ]  runtime_optional = [ @@ -132,7 +130,7 @@ runtime_optional = [  #	"sodium",  	#    "qolify",  	"ncr", -	"citresewn", +#	"citresewn",  ]  [plugins] diff --git a/src/compat/sodium/java/SodiumChunkReloader.kt b/src/compat/sodium/java/SodiumChunkReloader.kt index 932c338..0256b88 100644 --- a/src/compat/sodium/java/SodiumChunkReloader.kt +++ b/src/compat/sodium/java/SodiumChunkReloader.kt @@ -1,6 +1,6 @@  package moe.nea.firmament.compat.sodium -import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer +import net.caffeinemc.mods.sodium.client.render.SodiumWorldRenderer  import moe.nea.firmament.mixins.accessor.sodium.AccessorSodiumWorldRenderer  class SodiumChunkReloader : Runnable { diff --git a/src/compat/sodium/java/moe/nea/firmament/mixins/accessor/sodium/AccessorSodiumWorldRenderer.java b/src/compat/sodium/java/moe/nea/firmament/mixins/accessor/sodium/AccessorSodiumWorldRenderer.java index d585cbc..f75874d 100644 --- a/src/compat/sodium/java/moe/nea/firmament/mixins/accessor/sodium/AccessorSodiumWorldRenderer.java +++ b/src/compat/sodium/java/moe/nea/firmament/mixins/accessor/sodium/AccessorSodiumWorldRenderer.java @@ -1,7 +1,7 @@  package moe.nea.firmament.mixins.accessor.sodium; -import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; -import me.jellysquid.mods.sodium.client.render.chunk.RenderSectionManager; +import net.caffeinemc.mods.sodium.client.render.SodiumWorldRenderer; +import net.caffeinemc.mods.sodium.client.render.chunk.RenderSectionManager;  import org.spongepowered.asm.mixin.Mixin;  import org.spongepowered.asm.mixin.Pseudo;  import org.spongepowered.asm.mixin.gen.Accessor; @@ -9,6 +9,6 @@ import org.spongepowered.asm.mixin.gen.Accessor;  @Mixin(SodiumWorldRenderer.class)  @Pseudo  public interface AccessorSodiumWorldRenderer { -    @Accessor(value = "renderSectionManager", remap = false) -    RenderSectionManager getRenderSectionManager_firmament(); +	@Accessor(value = "renderSectionManager", remap = false) +	RenderSectionManager getRenderSectionManager_firmament();  } diff --git a/src/compat/sodium/java/moe/nea/firmament/mixins/custommodels/PatchBlockModelInSodiumChunkGenerator.java b/src/compat/sodium/java/moe/nea/firmament/mixins/custommodels/PatchBlockModelInSodiumChunkGenerator.java index 90f20bc..fe87310 100644 --- a/src/compat/sodium/java/moe/nea/firmament/mixins/custommodels/PatchBlockModelInSodiumChunkGenerator.java +++ b/src/compat/sodium/java/moe/nea/firmament/mixins/custommodels/PatchBlockModelInSodiumChunkGenerator.java @@ -3,8 +3,8 @@ package moe.nea.firmament.mixins.custommodels;  import com.llamalad7.mixinextras.injector.wrapoperation.Operation;  import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;  import com.llamalad7.mixinextras.sugar.Local; -import me.jellysquid.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderMeshingTask;  import moe.nea.firmament.features.texturepack.CustomBlockTextures; +import net.caffeinemc.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderMeshingTask;  import net.minecraft.block.BlockState;  import net.minecraft.client.render.block.BlockModels;  import net.minecraft.client.render.model.BakedModel; @@ -15,7 +15,7 @@ import org.spongepowered.asm.mixin.injection.At;  @Mixin(ChunkBuilderMeshingTask.class)  public class PatchBlockModelInSodiumChunkGenerator {      @WrapOperation( -        method = "execute(Lme/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildContext;Lme/jellysquid/mods/sodium/client/util/task/CancellationToken;)Lme/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput;", +        method = "execute(Lnet/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkBuildContext;Lnet/caffeinemc/mods/sodium/client/util/task/CancellationToken;)Lnet/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkBuildOutput;",          at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/block/BlockModels;getModel(Lnet/minecraft/block/BlockState;)Lnet/minecraft/client/render/model/BakedModel;"))      private BakedModel replaceBlockModel(BlockModels instance, BlockState state, Operation<BakedModel> original,                                           @Local(name = "blockPos") BlockPos.Mutable pos) { diff --git a/src/main/java/moe/nea/firmament/mixins/CustomDurabilityBarPatch.java b/src/main/java/moe/nea/firmament/mixins/CustomDurabilityBarPatch.java index 0f4d324..fde3580 100644 --- a/src/main/java/moe/nea/firmament/mixins/CustomDurabilityBarPatch.java +++ b/src/main/java/moe/nea/firmament/mixins/CustomDurabilityBarPatch.java @@ -14,7 +14,7 @@ import org.spongepowered.asm.mixin.injection.At;  @Mixin(DrawContext.class)  public class CustomDurabilityBarPatch {      @WrapOperation( -        method = "drawItemInSlot(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/item/ItemStack;IILjava/lang/String;)V", +        method = "drawItemBar",          at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;isItemBarVisible()Z")      )      private boolean onIsItemBarVisible( @@ -29,7 +29,7 @@ public class CustomDurabilityBarPatch {          return barOverride.get() != null;      } -    @WrapOperation(method = "drawItemInSlot(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/item/ItemStack;IILjava/lang/String;)V", +    @WrapOperation(method = "drawItemBar",          at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getItemBarStep()I"))      private int overrideItemStep(          ItemStack instance, Operation<Integer> original, @@ -40,7 +40,7 @@ public class CustomDurabilityBarPatch {          return original.call(instance);      } -    @WrapOperation(method = "drawItemInSlot(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/item/ItemStack;IILjava/lang/String;)V", +    @WrapOperation(method = "drawItemBar",          at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getItemBarColor()I"))      private int overrideItemColor(          ItemStack instance, Operation<Integer> original, diff --git a/src/main/java/moe/nea/firmament/mixins/CustomModelBakerPatch.java b/src/main/java/moe/nea/firmament/mixins/CustomModelBakerPatch.java deleted file mode 100644 index c1e359d..0000000 --- a/src/main/java/moe/nea/firmament/mixins/CustomModelBakerPatch.java +++ /dev/null @@ -1,49 +0,0 @@ -package moe.nea.firmament.mixins; - -import moe.nea.firmament.events.BakeExtraModelsEvent; -import net.minecraft.client.render.model.ModelLoader; -import net.minecraft.client.render.model.UnbakedModel; -import net.minecraft.client.util.ModelIdentifier; -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.Unique; -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(ModelLoader.class) -public abstract class CustomModelBakerPatch { - -    @Shadow -    @Final -    private Map<ModelIdentifier, UnbakedModel> modelsToBake; - -    @Shadow -    protected abstract void loadItemModel(ModelIdentifier id); - -    @Shadow -    abstract UnbakedModel getOrLoadModel(Identifier id); - -    @Shadow -    protected abstract void add(ModelIdentifier id, UnbakedModel model); - -    @Unique -    private void loadNonItemModel(ModelIdentifier identifier) { -        UnbakedModel unbakedModel = this.getOrLoadModel(identifier.id()); -        this.add(identifier, unbakedModel); -    } - - -    @Inject(method = "bake", at = @At("HEAD")) -    public void onBake(ModelLoader.SpriteGetter spliteGetter, CallbackInfo ci) { -        BakeExtraModelsEvent.Companion.publish(new BakeExtraModelsEvent(this::loadItemModel, this::loadNonItemModel)); -        modelsToBake.values().forEach(model -> model.setParents(this::getOrLoadModel)); -//        modelsToBake.keySet().stream() -//            .filter(it -> !it.id().getNamespace().equals("minecraft")) -//            .forEach(it -> System.out.println("Non minecraft texture is being loaded: " + it)); -    } -} diff --git a/src/main/java/moe/nea/firmament/mixins/CustomModelEventPatch.java b/src/main/java/moe/nea/firmament/mixins/CustomModelEventPatch.java index 61fc82e..e7207f4 100644 --- a/src/main/java/moe/nea/firmament/mixins/CustomModelEventPatch.java +++ b/src/main/java/moe/nea/firmament/mixins/CustomModelEventPatch.java @@ -7,6 +7,7 @@ import net.minecraft.client.render.item.ItemModels;  import net.minecraft.client.render.model.BakedModel;  import net.minecraft.client.render.model.BakedModelManager;  import net.minecraft.item.ItemStack; +import net.minecraft.util.Identifier;  import org.spongepowered.asm.mixin.Final;  import org.spongepowered.asm.mixin.Mixin;  import org.spongepowered.asm.mixin.Shadow; @@ -14,16 +15,15 @@ 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(ItemModels.class)  public class CustomModelEventPatch { -    @Shadow -    @Final -    private BakedModelManager modelManager; -    @Inject(method = "getModel(Lnet/minecraft/item/ItemStack;)Lnet/minecraft/client/render/model/BakedModel;", at = @At("HEAD"), cancellable = true) -    public void onGetModel(ItemStack stack, CallbackInfoReturnable<BakedModel> cir) { -        var model = CustomItemModelEvent.getModel(stack, modelManager); -        if (model != null) -            cir.setReturnValue(model); -    } +	@Inject(method = "getModel(Lnet/minecraft/item/ItemStack;)Lnet/minecraft/client/render/model/BakedModel;", at = @At("HEAD"), cancellable = true) +	public void onGetModel(ItemStack stack, CallbackInfoReturnable<BakedModel> cir) { +		var model = CustomItemModelEvent.getModel(stack, (ItemModels) (Object) this); +		if (model != null) +			cir.setReturnValue(model); +	}  } diff --git a/src/main/java/moe/nea/firmament/mixins/CustomSkullTexturePatch.java b/src/main/java/moe/nea/firmament/mixins/CustomSkullTexturePatch.java index 4b3f3c3..f3b616a 100644 --- a/src/main/java/moe/nea/firmament/mixins/CustomSkullTexturePatch.java +++ b/src/main/java/moe/nea/firmament/mixins/CustomSkullTexturePatch.java @@ -2,7 +2,6 @@  package moe.nea.firmament.mixins; -import com.mojang.authlib.GameProfile;  import moe.nea.firmament.features.texturepack.CustomSkyBlockTextures;  import net.minecraft.block.SkullBlock;  import net.minecraft.client.render.RenderLayer; @@ -15,8 +14,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;  @Mixin(SkullBlockEntityRenderer.class)  public class CustomSkullTexturePatch { -    @Inject(method = "getRenderLayer", at = @At("HEAD"), cancellable = true) -    private static void onGetRenderLayer(SkullBlock.SkullType type, ProfileComponent profile, CallbackInfoReturnable<RenderLayer> cir) { -        CustomSkyBlockTextures.INSTANCE.modifySkullTexture(type, profile, cir); -    } +	@Inject(method = "getRenderLayer", at = @At("HEAD"), cancellable = true) +	private static void onGetRenderLayer(SkullBlock.SkullType type, ProfileComponent profile, CallbackInfoReturnable<RenderLayer> cir) { +		CustomSkyBlockTextures.INSTANCE.modifySkullTexture(type, profile, cir); +	}  } diff --git a/src/main/java/moe/nea/firmament/mixins/DFUEntityIdFixPatch.java b/src/main/java/moe/nea/firmament/mixins/DFUEntityIdFixPatch.java index da04ca2..717d404 100644 --- a/src/main/java/moe/nea/firmament/mixins/DFUEntityIdFixPatch.java +++ b/src/main/java/moe/nea/firmament/mixins/DFUEntityIdFixPatch.java @@ -17,6 +17,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;  import java.util.Map; +// TODO: rework this  @Mixin(EntityIdFix.class)  public abstract class DFUEntityIdFixPatch extends DataFix {      @Shadow diff --git a/src/main/java/moe/nea/firmament/mixins/InjectCustomShaderPrograms.java b/src/main/java/moe/nea/firmament/mixins/InjectCustomShaderPrograms.java deleted file mode 100644 index 5306e42..0000000 --- a/src/main/java/moe/nea/firmament/mixins/InjectCustomShaderPrograms.java +++ /dev/null @@ -1,31 +0,0 @@ -package moe.nea.firmament.mixins; - -import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; -import com.llamalad7.mixinextras.sugar.Local; -import com.mojang.datafixers.util.Pair; -import moe.nea.firmament.events.RegisterCustomShadersEvent; -import net.minecraft.client.gl.ShaderProgram; -import net.minecraft.client.render.GameRenderer; -import net.minecraft.resource.ResourceFactory; -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; -import java.util.function.Consumer; - -@Mixin(GameRenderer.class) -public class InjectCustomShaderPrograms { - -    @Inject(method = "loadPrograms", -        at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/GameRenderer;loadBlurPostProcessor(Lnet/minecraft/resource/ResourceFactory;)V", -            shift = At.Shift.AFTER)) -    void addFirmamentShaders( -        ResourceFactory resourceFactory, CallbackInfo ci, -        @Local(index = 3) List<Pair<ShaderProgram, Consumer<ShaderProgram>>> list -    ) { -        var event = new RegisterCustomShadersEvent(list, resourceFactory); -        RegisterCustomShadersEvent.Companion.publish(event); -    } -} diff --git a/src/main/java/moe/nea/firmament/mixins/MixinHandledScreen.java b/src/main/java/moe/nea/firmament/mixins/MixinHandledScreen.java index fd50c72..1034a12 100644 --- a/src/main/java/moe/nea/firmament/mixins/MixinHandledScreen.java +++ b/src/main/java/moe/nea/firmament/mixins/MixinHandledScreen.java @@ -2,6 +2,9 @@  package moe.nea.firmament.mixins; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.sugar.Local;  import moe.nea.firmament.events.*;  import net.minecraft.client.gui.DrawContext;  import net.minecraft.client.gui.screen.ingame.HandledScreen; @@ -21,6 +24,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;  import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;  import org.spongepowered.asm.mixin.injection.callback.LocalCapture; +import java.util.Iterator; +  @Mixin(HandledScreen.class)  public abstract class MixinHandledScreen<T extends ScreenHandler> { @@ -90,15 +95,12 @@ public abstract class MixinHandledScreen<T extends ScreenHandler> {  	} -	@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/ingame/HandledScreen;drawSlot(Lnet/minecraft/client/gui/DrawContext;Lnet/minecraft/screen/slot/Slot;)V", shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILHARD) -	public void onAfterDrawSlot(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci, int i, int j, int k, Slot slot) { -		SlotRenderEvents.After event = new SlotRenderEvents.After(context, slot, mouseX, mouseY, delta); -		SlotRenderEvents.After.Companion.publish(event); -	} - -	@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/ingame/HandledScreen;drawSlot(Lnet/minecraft/client/gui/DrawContext;Lnet/minecraft/screen/slot/Slot;)V", shift = At.Shift.BEFORE), locals = LocalCapture.CAPTURE_FAILHARD) -	public void onBeforeDrawSlot(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci, int i, int j, int k, Slot slot) { -		SlotRenderEvents.Before event = new SlotRenderEvents.Before(context, slot, mouseX, mouseY, delta); -		SlotRenderEvents.Before.Companion.publish(event); +	@WrapOperation(method = "drawSlots", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/ingame/HandledScreen;drawSlot(Lnet/minecraft/client/gui/DrawContext;Lnet/minecraft/screen/slot/Slot;)V")) +	public void onDrawSlots(HandledScreen instance, DrawContext context, Slot slot, Operation<Void> original) { +		var before = new SlotRenderEvents.Before(context, slot); +		SlotRenderEvents.Before.Companion.publish(before); +		original.call(instance, context, slot); +		var after = new SlotRenderEvents.After(context, slot); +		SlotRenderEvents.After.Companion.publish(after);  	}  } diff --git a/src/main/java/moe/nea/firmament/mixins/ReplaceTextColorInHandledScreen.java b/src/main/java/moe/nea/firmament/mixins/ReplaceTextColorInHandledScreen.java index 190fda0..c9fb073 100644 --- a/src/main/java/moe/nea/firmament/mixins/ReplaceTextColorInHandledScreen.java +++ b/src/main/java/moe/nea/firmament/mixins/ReplaceTextColorInHandledScreen.java @@ -20,12 +20,16 @@ import org.spongepowered.asm.mixin.injection.At;  	AnvilScreen.class, BeaconScreen.class})  public class ReplaceTextColorInHandledScreen { +	// To my future self: double check those mixins, but don't be too concerned about errors. Some of the wrapopertions +	// only apply in some of the specified subclasses. +  	@WrapOperation(  		method = "drawForeground",  		at = @At(  			value = "INVOKE",  			target = "Lnet/minecraft/client/gui/DrawContext;drawText(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/text/Text;IIIZ)I"), -		expect = 0) +		expect = 0, +		require = 0)  	private int replaceTextColorWithVariableShadow(DrawContext instance, TextRenderer textRenderer, Text text, int x, int y, int color, boolean shadow, Operation<Integer> original) {  		return original.call(instance, textRenderer, text, x, y, CustomTextColors.INSTANCE.mapTextColor(text, color), shadow);  	} @@ -35,7 +39,8 @@ public class ReplaceTextColorInHandledScreen {  		at = @At(  			value = "INVOKE",  			target = "Lnet/minecraft/client/gui/DrawContext;drawTextWithShadow(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/text/Text;III)I"), -		expect = 0) +		expect = 0, +		require = 0)  	private int replaceTextColorWithShadow(DrawContext instance, TextRenderer textRenderer, Text text, int x, int y, int color, Operation<Integer> original) {  		return original.call(instance, textRenderer, text, x, y, CustomTextColors.INSTANCE.mapTextColor(text, color));  	} diff --git a/src/main/java/moe/nea/firmament/mixins/SlotUpdateListener.java b/src/main/java/moe/nea/firmament/mixins/SlotUpdateListener.java index 6c854d4..06ecbd4 100644 --- a/src/main/java/moe/nea/firmament/mixins/SlotUpdateListener.java +++ b/src/main/java/moe/nea/firmament/mixins/SlotUpdateListener.java @@ -23,14 +23,13 @@ public abstract class SlotUpdateListener extends ClientCommonNetworkHandler {  	@Inject(  		method = "onScreenHandlerSlotUpdate", -		at = @At(value = "INVOKE", target = "Lnet/minecraft/client/tutorial/TutorialManager;onSlotUpdate(Lnet/minecraft/item/ItemStack;)V")) +		at = @At(value = "TAIL"))  	private void onSingleSlotUpdate(  		ScreenHandlerSlotUpdateS2CPacket packet,  		CallbackInfo ci) {  		var player = this.client.player;  		assert player != null; -		if (packet.getSyncId() == ScreenHandlerSlotUpdateS2CPacket.UPDATE_PLAYER_INVENTORY_SYNC_ID -			|| packet.getSyncId() == 0) { +		if (packet.getSyncId() == 0) {  			PlayerInventoryUpdate.Companion.publish(new PlayerInventoryUpdate.Single(packet.getSlot(), packet.getStack()));  		} else if (packet.getSyncId() == player.currentScreenHandler.syncId) {  			ChestInventoryUpdateEvent.Companion.publish( @@ -40,8 +39,7 @@ public abstract class SlotUpdateListener extends ClientCommonNetworkHandler {  	}  	@Inject(method = "onInventory", -		at = @At(value = "INVOKE", target = "Lnet/minecraft/network/NetworkThreadUtils;forceMainThread(Lnet/minecraft/network/packet/Packet;Lnet/minecraft/network/listener/PacketListener;Lnet/minecraft/util/thread/ThreadExecutor;)V", -			shift = At.Shift.AFTER)) +		at = @At("TAIL"))  	private void onMultiSlotUpdate(InventoryS2CPacket packet, CallbackInfo ci) {  		var player = this.client.player;  		assert player != null; diff --git a/src/main/java/moe/nea/firmament/mixins/WorldRenderLastEventPatch.java b/src/main/java/moe/nea/firmament/mixins/WorldRenderLastEventPatch.java index 2ff4560..158576a 100644 --- a/src/main/java/moe/nea/firmament/mixins/WorldRenderLastEventPatch.java +++ b/src/main/java/moe/nea/firmament/mixins/WorldRenderLastEventPatch.java @@ -2,11 +2,10 @@  package moe.nea.firmament.mixins; -import com.llamalad7.mixinextras.sugar.Local;  import moe.nea.firmament.events.WorldRenderLastEvent;  import net.minecraft.client.render.*; +import net.minecraft.client.util.ObjectAllocator;  import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.world.tick.TickManager;  import org.joml.Matrix4f;  import org.spongepowered.asm.mixin.Final;  import org.spongepowered.asm.mixin.Mixin; @@ -17,21 +16,17 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;  @Mixin(WorldRenderer.class)  public class WorldRenderLastEventPatch { -    @Shadow -    @Final -    private BufferBuilderStorage bufferBuilders; +	@Shadow +	@Final +	private BufferBuilderStorage bufferBuilders; -    @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/WorldRenderer;renderChunkDebugInfo(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;Lnet/minecraft/client/render/Camera;)V", shift = At.Shift.BEFORE)) -    public void onWorldRenderLast( -        RenderTickCounter tickCounter, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, -        LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, Matrix4f matrix4f2, -        CallbackInfo ci, @Local MatrixStack matrixStack -    ) { -        var event = new WorldRenderLastEvent( -            matrixStack, tickCounter, renderBlockOutline, -            camera, gameRenderer, lightmapTextureManager, -            this.bufferBuilders.getEntityVertexConsumers() -        ); -        WorldRenderLastEvent.Companion.publish(event); -    } +	@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/WorldRenderer;renderLateDebug(Lnet/minecraft/client/render/FrameGraphBuilder;Lnet/minecraft/util/math/Vec3d;Lnet/minecraft/client/render/Fog;)V", shift = At.Shift.BEFORE)) +	public void onWorldRenderLast(ObjectAllocator allocator, RenderTickCounter tickCounter, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f positionMatrix, Matrix4f projectionMatrix, CallbackInfo ci) { +		var event = new WorldRenderLastEvent( +			new MatrixStack(), tickCounter, renderBlockOutline, +			camera, gameRenderer, lightmapTextureManager, +			this.bufferBuilders.getEntityVertexConsumers() +		); +		WorldRenderLastEvent.Companion.publish(event); +	}  } diff --git a/src/main/java/moe/nea/firmament/mixins/accessor/AccessorGameRenderer.java b/src/main/java/moe/nea/firmament/mixins/accessor/AccessorGameRenderer.java deleted file mode 100644 index f5d2202..0000000 --- a/src/main/java/moe/nea/firmament/mixins/accessor/AccessorGameRenderer.java +++ /dev/null @@ -1,14 +0,0 @@ - - -package moe.nea.firmament.mixins.accessor; - -import net.minecraft.client.render.Camera; -import net.minecraft.client.render.GameRenderer; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Invoker; - -@Mixin(GameRenderer.class) -public interface AccessorGameRenderer { -    @Invoker("getFov") -    double getFov_firmament(Camera camera, float tickDelta, boolean changingFov); -} diff --git a/src/main/java/moe/nea/firmament/mixins/customgui/PatchHandledScreen.java b/src/main/java/moe/nea/firmament/mixins/customgui/PatchHandledScreen.java index deac0a4..814f172 100644 --- a/src/main/java/moe/nea/firmament/mixins/customgui/PatchHandledScreen.java +++ b/src/main/java/moe/nea/firmament/mixins/customgui/PatchHandledScreen.java @@ -14,7 +14,6 @@ import net.minecraft.client.gui.screen.ingame.HandledScreen;  import net.minecraft.screen.ScreenHandler;  import net.minecraft.screen.slot.Slot;  import net.minecraft.text.Text; -import net.minecraft.util.collection.DefaultedList;  import org.jetbrains.annotations.Nullable;  import org.spongepowered.asm.mixin.Final;  import org.spongepowered.asm.mixin.Mixin; @@ -88,29 +87,18 @@ public class PatchHandledScreen<T extends ScreenHandler> extends Screen implemen  	} -	@Unique -	private Slot didBeforeSlotRender; -  	@WrapOperation( -		method = "render", +		method = "drawSlots",  		at = @At(  			value = "INVOKE", -			target = "Lnet/minecraft/util/collection/DefaultedList;get(I)Ljava/lang/Object;")) -	private Object beforeSlotRender(DefaultedList instance, int index, Operation<Object> original, @Local(argsOnly = true) DrawContext context) { -		var slot = (Slot) original.call(instance, index); +			target = "Lnet/minecraft/client/gui/screen/ingame/HandledScreen;drawSlot(Lnet/minecraft/client/gui/DrawContext;Lnet/minecraft/screen/slot/Slot;)V")) +	private void beforeSlotRender(HandledScreen instance, DrawContext context, Slot slot, Operation<Void> original) {  		if (override != null) { -			didBeforeSlotRender = slot;  			override.beforeSlotRender(context, slot);  		} -		return slot; -	} - -	@Inject(method = "render", -		at = @At(value = "INVOKE", target = "Lnet/minecraft/util/collection/DefaultedList;size()I")) -	private void afterSlotRender(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci) { -		if (override != null && didBeforeSlotRender != null) { -			override.afterSlotRender(context, didBeforeSlotRender); -			didBeforeSlotRender = null; +		original.call(instance, context, slot); +		if (override != null) { +			override.afterSlotRender(context, slot);  		}  	} diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/ApplyHeadModelInItemRenderer.java b/src/main/java/moe/nea/firmament/mixins/custommodels/ApplyHeadModelInItemRenderer.java index 64b358f..ffa59c6 100644 --- a/src/main/java/moe/nea/firmament/mixins/custommodels/ApplyHeadModelInItemRenderer.java +++ b/src/main/java/moe/nea/firmament/mixins/custommodels/ApplyHeadModelInItemRenderer.java @@ -1,33 +1,35 @@  package moe.nea.firmament.mixins.custommodels; -import com.llamalad7.mixinextras.injector.wrapoperation.Operation; -import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;  import com.llamalad7.mixinextras.sugar.Local; +import com.llamalad7.mixinextras.sugar.ref.LocalRef;  import moe.nea.firmament.features.texturepack.BakedModelExtra; +import net.minecraft.client.render.VertexConsumerProvider;  import net.minecraft.client.render.item.ItemRenderer;  import net.minecraft.client.render.model.BakedModel; -import net.minecraft.client.render.model.json.ModelTransformationMode; -import net.minecraft.entity.LivingEntity; +import net.minecraft.client.util.math.MatrixStack;  import net.minecraft.item.ItemStack; -import net.minecraft.world.World; +import net.minecraft.item.ModelTransformationMode;  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(ItemRenderer.class)  public class ApplyHeadModelInItemRenderer { -    @WrapOperation(method = "renderItem(Lnet/minecraft/entity/LivingEntity;Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/render/model/json/ModelTransformationMode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;Lnet/minecraft/world/World;III)V", -        at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/item/ItemRenderer;getModel(Lnet/minecraft/item/ItemStack;Lnet/minecraft/world/World;Lnet/minecraft/entity/LivingEntity;I)Lnet/minecraft/client/render/model/BakedModel;")) -    private BakedModel applyHeadModel(ItemRenderer instance, ItemStack stack, World world, LivingEntity entity, int seed, Operation<BakedModel> original, -                                      @Local(argsOnly = true) ModelTransformationMode modelTransformationMode) { -        var model = original.call(instance, stack, world, entity, seed); -        if (modelTransformationMode == ModelTransformationMode.HEAD -            && model instanceof BakedModelExtra extra) { -            var headModel = extra.getHeadModel_firmament(); -            if (headModel != null) { -                model = headModel; -            } -        } -        return model; -    } +	@Inject(method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ModelTransformationMode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/client/render/model/BakedModel;ZF)V", +		at = @At("HEAD")) +	private void applyHeadModel(ItemStack stack, ModelTransformationMode transformationMode, boolean leftHanded, +	                            MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, +	                            BakedModel model, boolean useInventoryModel, float z, CallbackInfo ci, +	                            @Local(argsOnly = true) LocalRef<BakedModel> modelMut +	) { +		if (transformationMode == ModelTransformationMode.HEAD +			&& model instanceof BakedModelExtra extra) { +			var headModel = extra.getHeadModel_firmament(); +			if (headModel != null) { +				modelMut.set(headModel); +			} +		} +	}  } diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/GlobalModelOverridePatch.java b/src/main/java/moe/nea/firmament/mixins/custommodels/GlobalModelOverridePatch.java index eee7557..c708862 100644 --- a/src/main/java/moe/nea/firmament/mixins/custommodels/GlobalModelOverridePatch.java +++ b/src/main/java/moe/nea/firmament/mixins/custommodels/GlobalModelOverridePatch.java @@ -8,6 +8,7 @@ import net.minecraft.client.render.model.BakedModel;  import net.minecraft.entity.LivingEntity;  import net.minecraft.item.ItemStack;  import net.minecraft.world.World; +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; @@ -17,13 +18,14 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;  @Mixin(ItemRenderer.class)  public abstract class GlobalModelOverridePatch { -    @Shadow -    public abstract ItemModels getModels(); +	@Shadow +	@Final +	private ItemModels models; -    @Inject(method = "getModel", at = @At("HEAD"), cancellable = true) -    private void overrideGlobalModel( -        ItemStack stack, World world, LivingEntity entity, -        int seed, CallbackInfoReturnable<BakedModel> cir) { -        CustomGlobalTextures.replaceGlobalModel(this.getModels(), stack, cir); -    } +	@Inject(method = "getModel(Lnet/minecraft/item/ItemStack;Lnet/minecraft/world/World;Lnet/minecraft/entity/LivingEntity;I)Lnet/minecraft/client/render/model/BakedModel;", at = @At("HEAD"), cancellable = true) +	private void overrideGlobalModel( +		ItemStack stack, World world, LivingEntity entity, +		int seed, CallbackInfoReturnable<BakedModel> cir) { +		CustomGlobalTextures.replaceGlobalModel(this.models, stack, cir); +	}  } diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/HeadModelReplacerPatch.java b/src/main/java/moe/nea/firmament/mixins/custommodels/HeadModelReplacerPatch.java new file mode 100644 index 0000000..7518041 --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/custommodels/HeadModelReplacerPatch.java @@ -0,0 +1,55 @@ + +package moe.nea.firmament.mixins.custommodels; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.sugar.Local; +import moe.nea.firmament.features.texturepack.BakedModelExtra; +import net.minecraft.block.AbstractSkullBlock; +import net.minecraft.block.Block; +import net.minecraft.block.Blocks; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.entity.LivingEntityRenderer; +import net.minecraft.client.render.entity.feature.HeadFeatureRenderer; +import net.minecraft.client.render.entity.model.EntityModel; +import net.minecraft.client.render.entity.model.ModelWithHead; +import net.minecraft.client.render.entity.state.LivingEntityRenderState; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.EquipmentSlot; +import net.minecraft.item.BlockItem; +import net.minecraft.item.ItemStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(HeadFeatureRenderer.class) +public class HeadModelReplacerPatch<S extends LivingEntityRenderState, M extends EntityModel<S> & ModelWithHead> { +	/** +	 * This class serves to disable the replacing of head models with the vanilla block model. Vanilla first selects loads +	 * the model containing the head model regularly in {@link LivingEntityRenderer#updateRenderState}, but then discards +	 * the model in {@link HeadFeatureRenderer#render(MatrixStack, VertexConsumerProvider, int, LivingEntityRenderState, float, float)} +	 * if it detects a skull block. This serves to disable that functionality if a head model override is present. +	 */ +	@WrapOperation(method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/client/render/entity/state/LivingEntityRenderState;FF)V", +		at = @At(value = "INVOKE", target = "Lnet/minecraft/item/BlockItem;getBlock()Lnet/minecraft/block/Block;")) +	private Block replaceSkull(BlockItem instance, Operation<Block> original, @Local BakedModel bakedModel) { +		var oldBlock = original.call(instance); +		if (oldBlock instanceof AbstractSkullBlock) { +			if (bakedModel instanceof BakedModelExtra extra && extra.getHeadModel_firmament() != null) +				return Blocks.ENCHANTING_TABLE; // Any non skull block. Let's choose the enchanting table because it is very distinct. +		} +		return oldBlock; +	} + +	/** +	 * We disable the has model override, since texture packs get precedent to server data. +	 */ +	@WrapOperation(method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/client/render/entity/state/LivingEntityRenderState;FF)V", +		at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/entity/feature/ArmorFeatureRenderer;hasModel(Lnet/minecraft/item/ItemStack;Lnet/minecraft/entity/EquipmentSlot;)Z")) +	private boolean replaceHasModel(ItemStack stack, EquipmentSlot slot, Operation<Boolean> original, +	                                @Local BakedModel bakedModel) { +		if (bakedModel instanceof BakedModelExtra extra && extra.getHeadModel_firmament() != null) +			return false; +		return original.call(stack, slot); +	} +} diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/ItemRendererTintContextPatch.java b/src/main/java/moe/nea/firmament/mixins/custommodels/ItemRendererTintContextPatch.java index 5ed0fbe..66feced 100644 --- a/src/main/java/moe/nea/firmament/mixins/custommodels/ItemRendererTintContextPatch.java +++ b/src/main/java/moe/nea/firmament/mixins/custommodels/ItemRendererTintContextPatch.java @@ -5,27 +5,27 @@ import moe.nea.firmament.features.texturepack.TintOverrides;  import net.minecraft.client.render.VertexConsumerProvider;  import net.minecraft.client.render.item.ItemRenderer;  import net.minecraft.client.render.model.BakedModel; -import net.minecraft.client.render.model.json.ModelTransformationMode;  import net.minecraft.client.util.math.MatrixStack;  import net.minecraft.item.ItemStack; +import net.minecraft.item.ModelTransformationMode;  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(ItemRenderer.class) +@Mixin(value = ItemRenderer.class, priority = 1010)  public class ItemRendererTintContextPatch { -	@Inject(method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/render/model/json/ModelTransformationMode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/client/render/model/BakedModel;)V", -		at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/model/BakedModel;getTransformation()Lnet/minecraft/client/render/model/json/ModelTransformation;"), allow = 1) -	private void onStartRendering(ItemStack stack, ModelTransformationMode renderMode, boolean leftHanded, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, BakedModel model, CallbackInfo ci) { +	@Inject(method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ModelTransformationMode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/client/render/model/BakedModel;ZF)V", +		at = @At(value = "HEAD"), allow = 1) +	private void onStartRendering(ItemStack stack, ModelTransformationMode transformationMode, boolean leftHanded, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, BakedModel model, boolean useInventoryModel, float z, CallbackInfo ci) {  		if (model instanceof BakedModelExtra extra) {  			TintOverrides.Companion.enter(extra.getTintOverrides_firmament());  		}  	} -	@Inject(method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/render/model/json/ModelTransformationMode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/client/render/model/BakedModel;)V", -		at = @At(value = "INVOKE", target = "Lnet/minecraft/client/util/math/MatrixStack;pop()V"), allow = 1) -	private void onEndRendering(ItemStack stack, ModelTransformationMode renderMode, boolean leftHanded, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, BakedModel model, CallbackInfo ci) { +	@Inject(method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ModelTransformationMode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/client/render/model/BakedModel;ZF)V", +		at = @At("TAIL"), allow = 1) +	private void onEndRendering(ItemStack stack, ModelTransformationMode transformationMode, boolean leftHanded, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, BakedModel model, boolean useInventoryModel, float z, CallbackInfo ci) {  		if (model instanceof BakedModelExtra extra) {  			TintOverrides.Companion.exit(extra.getTintOverrides_firmament());  		} diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/JsonUnbakedModelDataHolder.java b/src/main/java/moe/nea/firmament/mixins/custommodels/JsonUnbakedModelDataHolder.java index 20c69e2..12eea5b 100644 --- a/src/main/java/moe/nea/firmament/mixins/custommodels/JsonUnbakedModelDataHolder.java +++ b/src/main/java/moe/nea/firmament/mixins/custommodels/JsonUnbakedModelDataHolder.java @@ -1,6 +1,5 @@  package moe.nea.firmament.mixins.custommodels; -import com.google.gson.annotations.SerializedName;  import com.llamalad7.mixinextras.injector.ModifyReturnValue;  import com.llamalad7.mixinextras.sugar.Local;  import moe.nea.firmament.features.texturepack.BakedModelExtra; @@ -18,15 +17,20 @@ import org.spongepowered.asm.mixin.Mixin;  import org.spongepowered.asm.mixin.Shadow;  import org.spongepowered.asm.mixin.Unique;  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.Collection;  import java.util.Objects;  @Mixin(JsonUnbakedModel.class) -public class JsonUnbakedModelDataHolder implements JsonUnbakedModelFirmExtra { +public abstract class JsonUnbakedModelDataHolder implements JsonUnbakedModelFirmExtra {  	@Shadow  	@Nullable  	protected JsonUnbakedModel parent; + +	@Shadow +	public abstract String toString(); +  	@Unique  	@Nullable  	public Identifier headModel; @@ -67,30 +71,29 @@ public class JsonUnbakedModelDataHolder implements JsonUnbakedModelFirmExtra {  		return ((JsonUnbakedModelFirmExtra) this.parent).getHeadModel_firmament();  	} -	@ModifyReturnValue(method = "getModelDependencies", at = @At("RETURN")) -	private Collection<Identifier> addDependencies(Collection<Identifier> original) { +	@Inject(method = "resolve", at = @At("HEAD")) +	private void addDependencies(UnbakedModel.Resolver resolver, CallbackInfo ci) {  		var headModel = getHeadModel_firmament();  		if (headModel != null) { -			original.add(headModel); +			resolver.resolve(headModel);  		} -		return original;  	}  	@ModifyReturnValue( -		method = "bake(Lnet/minecraft/client/render/model/Baker;Lnet/minecraft/client/render/model/json/JsonUnbakedModel;Ljava/util/function/Function;Lnet/minecraft/client/render/model/ModelBakeSettings;Z)Lnet/minecraft/client/render/model/BakedModel;", +		method = "bake(Lnet/minecraft/client/render/model/Baker;Ljava/util/function/Function;Lnet/minecraft/client/render/model/ModelBakeSettings;)Lnet/minecraft/client/render/model/BakedModel;",  		at = @At(value = "RETURN"))  	private BakedModel bakeExtraInfo(BakedModel original, @Local(argsOnly = true) Baker baker) { +		if (!this.toString().contains("minecraft") && this.toString().contains("crimson")) { +			System.out.println("Found non minecraft model " + this); +		}  		if (original instanceof BakedModelExtra extra) {  			var headModel = getHeadModel_firmament();  			if (headModel != null) { -				UnbakedModel unbakedModel = baker.getOrLoadModel(headModel); -				extra.setHeadModel_firmament( -					Objects.equals(unbakedModel, parent) -						? null -						: baker.bake(headModel, ModelRotation.X0_Y0)); +				extra.setHeadModel_firmament(baker.bake(headModel, ModelRotation.X0_Y0));  			} -			if (getTintOverrides_firmament().hasOverrides()) +			if (getTintOverrides_firmament().hasOverrides()) {  				extra.setTintOverrides_firmament(getTintOverrides_firmament()); +			}  		}  		return original;  	} diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/PatchArmorTexture.java b/src/main/java/moe/nea/firmament/mixins/custommodels/PatchArmorTexture.java index 7c6f69e..4468150 100644 --- a/src/main/java/moe/nea/firmament/mixins/custommodels/PatchArmorTexture.java +++ b/src/main/java/moe/nea/firmament/mixins/custommodels/PatchArmorTexture.java @@ -6,26 +6,24 @@ import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;  import com.llamalad7.mixinextras.sugar.Local;  import moe.nea.firmament.features.texturepack.CustomGlobalArmorOverrides;  import net.minecraft.client.render.entity.feature.ArmorFeatureRenderer; -import net.minecraft.item.ArmorMaterial; +import net.minecraft.component.type.EquippableComponent;  import net.minecraft.item.ItemStack; +import net.minecraft.util.Identifier;  import org.spongepowered.asm.mixin.Mixin;  import org.spongepowered.asm.mixin.injection.At; -import java.util.List; +import java.util.Optional;  @Mixin(ArmorFeatureRenderer.class)  public class PatchArmorTexture { -    @WrapOperation( -        method = "renderArmor", -        at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ArmorMaterial;layers()Ljava/util/List;")) -    private List<ArmorMaterial.Layer> overrideLayers( -        ArmorMaterial instance, -        Operation<List<ArmorMaterial.Layer>> original, -        @Local ItemStack itemStack -    ) { -        var overrides = CustomGlobalArmorOverrides.overrideArmor(itemStack); -        if (overrides == null) -            return original.call(instance); -        return overrides; -    } +	@WrapOperation( +		method = "renderArmor", +		at = @At(value = "INVOKE", target = "Lnet/minecraft/component/type/EquippableComponent;model()Ljava/util/Optional;")) +	private Optional<Identifier> overrideLayers( +		EquippableComponent instance, Operation<Optional<Identifier>> original, @Local(argsOnly = true) ItemStack itemStack +	) { +		// TODO: check that all armour items are naturally equippable and have the equppable component. otherwise our call here will not be reached. +		var overrides = CustomGlobalArmorOverrides.overrideArmor(itemStack); +		return overrides.or(() -> original.call(instance)); +	}  } diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/PatchHeadFeatureRenderer.java b/src/main/java/moe/nea/firmament/mixins/custommodels/PatchHeadFeatureRenderer.java deleted file mode 100644 index 610a106..0000000 --- a/src/main/java/moe/nea/firmament/mixins/custommodels/PatchHeadFeatureRenderer.java +++ /dev/null @@ -1,45 +0,0 @@ - -package moe.nea.firmament.mixins.custommodels; - -import com.llamalad7.mixinextras.injector.wrapoperation.Operation; -import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; -import com.llamalad7.mixinextras.sugar.Local; -import moe.nea.firmament.features.texturepack.BakedModelExtra; -import net.minecraft.block.AbstractSkullBlock; -import net.minecraft.block.Block; -import net.minecraft.block.Blocks; -import net.minecraft.client.render.entity.feature.HeadFeatureRenderer; -import net.minecraft.client.render.entity.model.EntityModel; -import net.minecraft.client.render.item.HeldItemRenderer; -import net.minecraft.entity.LivingEntity; -import net.minecraft.item.BlockItem; -import net.minecraft.item.ItemStack; -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; - -@Mixin(HeadFeatureRenderer.class) -public class PatchHeadFeatureRenderer<T extends LivingEntity, M extends EntityModel<T>> { - -    @Shadow -    @Final -    private HeldItemRenderer heldItemRenderer; - -    @WrapOperation(method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/entity/LivingEntity;FFFFFF)V", -        at = @At(value = "INVOKE", target = "Lnet/minecraft/item/BlockItem;getBlock()Lnet/minecraft/block/Block;")) -    private Block replaceSkull(BlockItem instance, Operation<Block> original, @Local ItemStack itemStack, @Local(argsOnly = true) T entity) { -        var oldBlock = original.call(instance); -        if (oldBlock instanceof AbstractSkullBlock) { -            var bakedModel = this.heldItemRenderer.itemRenderer -                .getModel(itemStack, entity.getWorld(), entity, 0); -            if (bakedModel instanceof BakedModelExtra extra && extra.getHeadModel_firmament() != null) -                return Blocks.ENCHANTING_TABLE; // Any non skull block. Let's choose the enchanting table because it is very distinct. -        } -        return oldBlock; -    } - - - - -} diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/PatchLegacyArmorLayerSupport.java b/src/main/java/moe/nea/firmament/mixins/custommodels/PatchLegacyArmorLayerSupport.java new file mode 100644 index 0000000..8c0b3f8 --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/custommodels/PatchLegacyArmorLayerSupport.java @@ -0,0 +1,22 @@ +package moe.nea.firmament.mixins.custommodels; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import moe.nea.firmament.features.texturepack.CustomGlobalArmorOverrides; +import net.minecraft.client.render.entity.equipment.EquipmentModelLoader; +import net.minecraft.client.render.entity.equipment.EquipmentRenderer; +import net.minecraft.item.equipment.EquipmentModel; +import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(EquipmentRenderer.class) +public class PatchLegacyArmorLayerSupport { +	@WrapOperation(method = "render(Lnet/minecraft/item/equipment/EquipmentModel$LayerType;Lnet/minecraft/util/Identifier;Lnet/minecraft/client/model/Model;Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/util/Identifier;)V", +		at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/entity/equipment/EquipmentModelLoader;get(Lnet/minecraft/util/Identifier;)Lnet/minecraft/item/equipment/EquipmentModel;")) +	private EquipmentModel patchModelLayers(EquipmentModelLoader instance, Identifier id, Operation<EquipmentModel> original) { +		var modelOverride = CustomGlobalArmorOverrides.overrideArmorLayer(id); +		if (modelOverride != null) return modelOverride; +		return original.call(instance, id); +	} +} diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/PatchOverrideDeserializer.java b/src/main/java/moe/nea/firmament/mixins/custommodels/PatchOverrideDeserializer.java index 938d14d..abb1792 100644 --- a/src/main/java/moe/nea/firmament/mixins/custommodels/PatchOverrideDeserializer.java +++ b/src/main/java/moe/nea/firmament/mixins/custommodels/PatchOverrideDeserializer.java @@ -22,29 +22,29 @@ import java.util.Map;  @Mixin(ModelOverride.Deserializer.class)  public class PatchOverrideDeserializer { -    @ModifyReturnValue( -        method = "deserialize(Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Lnet/minecraft/client/render/model/json/ModelOverride;", -        at = @At(value = "RETURN")) -    private ModelOverride addCustomOverrides(ModelOverride original, @Local JsonObject jsonObject) { -        var originalData = (ModelOverrideData) original; -        originalData.setFirmamentOverrides(CustomModelOverrideParser.parseCustomModelOverrides(jsonObject)); -        return original; -    } +	@ModifyReturnValue( +		method = "deserialize(Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Lnet/minecraft/client/render/model/json/ModelOverride;", +		at = @At(value = "RETURN")) +	private ModelOverride addCustomOverrides(ModelOverride original, @Local JsonObject jsonObject) { +		var originalData = (ModelOverrideData) (Object) original; +		originalData.setFirmamentOverrides(CustomModelOverrideParser.parseCustomModelOverrides(jsonObject)); +		return original; +	} -    @ModifyExpressionValue( -        method = "deserializeMinPropertyValues(Lcom/google/gson/JsonObject;)Ljava/util/List;", -        at = @At(value = "INVOKE", target = "Ljava/util/Map$Entry;getValue()Ljava/lang/Object;")) -    private Object removeFirmamentPredicatesFromJsonIteration(Object original, @Local Map.Entry<String, JsonElement> entry) { -        if (entry.getKey().startsWith("firmament:")) return new JsonPrimitive(0F); -        return original; -    } +	@ModifyExpressionValue( +		method = "deserializeMinPropertyValues(Lcom/google/gson/JsonObject;)Ljava/util/List;", +		at = @At(value = "INVOKE", target = "Ljava/util/Map$Entry;getValue()Ljava/lang/Object;")) +	private Object removeFirmamentPredicatesFromJsonIteration(Object original, @Local Map.Entry<String, JsonElement> entry) { +		if (entry.getKey().startsWith("firmament:")) return new JsonPrimitive(0F); +		return original; +	} -    @Inject( -        method = "deserializeMinPropertyValues", -        at = @At(value = "INVOKE", target = "Ljava/util/Map;entrySet()Ljava/util/Set;") -    ) -    private void whatever(JsonObject object, CallbackInfoReturnable<List<ModelOverride.Condition>> cir, -                          @Local Map<Identifier, Float> maps) { -        maps.entrySet().removeIf(it -> it.getKey().getNamespace().equals("firmament")); -    } +	@Inject( +		method = "deserializeMinPropertyValues", +		at = @At(value = "INVOKE", target = "Ljava/util/Map;entrySet()Ljava/util/Set;") +	) +	private void whatever(JsonObject object, CallbackInfoReturnable<List<ModelOverride.Condition>> cir, +	                      @Local Map<Identifier, Float> maps) { +		maps.entrySet().removeIf(it -> it.getKey().getNamespace().equals("firmament")); +	}  } diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/ReferenceCustomModelsPatch.java b/src/main/java/moe/nea/firmament/mixins/custommodels/ReferenceCustomModelsPatch.java new file mode 100644 index 0000000..14c84ab --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/custommodels/ReferenceCustomModelsPatch.java @@ -0,0 +1,37 @@ +package moe.nea.firmament.mixins.custommodels; + +import moe.nea.firmament.events.BakeExtraModelsEvent; +import net.minecraft.client.render.model.BlockStatesLoader; +import net.minecraft.client.render.model.ItemModel; +import net.minecraft.client.render.model.ReferencedModelsCollector; +import net.minecraft.client.render.model.UnbakedModel; +import net.minecraft.client.util.ModelIdentifier; +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.CallbackInfo; + +import java.util.Map; + +@Mixin(ReferencedModelsCollector.class) +public abstract class ReferenceCustomModelsPatch { +	@Shadow +	protected abstract void addTopLevelModel(ModelIdentifier modelId, UnbakedModel model); + +	@Shadow +	@Final +	private Map<Identifier, UnbakedModel> inputs; + +	@Inject(method = "addBlockStates", at = @At("RETURN")) +	private void addFirmamentReferencedModels( +		BlockStatesLoader.BlockStateDefinition definition, CallbackInfo ci +	) { +		inputs.keySet().stream().filter(it->it.toString().contains("firm")).forEach(System.out::println); +		BakeExtraModelsEvent.Companion.publish(new BakeExtraModelsEvent( +			(modelIdentifier, identifier) -> addTopLevelModel(modelIdentifier, new ItemModel(identifier)))); + +	} +} diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/TestForFirmamentOverridePredicatesPatch.java b/src/main/java/moe/nea/firmament/mixins/custommodels/TestForFirmamentOverridePredicatesPatch.java index bc47d74..81ae3b8 100644 --- a/src/main/java/moe/nea/firmament/mixins/custommodels/TestForFirmamentOverridePredicatesPatch.java +++ b/src/main/java/moe/nea/firmament/mixins/custommodels/TestForFirmamentOverridePredicatesPatch.java @@ -17,33 +17,33 @@ import org.spongepowered.asm.mixin.injection.ModifyArg;  @Mixin(ModelOverrideList.class)  public class TestForFirmamentOverridePredicatesPatch { -    @ModifyArg(method = "<init>(Lnet/minecraft/client/render/model/Baker;Lnet/minecraft/client/render/model/json/JsonUnbakedModel;Ljava/util/List;)V", -        at = @At( -            value = "INVOKE", target = "Ljava/util/List;add(Ljava/lang/Object;)Z" -        )) -    public Object onInit( -        Object element, -        @Local ModelOverride modelOverride -    ) { -        var bakedOverride = (ModelOverrideList.BakedOverride) element; -        ((BakedOverrideData) bakedOverride) -            .setFirmamentOverrides(((ModelOverrideData) modelOverride).getFirmamentOverrides()); -        return element; -    } +	@ModifyArg(method = "<init>(Lnet/minecraft/client/render/model/Baker;Ljava/util/List;)V", +		at = @At( +			value = "INVOKE", target = "Ljava/util/List;add(Ljava/lang/Object;)Z" +		)) +	public Object onInit( +		Object element, +		@Local ModelOverride modelOverride +	) { +		var bakedOverride = (ModelOverrideList.BakedOverride) element; +		((BakedOverrideData) (Object) bakedOverride) +			.setFirmamentOverrides(((ModelOverrideData) (Object) modelOverride).getFirmamentOverrides()); +		return element; +	} -    @ModifyExpressionValue(method = "apply", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/model/json/ModelOverrideList$BakedOverride;test([F)Z")) -    public boolean testFirmamentOverrides(boolean originalValue, -                                          @Local ModelOverrideList.BakedOverride bakedOverride, -                                          @Local(argsOnly = true) ItemStack stack) { -        if (!originalValue) return false; -        var overrideData = (BakedOverrideData) bakedOverride; -        var overrides = overrideData.getFirmamentOverrides(); -        if (overrides == null) return true; -        if (!CustomSkyBlockTextures.TConfig.INSTANCE.getEnableModelOverrides()) return false; -        for (FirmamentModelPredicate firmamentOverride : overrides) { -            if (!firmamentOverride.test(stack)) -                return false; -        } -        return true; -    } +	@ModifyExpressionValue(method = "getModel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/model/json/ModelOverrideList$BakedOverride;test([F)Z")) +	public boolean testFirmamentOverrides(boolean originalValue, +	                                      @Local ModelOverrideList.BakedOverride bakedOverride, +	                                      @Local(argsOnly = true) ItemStack stack) { +		if (!originalValue) return false; +		var overrideData = (BakedOverrideData) (Object) bakedOverride; +		var overrides = overrideData.getFirmamentOverrides(); +		if (overrides == null) return true; +		if (!CustomSkyBlockTextures.TConfig.INSTANCE.getEnableModelOverrides()) return false; +		for (FirmamentModelPredicate firmamentOverride : overrides) { +			if (!firmamentOverride.test(stack)) +				return false; +		} +		return true; +	}  } diff --git a/src/main/kotlin/events/BakeExtraModelsEvent.kt b/src/main/kotlin/events/BakeExtraModelsEvent.kt index f75bedc..adaa495 100644 --- a/src/main/kotlin/events/BakeExtraModelsEvent.kt +++ b/src/main/kotlin/events/BakeExtraModelsEvent.kt @@ -1,21 +1,24 @@ -  package moe.nea.firmament.events -import java.util.function.Consumer +import java.util.function.BiConsumer +import net.minecraft.client.render.model.ReferencedModelsCollector  import net.minecraft.client.util.ModelIdentifier +import net.minecraft.util.Identifier +// TODO: Rename this event, since it is not really directly baking models anymore  class BakeExtraModelsEvent( -    private val addItemModel: Consumer<ModelIdentifier>, -    private val addAnyModel: Consumer<ModelIdentifier>, +	private val addAnyModel: BiConsumer<ModelIdentifier, Identifier>,  ) : FirmamentEvent() { -    fun addNonItemModel(modelIdentifier: ModelIdentifier) { -        this.addAnyModel.accept(modelIdentifier) -    } +	fun addNonItemModel(modelIdentifier: ModelIdentifier, identifier: Identifier) { +		this.addAnyModel.accept(modelIdentifier, identifier) +	} -    fun addItemModel(modelIdentifier: ModelIdentifier) { -        this.addItemModel.accept(modelIdentifier) -    } +	fun addItemModel(modelIdentifier: ModelIdentifier) { +		addNonItemModel( +			modelIdentifier, +			modelIdentifier.id.withPrefixedPath(ReferencedModelsCollector.ITEM_DIRECTORY)) +	} -    companion object : FirmamentEventBus<BakeExtraModelsEvent>() +	companion object : FirmamentEventBus<BakeExtraModelsEvent>()  } diff --git a/src/main/kotlin/events/CustomItemModelEvent.kt b/src/main/kotlin/events/CustomItemModelEvent.kt index e50eca4..d5c08f4 100644 --- a/src/main/kotlin/events/CustomItemModelEvent.kt +++ b/src/main/kotlin/events/CustomItemModelEvent.kt @@ -2,35 +2,37 @@ package moe.nea.firmament.events  import java.util.Optional  import kotlin.jvm.optionals.getOrNull +import net.minecraft.client.render.item.ItemModels  import net.minecraft.client.render.model.BakedModel -import net.minecraft.client.render.model.BakedModelManager  import net.minecraft.client.util.ModelIdentifier  import net.minecraft.item.ItemStack +import moe.nea.firmament.util.ErrorUtil  import moe.nea.firmament.util.collections.WeakCache  data class CustomItemModelEvent( -    val itemStack: ItemStack, -    var overrideModel: ModelIdentifier? = null, +	val itemStack: ItemStack, +	var overrideModel: ModelIdentifier? = null,  ) : FirmamentEvent() { -    companion object : FirmamentEventBus<CustomItemModelEvent>() { -        val cache = -            WeakCache.memoize<ItemStack, BakedModelManager, Optional<BakedModel>>("CustomItemModels") { stack, models -> -                val modelId = getModelIdentifier(stack) ?: return@memoize Optional.empty() -                val bakedModel = models.getModel(modelId) -                if (bakedModel === models.missingModel) return@memoize Optional.empty() -                Optional.of(bakedModel) -            } +	companion object : FirmamentEventBus<CustomItemModelEvent>() { +		val cache = +			WeakCache.memoize<ItemStack, ItemModels, Optional<BakedModel>>("CustomItemModels") { stack, models -> +				val modelId = getModelIdentifier(stack) ?: return@memoize Optional.empty() +				ErrorUtil.softCheck("Model Id needs to have an inventory variant") { modelId.variant() == "inventory" } +				val bakedModel = models.getModel(modelId.id) +				if (bakedModel == null || bakedModel === models.missingModelSupplier.get()) return@memoize Optional.empty() +				Optional.of(bakedModel) +			} -        @JvmStatic -        fun getModelIdentifier(itemStack: ItemStack?): ModelIdentifier? { -            if (itemStack == null) return null -            return publish(CustomItemModelEvent(itemStack)).overrideModel -        } +		@JvmStatic +		fun getModelIdentifier(itemStack: ItemStack?): ModelIdentifier? { +			if (itemStack == null) return null +			return publish(CustomItemModelEvent(itemStack)).overrideModel +		} -        @JvmStatic -        fun getModel(itemStack: ItemStack?, thing: BakedModelManager): BakedModel? { -            if (itemStack == null) return null -            return cache.invoke(itemStack, thing).getOrNull() -        } -    } +		@JvmStatic +		fun getModel(itemStack: ItemStack?, thing: ItemModels): BakedModel? { +			if (itemStack == null) return null +			return cache.invoke(itemStack, thing).getOrNull() +		} +	}  } diff --git a/src/main/kotlin/events/FinalizeResourceManagerEvent.kt b/src/main/kotlin/events/FinalizeResourceManagerEvent.kt index 0d411f1..12167f8 100644 --- a/src/main/kotlin/events/FinalizeResourceManagerEvent.kt +++ b/src/main/kotlin/events/FinalizeResourceManagerEvent.kt @@ -5,31 +5,28 @@ import java.util.concurrent.Executor  import net.minecraft.resource.ReloadableResourceManagerImpl  import net.minecraft.resource.ResourceManager  import net.minecraft.resource.ResourceReloader -import net.minecraft.util.profiler.Profiler  data class FinalizeResourceManagerEvent( -    val resourceManager: ReloadableResourceManagerImpl, +	val resourceManager: ReloadableResourceManagerImpl,  ) : FirmamentEvent() { -    companion object : FirmamentEventBus<FinalizeResourceManagerEvent>() +	companion object : FirmamentEventBus<FinalizeResourceManagerEvent>() -    inline fun registerOnApply(name: String, crossinline function: () -> Unit) { -        resourceManager.registerReloader(object : ResourceReloader { -            override fun reload( -                synchronizer: ResourceReloader.Synchronizer, -                manager: ResourceManager?, -                prepareProfiler: Profiler?, -                applyProfiler: Profiler?, -                prepareExecutor: Executor?, -                applyExecutor: Executor -            ): CompletableFuture<Void> { -                return CompletableFuture.completedFuture(Unit) -                    .thenCompose(synchronizer::whenPrepared) -                    .thenAcceptAsync({ function() }, applyExecutor) -            } +	inline fun registerOnApply(name: String, crossinline function: () -> Unit) { +		resourceManager.registerReloader(object : ResourceReloader { +			override fun reload( +				synchronizer: ResourceReloader.Synchronizer, +				manager: ResourceManager, +				prepareExecutor: Executor, +				applyExecutor: Executor +			): CompletableFuture<Void> { +				return CompletableFuture.completedFuture(Unit) +					.thenCompose(synchronizer::whenPrepared) +					.thenAcceptAsync({ function() }, applyExecutor) +			} -            override fun getName(): String { -                return name -            } -        }) -    } +			override fun getName(): String { +				return name +			} +		}) +	}  } diff --git a/src/main/kotlin/events/IsSlotProtectedEvent.kt b/src/main/kotlin/events/IsSlotProtectedEvent.kt index cd431f7..cd2b676 100644 --- a/src/main/kotlin/events/IsSlotProtectedEvent.kt +++ b/src/main/kotlin/events/IsSlotProtectedEvent.kt @@ -37,7 +37,7 @@ data class IsSlotProtectedEvent(              val event = IsSlotProtectedEvent(slot, action, false, itemStackOverride)              publish(event)              if (event.isProtected && !event.silent) { -                MC.player?.sendMessage(Text.translatable("firmament.protectitem").append(event.itemStack.name)) +                MC.sendChat(Text.translatable("firmament.protectitem").append(event.itemStack.name))                  CommonSoundEffects.playFailure()              }              return event.isProtected diff --git a/src/main/kotlin/events/RegisterCustomShadersEvent.kt b/src/main/kotlin/events/RegisterCustomShadersEvent.kt deleted file mode 100644 index 2f6d1f8..0000000 --- a/src/main/kotlin/events/RegisterCustomShadersEvent.kt +++ /dev/null @@ -1,24 +0,0 @@ -package moe.nea.firmament.events - -import com.mojang.datafixers.util.Pair -import java.util.function.Consumer -import net.minecraft.client.gl.ShaderProgram -import net.minecraft.client.render.VertexFormat -import net.minecraft.resource.ResourceFactory -import moe.nea.firmament.Firmament - -data class RegisterCustomShadersEvent( -    val list: MutableList<Pair<ShaderProgram, Consumer<ShaderProgram>>>, -    val resourceFactory: ResourceFactory, -) : FirmamentEvent() { -    companion object : FirmamentEventBus<RegisterCustomShadersEvent>() - -    fun register(name: String, vertexFormat: VertexFormat, saver: Consumer<ShaderProgram>) { -        require(name.startsWith("firmament_")) -        try { -            list.add(Pair.of(ShaderProgram(resourceFactory, name, vertexFormat), saver)) -        } catch (ex: Exception) { -            Firmament.logger.fatal("Could not load firmament shader $name", ex) -        } -    } -} diff --git a/src/main/kotlin/events/SlotRenderEvents.kt b/src/main/kotlin/events/SlotRenderEvents.kt index 5431573..5234176 100644 --- a/src/main/kotlin/events/SlotRenderEvents.kt +++ b/src/main/kotlin/events/SlotRenderEvents.kt @@ -3,20 +3,19 @@  package moe.nea.firmament.events  import net.minecraft.client.gui.DrawContext +import net.minecraft.client.render.RenderLayer  import net.minecraft.client.texture.Sprite  import net.minecraft.screen.slot.Slot  import net.minecraft.util.Identifier  import moe.nea.firmament.util.MC +import moe.nea.firmament.util.render.drawGuiTexture  interface SlotRenderEvents {      val context: DrawContext      val slot: Slot -    val mouseX: Int -    val mouseY: Int -    val delta: Float -	fun highlight(sprite: Sprite) { -		context.drawSprite( +	fun highlight(sprite: Identifier) { +		context.drawGuiTexture(  			slot.x, slot.y, 0, 16, 16,  			sprite  		) @@ -24,9 +23,6 @@ interface SlotRenderEvents {      data class Before(          override val context: DrawContext, override val slot: Slot, -        override val mouseX: Int, -        override val mouseY: Int, -        override val delta: Float      ) : FirmamentEvent(),          SlotRenderEvents {          companion object : FirmamentEventBus<Before>() @@ -34,9 +30,6 @@ interface SlotRenderEvents {      data class After(          override val context: DrawContext, override val slot: Slot, -        override val mouseX: Int, -        override val mouseY: Int, -        override val delta: Float      ) : FirmamentEvent(),          SlotRenderEvents {          companion object : FirmamentEventBus<After>() diff --git a/src/main/kotlin/features/chat/ChatLinks.kt b/src/main/kotlin/features/chat/ChatLinks.kt index 0681f57..5bce3f4 100644 --- a/src/main/kotlin/features/chat/ChatLinks.kt +++ b/src/main/kotlin/features/chat/ChatLinks.kt @@ -13,8 +13,10 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.async  import kotlin.math.min  import net.minecraft.client.gui.screen.ChatScreen +import net.minecraft.client.render.RenderLayer  import net.minecraft.client.texture.NativeImage  import net.minecraft.client.texture.NativeImageBackedTexture +import net.minecraft.scoreboard.ScoreboardCriterion.RenderType  import net.minecraft.text.ClickEvent  import net.minecraft.text.HoverEvent  import net.minecraft.text.Style @@ -28,6 +30,7 @@ import moe.nea.firmament.events.ScreenRenderPostEvent  import moe.nea.firmament.features.FirmamentFeature  import moe.nea.firmament.gui.config.ManagedConfig  import moe.nea.firmament.util.MC +import moe.nea.firmament.util.render.drawTexture  import moe.nea.firmament.util.transformEachRecursively  import moe.nea.firmament.util.unformattedString diff --git a/src/main/kotlin/features/debug/DeveloperFeatures.kt b/src/main/kotlin/features/debug/DeveloperFeatures.kt index 2001a3f..d4b118b 100644 --- a/src/main/kotlin/features/debug/DeveloperFeatures.kt +++ b/src/main/kotlin/features/debug/DeveloperFeatures.kt @@ -37,10 +37,10 @@ object DeveloperFeatures : FirmamentFeature {              builder.directory(gradleDir.toFile())              builder.inheritIO()              val process = builder.start() -            MC.player?.sendMessage(Text.translatable("firmament.dev.resourcerebuild.start")) +            MC.sendChat(Text.translatable("firmament.dev.resourcerebuild.start"))              val startTime = TimeMark.now()              process.toHandle().onExit().thenApply { -                MC.player?.sendMessage(Text.stringifiedTranslatable( +                MC.sendChat(Text.stringifiedTranslatable(                      "firmament.dev.resourcerebuild.done",                      startTime.passedTime()))                  Unit diff --git a/src/main/kotlin/features/debug/PowerUserTools.kt b/src/main/kotlin/features/debug/PowerUserTools.kt index 83e3aff..13320dc 100644 --- a/src/main/kotlin/features/debug/PowerUserTools.kt +++ b/src/main/kotlin/features/debug/PowerUserTools.kt @@ -9,6 +9,7 @@ import net.minecraft.entity.Entity  import net.minecraft.entity.LivingEntity  import net.minecraft.item.ItemStack  import net.minecraft.item.Items +import net.minecraft.nbt.NbtOps  import net.minecraft.text.Text  import net.minecraft.text.TextCodecs  import net.minecraft.util.hit.BlockHitResult @@ -54,15 +55,13 @@ object PowerUserTools : FirmamentFeature {  	var lastCopiedStack: Pair<ItemStack, Text>? = null  		set(value) {  			field = value -			if (value != null) -				lastCopiedStackViewTime = true +			if (value != null) lastCopiedStackViewTime = true  		}  	var lastCopiedStackViewTime = false  	@Subscribe  	fun resetLastCopiedStack(event: TickEvent) { -		if (!lastCopiedStackViewTime) -			lastCopiedStack = null +		if (!lastCopiedStackViewTime) lastCopiedStack = null  		lastCopiedStackViewTime = false  	} @@ -154,13 +153,13 @@ object PowerUserTools : FirmamentFeature {  			}  			ClipboardUtils.setTextContent(skullTexture.toString())  			lastCopiedStack = -				Pair( -					item, -					Text.stringifiedTranslatable("firmament.tooltip.copied.skull-id", skullTexture.toString()) -				) +				Pair(item, Text.stringifiedTranslatable("firmament.tooltip.copied.skull-id", skullTexture.toString()))  			println("Copied skull id: $skullTexture")  		} else if (it.matches(TConfig.copyItemStack)) { -			ClipboardUtils.setTextContent(item.encode(MC.currentOrDefaultRegistries).toPrettyString()) +			ClipboardUtils.setTextContent( +				ItemStack.CODEC +					.encodeStart(MC.currentOrDefaultRegistries.getOps(NbtOps.INSTANCE), item) +					.orThrow.toPrettyString())  			lastCopiedStack = Pair(item, Text.stringifiedTranslatable("firmament.tooltip.copied.stack"))  		}  	} diff --git a/src/main/kotlin/features/inventory/CraftingOverlay.kt b/src/main/kotlin/features/inventory/CraftingOverlay.kt index a958e25..d2c79fd 100644 --- a/src/main/kotlin/features/inventory/CraftingOverlay.kt +++ b/src/main/kotlin/features/inventory/CraftingOverlay.kt @@ -69,7 +69,7 @@ object CraftingOverlay : FirmamentFeature {  		if (!slot.hasStack()) {  			val itemStack = SBItemStack(expectedItem)?.asImmutableItemStack() ?: return  			event.context.drawItem(itemStack, event.slot.x, event.slot.y) -			event.context.drawItemInSlot( +			event.context.drawStackOverlay(  				MC.font,  				itemStack,  				event.slot.x, diff --git a/src/main/kotlin/features/inventory/ItemRarityCosmetics.kt b/src/main/kotlin/features/inventory/ItemRarityCosmetics.kt index 77f5071..26712da 100644 --- a/src/main/kotlin/features/inventory/ItemRarityCosmetics.kt +++ b/src/main/kotlin/features/inventory/ItemRarityCosmetics.kt @@ -4,6 +4,7 @@ package moe.nea.firmament.features.inventory  import java.awt.Color  import net.minecraft.client.gui.DrawContext +import net.minecraft.client.render.RenderLayer  import net.minecraft.item.ItemStack  import net.minecraft.util.Formatting  import net.minecraft.util.Identifier @@ -16,6 +17,7 @@ import moe.nea.firmament.util.MC  import moe.nea.firmament.util.mc.loreAccordingToNbt  import moe.nea.firmament.util.collections.lastNotNullOfOrNull  import moe.nea.firmament.util.collections.memoizeIdentity +import moe.nea.firmament.util.render.drawGuiTexture  import moe.nea.firmament.util.unformattedString  object ItemRarityCosmetics : FirmamentFeature { @@ -43,10 +45,10 @@ object ItemRarityCosmetics : FirmamentFeature {          "SUPREME" to Formatting.DARK_RED,      ).mapValues {          val c = Color(it.value.colorValue!!) -        Triple(c.red / 255F, c.green / 255F, c.blue / 255F) +        c.rgb      } -    private fun getSkyblockRarity0(itemStack: ItemStack): Triple<Float, Float, Float>? { +    private fun getSkyblockRarity0(itemStack: ItemStack): Int? {          return itemStack.loreAccordingToNbt.lastNotNullOfOrNull {              val entry = it.unformattedString              rarityToColor.entries.find { (k, v) -> k in entry }?.value @@ -57,13 +59,13 @@ object ItemRarityCosmetics : FirmamentFeature {      fun drawItemStackRarity(drawContext: DrawContext, x: Int, y: Int, item: ItemStack) { -        val (r, g, b) = getSkyblockRarity(item) ?: return -        drawContext.drawSprite( +        val rgb = getSkyblockRarity(item) ?: return +        drawContext.drawGuiTexture( +	        RenderLayer::getGuiTextured, +	        Identifier.of("firmament:item_rarity_background"),              x, y, -            0,              16, 16, -            MC.guiAtlasManager.getSprite(Identifier.of("firmament:item_rarity_background")), -            r, g, b, 1F +            rgb          )      } diff --git a/src/main/kotlin/features/inventory/PetFeatures.kt b/src/main/kotlin/features/inventory/PetFeatures.kt index 2c11e76..5ca10f7 100644 --- a/src/main/kotlin/features/inventory/PetFeatures.kt +++ b/src/main/kotlin/features/inventory/PetFeatures.kt @@ -7,6 +7,7 @@ import moe.nea.firmament.features.FirmamentFeature  import moe.nea.firmament.gui.config.ManagedConfig  import moe.nea.firmament.util.MC  import moe.nea.firmament.util.petData +import moe.nea.firmament.util.render.drawGuiTexture  import moe.nea.firmament.util.useMatch  object PetFeatures : FirmamentFeature { @@ -28,9 +29,9 @@ object PetFeatures : FirmamentFeature {  		val stack = event.slot.stack  		if (stack.petData?.active == true)  			petMenuTitle.useMatch(MC.screenName ?: return) { -				event.context.drawSprite( +				event.context.drawGuiTexture(  					event.slot.x, event.slot.y, 0, 16, 16, -					MC.guiAtlasManager.getSprite(Identifier.of("firmament:selected_pet_background")) +					Identifier.of("firmament:selected_pet_background")  				)  			}  	} diff --git a/src/main/kotlin/features/inventory/SlotLocking.kt b/src/main/kotlin/features/inventory/SlotLocking.kt index de54005..5507752 100644 --- a/src/main/kotlin/features/inventory/SlotLocking.kt +++ b/src/main/kotlin/features/inventory/SlotLocking.kt @@ -35,6 +35,7 @@ import moe.nea.firmament.util.mc.ScreenUtil.getSlotByIndex  import moe.nea.firmament.util.mc.SlotUtils.swapWithHotBar  import moe.nea.firmament.util.mc.displayNameAccordingToNbt  import moe.nea.firmament.util.mc.loreAccordingToNbt +import moe.nea.firmament.util.render.drawGuiTexture  import moe.nea.firmament.util.render.drawLine  import moe.nea.firmament.util.skyblockUUID  import moe.nea.firmament.util.unformattedString @@ -332,21 +333,19 @@ object SlotLocking : FirmamentFeature {  		val isUUIDLocked = (it.slot.stack?.skyblockUUID) in (lockedUUIDs ?: setOf())  		if (isSlotLocked || isUUIDLocked) {  			RenderSystem.disableDepthTest() -			it.context.drawSprite( +			it.context.drawGuiTexture(  				it.slot.x, it.slot.y, 0,  				16, 16, -				MC.guiAtlasManager.getSprite( -					when { -						isSlotLocked -> -							(Identifier.of("firmament:slot_locked")) - -						isUUIDLocked -> -							(Identifier.of("firmament:uuid_locked")) - -						else -> -							error("unreachable") -					} -				) +				when { +					isSlotLocked -> +						(Identifier.of("firmament:slot_locked")) + +					isUUIDLocked -> +						(Identifier.of("firmament:uuid_locked")) + +					else -> +						error("unreachable") +				}  			)  			RenderSystem.enableDepthTest()  		} diff --git a/src/main/kotlin/features/inventory/buttons/InventoryButton.kt b/src/main/kotlin/features/inventory/buttons/InventoryButton.kt index be173bd..a46bd76 100644 --- a/src/main/kotlin/features/inventory/buttons/InventoryButton.kt +++ b/src/main/kotlin/features/inventory/buttons/InventoryButton.kt @@ -18,6 +18,7 @@ import moe.nea.firmament.repo.RepoManager  import moe.nea.firmament.util.MC  import moe.nea.firmament.util.SkyblockId  import moe.nea.firmament.util.collections.memoize +import moe.nea.firmament.util.render.drawGuiTexture  @Serializable  data class InventoryButton( @@ -54,13 +55,13 @@ data class InventoryButton(      }      fun render(context: DrawContext) { -        context.drawSprite( +        context.drawGuiTexture(              0,              0,              0,              dimensions.width,              dimensions.height, -            MC.guiAtlasManager.getSprite(Identifier.of("firmament:inventory_button_background")) +            Identifier.of("firmament:inventory_button_background")          )          context.drawItem(getItem(), 1, 1)      } diff --git a/src/main/kotlin/features/inventory/buttons/InventoryButtonEditor.kt b/src/main/kotlin/features/inventory/buttons/InventoryButtonEditor.kt index c57563e..7bf9c73 100644 --- a/src/main/kotlin/features/inventory/buttons/InventoryButtonEditor.kt +++ b/src/main/kotlin/features/inventory/buttons/InventoryButtonEditor.kt @@ -84,7 +84,6 @@ class InventoryButtonEditor(          context.matrices.push()          context.matrices.translate(0f, 0f, -10f)          context.fill(lastGuiRect.minX, lastGuiRect.minY, lastGuiRect.maxX, lastGuiRect.maxY, -1) -        context.setShaderColor(1f, 1f, 1f, 1f)          context.matrices.pop()          for (button in buttons) {              val buttonPosition = button.getBounds(lastGuiRect) diff --git a/src/main/kotlin/features/inventory/storageoverlay/StorageBackingHandle.kt b/src/main/kotlin/features/inventory/storageoverlay/StorageBackingHandle.kt index 5c1ac34..8fad4df 100644 --- a/src/main/kotlin/features/inventory/storageoverlay/StorageBackingHandle.kt +++ b/src/main/kotlin/features/inventory/storageoverlay/StorageBackingHandle.kt @@ -40,6 +40,7 @@ sealed interface StorageBackingHandle {           * representable as a [StorageBackingHandle], meaning another screen is open, for example the enderchest icon           * selection screen.           */ +        @OptIn(ExperimentalContracts::class)          fun fromScreen(screen: Screen?): StorageBackingHandle? {  	        contract {  		        returnsNotNull() implies (screen != null) diff --git a/src/main/kotlin/features/inventory/storageoverlay/StorageOverlayScreen.kt b/src/main/kotlin/features/inventory/storageoverlay/StorageOverlayScreen.kt index f81315d..a5b2fd6 100644 --- a/src/main/kotlin/features/inventory/storageoverlay/StorageOverlayScreen.kt +++ b/src/main/kotlin/features/inventory/storageoverlay/StorageOverlayScreen.kt @@ -21,6 +21,7 @@ import moe.nea.firmament.util.MoulConfigUtils.clickMCComponentInPlace  import moe.nea.firmament.util.MoulConfigUtils.drawMCComponentInPlace  import moe.nea.firmament.util.assertTrueOr  import moe.nea.firmament.util.customgui.customGui +import moe.nea.firmament.util.render.drawGuiTexture  class StorageOverlayScreen : Screen(Text.literal("")) { @@ -162,13 +163,11 @@ class StorageOverlayScreen : Screen(Text.literal("")) {  		context.drawGuiTexture(upperBackgroundSprite,  		                       measurements.x,  		                       measurements.y, -		                       0,  		                       measurements.overviewWidth,  		                       measurements.overviewHeight)  		context.drawGuiTexture(playerInventorySprite,  		                       measurements.playerX,  		                       measurements.playerY, -		                       0,  		                       PLAYER_WIDTH,  		                       PLAYER_HEIGHT)  	} @@ -188,7 +187,7 @@ class StorageOverlayScreen : Screen(Text.literal("")) {  		items.withIndex().forEach { (index, item) ->  			val (x, y) = getPlayerInventorySlotPosition(index)  			context.drawItem(item, x, y, 0) -			context.drawItemInSlot(textRenderer, item, x, y) +			context.drawStackOverlay(textRenderer, item, x, y)  		}  	} @@ -357,7 +356,7 @@ class StorageOverlayScreen : Screen(Text.literal("")) {  			val slotY = (index / 9) * SLOT_SIZE + y + 4 + textRenderer.fontHeight + 1  			if (slots == null) {  				context.drawItem(stack, slotX, slotY) -				context.drawItemInSlot(textRenderer, stack, slotX, slotY) +				context.drawStackOverlay(textRenderer, stack, slotX, slotY)  			} else {  				val slot = slots[index]  				slot.x = slotX - slotOffset.x diff --git a/src/main/kotlin/features/inventory/storageoverlay/StorageOverviewScreen.kt b/src/main/kotlin/features/inventory/storageoverlay/StorageOverviewScreen.kt index 2cbd54e..9112fab 100644 --- a/src/main/kotlin/features/inventory/storageoverlay/StorageOverviewScreen.kt +++ b/src/main/kotlin/features/inventory/storageoverlay/StorageOverviewScreen.kt @@ -111,7 +111,7 @@ class StorageOverviewScreen() : Screen(Text.empty()) {                  context.fill(x, y, x + 18, y + 18, 0x40808080.toInt())              }              context.drawItem(stack, x + 1, y + 1) -            context.drawItemInSlot(MC.font, stack, x + 1, y + 1) +            context.drawStackOverlay(MC.font, stack, x + 1, y + 1)          }      } diff --git a/src/main/kotlin/features/mining/CommissionFeatures.kt b/src/main/kotlin/features/mining/CommissionFeatures.kt index d0acdfd..faba253 100644 --- a/src/main/kotlin/features/mining/CommissionFeatures.kt +++ b/src/main/kotlin/features/mining/CommissionFeatures.kt @@ -1,6 +1,6 @@  package moe.nea.firmament.features.mining -import net.minecraft.util.Identifier +import moe.nea.firmament.Firmament  import moe.nea.firmament.annotations.Subscribe  import moe.nea.firmament.events.SlotRenderEvents  import moe.nea.firmament.gui.config.ManagedConfig @@ -19,10 +19,8 @@ object CommissionFeatures {  		if (!Config.highlightCompletedCommissions) return  		if (MC.screenName != "Commissions") return  		val stack = event.slot.stack -		if(stack.loreAccordingToNbt.any { it.unformattedString == "COMPLETED" }) { -			event.highlight( -				MC.guiAtlasManager.getSprite(Identifier.of("firmament:completed_commission_background")) -			) +		if (stack.loreAccordingToNbt.any { it.unformattedString == "COMPLETED" }) { +			event.highlight(Firmament.identifier("completed_commission_background"))  		}  	}  } diff --git a/src/main/kotlin/features/mining/HotmPresets.kt b/src/main/kotlin/features/mining/HotmPresets.kt index 3f83f3d..533aa1e 100644 --- a/src/main/kotlin/features/mining/HotmPresets.kt +++ b/src/main/kotlin/features/mining/HotmPresets.kt @@ -9,9 +9,7 @@ import net.minecraft.client.gui.screen.ingame.HandledScreen  import net.minecraft.entity.player.PlayerInventory  import net.minecraft.item.Items  import net.minecraft.screen.GenericContainerScreenHandler -import net.minecraft.screen.ScreenHandler  import net.minecraft.screen.slot.Slot -import net.minecraft.screen.slot.SlotActionType  import net.minecraft.text.Text  import moe.nea.firmament.Firmament  import moe.nea.firmament.annotations.Subscribe @@ -31,6 +29,7 @@ import moe.nea.firmament.util.customgui.customGui  import moe.nea.firmament.util.mc.CommonTextures  import moe.nea.firmament.util.mc.SlotUtils.clickRightMouseButton  import moe.nea.firmament.util.mc.displayNameAccordingToNbt +import moe.nea.firmament.util.render.drawGuiTexture  import moe.nea.firmament.util.unformattedString  import moe.nea.firmament.util.useMatch @@ -81,7 +80,7 @@ object HotmPresets {  		override fun render(drawContext: DrawContext, delta: Float, mouseX: Int, mouseY: Int) {  			drawContext.drawGuiTexture(  				CommonTextures.genericWidget(), -				bounds.x, bounds.y, 0, +				bounds.x, bounds.y,  				bounds.width,  				bounds.height,  			) @@ -191,7 +190,7 @@ object HotmPresets {  		if (hotmInventoryName == MC.screenName  			&& event.slot.stack.displayNameAccordingToNbt.unformattedString in highlightedPerks  		) { -			event.highlight(MC.guiAtlasManager.getSprite(Firmament.identifier("hotm_perk_preset"))) +			event.highlight((Firmament.identifier("hotm_perk_preset")))  		}  	} diff --git a/src/main/kotlin/features/texturepack/CustomBlockTextures.kt b/src/main/kotlin/features/texturepack/CustomBlockTextures.kt index a149928..2f7f084 100644 --- a/src/main/kotlin/features/texturepack/CustomBlockTextures.kt +++ b/src/main/kotlin/features/texturepack/CustomBlockTextures.kt @@ -244,7 +244,7 @@ object CustomBlockTextures {              .flatMap { it.lookup.values }              .flatten()              .mapTo(mutableSetOf()) { it.replacement.blockModelIdentifier } -            .forEach { event.addNonItemModel(it) } +            .forEach { event.addNonItemModel(it, it.id) }      }      private fun prepare(manager: ResourceManager): BakedReplacements { @@ -263,7 +263,7 @@ object CustomBlockTextures {                  val island = SkyBlockIsland.forMode(mode)                  val islandMpa = map.getOrPut(island, ::mutableMapOf)                  for ((blockId, replacement) in json.replacements) { -                    val block = MC.defaultRegistries.getWrapperOrThrow(RegistryKeys.BLOCK) +                    val block = MC.defaultRegistries.getOrThrow(RegistryKeys.BLOCK)                          .getOptional(RegistryKey.of(RegistryKeys.BLOCK, blockId))                          .getOrNull()                      if (block == null) { diff --git a/src/main/kotlin/features/texturepack/CustomGlobalArmorOverrides.kt b/src/main/kotlin/features/texturepack/CustomGlobalArmorOverrides.kt index 7b6e62b..54e9e11 100644 --- a/src/main/kotlin/features/texturepack/CustomGlobalArmorOverrides.kt +++ b/src/main/kotlin/features/texturepack/CustomGlobalArmorOverrides.kt @@ -3,13 +3,13 @@  package moe.nea.firmament.features.texturepack  import java.util.Optional +import java.util.concurrent.atomic.AtomicInteger  import kotlinx.serialization.SerialName  import kotlinx.serialization.Serializable  import kotlinx.serialization.Transient  import kotlinx.serialization.UseSerializers -import kotlin.jvm.optionals.getOrNull -import net.minecraft.item.ArmorMaterial  import net.minecraft.item.ItemStack +import net.minecraft.item.equipment.EquipmentModel  import net.minecraft.resource.ResourceManager  import net.minecraft.resource.SinglePreparationResourceReloader  import net.minecraft.util.Identifier @@ -17,90 +17,139 @@ import net.minecraft.util.profiler.Profiler  import moe.nea.firmament.Firmament  import moe.nea.firmament.annotations.Subscribe  import moe.nea.firmament.events.FinalizeResourceManagerEvent -import moe.nea.firmament.events.subscription.SubscriptionOwner -import moe.nea.firmament.features.FirmamentFeature  import moe.nea.firmament.features.texturepack.CustomGlobalTextures.logger  import moe.nea.firmament.util.IdentifierSerializer  import moe.nea.firmament.util.collections.WeakCache  import moe.nea.firmament.util.skyBlockId -object CustomGlobalArmorOverrides : SubscriptionOwner { -    @Serializable -    data class ArmorOverride( -        @SerialName("item_ids") -        val itemIds: List<String>, -        val layers: List<ArmorOverrideLayer>, -        val overrides: List<ArmorOverrideOverride> = listOf(), -    ) { -        @Transient -        val bakedLayers = bakeLayers(layers) -    } - -    fun bakeLayers(layers: List<ArmorOverrideLayer>): List<ArmorMaterial.Layer> { -        return layers.map { ArmorMaterial.Layer(it.identifier, it.suffix, it.tint) } -    } - -    @Serializable -    data class ArmorOverrideLayer( -        val tint: Boolean = false, -        val identifier: Identifier, -        val suffix: String = "", -    ) - -    @Serializable -    data class ArmorOverrideOverride( -        val predicate: FirmamentModelPredicate, -        val layers: List<ArmorOverrideLayer>, -    ) { -        @Transient -        val bakedLayers = bakeLayers(layers) -    } - -    override val delegateFeature: FirmamentFeature -        get() = CustomSkyBlockTextures - -    val overrideCache = WeakCache.memoize<ItemStack, Optional<List<ArmorMaterial.Layer>>>("ArmorOverrides") { stack -> -        val id = stack.skyBlockId ?: return@memoize Optional.empty() -        val override = overrides[id.neuItem] ?: return@memoize Optional.empty() -        for (suboverride in override.overrides) { -            if (suboverride.predicate.test(stack)) { -                return@memoize Optional.of(suboverride.bakedLayers) -            } -        } -        return@memoize Optional.of(override.bakedLayers) -    } - -    @JvmStatic -    fun overrideArmor(stack: ItemStack): List<ArmorMaterial.Layer>? { -        if (!CustomSkyBlockTextures.TConfig.enableArmorOverrides) return null -        return overrideCache.invoke(stack).getOrNull() -    } - -    var overrides: Map<String, ArmorOverride> = mapOf() - -    @Subscribe -    fun onStart(event: FinalizeResourceManagerEvent) { -        event.resourceManager.registerReloader(object : -                                                   SinglePreparationResourceReloader<Map<String, ArmorOverride>>() { -            override fun prepare(manager: ResourceManager, profiler: Profiler): Map<String, ArmorOverride> { -                val overrideFiles = manager.findResources("overrides/armor_models") { -                    it.namespace == "firmskyblock" && it.path.endsWith(".json") -                } -                val overrides = overrideFiles.mapNotNull { -                    Firmament.tryDecodeJsonFromStream<ArmorOverride>(it.value.inputStream).getOrElse { ex -> -                        logger.error("Failed to load armor texture override at ${it.key}", ex) -                        null -                    } -                } -                val associatedMap = overrides.flatMap { obj -> obj.itemIds.map { it to obj } } -                    .toMap() -                return associatedMap -            } - -            override fun apply(prepared: Map<String, ArmorOverride>, manager: ResourceManager, profiler: Profiler) { -                overrides = prepared -            } -        }) -    } +object CustomGlobalArmorOverrides { +	@Serializable +	data class ArmorOverride( +		@SerialName("item_ids") +		val itemIds: List<String>, +		val layers: List<ArmorOverrideLayer>? = null, +		val model: Identifier? = null, +		val overrides: List<ArmorOverrideOverride> = listOf(), +	) { +		@Transient +		lateinit var modelIdentifier: Identifier +		fun bake() { +			modelIdentifier = bakeModel(model, layers) +			overrides.forEach { it.bake() } +		} + +		init { +			require(layers != null || model != null) { "Either model or layers must be specified for armor override" } +			require(layers == null || model == null) { "Can't specify both model and layers for armor override" } +		} +	} + +	@Serializable +	data class ArmorOverrideLayer( +		val tint: Boolean = false, +		val identifier: Identifier, +		val suffix: String = "", +	) + +	@Serializable +	data class ArmorOverrideOverride( +		val predicate: FirmamentModelPredicate, +		val layers: List<ArmorOverrideLayer>? = null, +		val model: Identifier? = null, +	) { +		init { +			require(layers != null || model != null) { "Either model or layers must be specified for armor override override" } +			require(layers == null || model == null) { "Can't specify both model and layers for armor override override" } +		} + +		@Transient +		lateinit var modelIdentifier: Identifier +		fun bake() { +			modelIdentifier = bakeModel(model, layers) +		} +	} + + +	val overrideCache = WeakCache.memoize<ItemStack, Optional<Identifier>>("ArmorOverrides") { stack -> +		val id = stack.skyBlockId ?: return@memoize Optional.empty() +		val override = overrides[id.neuItem] ?: return@memoize Optional.empty() +		for (suboverride in override.overrides) { +			if (suboverride.predicate.test(stack)) { +				return@memoize Optional.of(suboverride.modelIdentifier) +			} +		} +		return@memoize Optional.of(override.modelIdentifier) +	} + +	var overrides: Map<String, ArmorOverride> = mapOf() +	private var bakedOverrides: MutableMap<Identifier, EquipmentModel> = mutableMapOf() +	private val sentinelFirmRunning = AtomicInteger() + +	private fun bakeModel(model: Identifier?, layers: List<ArmorOverrideLayer>?): Identifier { +		require(model == null || layers == null) +		if (model != null) { +			return model +		} else if (layers != null) { +			val idNumber = sentinelFirmRunning.incrementAndGet() +			val identifier = Identifier.of("firmament:sentinel/$idNumber") +			val equipmentLayers = layers.map { +				EquipmentModel.Layer( +					it.identifier, if (it.tint) { +						Optional.of(EquipmentModel.Dyeable(Optional.empty())) +					} else { +						Optional.empty() +					}, +					false +				) +			} +			bakedOverrides[identifier] = EquipmentModel( +				mapOf( +					EquipmentModel.LayerType.HUMANOID to equipmentLayers, +					EquipmentModel.LayerType.HUMANOID_LEGGINGS to equipmentLayers, +				) +			) +			return identifier +		} else { +			error("Either model or layers must be non null") +		} +	} + + +	@Subscribe +	fun onStart(event: FinalizeResourceManagerEvent) { +		event.resourceManager.registerReloader(object : +			                                       SinglePreparationResourceReloader<Map<String, ArmorOverride>>() { +			override fun prepare(manager: ResourceManager, profiler: Profiler): Map<String, ArmorOverride> { +				val overrideFiles = manager.findResources("overrides/armor_models") { +					it.namespace == "firmskyblock" && it.path.endsWith(".json") +				} +				val overrides = overrideFiles.mapNotNull { +					Firmament.tryDecodeJsonFromStream<ArmorOverride>(it.value.inputStream).getOrElse { ex -> +						logger.error("Failed to load armor texture override at ${it.key}", ex) +						null +					} +				} +				val associatedMap = overrides.flatMap { obj -> obj.itemIds.map { it to obj } } +					.toMap() +				return associatedMap +			} + +			override fun apply(prepared: Map<String, ArmorOverride>, manager: ResourceManager, profiler: Profiler) { +				bakedOverrides.clear() +				prepared.forEach { it.value.bake() } +				overrides = prepared +			} +		}) +	} + +	@JvmStatic +	fun overrideArmor(itemStack: ItemStack): Optional<Identifier> { +		return overrideCache.invoke(itemStack) +	} + +	@JvmStatic +	fun overrideArmorLayer(id: Identifier): EquipmentModel? { +		return bakedOverrides[id] +	}  } diff --git a/src/main/kotlin/features/texturepack/CustomGlobalTextures.kt b/src/main/kotlin/features/texturepack/CustomGlobalTextures.kt index 2771699..a1203df 100644 --- a/src/main/kotlin/features/texturepack/CustomGlobalTextures.kt +++ b/src/main/kotlin/features/texturepack/CustomGlobalTextures.kt @@ -146,7 +146,7 @@ object CustomGlobalTextures : SinglePreparationResourceReloader<CustomGlobalText                  it.overrides                      .asSequence()                      .filter { it.predicate.test(stack) } -                    .map { models.modelManager.getModel(ModelIdentifier(it.model, "inventory")) } +                    .map { models.getModel(it.model) }                      .firstOrNull()              }              .intoOptional() diff --git a/src/main/kotlin/features/world/Waypoints.kt b/src/main/kotlin/features/world/Waypoints.kt index d535b4e..72b3c7e 100644 --- a/src/main/kotlin/features/world/Waypoints.kt +++ b/src/main/kotlin/features/world/Waypoints.kt @@ -1,5 +1,3 @@ - -  package moe.nea.firmament.features.world  import com.mojang.brigadier.arguments.IntegerArgumentType @@ -12,6 +10,7 @@ import kotlin.collections.set  import kotlin.time.Duration.Companion.hours  import kotlin.time.Duration.Companion.seconds  import net.minecraft.command.argument.BlockPosArgumentType +import net.minecraft.server.command.CommandOutput  import net.minecraft.server.command.ServerCommandSource  import net.minecraft.text.Text  import net.minecraft.util.math.BlockPos @@ -35,263 +34,279 @@ import moe.nea.firmament.util.TimeMark  import moe.nea.firmament.util.render.RenderInWorldContext  object Waypoints : FirmamentFeature { -    override val identifier: String -        get() = "waypoints" +	override val identifier: String +		get() = "waypoints" -    object TConfig : ManagedConfig(identifier, Category.MINING) { // TODO: add to misc -        val tempWaypointDuration by duration("temp-waypoint-duration", 0.seconds, 1.hours) { 30.seconds } -        val showIndex by toggle("show-index") { true } -        val skipToNearest by toggle("skip-to-nearest") { false } -        // TODO: look ahead size -    } +	object TConfig : ManagedConfig(identifier, Category.MINING) { // TODO: add to misc +		val tempWaypointDuration by duration("temp-waypoint-duration", 0.seconds, 1.hours) { 30.seconds } +		val showIndex by toggle("show-index") { true } +		val skipToNearest by toggle("skip-to-nearest") { false } +		// TODO: look ahead size +	} -    data class TemporaryWaypoint( -        val pos: BlockPos, -        val postedAt: TimeMark, -    ) +	data class TemporaryWaypoint( +		val pos: BlockPos, +		val postedAt: TimeMark, +	) -    override val config get() = TConfig +	override val config get() = TConfig -    val temporaryPlayerWaypointList = mutableMapOf<String, TemporaryWaypoint>() -    val temporaryPlayerWaypointMatcher = "(?i)x: (-?[0-9]+),? y: (-?[0-9]+),? z: (-?[0-9]+)".toPattern() +	val temporaryPlayerWaypointList = mutableMapOf<String, TemporaryWaypoint>() +	val temporaryPlayerWaypointMatcher = "(?i)x: (-?[0-9]+),? y: (-?[0-9]+),? z: (-?[0-9]+)".toPattern() -    val waypoints = mutableListOf<BlockPos>() -    var ordered = false -    var orderedIndex = 0 +	val waypoints = mutableListOf<BlockPos>() +	var ordered = false +	var orderedIndex = 0 -    @Serializable -    data class ColeWeightWaypoint( -        val x: Int, -        val y: Int, -        val z: Int, -        val r: Int = 0, -        val g: Int = 0, -        val b: Int = 0, -    ) +	@Serializable +	data class ColeWeightWaypoint( +		val x: Int, +		val y: Int, +		val z: Int, +		val r: Int = 0, +		val g: Int = 0, +		val b: Int = 0, +	) -    @Subscribe -    fun onRenderOrderedWaypoints(event: WorldRenderLastEvent) { -        if (waypoints.isEmpty()) return -        RenderInWorldContext.renderInWorld(event) { -            if (!ordered) { -                waypoints.withIndex().forEach { -                    color(0f, 0.3f, 0.7f, 0.5f) -                    block(it.value) -                    color(1f, 1f, 1f, 1f) -                    if (TConfig.showIndex) -                        withFacingThePlayer(it.value.toCenterPos()) { -                            text(Text.literal(it.index.toString())) -                        } -                } -            } else { -                orderedIndex %= waypoints.size -                val firstColor = Color.ofRGBA(0, 200, 40, 180) -                color(firstColor) -                tracer(waypoints[orderedIndex].toCenterPos(), lineWidth = 3f) -                waypoints.withIndex().toList() -                    .wrappingWindow(orderedIndex, 3) -                    .zip( -                        listOf( -                            firstColor, -                            Color.ofRGBA(180, 200, 40, 150), -                            Color.ofRGBA(180, 80, 20, 140), -                        ) -                    ) -                    .reversed() -                    .forEach { (waypoint, col) -> -                        val (index, pos) = waypoint -                        color(col) -                        block(pos) -                        color(1f, 1f, 1f, 1f) -                        if (TConfig.showIndex) -                            withFacingThePlayer(pos.toCenterPos()) { -                                text(Text.literal(index.toString())) -                            } -                    } -            } -        } -    } +	@Subscribe +	fun onRenderOrderedWaypoints(event: WorldRenderLastEvent) { +		if (waypoints.isEmpty()) return +		RenderInWorldContext.renderInWorld(event) { +			if (!ordered) { +				waypoints.withIndex().forEach { +					color(0f, 0.3f, 0.7f, 0.5f) +					block(it.value) +					color(1f, 1f, 1f, 1f) +					if (TConfig.showIndex) +						withFacingThePlayer(it.value.toCenterPos()) { +							text(Text.literal(it.index.toString())) +						} +				} +			} else { +				orderedIndex %= waypoints.size +				val firstColor = Color.ofRGBA(0, 200, 40, 180) +				color(firstColor) +				tracer(waypoints[orderedIndex].toCenterPos(), lineWidth = 3f) +				waypoints.withIndex().toList() +					.wrappingWindow(orderedIndex, 3) +					.zip( +						listOf( +							firstColor, +							Color.ofRGBA(180, 200, 40, 150), +							Color.ofRGBA(180, 80, 20, 140), +						) +					) +					.reversed() +					.forEach { (waypoint, col) -> +						val (index, pos) = waypoint +						color(col) +						block(pos) +						color(1f, 1f, 1f, 1f) +						if (TConfig.showIndex) +							withFacingThePlayer(pos.toCenterPos()) { +								text(Text.literal(index.toString())) +							} +					} +			} +		} +	} -    @Subscribe -    fun onTick(event: TickEvent) { -        if (waypoints.isEmpty() || !ordered) return -        orderedIndex %= waypoints.size -        val p = MC.player?.pos ?: return -        if (TConfig.skipToNearest) { -            orderedIndex = -                (waypoints.withIndex().minBy { it.value.getSquaredDistance(p) }.index + 1) % waypoints.size -        } else { -            if (waypoints[orderedIndex].isWithinDistance(p, 3.0)) { -                orderedIndex = (orderedIndex + 1) % waypoints.size -            } -        } -    } +	@Subscribe +	fun onTick(event: TickEvent) { +		if (waypoints.isEmpty() || !ordered) return +		orderedIndex %= waypoints.size +		val p = MC.player?.pos ?: return +		if (TConfig.skipToNearest) { +			orderedIndex = +				(waypoints.withIndex().minBy { it.value.getSquaredDistance(p) }.index + 1) % waypoints.size +		} else { +			if (waypoints[orderedIndex].isWithinDistance(p, 3.0)) { +				orderedIndex = (orderedIndex + 1) % waypoints.size +			} +		} +	} -    @Subscribe -    fun onProcessChat(it: ProcessChatEvent) { -        val matcher = temporaryPlayerWaypointMatcher.matcher(it.unformattedString) -        if (it.nameHeuristic != null && TConfig.tempWaypointDuration > 0.seconds && matcher.find()) { -            temporaryPlayerWaypointList[it.nameHeuristic] = TemporaryWaypoint( -                BlockPos( -                    matcher.group(1).toInt(), -                    matcher.group(2).toInt(), -                    matcher.group(3).toInt(), -                ), -                TimeMark.now() -            ) -        } -    } +	@Subscribe +	fun onProcessChat(it: ProcessChatEvent) { +		val matcher = temporaryPlayerWaypointMatcher.matcher(it.unformattedString) +		if (it.nameHeuristic != null && TConfig.tempWaypointDuration > 0.seconds && matcher.find()) { +			temporaryPlayerWaypointList[it.nameHeuristic] = TemporaryWaypoint( +				BlockPos( +					matcher.group(1).toInt(), +					matcher.group(2).toInt(), +					matcher.group(3).toInt(), +				), +				TimeMark.now() +			) +		} +	} -    @Subscribe -    fun onCommand(event: CommandEvent.SubCommand) { -        event.subcommand("waypoint") { -            thenArgument("pos", BlockPosArgumentType.blockPos()) { pos -> -                thenExecute { -                    val position = pos.get(this).toAbsoluteBlockPos(source.asFakeServer()) -                    waypoints.add(position) -                    source.sendFeedback( -                        Text.stringifiedTranslatable( -                            "firmament.command.waypoint.added", -                            position.x, -                            position.y, -                            position.z -                        ) -                    ) -                } -            } -        } -        event.subcommand("waypoints") { -            thenLiteral("clear") { -                thenExecute { -                    waypoints.clear() -                    source.sendFeedback(Text.translatable("firmament.command.waypoint.clear")) -                } -            } -            thenLiteral("toggleordered") { -                thenExecute { -                    ordered = !ordered -                    if (ordered) { -                        val p = MC.player?.pos ?: Vec3d.ZERO -                        orderedIndex = -                            waypoints.withIndex().minByOrNull { it.value.getSquaredDistance(p) }?.index ?: 0 -                    } -                    source.sendFeedback(Text.translatable("firmament.command.waypoint.ordered.toggle.$ordered")) -                } -            } -            thenLiteral("skip") { -                thenExecute { -                    if (ordered && waypoints.isNotEmpty()) { -                        orderedIndex = (orderedIndex + 1) % waypoints.size -                        source.sendFeedback(Text.translatable("firmament.command.waypoint.skip")) -                    } else { -                        source.sendError(Text.translatable("firmament.command.waypoint.skip.error")) -                    } -                } -            } -            thenLiteral("remove") { -                thenArgument("index", IntegerArgumentType.integer(0)) { indexArg -> -                    thenExecute { -                        val index = get(indexArg) -                        if (index in waypoints.indices) { -                            waypoints.removeAt(index) -                            source.sendFeedback(Text.stringifiedTranslatable( -                                "firmament.command.waypoint.remove", -                                index)) -                        } else { -                            source.sendError(Text.stringifiedTranslatable("firmament.command.waypoint.remove.error")) -                        } -                    } -                } -            } -            thenLiteral("import") { -                thenExecute { -                    val contents = ClipboardUtils.getTextContents() -                    val data = try { -                        Firmament.json.decodeFromString<List<ColeWeightWaypoint>>(contents) -                    } catch (ex: Exception) { -                        Firmament.logger.error("Could not load waypoints from clipboard", ex) -                        source.sendError(Text.translatable("firmament.command.waypoint.import.error")) -                        return@thenExecute -                    } -                    waypoints.clear() -                    data.mapTo(waypoints) { BlockPos(it.x, it.y, it.z) } -                    source.sendFeedback( -                        Text.stringifiedTranslatable( -                            "firmament.command.waypoint.import", -                            data.size -                        ) -                    ) -                } -            } -        } -    } +	@Subscribe +	fun onCommand(event: CommandEvent.SubCommand) { +		event.subcommand("waypoint") { +			thenArgument("pos", BlockPosArgumentType.blockPos()) { pos -> +				thenExecute { +					val position = pos.get(this).toAbsoluteBlockPos(source.asFakeServer()) +					waypoints.add(position) +					source.sendFeedback( +						Text.stringifiedTranslatable( +							"firmament.command.waypoint.added", +							position.x, +							position.y, +							position.z +						) +					) +				} +			} +		} +		event.subcommand("waypoints") { +			thenLiteral("clear") { +				thenExecute { +					waypoints.clear() +					source.sendFeedback(Text.translatable("firmament.command.waypoint.clear")) +				} +			} +			thenLiteral("toggleordered") { +				thenExecute { +					ordered = !ordered +					if (ordered) { +						val p = MC.player?.pos ?: Vec3d.ZERO +						orderedIndex = +							waypoints.withIndex().minByOrNull { it.value.getSquaredDistance(p) }?.index ?: 0 +					} +					source.sendFeedback(Text.translatable("firmament.command.waypoint.ordered.toggle.$ordered")) +				} +			} +			thenLiteral("skip") { +				thenExecute { +					if (ordered && waypoints.isNotEmpty()) { +						orderedIndex = (orderedIndex + 1) % waypoints.size +						source.sendFeedback(Text.translatable("firmament.command.waypoint.skip")) +					} else { +						source.sendError(Text.translatable("firmament.command.waypoint.skip.error")) +					} +				} +			} +			thenLiteral("remove") { +				thenArgument("index", IntegerArgumentType.integer(0)) { indexArg -> +					thenExecute { +						val index = get(indexArg) +						if (index in waypoints.indices) { +							waypoints.removeAt(index) +							source.sendFeedback(Text.stringifiedTranslatable( +								"firmament.command.waypoint.remove", +								index)) +						} else { +							source.sendError(Text.stringifiedTranslatable("firmament.command.waypoint.remove.error")) +						} +					} +				} +			} +			thenLiteral("import") { +				thenExecute { +					val contents = ClipboardUtils.getTextContents() +					val data = try { +						Firmament.json.decodeFromString<List<ColeWeightWaypoint>>(contents) +					} catch (ex: Exception) { +						Firmament.logger.error("Could not load waypoints from clipboard", ex) +						source.sendError(Text.translatable("firmament.command.waypoint.import.error")) +						return@thenExecute +					} +					waypoints.clear() +					data.mapTo(waypoints) { BlockPos(it.x, it.y, it.z) } +					source.sendFeedback( +						Text.stringifiedTranslatable( +							"firmament.command.waypoint.import", +							data.size +						) +					) +				} +			} +		} +	} -    @Subscribe -    fun onRenderTemporaryWaypoints(event: WorldRenderLastEvent) { -        temporaryPlayerWaypointList.entries.removeIf { it.value.postedAt.passedTime() > TConfig.tempWaypointDuration } -        if (temporaryPlayerWaypointList.isEmpty()) return -        RenderInWorldContext.renderInWorld(event) { -            color(1f, 1f, 0f, 1f) -            temporaryPlayerWaypointList.forEach { (player, waypoint) -> -                block(waypoint.pos) -            } -            color(1f, 1f, 1f, 1f) -            temporaryPlayerWaypointList.forEach { (player, waypoint) -> -                val skin = -                    MC.networkHandler?.listedPlayerListEntries?.find { it.profile.name == player } -                        ?.skinTextures -                        ?.texture -                withFacingThePlayer(waypoint.pos.toCenterPos()) { -                    waypoint(waypoint.pos, Text.stringifiedTranslatable("firmament.waypoint.temporary", player)) -                    if (skin != null) { -                        matrixStack.translate(0F, -20F, 0F) -                        // Head front -                        texture( -                            skin, 16, 16, -                            1 / 8f, 1 / 8f, -                            2 / 8f, 2 / 8f, -                        ) -                        // Head overlay -                        texture( -                            skin, 16, 16, -                            5 / 8f, 1 / 8f, -                            6 / 8f, 2 / 8f, -                        ) -                    } -                } -            } -        } -    } +	@Subscribe +	fun onRenderTemporaryWaypoints(event: WorldRenderLastEvent) { +		temporaryPlayerWaypointList.entries.removeIf { it.value.postedAt.passedTime() > TConfig.tempWaypointDuration } +		if (temporaryPlayerWaypointList.isEmpty()) return +		RenderInWorldContext.renderInWorld(event) { +			color(1f, 1f, 0f, 1f) +			temporaryPlayerWaypointList.forEach { (player, waypoint) -> +				block(waypoint.pos) +			} +			color(1f, 1f, 1f, 1f) +			temporaryPlayerWaypointList.forEach { (player, waypoint) -> +				val skin = +					MC.networkHandler?.listedPlayerListEntries?.find { it.profile.name == player } +						?.skinTextures +						?.texture +				withFacingThePlayer(waypoint.pos.toCenterPos()) { +					waypoint(waypoint.pos, Text.stringifiedTranslatable("firmament.waypoint.temporary", player)) +					if (skin != null) { +						matrixStack.translate(0F, -20F, 0F) +						// Head front +						texture( +							skin, 16, 16, +							1 / 8f, 1 / 8f, +							2 / 8f, 2 / 8f, +						) +						// Head overlay +						texture( +							skin, 16, 16, +							5 / 8f, 1 / 8f, +							6 / 8f, 2 / 8f, +						) +					} +				} +			} +		} +	} -    @Subscribe -    fun onWorldReady(event: WorldReadyEvent) { -        temporaryPlayerWaypointList.clear() -    } +	@Subscribe +	fun onWorldReady(event: WorldReadyEvent) { +		temporaryPlayerWaypointList.clear() +	}  }  fun <E> List<E>.wrappingWindow(startIndex: Int, windowSize: Int): List<E> { -    val result = ArrayList<E>(windowSize) -    if (startIndex + windowSize < size) { -        result.addAll(subList(startIndex, startIndex + windowSize)) -    } else { -        result.addAll(subList(startIndex, size)) -        result.addAll(subList(0, minOf(windowSize - (size - startIndex), startIndex))) -    } -    return result +	val result = ArrayList<E>(windowSize) +	if (startIndex + windowSize < size) { +		result.addAll(subList(startIndex, startIndex + windowSize)) +	} else { +		result.addAll(subList(startIndex, size)) +		result.addAll(subList(0, minOf(windowSize - (size - startIndex), startIndex))) +	} +	return result  }  fun FabricClientCommandSource.asFakeServer(): ServerCommandSource { -    val source = this -    return ServerCommandSource( -        source.player, -        source.position, -        source.rotation, -        null, -        0, -        "FakeServerCommandSource", -        Text.literal("FakeServerCommandSource"), -        null, -        source.player -    ) +	val source = this +	return ServerCommandSource( +		object : CommandOutput { +			override fun sendMessage(message: Text?) { +				source.player.sendMessage(message, false) +			} + +			override fun shouldReceiveFeedback(): Boolean { +				return true +			} + +			override fun shouldTrackOutput(): Boolean { +				return true +			} + +			override fun shouldBroadcastConsoleToOps(): Boolean { +				return true +			} +		}, +		source.position, +		source.rotation, +		null, +		0, +		"FakeServerCommandSource", +		Text.literal("FakeServerCommandSource"), +		null, +		source.player +	)  } diff --git a/src/main/kotlin/gui/BarComponent.kt b/src/main/kotlin/gui/BarComponent.kt index 8ef0753..b82c666 100644 --- a/src/main/kotlin/gui/BarComponent.kt +++ b/src/main/kotlin/gui/BarComponent.kt @@ -1,4 +1,3 @@ -  package moe.nea.firmament.gui  import com.mojang.blaze3d.systems.RenderSystem @@ -10,116 +9,115 @@ import io.github.notenoughupdates.moulconfig.observer.GetSetter  import io.github.notenoughupdates.moulconfig.platform.ModernRenderContext  import me.shedaniel.math.Color  import net.minecraft.client.gui.DrawContext +import net.minecraft.client.render.RenderLayer  import net.minecraft.util.Identifier  import moe.nea.firmament.Firmament  class BarComponent( -    val progress: GetSetter<Double>, val total: GetSetter<Double>, -    val fillColor: Color, -    val emptyColor: Color, +	val progress: GetSetter<Double>, val total: GetSetter<Double>, +	val fillColor: Color, +	val emptyColor: Color,  ) : GuiComponent() { -    override fun getWidth(): Int { -        return 80 -    } +	override fun getWidth(): Int { +		return 80 +	} -    override fun getHeight(): Int { -        return 8 -    } +	override fun getHeight(): Int { +		return 8 +	} -    data class Texture( -        val identifier: Identifier, -        val u1: Float, val v1: Float, -        val u2: Float, val v2: Float, -    ) { -        fun draw(context: DrawContext, x: Int, y: Int, width: Int, height: Int, color: Color) { -            context.drawTexturedQuad( -                identifier, -                x, y, x + width, x + height, 0, -                u1, u2, v1, v2, -                color.red / 255F, -                color.green / 255F, -                color.blue / 255F, -                color.alpha / 255F, -            ) -        } -    } +	data class Texture( +		val identifier: Identifier, +		val u1: Float, val v1: Float, +		val u2: Float, val v2: Float, +	) { +		fun draw(context: DrawContext, x: Int, y: Int, width: Int, height: Int, color: Color) { +			context.drawTexturedQuad( +				RenderLayer::getGuiTextured, +				identifier, +				x, y, x + width, x + height, +				u1, u2, v1, v2, +				color.color +			) +		} +	} -    companion object { -        val resource = Firmament.identifier("textures/gui/bar.png") -        val left = Texture(resource, 0 / 64F, 0 / 64F, 4 / 64F, 8 / 64F) -        val middle = Texture(resource, 4 / 64F, 0 / 64F, 8 / 64F, 8 / 64F) -        val right = Texture(resource, 8 / 64F, 0 / 64F, 12 / 64F, 8 / 64F) -        val segmentOverlay = Texture(resource, 12 / 64F, 0 / 64F, 15 / 64F, 8 / 64F) -    } +	companion object { +		val resource = Firmament.identifier("textures/gui/bar.png") +		val left = Texture(resource, 0 / 64F, 0 / 64F, 4 / 64F, 8 / 64F) +		val middle = Texture(resource, 4 / 64F, 0 / 64F, 8 / 64F, 8 / 64F) +		val right = Texture(resource, 8 / 64F, 0 / 64F, 12 / 64F, 8 / 64F) +		val segmentOverlay = Texture(resource, 12 / 64F, 0 / 64F, 15 / 64F, 8 / 64F) +	} -    private fun drawSection( -        context: DrawContext, -        texture: Texture, -        x: Int, -        y: Int, -        width: Int, -        sectionStart: Double, -        sectionEnd: Double -    ) { -        if (sectionEnd < progress.get() && width == 4) { -            texture.draw(context, x, y, 4, 8, fillColor) -            return -        } -        if (sectionStart > progress.get() && width == 4) { -            texture.draw(context, x, y, 4, 8, emptyColor) -            return -        } -        val increasePerPixel = (sectionEnd - sectionStart) / width -        var valueAtPixel = sectionStart -        for (i in (0 until width)) { -            val newTex = -                Texture(texture.identifier, texture.u1 + i / 64F, texture.v1, texture.u1 + (i + 1) / 64F, texture.v2) -            newTex.draw( -                context, x + i, y, 1, 8, -                if (valueAtPixel < progress.get()) fillColor else emptyColor -            ) -            valueAtPixel += increasePerPixel -        } -    } +	private fun drawSection( +		context: DrawContext, +		texture: Texture, +		x: Int, +		y: Int, +		width: Int, +		sectionStart: Double, +		sectionEnd: Double +	) { +		if (sectionEnd < progress.get() && width == 4) { +			texture.draw(context, x, y, 4, 8, fillColor) +			return +		} +		if (sectionStart > progress.get() && width == 4) { +			texture.draw(context, x, y, 4, 8, emptyColor) +			return +		} +		val increasePerPixel = (sectionEnd - sectionStart) / width +		var valueAtPixel = sectionStart +		for (i in (0 until width)) { +			val newTex = +				Texture(texture.identifier, texture.u1 + i / 64F, texture.v1, texture.u1 + (i + 1) / 64F, texture.v2) +			newTex.draw( +				context, x + i, y, 1, 8, +				if (valueAtPixel < progress.get()) fillColor else emptyColor +			) +			valueAtPixel += increasePerPixel +		} +	} -    override fun render(context: GuiImmediateContext) { -        val renderContext = (context.renderContext as ModernRenderContext).drawContext -        var i = 0 -        val x = 0 -        val y = 0 -        while (i < context.width - 4) { -            drawSection( -                renderContext, -                if (i == 0) left else middle, -                x + i, y, -                (context.width - (i + 4)).coerceAtMost(4), -                i * total.get() / context.width, (i + 4) * total.get() / context.width -            ) -            i += 4 -        } -        drawSection( -            renderContext, -            right, -            x + context.width - 4, -            y, -            4, -            (context.width - 4) * total.get() / context.width, -            total.get() -        ) -        RenderSystem.setShaderColor(1F, 1F, 1F, 1F) +	override fun render(context: GuiImmediateContext) { +		val renderContext = (context.renderContext as ModernRenderContext).drawContext +		var i = 0 +		val x = 0 +		val y = 0 +		while (i < context.width - 4) { +			drawSection( +				renderContext, +				if (i == 0) left else middle, +				x + i, y, +				(context.width - (i + 4)).coerceAtMost(4), +				i * total.get() / context.width, (i + 4) * total.get() / context.width +			) +			i += 4 +		} +		drawSection( +			renderContext, +			right, +			x + context.width - 4, +			y, +			4, +			(context.width - 4) * total.get() / context.width, +			total.get() +		) +		RenderSystem.setShaderColor(1F, 1F, 1F, 1F) -    } +	}  }  fun Identifier.toMoulConfig(): MyResourceLocation { -    return MyResourceLocation(this.namespace, this.path) +	return MyResourceLocation(this.namespace, this.path)  }  fun RenderContext.color(color: Color) { -    color(color.red, color.green, color.blue, color.alpha) +	color(color.red, color.green, color.blue, color.alpha)  }  fun RenderContext.color(red: Int, green: Int, blue: Int, alpha: Int) { -    color(red / 255f, green / 255f, blue / 255f, alpha / 255f) +	color(red / 255f, green / 255f, blue / 255f, alpha / 255f)  } diff --git a/src/main/kotlin/gui/entity/EntityRenderer.kt b/src/main/kotlin/gui/entity/EntityRenderer.kt index 8c7428d..ebff1a0 100644 --- a/src/main/kotlin/gui/entity/EntityRenderer.kt +++ b/src/main/kotlin/gui/entity/EntityRenderer.kt @@ -13,6 +13,7 @@ import net.minecraft.client.gui.screen.ingame.InventoryScreen  import net.minecraft.entity.Entity  import net.minecraft.entity.EntityType  import net.minecraft.entity.LivingEntity +import net.minecraft.entity.SpawnReason  import net.minecraft.util.Identifier  import moe.nea.firmament.util.MC  import moe.nea.firmament.util.assertNotNullOr @@ -23,7 +24,7 @@ import moe.nea.firmament.util.render.enableScissorWithTranslation  object EntityRenderer {      val fakeWorld = FakeWorld()      private fun <T : Entity> t(entityType: EntityType<T>): () -> T { -        return { entityType.create(fakeWorld)!! } +        return { entityType.create(fakeWorld, SpawnReason.LOAD)!! }      }      val entityIds: Map<String, () -> LivingEntity> = mapOf( diff --git a/src/main/kotlin/gui/entity/FakeWorld.kt b/src/main/kotlin/gui/entity/FakeWorld.kt index f354d5a..c17f2ad 100644 --- a/src/main/kotlin/gui/entity/FakeWorld.kt +++ b/src/main/kotlin/gui/entity/FakeWorld.kt @@ -1,35 +1,28 @@ -  package moe.nea.firmament.gui.entity -import com.mojang.datafixers.util.Pair -import com.mojang.serialization.Lifecycle -import java.util.* +import java.util.UUID  import java.util.function.BooleanSupplier  import java.util.function.Consumer -import java.util.stream.Stream -import kotlin.jvm.optionals.getOrNull -import kotlin.streams.asSequence  import net.minecraft.block.Block  import net.minecraft.block.BlockState  import net.minecraft.component.type.MapIdComponent  import net.minecraft.entity.Entity +import net.minecraft.entity.damage.DamageSource  import net.minecraft.entity.player.PlayerEntity  import net.minecraft.fluid.Fluid +import net.minecraft.item.FuelRegistry  import net.minecraft.item.map.MapState +import net.minecraft.particle.ParticleEffect  import net.minecraft.recipe.BrewingRecipeRegistry -import net.minecraft.recipe.Ingredient  import net.minecraft.recipe.RecipeManager -import net.minecraft.registry.BuiltinRegistries +import net.minecraft.recipe.RecipePropertySet +import net.minecraft.recipe.StonecuttingRecipe +import net.minecraft.recipe.display.CuttingRecipeDisplay  import net.minecraft.registry.DynamicRegistryManager -import net.minecraft.registry.Registry +import net.minecraft.registry.Registries  import net.minecraft.registry.RegistryKey  import net.minecraft.registry.RegistryKeys -import net.minecraft.registry.RegistryWrapper  import net.minecraft.registry.entry.RegistryEntry -import net.minecraft.registry.entry.RegistryEntryInfo -import net.minecraft.registry.entry.RegistryEntryList -import net.minecraft.registry.entry.RegistryEntryOwner -import net.minecraft.registry.tag.TagKey  import net.minecraft.resource.featuretoggle.FeatureFlags  import net.minecraft.resource.featuretoggle.FeatureSet  import net.minecraft.scoreboard.Scoreboard @@ -43,11 +36,8 @@ import net.minecraft.util.math.Box  import net.minecraft.util.math.ChunkPos  import net.minecraft.util.math.Direction  import net.minecraft.util.math.Vec3d -import net.minecraft.util.math.random.Random -import net.minecraft.util.profiler.DummyProfiler  import net.minecraft.world.BlockView  import net.minecraft.world.Difficulty -import net.minecraft.world.GameRules  import net.minecraft.world.MutableWorldProperties  import net.minecraft.world.World  import net.minecraft.world.biome.Biome @@ -59,430 +49,283 @@ import net.minecraft.world.chunk.EmptyChunk  import net.minecraft.world.chunk.light.LightingProvider  import net.minecraft.world.entity.EntityLookup  import net.minecraft.world.event.GameEvent +import net.minecraft.world.explosion.ExplosionBehavior  import net.minecraft.world.tick.OrderedTick  import net.minecraft.world.tick.QueryableTickScheduler  import net.minecraft.world.tick.TickManager -fun <T> makeRegistry(registryWrapper: RegistryWrapper.Impl<T>, key: RegistryKey<out Registry<T>>): Registry<T> { -    val inverseLookup = registryWrapper.streamEntries() -        .asSequence().map { it.value() to it.registryKey() } -        .toMap() -    val idLookup = registryWrapper.streamEntries() -        .asSequence() -        .map { it.registryKey() } -        .withIndex() -        .associate { it.value to it.index } -    val map = registryWrapper.streamEntries().asSequence().map { it.registryKey() to it.value() }.toMap(mutableMapOf()) -    val inverseIdLookup = idLookup.asIterable().associate { (k, v) -> v to k } -    return object : Registry<T> { -        override fun get(key: RegistryKey<T>?): T? { -            return registryWrapper.getOptional(key).getOrNull()?.value() -        } - -        override fun iterator(): MutableIterator<T> { -            return object : MutableIterator<T> { -                val iterator = registryWrapper.streamEntries().iterator() -                override fun hasNext(): Boolean { -                    return iterator.hasNext() -                } - -                override fun next(): T { -                    return iterator.next().value() -                } - -                override fun remove() { -                    TODO("Not yet implemented") -                } -            } -        } - -        override fun getRawId(value: T?): Int { -            return idLookup[inverseLookup[value ?: return -1] ?: return -1] ?: return -1 -        } - -        override fun get(id: Identifier?): T? { -            return get(RegistryKey.of(key, id)) -        } - -        override fun get(index: Int): T? { -            return get(inverseIdLookup[index] ?: return null) -        } - -        override fun size(): Int { -            return idLookup.size -        } - -        override fun getKey(): RegistryKey<out Registry<T>> { -            return key -        } - -        override fun getEntryInfo(key: RegistryKey<T>?): Optional<RegistryEntryInfo> { -            TODO("Not yet implemented") -        } - -        override fun getLifecycle(): Lifecycle { -            return Lifecycle.stable() -        } - -        override fun getDefaultEntry(): Optional<RegistryEntry.Reference<T>> { -            return Optional.empty() -        } - -        override fun getIds(): MutableSet<Identifier> { -            return idLookup.keys.mapTo(mutableSetOf()) { it.value } -        } - -        override fun getEntrySet(): MutableSet<MutableMap.MutableEntry<RegistryKey<T>, T>> { -            return map.entries -        } - -        override fun getKeys(): MutableSet<RegistryKey<T>> { -            return map.keys -        } - -        override fun getRandom(random: Random?): Optional<RegistryEntry.Reference<T>> { -            return registryWrapper.streamEntries().findFirst() -        } - -        override fun containsId(id: Identifier?): Boolean { -            return idLookup.containsKey(RegistryKey.of(key, id ?: return false)) -        } - -        override fun freeze(): Registry<T> { -            return this -        } - -        override fun getEntry(rawId: Int): Optional<RegistryEntry.Reference<T>> { -            val x = inverseIdLookup[rawId] ?: return Optional.empty() -            return Optional.of(RegistryEntry.Reference.standAlone(registryWrapper, x)) -        } - -        override fun streamEntries(): Stream<RegistryEntry.Reference<T>> { -            return registryWrapper.streamEntries() -        } - -        override fun streamTagsAndEntries(): Stream<Pair<TagKey<T>, RegistryEntryList.Named<T>>> { -            return streamTags().map { Pair(it, getOrCreateEntryList(it)) } -        } - -        override fun streamTags(): Stream<TagKey<T>> { -            return registryWrapper.streamTagKeys() -        } - -        override fun clearTags() { -        } - -        override fun getEntryOwner(): RegistryEntryOwner<T> { -            return registryWrapper -        } - -        override fun getReadOnlyWrapper(): RegistryWrapper.Impl<T> { -            return registryWrapper -        } - -        override fun populateTags(tagEntries: MutableMap<TagKey<T>, MutableList<RegistryEntry<T>>>?) { -        } - -        override fun getOrCreateEntryList(tag: TagKey<T>?): RegistryEntryList.Named<T> { -            return getEntryList(tag).orElseGet { RegistryEntryList.of(registryWrapper, tag) } -        } - -        override fun getEntryList(tag: TagKey<T>?): Optional<RegistryEntryList.Named<T>> { -            return registryWrapper.getOptional(tag ?: return Optional.empty()) -        } - -        override fun getEntry(value: T): RegistryEntry<T> { -            return registryWrapper.getOptional(inverseLookup[value]!!).get() -        } - -        override fun getEntry(key: RegistryKey<T>?): Optional<RegistryEntry.Reference<T>> { -            return registryWrapper.getOptional(key ?: return Optional.empty()) -        } - -        override fun getEntry(id: Identifier?): Optional<RegistryEntry.Reference<T>> { -            TODO("Not yet implemented") -        } - -        override fun createEntry(value: T): RegistryEntry.Reference<T> { -            TODO("Not yet implemented") -        } - -        override fun contains(key: RegistryKey<T>?): Boolean { -            return getEntry(key).isPresent -        } - -        override fun getId(value: T): Identifier? { -            return (inverseLookup[value] ?: return null).value -        } - -        override fun getKey(entry: T): Optional<RegistryKey<T>> { -            return Optional.ofNullable(inverseLookup[entry ?: return Optional.empty()]) -        } -    } -} -  fun createDynamicRegistry(): DynamicRegistryManager.Immutable { -    val wrapperLookup = BuiltinRegistries.createWrapperLookup() -    return object : DynamicRegistryManager.Immutable { -        override fun <E : Any?> getOptional(key: RegistryKey<out Registry<out E>>): Optional<Registry<E>> { -            val lookup = wrapperLookup.getOptionalWrapper(key).getOrNull() ?: return Optional.empty() -            val registry = makeRegistry(lookup, key as RegistryKey<out Registry<E>>) -            return Optional.of(registry) -        } - -        fun <T> entry(reg: RegistryKey<out Registry<T>>): DynamicRegistryManager.Entry<T> { -            return DynamicRegistryManager.Entry(reg, getOptional(reg).get()) -        } - -        override fun streamAllRegistries(): Stream<DynamicRegistryManager.Entry<*>> { -            return wrapperLookup.streamAllRegistryKeys() -                .map { entry(it as RegistryKey<out Registry<Any>>) } -        } -    } +	return DynamicRegistryManager.of(Registries.REGISTRIES)  }  class FakeWorld( -    registries: DynamicRegistryManager.Immutable = createDynamicRegistry(), +	registries: DynamicRegistryManager.Immutable = createDynamicRegistry(),  ) : World( -    Properties, -    RegistryKey.of(RegistryKeys.WORLD, Identifier.of("firmament", "fakeworld")), -    registries, -    registries[RegistryKeys.DIMENSION_TYPE].entryOf( -        RegistryKey.of( -            RegistryKeys.DIMENSION_TYPE, -            Identifier.of("minecraft", "overworld") -        ) -    ), -    { DummyProfiler.INSTANCE }, -    true, -    false, -    0, 0 +	Properties, +	RegistryKey.of(RegistryKeys.WORLD, Identifier.of("firmament", "fakeworld")), +	registries, +	registries.getOrThrow(RegistryKeys.DIMENSION_TYPE).getEntry( +		Identifier.of("minecraft", "overworld") +	).get(), +	true, +	false, +	0L, +	0  ) { -    object Properties : MutableWorldProperties { -        override fun getSpawnPos(): BlockPos { -            return BlockPos.ORIGIN -        } +	object Properties : MutableWorldProperties { +		override fun getSpawnPos(): BlockPos { +			return BlockPos.ORIGIN +		} -        override fun getSpawnAngle(): Float { -            return 0F -        } +		override fun getSpawnAngle(): Float { +			return 0F +		} -        override fun getTime(): Long { -            return 0 -        } +		override fun getTime(): Long { +			return 0 +		} -        override fun getTimeOfDay(): Long { -            return 0 -        } +		override fun getTimeOfDay(): Long { +			return 0 +		} -        override fun isThundering(): Boolean { -            return false -        } +		override fun isThundering(): Boolean { +			return false +		} -        override fun isRaining(): Boolean { -            return false -        } +		override fun isRaining(): Boolean { +			return false +		} -        override fun setRaining(raining: Boolean) { -        } +		override fun setRaining(raining: Boolean) { +		} -        override fun isHardcore(): Boolean { -            return false -        } - -        override fun getGameRules(): GameRules { -            return GameRules() -        } - -        override fun getDifficulty(): Difficulty { -            return Difficulty.HARD -        } - -        override fun isDifficultyLocked(): Boolean { -            return false -        } - -        override fun setSpawnPos(pos: BlockPos?, angle: Float) {} -    } +		override fun isHardcore(): Boolean { +			return false +		} + +		override fun getDifficulty(): Difficulty { +			return Difficulty.HARD +		} + +		override fun isDifficultyLocked(): Boolean { +			return false +		} + +		override fun setSpawnPos(pos: BlockPos?, angle: Float) {} +	} + +	override fun getPlayers(): List<PlayerEntity> { +		return emptyList() +	} -    override fun getPlayers(): List<PlayerEntity> { -        return emptyList() -    } - -    override fun getBrightness(direction: Direction?, shaded: Boolean): Float { -        return 1f -    } - -    override fun getGeneratorStoredBiome(biomeX: Int, biomeY: Int, biomeZ: Int): RegistryEntry<Biome> { -        return registryManager.get(RegistryKeys.BIOME).entryOf(BiomeKeys.PLAINS) -    } - -    override fun getEnabledFeatures(): FeatureSet { -        return FeatureFlags.VANILLA_FEATURES -    } - -    class FakeTickScheduler<T> : QueryableTickScheduler<T> { -        override fun scheduleTick(orderedTick: OrderedTick<T>?) { -        } - -        override fun isQueued(pos: BlockPos?, type: T): Boolean { -            return true -        } - -        override fun getTickCount(): Int { -            return 0 -        } - -        override fun isTicking(pos: BlockPos?, type: T): Boolean { -            return true -        } - -    } - -    override fun getBlockTickScheduler(): QueryableTickScheduler<Block> { -        return FakeTickScheduler() -    } - -    override fun getFluidTickScheduler(): QueryableTickScheduler<Fluid> { -        return FakeTickScheduler() -    } - - -    class FakeChunkManager(val world: FakeWorld) : ChunkManager() { -        override fun getChunk(x: Int, z: Int, leastStatus: ChunkStatus?, create: Boolean): Chunk { -            return EmptyChunk( -                world, -                ChunkPos(x, z), -                world.registryManager.get(RegistryKeys.BIOME).entryOf(BiomeKeys.PLAINS) -            ) -        } - -        override fun getWorld(): BlockView { -            return world -        } - -        override fun tick(shouldKeepTicking: BooleanSupplier?, tickChunks: Boolean) { -        } - -        override fun getDebugString(): String { -            return "FakeChunkManager" -        } - -        override fun getLoadedChunkCount(): Int { -            return 0 -        } - -        override fun getLightingProvider(): LightingProvider { -            return FakeLightingProvider(this) -        } -    } - -    class FakeLightingProvider(chunkManager: FakeChunkManager) : LightingProvider(chunkManager, false, false) - -    override fun getChunkManager(): ChunkManager { -        return FakeChunkManager(this) -    } - -    override fun playSound( -        source: PlayerEntity?, -        x: Double, -        y: Double, -        z: Double, -        sound: RegistryEntry<SoundEvent>?, -        category: SoundCategory?, -        volume: Float, -        pitch: Float, -        seed: Long -    ) { -    } - -    override fun syncWorldEvent(player: PlayerEntity?, eventId: Int, pos: BlockPos?, data: Int) { -    } - -    override fun emitGameEvent(event: RegistryEntry<GameEvent>?, emitterPos: Vec3d?, emitter: GameEvent.Emitter?) { -    } - -    override fun updateListeners(pos: BlockPos?, oldState: BlockState?, newState: BlockState?, flags: Int) { -    } - -    override fun playSoundFromEntity( -        source: PlayerEntity?, -        entity: Entity?, -        sound: RegistryEntry<SoundEvent>?, -        category: SoundCategory?, -        volume: Float, -        pitch: Float, -        seed: Long -    ) { -    } - -    override fun asString(): String { -        return "FakeWorld" -    } - -    override fun getEntityById(id: Int): Entity? { -        return null -    } - -    override fun getTickManager(): TickManager { -        return TickManager() -    } - -    override fun getMapState(id: MapIdComponent?): MapState? { -        return null -    } - -    override fun putMapState(id: MapIdComponent?, state: MapState?) { -    } - -    override fun increaseAndGetMapId(): MapIdComponent { -        return MapIdComponent(0) -    } - -    override fun setBlockBreakingInfo(entityId: Int, pos: BlockPos?, progress: Int) { -    } - -    override fun getScoreboard(): Scoreboard { -        return Scoreboard() -    } - -    override fun getRecipeManager(): RecipeManager { -        return RecipeManager(registryManager) -    } - -    object FakeEntityLookup : EntityLookup<Entity> { -        override fun get(id: Int): Entity? { -            return null -        } - -        override fun get(uuid: UUID?): Entity? { -            return null -        } - -        override fun iterate(): MutableIterable<Entity> { -            return mutableListOf() -        } - -        override fun <U : Entity?> forEachIntersects( -            filter: TypeFilter<Entity, U>?, -            box: Box?, -            consumer: LazyIterationConsumer<U>? -        ) { -        } - -        override fun forEachIntersects(box: Box?, action: Consumer<Entity>?) { -        } - -        override fun <U : Entity?> forEach(filter: TypeFilter<Entity, U>?, consumer: LazyIterationConsumer<U>?) { -        } - -    } - -    override fun getEntityLookup(): EntityLookup<Entity> { -        return FakeEntityLookup -    } - -    override fun getBrewingRecipeRegistry(): BrewingRecipeRegistry { -        return BrewingRecipeRegistry.EMPTY -    } +	override fun getBrightness(direction: Direction?, shaded: Boolean): Float { +		return 1f +	} + +	override fun getGeneratorStoredBiome(biomeX: Int, biomeY: Int, biomeZ: Int): RegistryEntry<Biome> { +		return registryManager.getOptionalEntry(BiomeKeys.PLAINS).get() +	} + +	override fun getSeaLevel(): Int { +		return 0 +	} + +	override fun getEnabledFeatures(): FeatureSet { +		return FeatureFlags.VANILLA_FEATURES +	} + +	class FakeTickScheduler<T> : QueryableTickScheduler<T> { +		override fun scheduleTick(orderedTick: OrderedTick<T>?) { +		} + +		override fun isQueued(pos: BlockPos?, type: T): Boolean { +			return true +		} + +		override fun getTickCount(): Int { +			return 0 +		} + +		override fun isTicking(pos: BlockPos?, type: T): Boolean { +			return true +		} + +	} + +	override fun getBlockTickScheduler(): QueryableTickScheduler<Block> { +		return FakeTickScheduler() +	} + +	override fun getFluidTickScheduler(): QueryableTickScheduler<Fluid> { +		return FakeTickScheduler() +	} + + +	class FakeChunkManager(val world: FakeWorld) : ChunkManager() { +		override fun getChunk(x: Int, z: Int, leastStatus: ChunkStatus?, create: Boolean): Chunk { +			return EmptyChunk( +				world, +				ChunkPos(x, z), +				world.registryManager.getOptionalEntry(BiomeKeys.PLAINS).get() +			) +		} + +		override fun getWorld(): BlockView { +			return world +		} + +		override fun tick(shouldKeepTicking: BooleanSupplier?, tickChunks: Boolean) { +		} + +		override fun getDebugString(): String { +			return "FakeChunkManager" +		} + +		override fun getLoadedChunkCount(): Int { +			return 0 +		} + +		override fun getLightingProvider(): LightingProvider { +			return FakeLightingProvider(this) +		} +	} + +	class FakeLightingProvider(chunkManager: FakeChunkManager) : LightingProvider(chunkManager, false, false) + +	override fun getChunkManager(): ChunkManager { +		return FakeChunkManager(this) +	} + +	override fun playSound( +		source: PlayerEntity?, +		x: Double, +		y: Double, +		z: Double, +		sound: RegistryEntry<SoundEvent>?, +		category: SoundCategory?, +		volume: Float, +		pitch: Float, +		seed: Long +	) { +	} + +	override fun syncWorldEvent(player: PlayerEntity?, eventId: Int, pos: BlockPos?, data: Int) { +	} + +	override fun emitGameEvent(event: RegistryEntry<GameEvent>?, emitterPos: Vec3d?, emitter: GameEvent.Emitter?) { +	} + +	override fun updateListeners(pos: BlockPos?, oldState: BlockState?, newState: BlockState?, flags: Int) { +	} + +	override fun playSoundFromEntity( +		source: PlayerEntity?, +		entity: Entity?, +		sound: RegistryEntry<SoundEvent>?, +		category: SoundCategory?, +		volume: Float, +		pitch: Float, +		seed: Long +	) { +	} + +	override fun createExplosion( +		entity: Entity?, +		damageSource: DamageSource?, +		behavior: ExplosionBehavior?, +		x: Double, +		y: Double, +		z: Double, +		power: Float, +		createFire: Boolean, +		explosionSourceType: ExplosionSourceType?, +		smallParticle: ParticleEffect?, +		largeParticle: ParticleEffect?, +		soundEvent: RegistryEntry<SoundEvent>? +	) { +		TODO("Not yet implemented") +	} + +	override fun asString(): String { +		return "FakeWorld" +	} + +	override fun getEntityById(id: Int): Entity? { +		return null +	} + +	override fun getTickManager(): TickManager { +		return TickManager() +	} + +	override fun getMapState(id: MapIdComponent?): MapState? { +		return null +	} + +	override fun putMapState(id: MapIdComponent?, state: MapState?) { +	} + +	override fun increaseAndGetMapId(): MapIdComponent { +		return MapIdComponent(0) +	} + +	override fun setBlockBreakingInfo(entityId: Int, pos: BlockPos?, progress: Int) { +	} + +	override fun getScoreboard(): Scoreboard { +		return Scoreboard() +	} + +	override fun getRecipeManager(): RecipeManager { +		return object : RecipeManager { +			override fun getPropertySet(key: RegistryKey<RecipePropertySet>?): RecipePropertySet { +				return RecipePropertySet.EMPTY +			} + +			override fun getStonecutterRecipes(): CuttingRecipeDisplay.Grouping<StonecuttingRecipe> { +				return CuttingRecipeDisplay.Grouping.empty() +			} +		} +	} + +	object FakeEntityLookup : EntityLookup<Entity> { +		override fun get(id: Int): Entity? { +			return null +		} + +		override fun get(uuid: UUID?): Entity? { +			return null +		} + +		override fun iterate(): MutableIterable<Entity> { +			return mutableListOf() +		} + +		override fun <U : Entity?> forEachIntersects( +			filter: TypeFilter<Entity, U>?, +			box: Box?, +			consumer: LazyIterationConsumer<U>? +		) { +		} + +		override fun forEachIntersects(box: Box?, action: Consumer<Entity>?) { +		} + +		override fun <U : Entity?> forEach(filter: TypeFilter<Entity, U>?, consumer: LazyIterationConsumer<U>?) { +		} + +	} + +	override fun getEntityLookup(): EntityLookup<Entity> { +		return FakeEntityLookup +	} + +	override fun getBrewingRecipeRegistry(): BrewingRecipeRegistry { +		return BrewingRecipeRegistry.EMPTY +	} + +	override fun getFuelRegistry(): FuelRegistry { +		TODO("Not yet implemented") +	}  } diff --git a/src/main/kotlin/gui/entity/ModifyHorse.kt b/src/main/kotlin/gui/entity/ModifyHorse.kt index 8ac011b..f094ca4 100644 --- a/src/main/kotlin/gui/entity/ModifyHorse.kt +++ b/src/main/kotlin/gui/entity/ModifyHorse.kt @@ -8,6 +8,7 @@ import kotlin.experimental.inv  import kotlin.experimental.or  import net.minecraft.entity.EntityType  import net.minecraft.entity.LivingEntity +import net.minecraft.entity.SpawnReason  import net.minecraft.entity.passive.AbstractHorseEntity  import net.minecraft.item.ItemStack  import net.minecraft.item.Items @@ -19,11 +20,11 @@ object ModifyHorse : EntityModifier {          var entity: AbstractHorseEntity = entity          info["kind"]?.let {              entity = when (it.asString) { -                "skeleton" -> EntityType.SKELETON_HORSE.create(fakeWorld)!! -                "zombie" -> EntityType.ZOMBIE_HORSE.create(fakeWorld)!! -                "mule" -> EntityType.MULE.create(fakeWorld)!! -                "donkey" -> EntityType.DONKEY.create(fakeWorld)!! -                "horse" -> EntityType.HORSE.create(fakeWorld)!! +                "skeleton" -> EntityType.SKELETON_HORSE.create(fakeWorld, SpawnReason.LOAD)!! +                "zombie" -> EntityType.ZOMBIE_HORSE.create(fakeWorld, SpawnReason.LOAD)!! +                "mule" -> EntityType.MULE.create(fakeWorld, SpawnReason.LOAD)!! +                "donkey" -> EntityType.DONKEY.create(fakeWorld, SpawnReason.LOAD)!! +                "horse" -> EntityType.HORSE.create(fakeWorld, SpawnReason.LOAD)!!                  else -> error("Unknown horse kind $it")              }          } diff --git a/src/main/kotlin/repo/RepoDownloadManager.kt b/src/main/kotlin/repo/RepoDownloadManager.kt index d674f23..3efd83b 100644 --- a/src/main/kotlin/repo/RepoDownloadManager.kt +++ b/src/main/kotlin/repo/RepoDownloadManager.kt @@ -5,7 +5,7 @@ package moe.nea.firmament.repo  import io.ktor.client.call.body  import io.ktor.client.request.get  import io.ktor.client.statement.bodyAsChannel -import io.ktor.utils.io.jvm.nio.copyTo +import io.ktor.utils.io.copyTo  import java.io.IOException  import java.nio.file.Files  import java.nio.file.Path diff --git a/src/main/kotlin/repo/RepoManager.kt b/src/main/kotlin/repo/RepoManager.kt index c052fb9..e5103fc 100644 --- a/src/main/kotlin/repo/RepoManager.kt +++ b/src/main/kotlin/repo/RepoManager.kt @@ -9,10 +9,12 @@ import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents  import kotlinx.coroutines.launch  import net.minecraft.client.MinecraftClient  import net.minecraft.network.packet.s2c.play.SynchronizeRecipesS2CPacket +import net.minecraft.recipe.display.CuttingRecipeDisplay  import moe.nea.firmament.Firmament  import moe.nea.firmament.Firmament.logger  import moe.nea.firmament.events.ReloadRegistrationEvent  import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.MC  import moe.nea.firmament.util.MinecraftDispatcher  import moe.nea.firmament.util.SkyblockId  import moe.nea.firmament.util.tr @@ -77,7 +79,7 @@ object RepoManager {  	private fun trySendClientboundUpdateRecipesPacket(): Boolean {  		return MinecraftClient.getInstance().world != null && MinecraftClient.getInstance().networkHandler?.onSynchronizeRecipes( -			SynchronizeRecipesS2CPacket(mutableListOf()) +			SynchronizeRecipesS2CPacket(mutableMapOf(), CuttingRecipeDisplay.Grouping.empty()) // TODO: check https://hackmd.io/@shedaniel/rei17_primer and source to see if this still resyncs  		) != null  	} @@ -112,7 +114,7 @@ object RepoManager {  			ItemCache.ReloadProgressHud.isEnabled = true  			neuRepo.reload()  		} catch (exc: NEURepositoryException) { -			MinecraftClient.getInstance().player?.sendMessage( +			MC.sendChat(  				tr("firmament.repo.reloadfail",  				   "Failed to reload repository. This will result in some mod features not working.")  			) diff --git a/src/main/kotlin/util/MC.kt b/src/main/kotlin/util/MC.kt index fc42be9..27b9457 100644 --- a/src/main/kotlin/util/MC.kt +++ b/src/main/kotlin/util/MC.kt @@ -92,7 +92,7 @@ object MC {  	inline val currentRegistries: RegistryWrapper.WrapperLookup? get() = world?.registryManager  	val defaultRegistries: RegistryWrapper.WrapperLookup = BuiltinRegistries.createWrapperLookup()  	inline val currentOrDefaultRegistries get() = currentRegistries ?: defaultRegistries -	val defaultItems: RegistryWrapper.Impl<Item> = defaultRegistries.getWrapperOrThrow(RegistryKeys.ITEM) +	val defaultItems: RegistryWrapper.Impl<Item> = defaultRegistries.getOrThrow(RegistryKeys.ITEM)  } diff --git a/src/main/kotlin/util/data/IDataHolder.kt b/src/main/kotlin/util/data/IDataHolder.kt index cc97b58..1e9ba98 100644 --- a/src/main/kotlin/util/data/IDataHolder.kt +++ b/src/main/kotlin/util/data/IDataHolder.kt @@ -1,77 +1,71 @@ - -  package moe.nea.firmament.util.data  import java.util.concurrent.CopyOnWriteArrayList  import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents  import kotlin.reflect.KClass -import net.minecraft.client.MinecraftClient -import net.minecraft.server.command.CommandOutput  import net.minecraft.text.Text  import moe.nea.firmament.Firmament  import moe.nea.firmament.events.ScreenChangeEvent +import moe.nea.firmament.util.MC  interface IDataHolder<T> { -    companion object { -        internal var badLoads: MutableList<String> = CopyOnWriteArrayList() -        private val allConfigs: MutableMap<KClass<out IDataHolder<*>>, IDataHolder<*>> = mutableMapOf() -        private val dirty: MutableSet<KClass<out IDataHolder<*>>> = mutableSetOf() +	companion object { +		internal var badLoads: MutableList<String> = CopyOnWriteArrayList() +		private val allConfigs: MutableMap<KClass<out IDataHolder<*>>, IDataHolder<*>> = mutableMapOf() +		private val dirty: MutableSet<KClass<out IDataHolder<*>>> = mutableSetOf() -        internal fun <T : IDataHolder<K>, K> putDataHolder(kClass: KClass<T>, inst: IDataHolder<K>) { -            allConfigs[kClass] = inst -        } +		internal fun <T : IDataHolder<K>, K> putDataHolder(kClass: KClass<T>, inst: IDataHolder<K>) { +			allConfigs[kClass] = inst +		} -        fun <T : IDataHolder<K>, K> markDirty(kClass: KClass<T>) { -            if (kClass !in allConfigs) { -                Firmament.logger.error("Tried to markDirty '${kClass.qualifiedName}', which isn't registered as 'IConfigHolder'") -                return -            } -            dirty.add(kClass) -        } +		fun <T : IDataHolder<K>, K> markDirty(kClass: KClass<T>) { +			if (kClass !in allConfigs) { +				Firmament.logger.error("Tried to markDirty '${kClass.qualifiedName}', which isn't registered as 'IConfigHolder'") +				return +			} +			dirty.add(kClass) +		} -        private fun performSaves() { -            val toSave = dirty.toList().also { -                dirty.clear() -            } -            for (it in toSave) { -                val obj = allConfigs[it] -                if (obj == null) { -                    Firmament.logger.error("Tried to save '${it}', which isn't registered as 'ConfigHolder'") -                    continue -                } -                obj.save() -            } -        } +		private fun performSaves() { +			val toSave = dirty.toList().also { +				dirty.clear() +			} +			for (it in toSave) { +				val obj = allConfigs[it] +				if (obj == null) { +					Firmament.logger.error("Tried to save '${it}', which isn't registered as 'ConfigHolder'") +					continue +				} +				obj.save() +			} +		} -        private fun warnForResetConfigs(player: CommandOutput) { -            if (badLoads.isNotEmpty()) { -                player.sendMessage( -                    Text.literal( -                        "The following configs have been reset: ${badLoads.joinToString(", ")}. " + -                            "This can be intentional, but probably isn't." -                    ) -                ) -                badLoads.clear() -            } -        } +		private fun warnForResetConfigs() { +			if (badLoads.isNotEmpty()) { +				MC.sendChat( +					Text.literal( +						"The following configs have been reset: ${badLoads.joinToString(", ")}. " + +							"This can be intentional, but probably isn't." +					) +				) +				badLoads.clear() +			} +		} -        fun registerEvents() { -            ScreenChangeEvent.subscribe("IDataHolder:saveOnScreenChange") { event -> -                performSaves() -                val p = MinecraftClient.getInstance().player -                if (p != null) { -                    warnForResetConfigs(p) -                } -            } -            ClientLifecycleEvents.CLIENT_STOPPING.register(ClientLifecycleEvents.ClientStopping { -                performSaves() -            }) -        } +		fun registerEvents() { +			ScreenChangeEvent.subscribe("IDataHolder:saveOnScreenChange") { event -> +				performSaves() +				warnForResetConfigs() +			} +			ClientLifecycleEvents.CLIENT_STOPPING.register(ClientLifecycleEvents.ClientStopping { +				performSaves() +			}) +		} -    } +	} -    val data: T -    fun save() -    fun markDirty() -    fun load() +	val data: T +	fun save() +	fun markDirty() +	fun load()  } diff --git a/src/main/kotlin/util/render/DrawContextExt.kt b/src/main/kotlin/util/render/DrawContextExt.kt index fc38aa6..14ee8e7 100644 --- a/src/main/kotlin/util/render/DrawContextExt.kt +++ b/src/main/kotlin/util/render/DrawContextExt.kt @@ -4,12 +4,49 @@ import com.mojang.blaze3d.systems.RenderSystem  import me.shedaniel.math.Color  import org.joml.Matrix4f  import net.minecraft.client.gui.DrawContext +import net.minecraft.client.render.RenderLayer +import net.minecraft.util.Identifier  import moe.nea.firmament.util.MC  fun DrawContext.isUntranslatedGuiDrawContext(): Boolean {  	return (matrices.peek().positionMatrix.properties() and Matrix4f.PROPERTY_IDENTITY.toInt()) != 0  } +@Deprecated("Use the other drawGuiTexture") +fun DrawContext.drawGuiTexture( +	x: Int, y: Int, z: Int, width: Int, height: Int, sprite: Identifier +) = this.drawGuiTexture(RenderLayer::getGuiTextured, sprite, x, y, width, height) + +fun DrawContext.drawGuiTexture( +	sprite: Identifier, +	x: Int, y: Int, width: Int, height: Int +) = this.drawGuiTexture(RenderLayer::getGuiTextured, sprite, x, y, width, height) + +fun DrawContext.drawTexture( +	sprite: Identifier, +	x: Int, +	y: Int, +	u: Float, +	v: Float, +	width: Int, +	height: Int, +	textureWidth: Int, +	textureHeight: Int +) { +	this.drawTexture(RenderLayer::getGuiTextured, +	                 sprite, +	                 x, +	                 y, +	                 u, +	                 v, +	                 width, +	                 height, +	                 width, +	                 height, +	                 textureWidth, +	                 textureHeight) +} +  fun DrawContext.drawLine(fromX: Int, fromY: Int, toX: Int, toY: Int, color: Color) {  	// TODO: push scissors  	// TODO: use matrix translations and a different render layer @@ -18,11 +55,12 @@ fun DrawContext.drawLine(fromX: Int, fromY: Int, toX: Int, toY: Int, color: Colo  		return  	}  	RenderSystem.lineWidth(MC.window.scaleFactor.toFloat()) -	val buf = this.vertexConsumers.getBuffer(RenderInWorldContext.RenderLayers.LINES) -	buf.vertex(fromX.toFloat(), fromY.toFloat(), 0F).color(color.color) -		.normal(toX - fromX.toFloat(), toY - fromY.toFloat(), 0F) -	buf.vertex(toX.toFloat(), toY.toFloat(), 0F).color(color.color) -		.normal(toX - fromX.toFloat(), toY - fromY.toFloat(), 0F) -	this.draw() +	draw { vertexConsumers -> +		val buf = vertexConsumers.getBuffer(RenderInWorldContext.RenderLayers.LINES) +		buf.vertex(fromX.toFloat(), fromY.toFloat(), 0F).color(color.color) +			.normal(toX - fromX.toFloat(), toY - fromY.toFloat(), 0F) +		buf.vertex(toX.toFloat(), toY.toFloat(), 0F).color(color.color) +			.normal(toX - fromX.toFloat(), toY - fromY.toFloat(), 0F) +	}  } diff --git a/src/main/kotlin/util/render/FacingThePlayerContext.kt b/src/main/kotlin/util/render/FacingThePlayerContext.kt index eb37e35..daa8da9 100644 --- a/src/main/kotlin/util/render/FacingThePlayerContext.kt +++ b/src/main/kotlin/util/render/FacingThePlayerContext.kt @@ -76,13 +76,10 @@ class FacingThePlayerContext(val worldContext: RenderInWorldContext) {          u1: Float, v1: Float,          u2: Float, v2: Float,      ) { -        RenderSystem.setShaderTexture(0, texture) -        RenderSystem.setShader(GameRenderer::getPositionTexColorProgram) +		val buf = worldContext.vertexConsumers.getBuffer(RenderLayer.getGuiTexturedOverlay(texture))          val hw = width / 2F          val hh = height / 2F          val matrix4f: Matrix4f = worldContext.matrixStack.peek().positionMatrix -        val buf = Tessellator.getInstance() -            .begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR)          buf.vertex(matrix4f, -hw, -hh, 0F)              .color(-1)              .texture(u1, v1).next() @@ -95,7 +92,7 @@ class FacingThePlayerContext(val worldContext: RenderInWorldContext) {          buf.vertex(matrix4f, +hw, -hh, 0F)              .color(-1)              .texture(u2, v1).next() -        BufferRenderer.drawWithGlobalProgram(buf.end()) +	    worldContext.vertexConsumers.draw()      }  } diff --git a/src/main/kotlin/util/render/FirmamentShaders.kt b/src/main/kotlin/util/render/FirmamentShaders.kt index 1094bc2..5147088 100644 --- a/src/main/kotlin/util/render/FirmamentShaders.kt +++ b/src/main/kotlin/util/render/FirmamentShaders.kt @@ -1,23 +1,16 @@  package moe.nea.firmament.util.render -import net.minecraft.client.gl.ShaderProgram +import net.minecraft.client.gl.Defines +import net.minecraft.client.gl.ShaderProgramKey  import net.minecraft.client.render.RenderPhase  import net.minecraft.client.render.VertexFormats -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.events.RegisterCustomShadersEvent +import moe.nea.firmament.Firmament  object FirmamentShaders { -    private lateinit var _LINES: ShaderProgram -    val LINES = RenderPhase.ShaderProgram({ _LINES }) +	val _LINES: ShaderProgramKey = +		ShaderProgramKey(Firmament.identifier("rendertype_lines"), VertexFormats.LINES, Defines.EMPTY) +	val LINES = RenderPhase.ShaderProgram(_LINES) -    @Subscribe -    fun registerCustomShaders(event: RegisterCustomShadersEvent) { -        event.register( -            "firmament_rendertype_lines", -            VertexFormats.LINES, -            { _LINES = it }, -        ) -    }  } diff --git a/src/main/kotlin/util/render/RenderCircleProgress.kt b/src/main/kotlin/util/render/RenderCircleProgress.kt index a2f42b5..9cc383c 100644 --- a/src/main/kotlin/util/render/RenderCircleProgress.kt +++ b/src/main/kotlin/util/render/RenderCircleProgress.kt @@ -1,4 +1,3 @@ -  package moe.nea.firmament.util.render  import com.mojang.blaze3d.systems.RenderSystem @@ -9,7 +8,8 @@ import kotlin.math.atan2  import kotlin.math.tan  import net.minecraft.client.gui.DrawContext  import net.minecraft.client.render.BufferRenderer -import net.minecraft.client.render.GameRenderer +import net.minecraft.client.render.RenderLayer +import net.minecraft.client.render.RenderPhase  import net.minecraft.client.render.Tessellator  import net.minecraft.client.render.VertexFormat.DrawMode  import net.minecraft.client.render.VertexFormats @@ -17,79 +17,77 @@ import net.minecraft.util.Identifier  object RenderCircleProgress { -    fun renderCircle( -        drawContext: DrawContext, -        texture: Identifier, -        progress: Float, -        u1: Float, -        u2: Float, -        v1: Float, -        v2: Float, -    ) { -        RenderSystem.setShaderTexture(0, texture) -        RenderSystem.setShader(GameRenderer::getPositionTexColorProgram) -        RenderSystem.enableBlend() -        val matrix: Matrix4f = drawContext.matrices.peek().positionMatrix -        val bufferBuilder = Tessellator.getInstance().begin(DrawMode.TRIANGLES, VertexFormats.POSITION_TEXTURE_COLOR) - -        val corners = listOf( -            Vector2f(0F, -1F), -            Vector2f(1F, -1F), -            Vector2f(1F, 0F), -            Vector2f(1F, 1F), -            Vector2f(0F, 1F), -            Vector2f(-1F, 1F), -            Vector2f(-1F, 0F), -            Vector2f(-1F, -1F), -        ) +	fun renderCircle( +		drawContext: DrawContext, +		texture: Identifier, +		progress: Float, +		u1: Float, +		u2: Float, +		v1: Float, +		v2: Float, +	) { +		RenderSystem.enableBlend() +		drawContext.draw { +			val bufferBuilder = it.getBuffer(RenderLayer.getGuiTexturedOverlay(texture)) +			val matrix: Matrix4f = drawContext.matrices.peek().positionMatrix -        for (i in (0 until 8)) { -            if (progress < i / 8F) { -                break -            } -            val second = corners[(i + 1) % 8] -            val first = corners[i] -            if (progress <= (i + 1) / 8F) { -                val internalProgress = 1 - (progress - i / 8F) * 8F -                val angle = lerpAngle( -                    atan2(second.y, second.x), -                    atan2(first.y, first.x), -                    internalProgress -                ) -                if (angle < tau / 8 || angle >= tau * 7 / 8) { -                    second.set(1F, tan(angle)) -                } else if (angle < tau * 3 / 8) { -                    second.set(1 / tan(angle), 1F) -                } else if (angle < tau * 5 / 8) { -                    second.set(-1F, -tan(angle)) -                } else { -                    second.set(-1 / tan(angle), -1F) -                } -            } +			val corners = listOf( +				Vector2f(0F, -1F), +				Vector2f(1F, -1F), +				Vector2f(1F, 0F), +				Vector2f(1F, 1F), +				Vector2f(0F, 1F), +				Vector2f(-1F, 1F), +				Vector2f(-1F, 0F), +				Vector2f(-1F, -1F), +			) -            fun ilerp(f: Float): Float = -                ilerp(-1f, 1f, f) +			for (i in (0 until 8)) { +				if (progress < i / 8F) { +					break +				} +				val second = corners[(i + 1) % 8] +				val first = corners[i] +				if (progress <= (i + 1) / 8F) { +					val internalProgress = 1 - (progress - i / 8F) * 8F +					val angle = lerpAngle( +						atan2(second.y, second.x), +						atan2(first.y, first.x), +						internalProgress +					) +					if (angle < tau / 8 || angle >= tau * 7 / 8) { +						second.set(1F, tan(angle)) +					} else if (angle < tau * 3 / 8) { +						second.set(1 / tan(angle), 1F) +					} else if (angle < tau * 5 / 8) { +						second.set(-1F, -tan(angle)) +					} else { +						second.set(-1 / tan(angle), -1F) +					} +				} -            bufferBuilder -                .vertex(matrix, second.x, second.y, 0F) -                .texture(lerp(u1, u2, ilerp(second.x)), lerp(v1, v2, ilerp(second.y))) -                .color(-1) -                .next() -            bufferBuilder -                .vertex(matrix, first.x, first.y, 0F) -                .texture(lerp(u1, u2, ilerp(first.x)), lerp(v1, v2, ilerp(first.y))) -                .color(-1) -                .next() -            bufferBuilder -                .vertex(matrix, 0F, 0F, 0F) -                .texture(lerp(u1, u2, ilerp(0F)), lerp(v1, v2, ilerp(0F))) -                .color(-1) -                .next() -        } -        BufferRenderer.drawWithGlobalProgram(bufferBuilder.end()) -        RenderSystem.disableBlend() -    } +				fun ilerp(f: Float): Float = +					ilerp(-1f, 1f, f) +				bufferBuilder +					.vertex(matrix, second.x, second.y, 0F) +					.texture(lerp(u1, u2, ilerp(second.x)), lerp(v1, v2, ilerp(second.y))) +					.color(-1) +					.next() +				bufferBuilder +					.vertex(matrix, first.x, first.y, 0F) +					.texture(lerp(u1, u2, ilerp(first.x)), lerp(v1, v2, ilerp(first.y))) +					.color(-1) +					.next() +				bufferBuilder +					.vertex(matrix, 0F, 0F, 0F) +					.texture(lerp(u1, u2, ilerp(0F)), lerp(v1, v2, ilerp(0F))) +					.color(-1) +					.next() +			} +		} +		RenderSystem.disableBlend() +	}  } diff --git a/src/main/kotlin/util/render/RenderInWorldContext.kt b/src/main/kotlin/util/render/RenderInWorldContext.kt index b61b9aa..ae8d6d3 100644 --- a/src/main/kotlin/util/render/RenderInWorldContext.kt +++ b/src/main/kotlin/util/render/RenderInWorldContext.kt @@ -8,14 +8,12 @@ import java.lang.Math.pow  import org.joml.Matrix4f  import org.joml.Vector3f  import net.minecraft.client.gl.VertexBuffer -import net.minecraft.client.render.BufferBuilder -import net.minecraft.client.render.BufferRenderer  import net.minecraft.client.render.Camera -import net.minecraft.client.render.GameRenderer  import net.minecraft.client.render.RenderLayer  import net.minecraft.client.render.RenderPhase  import net.minecraft.client.render.RenderTickCounter  import net.minecraft.client.render.Tessellator +import net.minecraft.client.render.VertexConsumer  import net.minecraft.client.render.VertexConsumerProvider  import net.minecraft.client.render.VertexFormat  import net.minecraft.client.render.VertexFormats @@ -47,7 +45,7 @@ class RenderInWorldContext private constructor(                                                RenderLayer.MultiPhaseParameters.builder()                                                    .depthTest(RenderPhase.ALWAYS_DEPTH_TEST)                                                    .transparency(RenderPhase.TRANSLUCENT_TRANSPARENCY) -                                                  .program(RenderPhase.COLOR_PROGRAM) +                                                  .program(RenderPhase.POSITION_COLOR_PROGRAM)                                                    .build(false))          val LINES = RenderLayer.of("firmament_rendertype_lines",                                     VertexFormats.LINES, @@ -72,7 +70,7 @@ class RenderInWorldContext private constructor(      fun block(blockPos: BlockPos) {          matrixStack.push()          matrixStack.translate(blockPos.x.toFloat(), blockPos.y.toFloat(), blockPos.z.toFloat()) -        buildCube(matrixStack.peek().positionMatrix, tesselator) +        buildCube(matrixStack.peek().positionMatrix, vertexConsumers.getBuffer(RenderLayer.getDebugFilledBox()))          matrixStack.pop()      } @@ -136,22 +134,24 @@ class RenderInWorldContext private constructor(      }      fun tinyBlock(vec3d: Vec3d, size: Float) { -        RenderSystem.setShader(GameRenderer::getPositionColorProgram) +	    val buf = vertexConsumers.getBuffer(RenderLayer.getDebugFilledBox()) // TODO: custom rendewr layer here, maybe          matrixStack.push()          matrixStack.translate(vec3d.x, vec3d.y, vec3d.z)          matrixStack.scale(size, size, size)          matrixStack.translate(-.5, -.5, -.5) -        buildCube(matrixStack.peek().positionMatrix, tesselator) +        buildCube(matrixStack.peek().positionMatrix, buf)          matrixStack.pop() +	    vertexConsumers.draw()      }      fun wireframeCube(blockPos: BlockPos, lineWidth: Float = 10F) { -        RenderSystem.setShader(GameRenderer::getRenderTypeLinesProgram) +	    val buf = vertexConsumers.getBuffer(RenderLayer.LINES)          matrixStack.push()          RenderSystem.lineWidth(lineWidth / pow(camera.pos.squaredDistanceTo(blockPos.toCenterPos()), 0.25).toFloat())          matrixStack.translate(blockPos.x.toFloat(), blockPos.y.toFloat(), blockPos.z.toFloat()) -        buildWireFrameCube(matrixStack.peek(), tesselator) -        matrixStack.pop() +        buildWireFrameCube(matrixStack.peek(), buf) +	    matrixStack.pop() +	    vertexConsumers.draw()      }      fun line(vararg points: Vec3d, lineWidth: Float = 10F) { @@ -165,6 +165,7 @@ class RenderInWorldContext private constructor(      fun line(points: List<Vec3d>, lineWidth: Float = 10F) {          RenderSystem.lineWidth(lineWidth) +	    // TODO: replace with renderlayers          val buffer = tesselator.begin(VertexFormat.DrawMode.LINES, VertexFormats.LINES)          val matrix = matrixStack.peek() @@ -191,7 +192,7 @@ class RenderInWorldContext private constructor(      companion object {          private fun doLine(              matrix: MatrixStack.Entry, -            buf: BufferBuilder, +            buf: VertexConsumer,              i: Float,              j: Float,              k: Float, @@ -213,9 +214,7 @@ class RenderInWorldContext private constructor(          } -        private fun buildWireFrameCube(matrix: MatrixStack.Entry, tessellator: Tessellator) { -            val buf = tessellator.begin(VertexFormat.DrawMode.LINES, VertexFormats.LINES) - +        private fun buildWireFrameCube(matrix: MatrixStack.Entry, buf: VertexConsumer) {              for (i in 0..1) {                  for (j in 0..1) {                      val i = i.toFloat() @@ -225,11 +224,9 @@ class RenderInWorldContext private constructor(                      doLine(matrix, buf, i, j, 0F, i, j, 1F)                  }              } -            BufferRenderer.drawWithGlobalProgram(buf.end())          } -        private fun buildCube(matrix: Matrix4f, tessellator: Tessellator) { -            val buf = tessellator.begin(VertexFormat.DrawMode.TRIANGLES, VertexFormats.POSITION_COLOR) +        private fun buildCube(matrix: Matrix4f, buf: VertexConsumer) {              buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next()              buf.vertex(matrix, 0.0F, 0.0F, 1.0F).color(-1).next()              buf.vertex(matrix, 0.0F, 1.0F, 1.0F).color(-1).next() @@ -266,7 +263,6 @@ class RenderInWorldContext private constructor(              buf.vertex(matrix, 1.0F, 1.0F, 1.0F).color(-1).next()              buf.vertex(matrix, 0.0F, 1.0F, 1.0F).color(-1).next()              buf.vertex(matrix, 1.0F, 0.0F, 1.0F).color(-1).next() -            RenderLayers.TRANSLUCENT_TRIS.draw(buf.end())          } diff --git a/src/main/resources/assets/minecraft/shaders/core/firmament_rendertype_lines.fsh b/src/main/resources/assets/firmament/shaders/code/rendertype_lines.fsh index 057f31f..057f31f 100644 --- a/src/main/resources/assets/minecraft/shaders/core/firmament_rendertype_lines.fsh +++ b/src/main/resources/assets/firmament/shaders/code/rendertype_lines.fsh diff --git a/src/main/resources/assets/minecraft/shaders/core/firmament_rendertype_lines.json b/src/main/resources/assets/firmament/shaders/code/rendertype_lines.json index 0828480..f276639 100644 --- a/src/main/resources/assets/minecraft/shaders/core/firmament_rendertype_lines.json +++ b/src/main/resources/assets/firmament/shaders/code/rendertype_lines.json @@ -1,6 +1,6 @@  { -    "vertex": "firmament_rendertype_lines", -    "fragment": "firmament_rendertype_lines", +    "vertex": "firmament:rendertype_lines", +    "fragment": "firmament:rendertype_lines",      "samplers": [      ],      "uniforms": [ diff --git a/src/main/resources/assets/minecraft/shaders/core/firmament_rendertype_lines.vsh b/src/main/resources/assets/firmament/shaders/code/rendertype_lines.vsh index b2d0f99..b2d0f99 100644 --- a/src/main/resources/assets/minecraft/shaders/core/firmament_rendertype_lines.vsh +++ b/src/main/resources/assets/firmament/shaders/code/rendertype_lines.vsh diff --git a/src/main/resources/firmament.accesswidener b/src/main/resources/firmament.accesswidener index 60b31e3..5d64acc 100644 --- a/src/main/resources/firmament.accesswidener +++ b/src/main/resources/firmament.accesswidener @@ -5,6 +5,7 @@ accessible class net/minecraft/client/font/TextRenderer$Drawer  accessible field net/minecraft/client/gui/hud/InGameHud SCOREBOARD_ENTRY_COMPARATOR Ljava/util/Comparator;  accessible field net/minecraft/client/render/item/HeldItemRenderer itemRenderer Lnet/minecraft/client/render/item/ItemRenderer; +accessible field net/minecraft/client/render/item/ItemModels missingModelSupplier Ljava/util/function/Supplier;  accessible class net/minecraft/client/render/model/json/ModelOverride$Deserializer  accessible class net/minecraft/client/render/model/json/ModelOverrideList$BakedOverride @@ -14,7 +15,7 @@ accessible field net/minecraft/entity/passive/AbstractHorseEntity items Lnet/min  accessible field net/minecraft/entity/passive/AbstractHorseEntity SADDLED_FLAG I  accessible field net/minecraft/entity/passive/AbstractHorseEntity HORSE_FLAGS Lnet/minecraft/entity/data/TrackedData;  accessible method net/minecraft/resource/NamespaceResourceManager loadMetadata (Lnet/minecraft/resource/InputSupplier;)Lnet/minecraft/resource/metadata/ResourceMetadata; -accessible method net/minecraft/client/gui/DrawContext drawTexturedQuad (Lnet/minecraft/util/Identifier;IIIIIFFFFFFFF)V +accessible method net/minecraft/client/gui/DrawContext drawTexturedQuad (Ljava/util/function/Function;Lnet/minecraft/util/Identifier;IIIIFFFFI)V  mutable field net/minecraft/screen/slot/Slot x I  mutable field net/minecraft/screen/slot/Slot y I diff --git a/src/main/resources/firmament.mixins.json b/src/main/resources/firmament.mixins.json index dbb8290..d78d124 100644 --- a/src/main/resources/firmament.mixins.json +++ b/src/main/resources/firmament.mixins.json @@ -1,7 +1,10 @@  { -    "required": true, -    "plugin": "moe.nea.firmament.init.MixinPlugin", -    "package": "moe.nea.firmament.mixins", -    "compatibilityLevel": "JAVA_21", -    "refmap": "Firmament-refmap.json" +	"required": true, +	"plugin": "moe.nea.firmament.init.MixinPlugin", +	"package": "moe.nea.firmament.mixins", +	"compatibilityLevel": "JAVA_21", +	"refmap": "Firmament-refmap.json", +	"injectors": { +		"defaultRequire": 1 +	}  } | 
