From 17908802c0c064e61bb8e3121333b963bf4cd942 Mon Sep 17 00:00:00 2001 From: Nebojsa Majic <79749977+Onako2@users.noreply.github.com> Date: Thu, 28 Nov 2024 09:11:33 +0100 Subject: [PATCH 01/12] Update to 1.21.3 (#41) --- README.md | 2 +- build.gradle | 8 +-- gradle.properties | 8 +-- gradle/wrapper/gradle-wrapper.properties | 2 +- .../purpurmc/purpur/client/config/Seats.java | 3 + .../purpurmc/purpur/client/entity/Mob.java | 1 + .../purpurmc/purpur/client/entity/Seat.java | 1 - .../purpur/client/gui/screen/MobScreen.java | 37 ++++++---- .../purpur/client/gui/screen/MobsScreen.java | 3 +- .../gui/screen/widget/DoubleButton.java | 5 +- .../client/gui/screen/widget/MobButton.java | 2 + .../client/gui/screen/widget/MobsList.java | 13 ++-- .../client/mixin/MixinItemEnchantments.java | 9 ++- .../client/mixin/MixinLoadingOverlay.java | 63 ++++++++++-------- .../client/mixin/mob/MixinCreaking.java | 22 ++++++ .../assets/purpurclient/lang/de_de.json | 1 + .../assets/purpurclient/lang/en_us.json | 1 + .../assets/purpurclient/textures/mobs.png | Bin 28769 -> 30462 bytes src/main/resources/fabric.mod.json | 2 +- src/main/resources/purpurclient.accesswidener | 1 + src/main/resources/purpurclient.mixins.json | 3 +- 21 files changed, 116 insertions(+), 71 deletions(-) create mode 100644 src/main/java/org/purpurmc/purpur/client/mixin/mob/MixinCreaking.java diff --git a/README.md b/README.md index be3fe6d..c8494dd 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ PurpurClient is designed to work together with [Purpur](https://github.com/Purpu -### Current Features in 1.20.6: +### Current Features in 1.21.3: * Customizable mob passenger offsets * Adds bee counts inside beehives to debug screen¹ diff --git a/build.gradle b/build.gradle index 6b20e4b..4d19fa0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id 'com.github.johnrengelman.shadow' version '8.1.1' - id 'fabric-loom' version '1.6-SNAPSHOT' + id 'fabric-loom' version '1.7-SNAPSHOT' id "com.modrinth.minotaur" version "2.+" } @@ -35,9 +35,9 @@ dependencies { // this is dumb as hell. bloats jar way too much. todo: switch to a different config provider include(modImplementation("org.spongepowered:configurate-hocon:${project.configurate_version}")) include("org.spongepowered:configurate-core:${project.configurate_version}") - include("com.google.guava:guava:31.1-jre") - include("com.typesafe:config:1.4.2") - include("io.leangen.geantyref:geantyref:1.3.12") + include("com.google.guava:guava:33.3-jre") + include("com.typesafe:config:1.4.3") + include("io.leangen.geantyref:geantyref:1.3.16") } processResources { diff --git a/gradle.properties b/gradle.properties index 29ba72d..9933603 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,10 +1,10 @@ org.gradle.jvmargs=-Xmx2G -minecraft_version=1.21 -loader_version=0.15.11 +minecraft_version=1.21.3 +loader_version=0.16.7 #parchment_version=2024.05.01 # TODO: update when available -fabric_version=0.100.1+1.21 -modmenu_version=11.0.0-beta.1 +fabric_version=0.106.1+1.21.3 +modmenu_version=12.0.0-beta.1 configurate_version=4.1.2 maven_group=org.purpurmc.purpur.client diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a80b22c..9355b41 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/src/main/java/org/purpurmc/purpur/client/config/Seats.java b/src/main/java/org/purpurmc/purpur/client/config/Seats.java index 089ed29..68dc7f9 100644 --- a/src/main/java/org/purpurmc/purpur/client/config/Seats.java +++ b/src/main/java/org/purpurmc/purpur/client/config/Seats.java @@ -22,6 +22,7 @@ public class Seats { public Seat cod = new Seat(0.0D, 0.0D, 0.0D); public Seat cow = new Seat(0.0D, 0.0D, 0.0D); public Seat creeper = new Seat(0.0D, 0.0D, 0.0D); + public Seat creaking = new Seat(0.0D, 0.0D, 0.0D); public Seat dolphin = new Seat(0.0D, 0.0D, 0.0D); public Seat donkey = new Seat(0.0D, 0.0D, 0.0D); public Seat drowned = new Seat(0.0D, 0.0D, 0.0D); @@ -105,6 +106,7 @@ public void setAllSeats(double x, double y, double z) { cod.setSeat(z, y, z); cow.setSeat(z, y, z); creeper.setSeat(z, y, z); + creaking.setSeat(z, y, z); dolphin.setSeat(z, y, z); donkey.setSeat(z, y, z); drowned.setSeat(z, y, z); @@ -190,6 +192,7 @@ public Seat getSeat(Mob mob) { case COD -> this.cod; case COW -> this.cow; case CREEPER -> this.creeper; + case CREAKING -> this.creaking; case DOLPHIN -> this.dolphin; case DONKEY -> this.donkey; case DROWNED -> this.drowned; diff --git a/src/main/java/org/purpurmc/purpur/client/entity/Mob.java b/src/main/java/org/purpurmc/purpur/client/entity/Mob.java index 53f7518..1e2943e 100644 --- a/src/main/java/org/purpurmc/purpur/client/entity/Mob.java +++ b/src/main/java/org/purpurmc/purpur/client/entity/Mob.java @@ -18,6 +18,7 @@ public enum Mob { COD(EntityType.COD, 7, 0), COW(EntityType.COW, 8, 0), CREEPER(EntityType.CREEPER, 9, 0), + CREAKING(EntityType.CREAKING, 1, 5), DOLPHIN(EntityType.DOLPHIN, 10, 0), DONKEY(EntityType.DONKEY, 11, 0), DROWNED(EntityType.DROWNED, 12, 0), diff --git a/src/main/java/org/purpurmc/purpur/client/entity/Seat.java b/src/main/java/org/purpurmc/purpur/client/entity/Seat.java index 0fd4c6c..a14ba8b 100644 --- a/src/main/java/org/purpurmc/purpur/client/entity/Seat.java +++ b/src/main/java/org/purpurmc/purpur/client/entity/Seat.java @@ -1,6 +1,5 @@ package org.purpurmc.purpur.client.entity; -import org.purpurmc.purpur.client.util.Constants; import org.spongepowered.configurate.objectmapping.ConfigSerializable; @ConfigSerializable diff --git a/src/main/java/org/purpurmc/purpur/client/gui/screen/MobScreen.java b/src/main/java/org/purpurmc/purpur/client/gui/screen/MobScreen.java index efc32a3..6b24b02 100644 --- a/src/main/java/org/purpurmc/purpur/client/gui/screen/MobScreen.java +++ b/src/main/java/org/purpurmc/purpur/client/gui/screen/MobScreen.java @@ -4,6 +4,10 @@ import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Axis; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.client.renderer.CoreShaders; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.world.entity.EntitySpawnReason; import org.joml.Matrix4fStack; import org.joml.Quaternionf; import org.purpurmc.purpur.client.PurpurClient; @@ -19,13 +23,11 @@ import org.purpurmc.purpur.client.mixin.accessor.AccessSlime; import java.util.ArrayList; + import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.Renderable; import net.minecraft.client.gui.screens.Screen; -import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; -import net.minecraft.client.renderer.GameRenderer; -import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.entity.EntityRenderDispatcher; import net.minecraft.network.chat.Component; import net.minecraft.world.entity.Entity; @@ -63,6 +65,7 @@ public class MobScreen extends AbstractScreen { private final Component noPreview = Component.translatable("purpurclient.options.no-preview"); private final Component notImplemented = Component.translatable("purpurclient.options.not-implemented"); + private final Component experimentDisabled = Component.translatable("purpurclient.options.experiment-disabled"); public MobScreen(Screen parent, Mob mob) { super(parent); @@ -98,7 +101,7 @@ public void init() { } this.fakePlayer = new FakePlayer(this.minecraft.level, this.minecraft.player); - this.fakeEntity = this.mob.getType().create(this.minecraft.level); + this.fakeEntity = this.mob.getType().create(this.minecraft.level, EntitySpawnReason.NATURAL); if (this.fakeEntity == null) { // we need an entity to ride this.fakePlayer = null; @@ -146,16 +149,23 @@ protected void addOptions() { @Override public void render(GuiGraphics context, int mouseX, int mouseY, float delta) { - renderBackground(context, mouseX, mouseY, delta); - - RenderSystem.setShader(GameRenderer::getPositionTexShader); + if (this.minecraft.level == null) { + super.renderPanorama(context, delta); + } else { + super.renderBlurredBackground(); + } + RenderSystem.setShader(CoreShaders.POSITION_TEX); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); RenderSystem.setShaderTexture(0, AbstractContainerScreen.INVENTORY_LOCATION); if (this.fakePlayer != null && this.fakeEntity != null) { drawPreviewModel(this.fakePlayer, this.fakeEntity); } else { - context.drawCenteredString(this.font, this.noPreview, this.centerX - 80, 125, 0xFFFFFFFF); + if (this.minecraft.level != null) { + context.drawCenteredString(this.font, this.experimentDisabled, this.centerX - 80, 125, 0xFFFFFFFF); + } else { + context.drawCenteredString(this.font, this.noPreview, this.centerX - 80, 125, 0xFFFFFFFF); + } } PoseStack matrices = context.pose(); @@ -171,6 +181,7 @@ public void render(GuiGraphics context, int mouseX, int mouseY, float delta) { } } matrices.popPose(); + context.fillGradient(0, 0, this.width, this.height, 0x800F4863, 0x80370038); } public void drawPreviewModel(FakePlayer player, Entity vehicle) { @@ -179,13 +190,13 @@ public void drawPreviewModel(FakePlayer player, Entity vehicle) { matrixStack.translate((float) (this.centerX + this.previewX), (float) this.previewY, 1500); matrixStack.scale(1.0F, 1.0F, -1.0F); - RenderSystem.applyModelViewMatrix(); + PoseStack matrixStack2 = new PoseStack(); matrixStack2.translate(0.0D, 0.0D, 1000.0D); float zoom = this.previewZoom * this.previewZoomMultiplier; matrixStack2.scale(zoom, zoom, zoom); - Quaternionf quaternion = Axis.ZP.rotationDegrees(180.0F); + Quaternionf quaternion = Axis.ZP.rotationDegrees(-180.0F); Quaternionf quaternion2 = Axis.XP.rotationDegrees(this.previewPitch); Quaternionf quaternion3 = Axis.YP.rotationDegrees(-this.previewYaw); quaternion2.mul(quaternion3); @@ -199,17 +210,15 @@ public void drawPreviewModel(FakePlayer player, Entity vehicle) { renderer.setRenderShadow(false); MultiBufferSource.BufferSource immediate = Minecraft.getInstance().renderBuffers().bufferSource(); - //noinspection deprecation Minecraft.getInstance().execute(() -> { - fixEntityRender(vehicle, matrixStack2, () -> renderer.render(vehicle, vehicle.getX(), vehicle.getY(), vehicle.getZ(), 0.0F, 1.0F, matrixStack2, immediate, 0xF000F0)); - renderer.render(player, player.getX(), player.getY(), player.getZ(), 0.0F, 1.0F, matrixStack2, immediate, 0xF000F0); + fixEntityRender(vehicle, matrixStack2, () -> renderer.render(vehicle, vehicle.getX(), vehicle.getY(), vehicle.getZ(), 0.0F, matrixStack2, immediate, 0xF000F0)); + renderer.render(player, player.getX(), player.getY(), player.getZ(), 0.0F, matrixStack2, immediate, 0xF000F0); }); immediate.endBatch(); renderer.setRenderShadow(true); matrixStack.popMatrix(); - RenderSystem.applyModelViewMatrix(); Lighting.setupFor3DItems(); } diff --git a/src/main/java/org/purpurmc/purpur/client/gui/screen/MobsScreen.java b/src/main/java/org/purpurmc/purpur/client/gui/screen/MobsScreen.java index 5d514cf..d6069c9 100644 --- a/src/main/java/org/purpurmc/purpur/client/gui/screen/MobsScreen.java +++ b/src/main/java/org/purpurmc/purpur/client/gui/screen/MobsScreen.java @@ -5,14 +5,13 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.AbstractWidget; -import net.minecraft.client.gui.components.MobsList; -import net.minecraft.client.gui.components.OptionsList; import net.minecraft.client.gui.screens.options.OptionsSubScreen; import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import org.purpurmc.purpur.client.entity.Mob; import org.purpurmc.purpur.client.gui.screen.widget.MobButton; +import org.purpurmc.purpur.client.gui.screen.widget.MobsList; public class MobsScreen extends OptionsSubScreen { public final static MutableComponent MOBS_BTN = Component.translatable("purpurclient.options.mobs"); diff --git a/src/main/java/org/purpurmc/purpur/client/gui/screen/widget/DoubleButton.java b/src/main/java/org/purpurmc/purpur/client/gui/screen/widget/DoubleButton.java index c699505..4f24a8a 100644 --- a/src/main/java/org/purpurmc/purpur/client/gui/screen/widget/DoubleButton.java +++ b/src/main/java/org/purpurmc/purpur/client/gui/screen/widget/DoubleButton.java @@ -7,6 +7,7 @@ import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.components.WidgetSprites; import net.minecraft.client.gui.narration.NarrationElementOutput; +import net.minecraft.client.renderer.RenderType; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Mth; @@ -58,9 +59,9 @@ public void renderWidget(GuiGraphics context, int mouseX, int mouseY, float delt private void drawButton(GuiGraphics context, Component text, int x, boolean i) { RenderSystem.enableDepthTest(); - context.setColor(1.0F, 1.0F, 1.0F, this.alpha); + RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, this.alpha); RenderSystem.enableBlend(); - context.blitSprite(TEXTURES.get(this.active, i), x, this.getY(), this.height, this.height); + context.blitSprite(RenderType::guiTextured, TEXTURES.get(this.active, i), x, this.getY(), this.height, this.height); context.drawCenteredString(Minecraft.getInstance().font, text, x + this.height / 2, this.getY() + (this.height - 8) / 2, (this.active ? 0xFFFFFF : 0xA0A0A0) | Mth.ceil(this.alpha * 255.0f) << 24); } diff --git a/src/main/java/org/purpurmc/purpur/client/gui/screen/widget/MobButton.java b/src/main/java/org/purpurmc/purpur/client/gui/screen/widget/MobButton.java index 6dcba31..6650cd3 100644 --- a/src/main/java/org/purpurmc/purpur/client/gui/screen/widget/MobButton.java +++ b/src/main/java/org/purpurmc/purpur/client/gui/screen/widget/MobButton.java @@ -6,6 +6,7 @@ import net.minecraft.client.gui.components.SpriteIconButton; import net.minecraft.client.gui.components.Tooltip; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.renderer.RenderType; import net.minecraft.resources.ResourceLocation; import org.purpurmc.purpur.client.entity.Mob; import org.purpurmc.purpur.client.gui.screen.MobScreen; @@ -29,6 +30,7 @@ public MobButton(Minecraft client, Screen screen, Mob mob) { public void renderWidget(GuiGraphics context, int mouseX, int mouseY, float delta) { super.renderWidget(context, mouseX, mouseY, delta); context.blit( + RenderType::guiTextured, MOBS_TEXTURE, this.getX(), this.getY(), diff --git a/src/main/java/org/purpurmc/purpur/client/gui/screen/widget/MobsList.java b/src/main/java/org/purpurmc/purpur/client/gui/screen/widget/MobsList.java index 5660b20..53239a7 100644 --- a/src/main/java/org/purpurmc/purpur/client/gui/screen/widget/MobsList.java +++ b/src/main/java/org/purpurmc/purpur/client/gui/screen/widget/MobsList.java @@ -1,20 +1,17 @@ -package net.minecraft.client.gui.components; +package org.purpurmc.purpur.client.gui.screen.widget; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; + import java.util.List; -import java.util.Map; + import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.Minecraft; -import net.minecraft.client.OptionInstance; -import net.minecraft.client.Options; import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.gui.components.events.GuiEventListener; -import net.minecraft.client.gui.narration.NarratableEntry; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.components.OptionsList; import net.minecraft.client.gui.screens.options.OptionsSubScreen; import net.minecraft.client.gui.screens.Screen; -import org.jetbrains.annotations.Nullable; @Environment(EnvType.CLIENT) public class MobsList extends OptionsList { diff --git a/src/main/java/org/purpurmc/purpur/client/mixin/MixinItemEnchantments.java b/src/main/java/org/purpurmc/purpur/client/mixin/MixinItemEnchantments.java index 329987e..f0b7cba 100644 --- a/src/main/java/org/purpurmc/purpur/client/mixin/MixinItemEnchantments.java +++ b/src/main/java/org/purpurmc/purpur/client/mixin/MixinItemEnchantments.java @@ -2,7 +2,6 @@ import com.mojang.serialization.Codec; import net.minecraft.world.item.enchantment.ItemEnchantments; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.Constant; @@ -10,23 +9,23 @@ @Mixin(ItemEnchantments.class) public class MixinItemEnchantments { - @Shadow @Final + @Shadow private static final Codec LEVEL_CODEC = Codec.intRange(0, Integer.MAX_VALUE); @ModifyConstant(method = "", constant = @Constant(intValue = 255)) - private static int injectConstructor(int constant) { + private int injectConstructor(int constant) { return Integer.MAX_VALUE; } @Mixin(ItemEnchantments.Mutable.class) public static class MixinItemEnchantmentsMutable { @ModifyConstant(method = "set", constant = @Constant(intValue = 255)) - private static int injectSet(int constant) { + private int injectSet(int constant) { return Integer.MAX_VALUE; } @ModifyConstant(method = "upgrade", constant = @Constant(intValue = 255)) - private static int injectUpgrade(int constant) { + private int injectUpgrade(int constant) { return Integer.MAX_VALUE; } } diff --git a/src/main/java/org/purpurmc/purpur/client/mixin/MixinLoadingOverlay.java b/src/main/java/org/purpurmc/purpur/client/mixin/MixinLoadingOverlay.java index 42b5466..5613efe 100644 --- a/src/main/java/org/purpurmc/purpur/client/mixin/MixinLoadingOverlay.java +++ b/src/main/java/org/purpurmc/purpur/client/mixin/MixinLoadingOverlay.java @@ -1,6 +1,13 @@ package org.purpurmc.purpur.client.mixin; import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.VertexFormat; +import net.minecraft.client.renderer.RenderStateShard; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.ARGB; +import net.minecraft.util.TriState; import org.purpurmc.purpur.client.PurpurClient; import org.purpurmc.purpur.client.gui.SplashTexture; import org.spongepowered.asm.mixin.Final; @@ -13,17 +20,17 @@ import java.util.Optional; import java.util.function.Consumer; +import java.util.function.Function; + import net.minecraft.Util; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.screens.LoadingOverlay; -import net.minecraft.client.renderer.GameRenderer; import net.minecraft.server.packs.resources.ReloadInstance; -import net.minecraft.util.FastColor; import net.minecraft.util.Mth; @Mixin(LoadingOverlay.class) -public class MixinLoadingOverlay { +public abstract class MixinLoadingOverlay { @Shadow @Final private Minecraft minecraft; @@ -46,6 +53,21 @@ public class MixinLoadingOverlay { @Unique private float delta; + @Unique + private RenderType.CompositeRenderType PURPUR_LOGO = RenderType.create( + "purpur_splash", + DefaultVertexFormat.POSITION_TEX_COLOR, + VertexFormat.Mode.QUADS, + RenderType.SMALL_BUFFER_SIZE, + RenderType.CompositeState.builder() + .setTextureState(new RenderStateShard.TextureStateShard(SplashTexture.SPLASH, TriState.DEFAULT, false)) + .setShaderState(RenderStateShard.POSITION_TEXTURE_COLOR_SHADER) + .setTransparencyState(RenderStateShard.TRANSLUCENT_TRANSPARENCY) + .setDepthTestState(RenderStateShard.NO_DEPTH_TEST) + .setWriteMaskState(RenderStateShard.COLOR_WRITE) + .createCompositeState(false) + ); + @Inject(method = "registerTextures", at = @At("HEAD")) private static void registerTextures(Minecraft client, CallbackInfo ci) { client.getTextureManager().register(SplashTexture.SPLASH, new SplashTexture()); @@ -83,26 +105,22 @@ public void render(GuiGraphics context, int mouseX, int mouseY, float delta, Cal this.delta = 0; opacity = Mth.clamp(g, 0.0f, 1.0f); } else { - this.delta += this.minecraft.getTimer().getRealtimeDeltaTicks(); + this.delta += this.minecraft.getDeltaTracker().getRealtimeDeltaTicks(); opacity = Mth.clampedLerp(-0.5F, 1.0F, this.delta / 30F); } - RenderSystem.setShaderTexture(0, SplashTexture.SPLASH); - RenderSystem.enableBlend(); - RenderSystem.setShader(GameRenderer::getPositionTexShader); - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, opacity); - context.blit(SplashTexture.SPLASH, 0, 0, width, height, 0, 0, 1024, 544, 1024, 1024); // background - context.blit(SplashTexture.SPLASH, (int) ((width - 112) * Mth.lerp(easeOut(opacity), 0.8D, 1.0D)), 10, 112, 112, 0, 546, 256, 256, 1024, 1024); // logo - context.blit(SplashTexture.SPLASH, 40 + (int) ((20) * -Mth.lerp(easeOut(opacity), 0.0D, 1.0D)), height - 70, 180, 17, 256, 548, 367, 33, 1024, 1024); // slogan - context.blit(SplashTexture.SPLASH, (int) ((20) * Mth.lerp(easeOut(opacity), -1.0D, 1.0D)), height - 50, 100, 30, 256, 587, 210, 61, 1024, 1024); // Purpur - context.blit(SplashTexture.SPLASH, width - 105, (int) ((height - 15) * Mth.lerp(easeOut(opacity), 0.75D, 1.0D)), 100, 12, 256, 658, 200, 23, 1024, 1024); // url - RenderSystem.disableBlend(); + Function guiTextured = resourceLocation -> PURPUR_LOGO; + context.blit(guiTextured, SplashTexture.SPLASH, 0, 0, 0, 0, width, height, 1024, 544, 1024, 1024); // background + context.blit(guiTextured, SplashTexture.SPLASH, (int) ((width - 112) * Mth.lerp(easeOut(opacity), 0.8D, 1.0D)), 10, 0, 546, 112, 112, 256, 256, 1024, 1024); // logo + context.blit(guiTextured, SplashTexture.SPLASH, 40 + (int) ((20) * -Mth.lerp(easeOut(opacity), 0.0D, 1.0D)), height - 70, 256, 548, 180, 17, 367, 33, 1024, 1024); // slogan + context.blit(guiTextured, SplashTexture.SPLASH, (int) ((20) * Mth.lerp(easeOut(opacity), -1.0D, 1.0D)), height - 50, 256, 587, 100, 30, 210, 61, 1024, 1024); // Purpur + context.blit(guiTextured, SplashTexture.SPLASH, width - 105, (int) ((height - 15) * Mth.lerp(easeOut(opacity), 0.75D, 1.0D)), 256, 658, 100, 12, 200, 23, 1024, 1024); // url int scale = (int) ((double) this.minecraft.getWindow().getGuiScaledHeight() * 0.625D); float reloadProgress = this.reload.getActualProgress(); this.currentProgress = Mth.clamp(this.currentProgress * 0.95f + reloadProgress * 0.050000012f, 0.0f, 1.0f); if (f < 1.0f) { - this.renderProgressBar(context, width / 2 - 100, scale - 5, width / 2 + 100, scale + 5, 1.0f - Mth.clamp(f, 0.0f, 1.0f)); + this.drawProgressBar(context, width / 2 - 100, scale - 5, width / 2 + 100, scale + 5, 1.0f - Mth.clamp(f, 0.0f, 1.0f)); } if (f >= 2.0f) { this.minecraft.setOverlay(null); @@ -116,22 +134,13 @@ public void render(GuiGraphics context, int mouseX, int mouseY, float delta, Cal } this.fadeOutStart = Util.getMillis(); if (this.minecraft.screen != null) { - this.minecraft.screen.init(this.minecraft, this.minecraft.getWindow().getGuiScaledWidth(), this.minecraft.getWindow().getGuiScaledHeight()); + this.minecraft.screen.init(this.minecraft, context.guiWidth(), context.guiHeight()); } } } - @Unique - private void renderProgressBar(GuiGraphics context, int minX, int minY, int maxX, int maxY, float opacity) { - int i = Mth.ceil((float) (maxX - minX - 2) * this.currentProgress); - int j = Math.round(opacity * 255.0f); - int k = FastColor.ARGB32.color(j, 255, 255, 255); - context.fill(minX + 2, minY + 2, minX + i, maxY - 2, k); - context.fill(minX + 1, minY, maxX - 1, minY + 1, k); - context.fill(minX + 1, maxY, maxX - 1, maxY - 1, k); - context.fill(minX, minY, minX + 1, maxY, k); - context.fill(maxX, minY, maxX - 1, maxY, k); - } + @Shadow + abstract void drawProgressBar(GuiGraphics guiGraphics, int minX, int minY, int maxX, int maxY, float delta); @Unique private float easeIn(float t) { diff --git a/src/main/java/org/purpurmc/purpur/client/mixin/mob/MixinCreaking.java b/src/main/java/org/purpurmc/purpur/client/mixin/mob/MixinCreaking.java new file mode 100644 index 0000000..f186078 --- /dev/null +++ b/src/main/java/org/purpurmc/purpur/client/mixin/mob/MixinCreaking.java @@ -0,0 +1,22 @@ +package org.purpurmc.purpur.client.mixin.mob; + +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.monster.creaking.Creaking; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; +import org.purpurmc.purpur.client.entity.RidableEntity; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(Creaking.class) +public abstract class MixinCreaking extends Mob implements RidableEntity { + public MixinCreaking(EntityType entityType, Level world) { + super(entityType, world); + } + + @Override + public Vec3 getPassengerRidingPosition(Entity passenger) { + return super.getPassengerRidingPosition(passenger).add(getSeats().creaking.x, getSeats().creaking.y, getSeats().creaking.z); + } +} diff --git a/src/main/resources/assets/purpurclient/lang/de_de.json b/src/main/resources/assets/purpurclient/lang/de_de.json index f5065b8..9ba7b58 100644 --- a/src/main/resources/assets/purpurclient/lang/de_de.json +++ b/src/main/resources/assets/purpurclient/lang/de_de.json @@ -21,6 +21,7 @@ "purpurclient.options.on": "%s: \u00a7aAN", "purpurclient.options.off": "%s: \u00a7cAUS", + "purpurclient.options.experiment-disabled": "Bitte aktiviere das Experiment, das für diesen Mob erforderlich ist", "purpurclient.options.no-preview": "Vorschau deaktiviert", "purpurclient.options.not-implemented": "Noch nicht implementiert", diff --git a/src/main/resources/assets/purpurclient/lang/en_us.json b/src/main/resources/assets/purpurclient/lang/en_us.json index 4607f18..bee0679 100644 --- a/src/main/resources/assets/purpurclient/lang/en_us.json +++ b/src/main/resources/assets/purpurclient/lang/en_us.json @@ -21,6 +21,7 @@ "purpurclient.options.on": "%s: \u00a7aON", "purpurclient.options.off": "%s: \u00a7cOFF", + "purpurclient.options.experiment-disabled": "Please enable the experiment required for this mob", "purpurclient.options.no-preview": "Preview disabled", "purpurclient.options.not-implemented": "Not implemented yet", diff --git a/src/main/resources/assets/purpurclient/textures/mobs.png b/src/main/resources/assets/purpurclient/textures/mobs.png index 87e8b7d02cce181a0bd7d9ee5713ab4919d59b86..ae2a32900dcd4d1e2f532001562f3eef7909e8e9 100644 GIT binary patch literal 30462 zcmb5WbzGER*EN0(X@Q8+DIqE)B7;b(fJlglIy6WlCEdeVgp@Q=gCZru&_jcYGz=wO z(um|xL(T6D-{-#H`~E%uye|ggN4e&lv(MgZueJ6BKYVbH<`nBG2!d$tt0+E#ATsbr zGUx;q__XQSw+BAKTpr!K1Lb$JFM=;9tZr-EhM>ZT(+AHe!Ph5WsOY*tkO&Xy7wpT_ zSQG@gN8eYx{n*oJIfXj;!jrN_F+mmOB9sahtVQaKQ*(5)lvRL`Q?ryR-1KR?DXlGS znyrD0PVb+@>BLlLqZH|#3s%p+ROR}3Gb`5;SN$-#4mT0H$*Z~gza&Uc{9hjm2N(5} z@{vn%E;-)r!PAL%7+RyO=UN1+o)1-I%THH1o zz`XdiKV>o0=eTE%s0=XVF^)=3R_7Us2~#!ud90{&+;Y8Eq%kxp$7!W$_I94_ zt=LAvDREKaqy*lK0}8Jei>%(8Yk81=u&4X6aj@uIcfhjkLbvL#Vl|3OjN%a%;mT}q zGKKN?si_Zyd=hy-Kkf290ezc<-m_g)V5@;Ujv>F2De$?>AGz6zo|d|l3j64@v+|M* ziYU%1{EiR%&g`Z0_Cvfs-8ARu(jCO_c7uObNU5BJy&O|v`KdON+8#OKdk#i@+9O1icn320X<8HBna&^<09hr`u)f{s=5x>n=Lad`HQle;a^4sg$%0FLnLq`kC7~A5`sv%E8 z9x_{SB|&KkhZm5JmNwm>DeGWZ7A8Cscv zh3N=++AFf1SB-h(7wDin(^hMd=2?xg7QKPmjeXCYa{Xi|q1r?%ZU32%Y+*(|vn_U} z#q*l0%&ARy`28^? zPD6w4aP{2}m2t*ITcvm9MQROXIEf8$WF)6mtf1DM<$+R$XSGK4(^Qm;9?DVM0Qzx`G#_wEPB>r_QaJlyF$-h!SH+7 zbPvOu)GwzGJX4rh9WeWxXZc7I;hk#8bIopn9y0eaF5A@|#d~rehTz4Gfy#H}dYW^F+x-b9U^2gsz zn;e_UxYCJ2J8gJ*MAMKq`M`SrsXIp0sCcZaKzA0l6uu$u8wdAhY3q@&8w#@i(P=t^ zoWu2)9ef7&nrF&teEq#J7b6AguZ+|5bNZo6*yZst?NB=x18}oL(ckVxrLcPR+{?Pb z(kK1$QDtdnj7VPP@La;pR5Db8jB)o8#C;JZ??tT;u2e)`zg+fMy_um#CI8RROk2FD zfAb=A^U>B{`g7~ztDenqXWQ19 zAS5;&=|v}}Z>ngRLNB8|+jt=|h{y6@Jd+H8+x5Oaf>^~u?= zN!%Ev%IAs#m5YdvXU3Ni3m`8C?SAl(Aw~4W(m*CA%pj1W&RteBqEt;W3|&DTnZhZ- zgkx9#^kh2fJ11Tsft0`t`l$ir~`}=$Woz9g8 z8lG1=o?xr=Dx;3B=c!gyF8n;1pIlr1+iFd3Kz6sNd)9-)*&?g)t=|ZuY`DmoQ-gCf z2}`tD@4HxH-g+%j?)nGi9h)bEv>~kagC9eU1bdjr9OF-f(n3bj^DdECLkHMep)kYw zqEh1TSMm#Q$@~*E8L>-H{m7wRfj2ufO2+|qb1m7fN15|J5})_!F53}N_UOLJ+fx+X z?+0LMk23W5^n4c>c;)dss*OdiH2QF!;R1=K>yR&DHvY53?gstPjD&|{9hM5@lhb4h znKo^)e!p5J49EupxUSMQ7q&keD$<&kaG^k@?|!I#>Oh66qBXcp?Kq~%Qry&&es)x8 zDX#sq1YV%KJu>G;fd?7Chdl>guSp*&e@1+M9@;e`_Bpkj+iUvHQDA(fxMWpo2MmrF%wH&~3I#nQqL;_m;Sz zllJ2$Al;6Xw-BAKyLVrK4cA#%{mc2`y8AP1kSm+o`w9a-)(thNtFd$VMN5jV>$=2Q z)32n0l)ES{rmjGp;oEXr(t4wR@ZOg?va`94+oFky}n!LT3a z?B;;!$xrp&5=&o6sw`(cau!9n2ZQpJ5}O1w@zvXb^K!VXj%QxX)4LYNS-r3PMJxSQ zo_=YNL)8(z_ur2rHiYD0*Os5Q3*TN#cJ*l;c8J67dJB9Wp?}#uSF;r;>6g)Dt;A{z zvT_1E$uoCbd(>x-9vWP$fuVky>G%qwY!|q{70r_WuxuUK-TPxaV~t#WZN^qQY%;W45}{Q(ZlcqSN-l z30=nX=g;qm`(jEKmsrc}6z_b%I)EZd2OV+3Q0LO)>C$k#EpgXWE(h_S@a&Lf9D4M! zMHE(VyK9yDWJqOgyZCQkcEZi<>m=1RijV_7nT;{3i;MX zi;DXTH5Wtc<&^b^HM_5NE5nn7^2a%kl=;=-Tq7*b_;1L>2{VBI{xQ_xxetR4s3OcK zAOQzxEzySbsm=F!^JW~V52g}p z$vkJbgFh@``rbx)gbOny*c#WoQM~W7SKed1>=Hou;;g5ee$p|s!h7>qpn;SbnbRRT zkuPqbK0dEvIM!~dZSY~`^m;njxQ&I^l9EF;_HT#2OOEXNNp~lA+uX4Cr0?LAMg?py zska#FYw4Lvv(8Yw5wnrC(Q#%PuC=^q?~#ARq`|Df(i_k{&d|Hi{_5=zv-?ob%dUXD z)d_*l#6QnR16TJ|BhD>?(o(Mi(c$OK&dL83c!|PEL2HEx@*y~YdEVRmR%{Gh!g!GL zF&CIKp=hMy^r7Ld6m8>0F}=vfTl3u)=Q_@A`W5|oX14PC6|}Qn?kPvH+ZIvxK3jE2 zJk0g-dx+alh{aK@;SD-+3A1a{JFq;w=|)Q9C!ix`t}ljyJu+2_eb(9@@7~04HWl^a zg-<|Da*)jSTF2?L@@`yt`nTFfS2Y*=0|GXeRD17bc6|?iZ9P`))R(1w`aGG=p-+hb z@~lE*$+rd!rDfg+@qjXs4|jwU`?C@yULSf00Bix!fMqAzZq06wr$U(fw*vM)G%2Tl z^-{ylp9`hc_Tw%UekN*^%KarS|D=GWkxrOrO2PqCQS2-TUC5pY zQe?v5UOcINtOcsG(cYGfAugXzVz@7b=VC@v;onW)kc5has@|FBGtH5@e9Pn9lO;+& z&vVHuemaQ=^O$v|><Iw7``b_v&`jPu@{^(bzMi)fZVD|_ecxQDpC zkyymj_LMt!_uMmoxhQv^vR%VB?PMW4Ck{(i?5+D3j$9+ppDFj-=tAD`Q1=%&b0&+* z&6fE*fNEDA@B5pn-BV;Mi<{U+US9ONr8vk>#%n2pg?6?1{60f_H}wJ z!I8pO&&xui$bAm2HvQKYZGrb#%HYlbn4bl05d})xv1;#VOU*KIb;nUx3LRBh@<}Tv z_=c4oYX|yf!c!dk{TxGmxwblTlRpJ~iBkD>C!y-Q1twDpF4bm>kG~k?kd<0Lnh<;C zvb*%0+@4Tijql$O-+S1DcczDSZGDCOB8)FAVqwlcLYhamg9<;JLoQq~y`#Xle)Gd? zh>p6Uy|jfZ1X|mC2j}Z?+&pj7yR&4q_)nIt`j2Cke;vW+NE0W_#c44(+>E~t$>7_? z`JDe9j;2$ZvRg5c@Pmei2BE0!y1UR#&hn#;W!I6g`0nAKi!pNUbnE0V7sG#RvccNJzEUSAOAudcI*J#v2I042;oBh%Du zJI5odELcBy5SUN_C)Bw>%uXBk`FiF!G^!kWi_{bwY)6q)T=&OWh4kfQ_|>AUd*2cA zT_KZVrp2s-3}amH*56ZF=^A5K=pT8rw>`jNXOy6>omGVI`xVu?QLCohT!XRgjj;Tg z5hxFP!$V>{1D5}np75&5p`vnv2CSR{UtSNrLQ35uK7f1RYx zDdF*>=wMAz6|@TfBxOe3)kry=qq9!`xXy^?i@x-rzyHUTiKT6o9{gs=+rRWLO{N)# zGVK(v?*e>P`^xG(gW158z~R;pf8YH5SlGSOxEA4A`G$7gJvn~>%h~P!*ZNHR!%HH0 zp=4%mh~46Dqup?&>G=M39}_LKnEuG-pq}%_GZRgLGoQO$1MDxgaYvhR50wls8l9f=)|4RsQ23DY-n;welUy1c=)p+*~^kb!u%$qg2-iJBm%~b z=?dUzS-4xe1Q)JSRIF}X27Tnragm!oxX0I{91guOML{oOmPfKuo}ImW-A{4jqnOQD zyARo=GX*dc#Zw*3DatGlph*lx{s-B(GNDu3S7#n7=a2B-$F<>L3X_7~a9?4^q@B?R zVU(#!`XoZ>|N0~7m0`S*s-C|4-)kFXtHX8j+NtjPm#)XLlz2 zvmWjp?XMPJF{oQH8{+@oS6rSFkNB>N*?XHTdX+r}u+Eu3 z*sgaXJkXNnV%}ZB#_pvm#>$Pd^+HhJVwXbg{M;vvz1YH~x5N3n(~xl25S0zc!=mtTmF*Zc2zJEq3TpMdw1l zlJ(=Z?-9ej3EctV(EDHQhi4`PSJ^?HKiXM8Y}or1Oy zScC1tMRJ7`L)Txfi#xz^YqXv|-Ft=|%xW-QRk zcx6v4SVwBs($Gr5E+qut#u|BERMWq_ezPu(P7OL?F%#Xty%W2+YT+*M>Vje5=X0ibhKM!2!p`$8)+TfDzCAi}W zx)x^rKMC)>pWXg5G%57u$;^c>+J7H^G2D#F9;h>&R-w1)Maz5*6dcPhHGPm6X?)WJ z#MSxEKFv3vA|uE4)|H(*i|!iSAuX{xAg{wP>FBLegetae@SQ5@wE>K93iFW{dc#Ck zKfw!KGhO4bqJ{q{HmMebANsp}y)%Ksoq>8p%q&FO;y?#FH@x5my?2p{7eje(0fT(n#+7=!?1BlLU-6tRrB6& zuc`gqV(~8T`KLdV*p>)1p_r7Z58BZd@j<8Lwa*GTDim0drIXOXf9x~L^RhfOG=6lJ z9@6m*nbe^`jo0`@H^YB&kSHZ|wQWXs>yk*@CAiPgX83O}nTfb}C&gUE+{L^i;mAnR z9kTuGAzJLL9PeVSga34+Ov5R0kv+>pSflh^vg$m8E15#%WF1wKR4SRm?^Ly5e&u|A zzuV?*N*(7194_U>uZ*&3jZ1-g9u(~F>=_@KywBp3U05c4ZMfhZ6!RY|z!csS1Q|h8 z{mY$C5lrZKGZF$U0OUfodHe}Av{Hx4jc5A)h+cOZr_#wHr+mv>^PgC%0$2fvxJd#L zmpJu^&idNQSaoZDW)V+1CqKgCF)Z9(t1^*q6(Ah1iw__gQ^_ z3hi~V%PB85RoEI9+(&D+?WL%l*GqnoOO>oC*rW3++kg619~OE0s)sl1s*ft{s-ND= ztmTrRh5e)9%~HnC5zZ2BcF*C9g)L)Am4FOYJ|lx6L&3KZTyhGlNBH2NDJP*1R%$;L zFKh3JZ$C7%_b@5(lAqWPgnm`%muc#CeN! zXb7oQvt29Eea1TYmF}0I`_(6cp7c*dO*v2aj>nxKu}|+x&HjepCf|yS;@#0o>u;n zG6OfliYQe)B6TBuzrtW-SiZYG-y)QNTX^(Nx%BFt*NKdoF#(i0?$2szUR?j>9;3@I za{{_|8)|k~5F%yaunrGcnpcOzOxDvPp)uX=(I z8!k9JBdd2DUT?gq6y!&n7UW*;-;ot!-eiINH2v2;t>l+<2S!Z*04;JZK`#k@eu-rd z8;Sny!~g6h!zwhHaFk?sfc>j~d%}OG^d#hi$m%u2+NIBPRjjB=3pp%6lM-HXOkN|i zj1U*t>}NzhmcjO+Nq&k2Ztgi8{WOzZ4tr$W)5#buVcb!U{+M{SOP;v3m-CZK=SPOO zwql~KjaFN4Wc~OM6X~6L5}F=n$a1oO*R#f`WNi|C=P_pY%G|U1w22dR)0T_-`$*;0 z*neItvzXf;7%K5Ds$6tYkm#K-WDuyUYKhZubFoeGw_OfR;8r7LX<< zLJliFbkvs?`s`E6AtzjZVJyJk!R_p4kOBXGErfC6b#I{;(EEb=sWlU|pOkPSSM7c) z^HCK>{uvqMUwic3Zw|j#V>?yJ$+p{kB&!Zh3i{PfaNU;)Cx>u=$EW)-(1^*{*L@|- zAbyvX$veP!L;RD)Io96FYczHSK|QP~N_g*>ETtO3otS?j7YB#u{H$dHDac*oPv zu|RO*%dpPOl=P)X8Lud_H*~*oQuPJog^l9YYBrKU9RgtD6E!4;&&oG?ui=l}QfGYo z2b)3m8k)5F?@h=ys<~CTX>8XY?zdmmJR*v>`%n+`9&w=efba6%)Zf8U+>ruRO#}J< zB#ucEC6w!|n)L8jrWESI&mwKpfVyD;Kz*52d}5N_p3K{9v?YF~e5=Y_v;ODeUK2UC z^3d*ptNn}FTq^=*M!1!RZV5aMA^pl8_nonRw1B+VkeK{%)L<;a!7xS{d*#kax6aS& z%W6H$^Q!0(LJQF*MeWw%TO0GXVjH`WDOWA@yAn$iH@%@c)?cF9&2J$6TSCJHrIGtA zwFo5MRkljeMD??stADtce=X%90rA!2?*v7+{(kJK3oSf0@jx*1mvMk`L*`=66HwZS z&bU`WvX=;fT^Nmg9IH57eb_D=vw3`7;vQn5@v~-sZ(rDC zM8Q`#X502#ahtkGGdI#>`Jhn0eM(;WA6Dyr{$3)eFf=)N$o%jlsi_gi+5>r7$QXI_ zQY*SKY@uF5vfIPh|2Y{-=KLfB?zbkmxOV+^ABV z9w2ZIO7kfUe*-_lSDj~D3IDOS2b&Q0rSbA@g0eH`gYm+$$0n{&&{O(Tu1T~f+=Hzr zr9e_aUxO)>mA_G*9${Ww7L6-8-Q&SWc`1XFR6uZpFbAkl`o0j}F@I1LA8>C+T$Gx`bzB3I1kWdvS&-PfSi= z@5B}8AM)_qx`gXJptEeSEm<82RVhAhHa5RFd>miaKl+tdtTsP>o&t^Q`L?^JDUFx+#I^GxdTMZ70kCK6Yd@}odXT% zgQFT%rrvsQUB1?o>s62KoX53YS8f#j8oKdW_nF=-v$XM8api!pisAE=`@wFwPu=z* z-Kuy_)bqI!h-vHUJ;8lM#@1b1E2>wwe}&nB&L5-z*Qdx+kd;Rg7k=U;5C@yd{mi0< zE2Bop!9^-O0evXSc-333M@Go`?X~Rd_Usq!P~WGgpGde^%;y`KY2HZDPwSDDG3E1F znmC@JQ_)V>ad9Wx7qb{IMj}Jd@Le3%ee++KSjhQwy$>6T#sE$IPZmC6O@n&~A7;u6 z*A*Uv=3CI(p|AW8k|yDq4}gy8Ox@u&+u_+!2g@fLlf_MO~FDYy* z4C31Dox{}8UN+kujeEz+0RhtAbmJh0KNAxnUU!mCA9`^!$9uhZvD!3CYv@(hBm7mX z1ZpDVj%>W8yL@1rbY`vT!_xVCWmoo^+8r#c_2wUylpFImZQ`=LWCgo;tk~J)sRKg1 z5uZ05=5Nl=Q}4~6*pR5tw_hT(I({V;lQYz)!NQb>VO?jB*1crNP-dfZg8s<8#X!f<#WpN#MpZt> zt|j}NI1pH|&`cTX4f)t57;4`RkdBzm`w(69*&=doyj@PVRNaD&N4$Ifkzlgl)h9x} zS843^f~al?tBY5rPWLAdZ6#C9U94Z3weF~AZJd#!C>T7*a%(-XtWR!mF8N8=x5;`7 zMBs#S#Bt!~lB&^bE-*|ahv-cR-hhDd2Fr5?qtYs@Nm}^eoB*u_Qnp!=Hbp6 zVYPw1^8$+l|I~m@S`=g5jKE`P(w^v9eIh7qKZ~nQlB$ym=Z`d9usZ_PnoQPx$^AT; zE7Vm5Td$?8NAoOByDvr?!sO=Vkx$fKWv(3*R#9MkkfwP#u6P8=!}q>?-8 zqnbe4DS39!Y)^t0RBQ4j`y!~864ZQ znze-9V^-IH$*bl6)jeQ?G>Bhs)z;BGtc3yaq6kFdA}jQst(@71U;>V0Z!?tdF>%zUHF{@i&; zM_W2JO@mkD+8l0zs^G`5O5$Zi2@#|imvD8Sln_Q_q-@-Jwmn!GX{H03JI{^-MH=Y8 z2uUEKPSX%V*q4r@w4~d1aepszMiO+ZCqjU|Kn*l^*69P!BMp8akY)gqg81jfK`JNc z%;J3xkN_hCk^hG>@wYzlhB0w}1Me@r*JVJE_aMezqF7^=@3p#Lb>#xT-RM6a9Vr^f zbjDW#cL|3^B93@ivdCWo_NRal;gCcyOAcXd6H=C>Y$7KU|Z*6EO3u5@>god<$U~tzq%5#}krgfVsNJ`1 z3+KqM_N&@n#l>We#gR#wk9^XaiCsQ5!XzjzlBg==!+L%_+v)4Yv!E2}Grr{oJEVA& zWn8n-hjpmv*uF8~x%2KuPf^FSV2cOH*)}ptMk$_L@-ivo^bUPBwhCkUHjFW@SPg|b zwhyhIu-f>&XG#g^Y3%Gv5){>X|Njf^rhd>(WqPZI7T%?cVMT{NdaYJtB`kkB6X9t)B zbIVAEu&`jyzMK6zm`qIF(eN*7F5mY`b%z`B2=CEcOzj_4>}kMVnxAP&%bPCiVGzfp z<(Xk0HBO#M&znvubIs}?v@@GGse5z^n1_oUb|#nd4$O_C{U*FE{5A58Ex-MmUL=sxxw(zR<+aG` z`@1tnD}38oZ)Ar?CNIf}U+WAioN$`8M3m*C96}HfGyM69LgjE~^=N@G7x~!)iOBk zz=XlB2Eepp7~D;aQ0D`^U-rR#vrQk^SZc!oq4nkb6KFEm*M7n0(qA#>k>qOyR#7f; zJWI@r^J6gms~#%ZS}Xl!^YIy(46W)|4X1CmQ#)UmKWI$I%L{~5A0EpWLIhbz=1E#T z9RrkF*g>GO-~2dZwenTv&^=h88G}7s|0bb4?&9cEE~kI}YPCeo{P^|@zcTZ_T^4UX zFLKb+9xL3OdB^=&L)U6eHkEAUmphC#rMbS0i*lT}cUIhVW_8b}?GR;xYLJekPg>;i zI~Fm=+SVPTMO;dB>d!S$b?0X0p%)XKO8J~srW)LfQdmsVlxl$*MF4iAX3p`(P`Bs3 zaDr9j^XZ50$0eCOpf`-MZFC_K(gT+V8gIg$u}CHu3cKp#u{g;_R-GvtRVWiNKd%gx`_D7ekKHKF z6C6q5{fe*>bCECJiB3Hq0oCK6gj`>^AKV>~mv3M;On9y=cZh0kgBH~_GujjLFkQ$k zp9P(3@ULYnByG>5{Zo(0#ssHOqJSinjP#}%F_;V{qg-)qPo@>d*5y8@?OQk3zD z3^utS4kT(NdMZ$Y{Wh*h*tM{yYxwVH>*d>d7!(+#{A@pLAJ_DLAVUVpk4nmW)m9`* z&UIcARbHi`?15WERM{3-%*2%+4ej=Pa<=*MxP&?O%HtTl$5%Dn{`5(Wx&I6uD6g68 zymgx#CFUPze?5qx1~p$9E;&?}WnI(*X1;^aqznz?CC^ikXxO4H-+X0&Fk6C7|ISr` zC2@i05Z$IQ6lsSi63~IgDvpOCQ(mVPLJgB@mRn5Oas3U2hjZy{B z&9{p~2VLm%WJQKsKA5A737crCic0dXLdy?K(gR-4ap@8&(V z{=M%%s6_PloE_0y+ar#a;@%FuWMRs9@$}Cp;NF2B%z{BKHrKfiR+Sr5phu;Nr~k6d8clu2Lhq2CD7Y9_Nu;3;?|1eD`&Fa*J@)7r@um-H=C9T-` zPS;thHDr&AtFXQt;07d`Zb8+xwjaAcGE9e3NDVZ$ZLsl5luyLbQbgd|wkRo z&#mF{p-_JvY^(0)rZq9O+AAh)GeH^Ad-QFqj3|d_r!v8&px;YAN28aTD#xT7c%U_8TB|a4qnr>kk{Z)+hlhnn1ZY7|6DmN`SD|{+)&H(U6vW^t$M0$7|GbGUzLer2c4S zkx58l%~#t$bWb1q8N!vojj9O3SummGXa7t{2LKkc-I4Ni)PneYgfgEfv{&=+BEnrY zygM_mV-)xI@bmlvDa1>j*@jzy#6IWAT3`@7vT?3uY3uEuU%AoEwtuC!m)m$8>qzVa zxQv&*7@(QwMr^(}g9&&UeV(g)(9OUbNR=n)=Ov)8T!nIYWbGKNpo3Cw|LEz)`JMIC zsJSc)bTlt(jEL0ctDcNdf=AAi@V#Hcno77^VU?*qRQv-NmHSLF>G`Ft+N-x_ue68} zot55cm9meXT01tNHC=^*K8i0(yI!Bdhlth=GRylH0f!#NNm$wA_GEBEY&Eq5#HG@B z>Nt{0#?SNJa#3QCy2(R~UVJNhhXsn<1WWo|IL>;zKVEFSqQ|j~`Vye_nSF<@S{VB6 zFHe??1psfTF5`>8WE#9!T^h*!+(9Cp#^tLHdbb1sm$L{2eK9W)NnYpr)l z*arWqR*)UP)-P z8M}q*pN>gCs8PD^w5w3Vv@FCFbETpJ`QcH+A1w?I|6|d6H7TUSrEJ;-1^kaij?>TU zeWmVRfBsOsp}5BsBmCeO?g|Tj%4m8!QTjBDdk1JHE`Dc?v4PszQvaMJ@6NHSf>a(A z2Zd@bu{NNH4lo7Bb@8x9tWyT?dWfi0kvNX2;X%zlsK94P(KJkTaYj|$7~67FTDYk% zTPw^oR`?tP5{Bv^#vuu2#2w6t}D7o&2=+EF{bN*ryyZ z&DxjqfZ@5j1Irgg|4CT*3|s*KkQ}Fsb`R)=M_-H0l0NPvMd|gs3O`t%WIyY`a}~~h znrcFbd{h~ZdMXfd(CBH=Mjb$7&=A16l3E8CFOZG_fvpt6$S*HtsC?@}!bvBEB=^hW zXR{u<9J5IONpS@g=(cWGBz&>U75(az8aZHIp;1e9*~N71RfL-#OLXrRrTv<^5hV&I zcT^v1x4eHpBIF)KS5gu3yRCwPtWHi^RwVf{Y_eN=g{NQbtgLm}k;Ohy@eJgA+Julc zt4mh@dPjs?-ia$PK;wsG_r|w2GarVvvY)-Vj=C}_m4**vy(PXrkQMnlm*A`WT$jK1 zuf9|hJCrCjHxV@=1>J9lpc6p=4Aj70 zxpD23z_Rx}2*w=%O}c2JOG^=&2xAKa*T-!A6;VKYAYn7Ur{qUfl&GQ8jPI?-;)F}= zcN`GMG*|^g{j?6?!QKT|(?UpTs9R-j#94|5=xTP0r|CC$7m>moN9N(ek!B7uo^@h) zNlyRKpdT+)zQ1BG{(FNQ7tL*w^xc%mpi;LtV7uZ#LNS*%x-48C`c^t7cKDU zuw#uLOr|Q$U7|p-_SGQWoBOl1`toFdJdP$5?d4NC%S-`@A^STdCz1j4_u7AhE{#NR0>1sKB}qeZWtmlmn$XbH|@l{L$J zXo4P{mkgN5Hez(D3jMu)P-&vi)1>G^iPjE{zGY1=KTcL(tm$wmjslXxj!DhG3v)TD z@|jgnlr50X*jas`ksFf^f6{hS8BL($PLfTMGbUI$5aTmCANYvRm){M$-k0Gnbrq3+ zCRSKGQ8iBF?tHS#16%!DbjZ2oU%|}K=3QN4l?z%cJDz+N0oFjU-vXMLFX-s#)^C^q zl(XUO*T@D%QPaB4f6xWQmus z_JF4ZPYFQLb*jOME%~KW`29mA-Epeyaj4mmqS~@kqM=T)x%#e2-|!$&Qs;)q^5GD9 zWp_dN*5a#o8H)!|KXbGQQE1684>P59usM%&Zc?KMveek=WyYX9by5j}V-Z0~s!%2YY{Q4A#U6FN%7d&#+Y?K9ZpjWs0@m zz1N zSm!B^0)b1LG(kaf%oFw3eq70-TRJ}WzTF}UQRRoF%mQ#GtBi|~fD$ICvd^R%pSCliv5O!Gzufp@a+1>Y=-|Wj z4s^yE;jxyd6Y&*k2ylnv@1MXZqWffewzYHzNvDm832!167Dz+P3pj`!w zgGpKVnCiinJTk-48|^x!PbO4bBx&y_KGI%+x9LoAcNw3MikP)Ubvxf)oLX%Sd9}*| zjnhodQ|y*O)DZGTfp(a4U)e1(1)1B>iOWv_{V`P!^o7aG$V*%g-1WjEmwhYhMA73= z+CGsM3*GrGvGu~UX_){2g>QkvwK~`&Zi% ze%#9#QF`sD{sORgZQ6L%NW?xh(}um7p>(EVnVf^!qL;57aBHMjN~rV^XQBy*r^EoY-+Ct0;p^{Q0;qJx#)`jwb^b?;0+;3x8mG{uMYj-hUnR zVGHgzcJo&xgbmp10g~guZ0zy7r#pEG7OpS4t$BfY%H7cWijDnH;g49XHf@U{rpWTmC>eOLV|cijtL#&Vw>23qv?J?|zG090_n4q7ErEx#*t5LstxY1dd@yV>M^A{K+^c$+Qr3to+ z4q3r3?c8PC#s|_?crTX@7%W~(8&NtQVrXXgJ3KMco513wIW_j_{?1wMZWPozKxq z0PgX8sKOemf$1|~{Q9WQ0pl*I1|<0cNMD_R>GF;>8i6;R0Ygkc4Fn##F_M-;8g?T6 z0BO#Z8&aGzChj5F>Pl0%&Ynl&Q(uL3%aM>!IBKrvJN1+M3QOJ4L zmI`!XAaLoqoM9tw6$_dJIz}4VC<+GRx+i3zW;hFBE zX`vp0`N{`fK#T4Kw%gXe(t|y&D~}q$?A3 zDIo#4>>=RFDm*wN6SQgI*M9pun6*5-+wK$FYtyi8w-Nqqb|!F=O&TYV=M(?*QxgKw z!sB2zbj68RAQQu&1~E(e3lmy!U3Xi6n-ehL*7>_N?{;WWwR;iDpd)FXn6|z5xHXfh ztgn-&PK;zx;Q&`{aM$Y)C$}Hk7|x+~dafhgUuNTk6k^|F%%6C;vnG!N^vnZ#y5#L4 z_vgS+WXp@wgelDAnSuCQXN5>C{011U$VCc^t*0RlZz(R^0`yyf6LD>PS(&)Mdz8)Z zat=fZAZ+V_tMUxpe}VoGY~rPY4F?IEkhF^>reVknpI8Vo}ST|N~` zGP96;OvpRX8loDE?^VMOBINcihy1;;!vd54`(6Ps+OL3^M27%_7E{aEiTu`){Z0nC znisp*WOuvnx(*Vm%_ro%*WWU!8wyacPZf&R9c{e8%p}fAZ zu`saz#^+1a-tb!kyEEY~B@~wrmKahyfYJE(v=XN+h(rnqj*sG3>z0&1d_H5fC$uu{ zBy|$P%Iuy{ilT*vCl4E+0|l@s?Wv)u&9o&ja3)u~=o<8joC|s$=3Q=i)c5Oj(IO6$ z+Vbh)p+OU%=qONK8{&R(6FR^(4DP)Nfu#mQRfjV-M>A%198uBU4aU~Np~Sujaq0G!1UL7AQ(jsfPQc*gb?yujc)DJ-Ipo_ z7UaJr2&YBu7FyMA{@7_f=IDG#prEdhR7X4kTL8>IAiJ7=x19qhLIoPE@(}d{eDR#o zQIcb=P5v%%J;J{nHaW{={CU%+*Ls3KzH6={$=@}9&vDx4NakpzYBf{VXS*u{7@CQ` zM_%5`zYt!_0(Of*+z?1aJtxmWdbA!I)lSR!uo;=;YBRGMN)RS`|LDA+aE8J+8h^dJ zm*Gi)`rq8dowA)(otxb|6Jp7p;qBPjSJCk>1@*YtgoFj4i^`v+v-t`PsNp%ir`>(f zTVV6Xu`cruhJW+b*kWqpM4a0FGS5St{s&IQE9nt(t!Ak+6?R7mW4BVmJDv%io1RUE zT8B~#(6ztY`Fx4^1!hDDnq^g$8s+4%E#8Bl0xr@123@-Y)4yPvT5Gz9T^guG8TQeq zRX(rI+VT!u{Dv_kne@SM8mu0-cK3=AY_gcke?6AdWyl^|{toCNKnWWJ9{*!rn>#!n zu=K2jAKC_pGy6p6qa{pTW$P-aCVS$J{)>Nph$3HrA&&cX|ERsUAq8kHmNS|SHkpSV z@0qK6GvaRKyS_mvw(4!2ZL=9Ev)|lk6HU@5KP$J(ExXxum#ssQS^zpIwH*+toUIpj z-Os}&alh!07`RY41_rLlp^1rkcm?Sebt+wd+PDO=1F&rzH{77>c<(_0*z+}&`A)tl z#Qq*j)yip!@DUQ@z>W0%YM}y5wW~V$W@^fmU~+^Sswu@?7&IJ>MG8P_!;~af=bP~< zE7puKkN?9)+=8y{O%Nl)ibKmIW)F98TF_dNc?-QrloAUIi|*%rMqxek3vD5&V^@M& zM6d@m8Na*cM-)K&Mq&PHmUaXLPd9eIWOH<_+h2Y2TDPpt0zcPbwaCOEyYb%3eG)g2 z3|zuGq{^pwJRkP}n3gp+Bkn(6QcXQecfTsM!v>;rVd9;TEBjitwOT`Il69f$wt{)p zr#ngBH#S(2TZLi8U~>4_u6I1sv^HV*^eapO^w@rI@nKcUs_uS zv&&JQ_a-|e$J2fU(#o1rDZ&Q4)(P{AIRdF?N{)anwxP@A(*ZlgQv)`GC!uNG^C|KS z7|yF>5BVL^ZHph+2#>z?2rTdf+yT>KTl1o~M<@!Yqt4-^k|HQz2dyFf{X3JTN_+_$ zLVCrP8jQk5)q}C8D7A_$@Qm~X`^9^LBztO5AgA|&H+ttuZ_cOulANXW9?U;@uo~1{8i;2RcOU8skn!`iq9~otGwo4Jj#XP4D~Px#e7B=v=Egp0_k~oL$m~Dh=B(@~JQr zywOXUw&J2$p@Asv$MOM(67i^&VLkft1AMxgA9O!oOmagF z@lBjQc15F)f*Jshm`V5KgT=PIelzd&I^+P^r|Gqo2bwZ3`lpIgaJZp zF-)k=W$e;?CDlNQ8pSLB7hWAQqGYJXJtW-DV^jfZR%A+aPHiC08uN7uW2Jio17lVw#%u+@k^D3I23m*e%2Y(bS_-x-gv*3Q1 z4Dd1^urM`L^HUV;8iec8(<_c|KO`Zw9IXtpV0c~v$lZ|rpIc{CKnf*!h^A?v?yGU& zW^LIn?(E*7TEoceIhsWy8}`{g=edTyVS|~aee`B%W~{v1=G4oHRxltkwAv@ysz$y zFJM(3UdzDQ?p}X7Z03F9DtA8-{|jx)SMm&uX;8ubpSs|Rwhn~DrS7fxuPzbkkzh#n zl1ActG+@g9wqnpvs@(1WzxKW}s;RYGcTp4-0m}xIsv^1-0g+CCu(t>b0@4))R1`u9 zh%{*l=oUdKO78(e5s@Y}p#-Ib9y$`bAR#~kl7tc=UM1G4&d9;KUekl@X%X4Gj(&?KWX<#UB&U9?`OQpV{h(C;iDB%pJ_|V zJvm6H?gIJhV$~mWNJ4t-4UiQ|G{T1L4h49>N{&~nD3qzwZG5Dw=XIiIdOE7j1Geh2 z)S3}ln;}hF=0BwEw5^s_1#LbA$ z{K0Guv}T#winqrBwh8XKl1f0@6A2yQ(7A>#q?cXfv1D9Mz3H?1HF1l_L$_7 z`peDjavzX=`wBF-k|Q+f`-hTdAMg=8I>{zrIa&f7{yNv72?jtt zjMXUazU6Jp-hA2%F${c@>ea#zE%D@RA_!`1pk2h71DAS9g~iwb=N=6a^#$XCY6>|M zMZECA_}0xFMXW%UB5^Zk@V>VSW!FETOHQvq*)VI6NY64q8H=bk)NN&zORd(qFSSV3 z^rmZkRl%qoi~-)KZJow0re?@QshxuP<3TNae^{Ylr$yB<;AIToOV^b{z;Uu>gIC@^ z@FoR4r}OoO>Ys&PK$+LW-EV$53ML$I*D>(&=<#*Wswz7=qD#^NWYn zLT9>-jSoGG&YKh`c*(=`3RKB6-IUY!fm4dlml<*R!D6zx-}nV#{7llMimOJs`z@4# zDk1rCE?1Kl@4|oKi7Sg-gnC_bZ({Z71&qM)*T4K&99abfj* zIWrI`D?b<#iGaskSsqQiD=b}|g|SULZJYQ(mtE_bGrV<$V}{ISK80i^UTVQU_kRn) zql1nEM=T4sX{U`&F2?f*M@FD5(b|HaeM8mdULdqCd)tY}xR_^Oj@G0&jd(cw@*Ej~ z!Ny%${{TuvAfHB!;@Sp$%-b3k(lg`7QaiNXEy%?c?T8i_HiHC@ThypaAiXTGTXE980VK~Ux7wT5*PnDUx@6fl$D zOkbqD31ZBIUT<-zbZ=bQzJetWH1oha7QxvmI6ZF1_@#p+6HpuDY#!AXQUx9we*tQ5 zRlMMIQ1O8g1DzBqe{a^}sNEL=z%AEUxm8>_v`TC;wbvt%C3v9gkDS5YOW&J(@h#vu zpn7lmxXlg{iLqH9M=6m>)6N4XxWReJ=0%~~;KoPVF0ppNdGqg-1r%7(agW51#OjUGVlxO7&3?z!K#%eehHUip%e z@2ZXn#uX4OF^lcJV)>`OYXDaW;(`u!n_!dhL@CH!Sn4nUj-rlqgRtB2uGLYucNgH~ z$1NN)gAsAI{#+s4T;Rk+F++w?Zsou_v&5cbo7Tl3vo|DJF+}!`lm0IGqEj~x>7%^1 z1D(*gvY)tlMXT_&QO5DWGsm8TI3W$3oS<(cuFPTSMz2@o1g4WTm-F+}o&F=1M)n`f zetvv5*6F>08Se2f_aYSh5d3tf{7b^e7u%OpE?cL(O(=Roe4ALfRb+e4g`begY~!2L zA51{&KfyHk?o6ESqNYRQ?gphb$pd1^+G7bBLWu`l&BK+QZrB@$_jkjHyXOPeJ}gH{ z1g2Qm20V23uO7y@8Ds(yDCbooN7I=g?@nDYkieuyL-g8 zaZV8XcvPkmx!L8t!y-jd8(3E-{hA-qI`Rqln2CV)#q2c2)?l7e_1k{7;%|T~5R9OM zr~ycPViGm06kJ~oQ_lShz`7ALy3FkyGX%nl-E-_Mo`}lAoylb>jQ{eC!`Cs^xsjl2fV7 zVuNgsw1am-6^*kM4TaKO3v`W8m-ud-x2B&v%=vit1o!+|9k9nca6y$5*c@9woQG4t+bDRs4XcH8XT zGEq9(^+?i{sy!rsieK4#j~$)QMgWcmA$NMA~0`=4+N@ud-5y6IA~NW4mQ{s%B+ zLsW6kpN%ez-mG+5E}~lQO^!M?ERlejN%5HsE-K^&qv8+%PS)E}bPqpcrvz>p? z9!f6L#7~mD_IM*3YlBM0C5$zp1=E}#?`AdK%i|UN6Rn)@N4qu{c(L|}7ihlb1ZoQv zRA^s}L5~vc0!~5S?kVNxt_x$mH>3>)?}>@H3>BQqQ~(up+xYL<*Qw%K$-V*xdj$?m z!%{KGW4xt9+fd^Y_hDeCTHTrrvCk>;!`<9m6U0fW_)W2JY&}74x9LzBJ0Rv_nkpR^HrY1*N6{&>TdqVWWbV?q45_H>^!77(NUn+-71&P zz*4Sdp=(^>W~T+I6L&Ggb0cNwa`|CpBbZKys9Cpc2pDkl29BPOj;Mn}kInQoeny&; zBV%9Ze?MXBc@8`~mlUkf;&T#fdy?^MER&%Q({DRabNr@a&CYm70?uJWTzhwn%vN}J zFqj>f2(rk8ntllZ27*_vV!gj|f_{v893q1i>PCjn%Wnx7+n723YF&#zeo_MP^q%2{ zYil`qohcciU`ihtvvhrWvc?MQZiRnk>bdu5NUM)q$71_C;90La>CXAr*8+c|i)Ftp=M0#r z8$%U-9{aumFwlDNk&Yo#0J@Vd18(~h#LBZDR6!N!Oe#)F0r3@dUu!IYzA*K(CN6@g z`ENg}2nj=GL-PD7x6UvNhuxeJTT%0G^>RZlZlWS(XH&x54fEQhY|Q6A6c-v#AGFB6 zC#XS7uTbYc|J^K2c49Pvn*&1vjn(${&#v2GarqU+*0Y7~3=faUBl2sI zd#|P{0_JLrgMXd$VG~MA!Zh{^2Y(f<+4gKY zw?_QbhpFC0eaX)T%FHL@Y7V=4Nxhwq>8Q`Q&@si@4>HsLyL>q)#&pJ{fvvmvXpzhB9r7hc7DsR1MZClX>w{LhF8R%1* zpjP%$6xbiFsbjg;PS|30j!~w)K$oozb#z@RGLwp#^~cgug%?L;?6bI%a1Yzcs@;Pk zs@+~h$W75*diO=!*s9(L15mWZtm6h)UkT8)v7_@6Wqv$5+WQ(*kgrQ@-*<1o{dOq0 zoEqb*iXN=wUcx9v1$3|er5s?VGt7LTV@b3s25)7~Cb! zB;c45cP_%M<`>0^mB8MMVC72nPUqsfrwgVt=JKLvX}-wi7^KSChh#jo&qFipjXJZd zpT%BJ?iTqx6!Ypp2;~+dX65E569{v-U^%QNmkT{EqNQ4+FEltB07s~98n9 zQOnP?zzQY&Eod})L=Zx9f={%HU6;4Y3scyxxW{+R#}O~#?O0&9U{0)^jx2g+XGQaC z0UI%eUogG4luZ+{U&C5)_*9vo#vf2q&ZaO1JNLCrW@ipX)V||+0uDacHP*JK$qh*F z%d)ajiy&hpnT>AoI&u z=MBAg=-C~`r5Y@hVUw=g>~}QFC3@EWJ@NbD!wl!9w(}zOmmNwVMI2EKU|Jy74hcwQAm;M&Ja0-V=MY2gyn`IIk*}@$X z8H336bz6zvrjZ6>8vVc-JSqsPQ{I82fG|X_VNk(sgkcU91st;IekLRa~ zWy)98me`)VysiQKp^g(0EcE2au+6)WVOe-E!{6OUUwM(P5w%FiM)h1oc|kU5wSNyU zrJC4YEZ~@_zGps2&D6-G`fvgs+oEVm<;W5V)lL|xNr@Oggomy6g?f|2zv_XV%#Or_ ziM&|j*doTMq~ML@cUN!1B!t{ld_U^i2%o1Bay!fd>&8Bco=m!(W4m)fgmKE^IL8^0 zN{qeVq)+3(K~d*=6&Uy^H0S=)U`qeSLQKVNgZRsorLbbdVCg*(Fl)8YtG0M>yAOp2 zlO(sETeiPd24FNf`^Ngx-P@p0+-hI6n)ke?)AF))sSYE(sK!Qo=}t!F1q*@#qdE>^ zM)D8-NP0|KC4RCH!AM1E7(1JY7hJq!d-0Hx4`OC?(T9U^Z)`e9`h7yR+}MQBsYW!^ z(#`DB67(I&#SC|@hz5`8uAOcWU>ql$4J9B|9j<)<-fw3;%;#JM=nXUN(T&2#ma&gy z$qS~@DUc(AfcE{>!$4dH@Q}0?RM-k`P}BZ~4uAB?v~&}F%Y-l=cO5iV9oc3T)Jq8v zBUFI%yOk3^5h?<-^7JBhg*Z*#qCz{v_Ont3LhqIaW$47&);-OVGdRum6g^f?yGAGavExs2wxv{sD7%D3SLahSY&jo|mr-H}4 zw^E8Gt#{-er2IG-GVX3qg)|cSE}Qa%_)YD^-n9?jf$Y(t&lw#gHk!j+o{(dzSejQz zbMMXZKyE2^)t6>ym??U_4q0>pl3zDF)eg*tNK;;dd{)kr9ewxqXO&>Ho$TeBfabLs z&Q9ekx|6|QRp^Tf7=pogU6j5EGHg=+F2>j7&yJfH5@IDBow6AJ_*(escrDchoRO9@ zK8LtdMlwUl>*OEwAnV^UJb`9ayyw}w+uexuu_g0x-y4u?2aC6>AaZvQK^K({dSS7H z+q!fgxXbDn80uH>p{~xuw(--0l8(18Xd>81WIn%fakLeeHcPgT=`pQFX|LnSKfc_z z@s*xS!$~gBzSbgBBgBJ!NVUG+Z-%e)2Gn}JXdL>ne|VglZ0J~2h={sXgiK3~A6O5v z4x)-T)7&CH{%JE?k9wC_a`SbUh0^%8Q+)A~>&6FfJZr;Nx>db7Ml0vgVKQ zSPk#&BK#R3Tu%yY48wn%20&U~R48)o-LH2Y74vTzf_Otfu)jm+UrJtgo)9ZrQLT|L zg28%ZCRbGYjq5(%6NxX-$q07z2sSljv2WIu(2NHh`>>Ql!_;y$7QpcoIWR51x;E zRT07XL7k;{w<)1{gc;s78_f~;j{izISAh7-`mMc1H=G1ZXHo;cek0w<&dIy}cIW98 z!rb-)Fvn#1qZ8%JwkuR3MGOd^)0erwkSi5s$xbSWktGSO3E+KyLmIk7FD)((=4FuY zhAC^W0o<|vC$&JGi5n5w^LJ`ZeM~?7^OomS zEs-RD@DRFbRHu72u}91}XHQrjohEO;>N37&3nxW<;OlLh))f_3_hs8Mh{#K2qouD9U0IfCWzyG9{*IYa(; z_4KhS5tK<)ng!ZGxzn7oF#ORN#an1+CgpOqQr#z+_(8*%ymfcy5(P(A0$JiBQ!i7a z;B(0ckzWu_Z1=5P<3WwnG}T8<&T|={;lfqn>SE(_D*nNSS>~lKdckobqPOa}Irke% zJyG0Z^1%>!aT@7Z)4|n64N)Na8Sso16NTszj>bTOgVoNfpGx_>KWf-v_&lb~qNJC9(w zJdEU+p%kB{OcAmFBp#K}X&Cp(DFCkwtj%{~rax0Az0k>xBkBC&FvmJyy)Mf-+0#N8 ztUzAXeLc+do+PwJ+Q@#O|0BEBrlh|hvV=-K>MeOkdkHvG&!7tPY=7DtBp|w<-yozW zdU_>hg!sFzcB_Pueg*AMO?g1#l_+ou&bccK90u08?0h-Ecg}6EGdaDHrwO#j{4eRV z>GHQuS((vKH!YVeb43`Sq0EP3^0!B_QA+}Fvl#rE2jHfVh}!aiyC3kj?@J1hHAJhN z9KVAnXE@JC{~>}^Rs_~)K>o8o!XqlyK^NYw**Evxc~-_M@ZoH~sfjNb843J}xg;E~ zrvMN=>t#RvjALdwohM{ePSTJ)q5N%_*NU)u%Gl&HdG#$J&m@Mly)6rrnF@Px0=SOV zO7j)pMu(+^N80$AvA&-@NSj?MpxAaiMis)*8${E1SYUUBqiGxUE7z|^wqbdaVi>{b zt{OH4LcJ= zv*Ly+!Bbe2@l5H(#?$;@l$1nW>+${97NlzMdjNgw2LTTxSinH5>_N9^YsC1@e_A7e zHiWCYeppUJuoX;i{P<8&*!GLFtq@4JkSN$U%$}V*@LmQAYG7(O?uzk)zTN+4QTV5! zlA8&xmRSK@>32qJ&MJ!xRHsv(J74|0jTGUB-#83bn>E}4a!dLdj=tG;GCXEAuT!j9 zuT-Q5XL{6m0XHgxXyq;4CjXZXQTovD+w;buu!&FWUvn7KaPSu{JY^=LmGv=XiMma9gc71v3i`-PJPLDdIbw)9G-DUHEL zW5)u|lnz~C?&U>BKCT$Av2SxEqz-*P5QXVG42{-Pfz7*A!X3uGJW5e67AVg*q8d+{ z$viPH$Q>BUcY1{OZFpz4qum;5v#FM5;|=NhX!-c8SFeatxg1}n1)&|JNKLbqnKP25 zF?pgJM?qKM*h0HHjv@CgV)&Eq2NsT+21@NHiA}`h2|eVseD|If_Lgw zl*0+j=~JyMK$*sE3W$n(XJz(ULZ>-rWZ1cu9SdJ|AktU&y%U-dIn8eboIZd}P2CK| zp<`MAbi&{{_wyC%BVz|DQuSQv=k)X-i-63LVeg>*zp#(!OKG!SYap2rpY3^pr4`uL zMK-!C!9$Z?T~x2|3sF$pl>uU%6jl)xKt*=rxtu|W?rkCyCXcQN&)_lG#VQG zKO6xJYrNRq)$pW_1lIR9BWGB{!ADQu>OCA->}?TItmjjv1O-GZdm9A%;hVr1Hg6hh zZS4jR!f4FHLs^4|uw~1q?3*_~JtCQcW}*M_>TrjggaGY=SqNS+!;-b{i$61Qh%J-& zX)eIL%IZeNq-3y?=l9vr<0nCa z@4FTdP)7VmCU19L183I(^$fw`z&S(fsA-m5*C?lLFdfQvD7vs3l$2*2ql!CBC;Vc` zlJ!}^_ch9=8WC?5JV$nT@+FnM@N4!{kW{-VQv3E0N67y?$A8p@MG@V8Ce7Qgn@cNl zuZ;qtO6YUL@>w~SE~&nywHZ4<^K`_H)@Cd}Yk+Yz&0-W?w4tu+t73p%Dl}tiGSQjk z0k@}*jtk4H;2d{WB>*D7ePAD91}z9`_|Q@y?@2>ix&&;%3RFB~;h>mI*}D!LuQD@( zKkhJX0wTL2mHavgpx=_zKP_pm2pfRs-Zea}f}@-#L|^fm@gAw3jJ8XLP$)=Q6uOkP zT6O(M?r@jT z4O&WhHRer|g}`=NE289V5)9&meUwD5W=C&J>oA2u$Hx<)9W>w=|6$53ovp_U zXP+)uD9!mx>@(jFu{+z<_9#*B;>72Wj7eETM4;2o4_>&nirro4>Sof2{23vnc@wO4 zLKW_JW?l=h0b7)eRS&NExn9EwYi@ZP$oqUbiklM5tl>(Vq${9S0uGMKIYSx`oLQ#= z?Q$WDx9=`!(NqY}2EPf{sH z+=7kmnsD!5?~I;Y*P_13D#Zv4O&r4i*$Y zovhyC`vF`{x0b6*i)uYdZJiwMGW!?4DA$Fr$>CA)IdU4{Up3A$)p9j!YY*_=i?yQ9 zHE>l#ZZGsU(#Jxn^i@|4ZhpYr$vEHHD?f}6Xn^==UenB*wx4@*RP$Q!3QQz3RW}&o zlNH(!m^?SsA~%FrH=z#n^8sLRAn@@iSq~3l#cTm1saW1EZGXqiJar1-4R{>*@-P6M zRDG{qdp2dN_7h5-#f;YWZa)k(pK$H_G3!IdN*7mv{^O;)P)xRBL*Uc2CXR>1&zF>f zdn@Hf;P*!zX_-BIZWU)0vTYx4^209`1`3NPpGj!rJAKn!kH6s2tzhwH50h6+`ZdZW zV`OPG<)aC{+8ubt*;)uby!xkuy?iEalXc~j3zN$>-{tnh0;7*;yOJV#oqL;X?h$pT zC&uL6IUcr6I9Iywh^!-cA6gg~OBFx5S~E_94+q*SVb{dmXyVY zJvf>dAjhqyEBJMCb&bkz%Q#F9#O&nJm(w(^RuSS)n=`LSq*Vs(^;K6s4YDRGL!+vV zD7Tj1RH0J}GkP}I;X_YEATQ1^C<7hbA)$Lavd@+n86ZKp?kCQ3ZsqT^bfAp&qw3K9 z{e(#J>MIuro+J*mk;TbNuZx|hSMn>_Ir$rJai#uE1Xt!~)T-od=)~akDO`Kv(U#nM zalIKTuAQqV3yiXIE6M+g;a2*A3g6o(Eef;$q@KiSi1QHAsW+|MX?)@@Kd4HPx>jSZmKLU1RST;b zDv>@CULCV+aPkeGN*y2uFuj*GLm^s>3UF2TfN^Tg3%g0_ zE@2iqdDH9kX^KftGNb|@o1zHo`0S0|Hoxek&3o1RSkz6jzH@|aVX6PAvN!6I3B=N1 z8yn&!Lo2x#K9AaVp`&iL3{u#;(Y?yxK)vHZg2%v%hkvk_I5m;l!``VITpX{9jod~C z1z)69K^0g6CGH-?mH3Z$8v?$n%Zxf*xsQ1?rgl!lxvkbTVo)z8m+t8RqsHHI97pcH z|EtnPR~YL~e_e@m@xnf~a>WKbKIw&+TjU)VeD<=Xlh3f=$!FUyZp)25UDftjpZ*QX zIHAmN|NlQ@qXw)sBkd=r#*^7dk6Yf7Oov|zX;5TTpK*jpqZz>>G){lRggUz?1lW`9 zmy`FbcioysZ0M8VgHKCHh(HN$c_IpZ>*LNStLc`xIqxsp@=dtre03t6&7K$7oj6x!p7TwCvfgDS-{9T<<(*uHwg)rM0ncA2UlnLAGEtCplJj745j&zetdAH` z=)L!O%DXvM3F|q04C`Vgj}0<&vPsnbafWdJ%k!^!;3~wLhm4oks+IOH`S=EB$kYaD zbq|T~ItM1xSpQS+ahIBEc=luXzC5eZ2?0@}s^2u{@$$^sj1bRPJgHzi zZGHhmI8f$jlKPNXKuCVFU|Z=eq3(mQuYc_6b6;ft0_EpGbu(&}QL*J45~Q_8+TrQ< zZWQvZEMlyGGodu6Y~Wbl=O$3P3@IW zL=>;~9OmSLee3(G6x{u1s+Omwk(hQ%rHPp0QjRk@E`YZCx{GuXK2c8n6a`Tg`(E!4 z;xCu>Z$bARSQ!k+a}Q8_4bE6mZTzWi8OzAc#>00I!aAkK;zq!l%eS(#3!TXBELIA< zqvIYzxM{&wbow67i$d74-Csk8zmFpXseTLxgh!!pC)yz#Ax?tG?3Q2U40zx{Dl37!E%2T(}$c)N#Z!WzX~YK1MReI0XNoT=JVcQ@OD%v zL~m-omMCJp+HVlY4-!e=YGP1*Sf9r)PXgDNL)oj2f(5IiR@suJ&IZ#SnyAJ!+w_fS zn0v|Y_Gu1;)ftT8f;`ucZ65w7>Cw{%_Y+nN2M%bm-;Pt!79P74`f!kR3`}JVxa#T{ zy+5%bO<>))X~-0P;$oDTu~%D6PF2N)KCF5i_-%+wl|jr?HfrvNj6~8?Wr4N&;y_ic zFHZ>z0xB!t`(pis=_UKc1d!9Rb2KCw3T4O>IM)ncJ`NUW8kt;nbswuCFT<1E0>X{b z?75YE=r>c9ABo8tp#FO2-xw25x1MjBlG|uJ&O$$Axl%Mu9&7?i-`STl;p-{7vbpzo;=S5V{ z(_BO5-tgzl7N(SP_U_sODX~D=lbd$&|Bk@FBk=DC{C`KlGe;+s&68vA=BrWk S(r16UTQ`h#Oa6ZN@_zuuLPymA literal 28769 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%0AN$a}&Y0e7~Uqd+dk2FW6X` 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 Kzxu|5Xa5J$-!ujQ diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index f701df9..4c39206 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -30,7 +30,7 @@ "depends": { "fabricloader": ">=0.15.10", "fabric": "*", - "minecraft": ">=1.20.5" + "minecraft": ">=1.21.2" }, "custom": { "modmenu": { diff --git a/src/main/resources/purpurclient.accesswidener b/src/main/resources/purpurclient.accesswidener index c641d93..7cb8efe 100644 --- a/src/main/resources/purpurclient.accesswidener +++ b/src/main/resources/purpurclient.accesswidener @@ -1,3 +1,4 @@ accessWidener v2 named accessible method net/minecraft/client/gui/components/SpriteIconButton (IILnet/minecraft/network/chat/Component;IILnet/minecraft/resources/ResourceLocation;Lnet/minecraft/client/gui/components/Button$OnPress;Lnet/minecraft/client/gui/components/Button$CreateNarration;)V +accessible method net/minecraft/client/gui/components/OptionsList$Entry (Ljava/util/List;Lnet/minecraft/client/gui/screens/Screen;)V diff --git a/src/main/resources/purpurclient.mixins.json b/src/main/resources/purpurclient.mixins.json index d3b3bb5..09e0f4a 100644 --- a/src/main/resources/purpurclient.mixins.json +++ b/src/main/resources/purpurclient.mixins.json @@ -8,8 +8,8 @@ "MixinDebugScreenOverlay", "MixinItemEnchantments", "MixinItemEnchantments$MixinItemEnchantmentsMutable", - "MixinMinecraftClient", "MixinLoadingOverlay", + "MixinMinecraftClient", "MixinWindow", "accessor.AccessAbstractPiglin", "accessor.AccessEntity", @@ -30,6 +30,7 @@ "mob.MixinChicken", "mob.MixinCod", "mob.MixinCow", + "mob.MixinCreaking", "mob.MixinCreeper", "mob.MixinDolphin", "mob.MixinDonkey", From b5d54da2627ce461e0b06e110f95854602fce7d6 Mon Sep 17 00:00:00 2001 From: Onako2 <79749977+Onako2@users.noreply.github.com> Date: Thu, 28 Nov 2024 15:39:00 +0100 Subject: [PATCH 02/12] It runs! yay! --- gradle.properties | 6 ++--- .../purpurmc/purpur/client/PurpurClient.java | 18 +++++++++++---- .../purpur/client/gui/SplashTexture.java | 17 ++++++++------ .../gui/screen/widget/DoubleButton.java | 3 ++- .../client/mixin/MixinLoadingOverlay.java | 22 +++++++++---------- 5 files changed, 39 insertions(+), 27 deletions(-) diff --git a/gradle.properties b/gradle.properties index 9933603..62fcae8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,9 +1,9 @@ org.gradle.jvmargs=-Xmx2G -minecraft_version=1.21.3 -loader_version=0.16.7 +minecraft_version=1.21.4-pre3 +loader_version=0.16.9 #parchment_version=2024.05.01 # TODO: update when available -fabric_version=0.106.1+1.21.3 +fabric_version=0.110.2+1.21.4 modmenu_version=12.0.0-beta.1 configurate_version=4.1.2 diff --git a/src/main/java/org/purpurmc/purpur/client/PurpurClient.java b/src/main/java/org/purpurmc/purpur/client/PurpurClient.java index 6a0fa6f..6619ff9 100644 --- a/src/main/java/org/purpurmc/purpur/client/PurpurClient.java +++ b/src/main/java/org/purpurmc/purpur/client/PurpurClient.java @@ -2,24 +2,28 @@ import com.mojang.blaze3d.platform.IconSet; import com.mojang.blaze3d.platform.Window; -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; -import java.util.List; import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationConnectionEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationNetworking; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.ShareToLanScreen; import net.minecraft.server.packs.VanillaPackResources; import net.minecraft.server.packs.resources.IoSupplier; import org.purpurmc.purpur.client.config.Config; import org.purpurmc.purpur.client.config.ConfigManager; +import org.purpurmc.purpur.client.gui.screen.OptionsScreen; import org.purpurmc.purpur.client.network.ClientboundBeehivePayload; import org.purpurmc.purpur.client.network.ServerboundBeehivePayload; import org.purpurmc.purpur.client.network.ServerboundPurpurClientHelloPayload; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.List; + public class PurpurClient implements ClientModInitializer { private static PurpurClient instance; @@ -54,6 +58,12 @@ public void onInitializeClient() { ClientConfigurationNetworking.send(new ServerboundPurpurClientHelloPayload()); }); + // Temporary so we can open the config screen without ModMenu TODO: Remove once ModMenu is updated + ClientTickEvents.END_CLIENT_TICK.register(client -> { + if (client.screen != null && client.screen.getClass().equals(ShareToLanScreen.class)) { + client.setScreen(new OptionsScreen(client.screen)); + } + }); if (getConfig().useWindowTitle) { Minecraft.getInstance().execute(this::updateTitle); diff --git a/src/main/java/org/purpurmc/purpur/client/gui/SplashTexture.java b/src/main/java/org/purpurmc/purpur/client/gui/SplashTexture.java index c6525b8..f4865bd 100644 --- a/src/main/java/org/purpurmc/purpur/client/gui/SplashTexture.java +++ b/src/main/java/org/purpurmc/purpur/client/gui/SplashTexture.java @@ -1,13 +1,16 @@ package org.purpurmc.purpur.client.gui; -import org.purpurmc.purpur.client.PurpurClient; import com.mojang.blaze3d.platform.NativeImage; -import java.io.IOException; -import java.io.InputStream; import net.minecraft.client.renderer.texture.SimpleTexture; +import net.minecraft.client.renderer.texture.TextureContents; import net.minecraft.client.resources.metadata.texture.TextureMetadataSection; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.ResourceManager; +import org.jetbrains.annotations.NotNull; +import org.purpurmc.purpur.client.PurpurClient; + +import java.io.IOException; +import java.io.InputStream; public class SplashTexture extends SimpleTexture { public static final ResourceLocation SPLASH = ResourceLocation.fromNamespaceAndPath("purpurclient", "textures/splash.png"); @@ -17,12 +20,12 @@ public SplashTexture() { } @Override - protected TextureImage getTextureImage(ResourceManager resourceManager) { - TextureImage data; + public @NotNull TextureContents loadContents(ResourceManager resourceManager) { + TextureContents data; try (InputStream in = PurpurClient.class.getResourceAsStream("/assets/purpurclient/textures/splash.png")) { - data = new TextureImage(new TextureMetadataSection(true, true), NativeImage.read(in)); + data = new TextureContents(NativeImage.read(in), new TextureMetadataSection(true, true)); } catch (IOException e) { - return new TextureImage(e); + throw new RuntimeException("Failed to load splash texture", e); } return data; } diff --git a/src/main/java/org/purpurmc/purpur/client/gui/screen/widget/DoubleButton.java b/src/main/java/org/purpurmc/purpur/client/gui/screen/widget/DoubleButton.java index 4f24a8a..0f643df 100644 --- a/src/main/java/org/purpurmc/purpur/client/gui/screen/widget/DoubleButton.java +++ b/src/main/java/org/purpurmc/purpur/client/gui/screen/widget/DoubleButton.java @@ -11,6 +11,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Mth; +import org.jetbrains.annotations.NotNull; import org.purpurmc.purpur.client.config.options.DoubleOption; public class DoubleButton extends AbstractWidget implements Tickable { @@ -127,7 +128,7 @@ public void updateWidgetNarration(NarrationElementOutput builder) { } @Override - public Component getMessage() { + public @NotNull Component getMessage() { return this.option.text(); } diff --git a/src/main/java/org/purpurmc/purpur/client/mixin/MixinLoadingOverlay.java b/src/main/java/org/purpurmc/purpur/client/mixin/MixinLoadingOverlay.java index 5613efe..378879a 100644 --- a/src/main/java/org/purpurmc/purpur/client/mixin/MixinLoadingOverlay.java +++ b/src/main/java/org/purpurmc/purpur/client/mixin/MixinLoadingOverlay.java @@ -1,12 +1,17 @@ package org.purpurmc.purpur.client.mixin; -import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.VertexFormat; +import net.minecraft.Util; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.LoadingOverlay; import net.minecraft.client.renderer.RenderStateShard; import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.ARGB; +import net.minecraft.server.packs.resources.ReloadInstance; +import net.minecraft.util.Mth; import net.minecraft.util.TriState; import org.purpurmc.purpur.client.PurpurClient; import org.purpurmc.purpur.client.gui.SplashTexture; @@ -22,13 +27,6 @@ import java.util.function.Consumer; import java.util.function.Function; -import net.minecraft.Util; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.gui.screens.LoadingOverlay; -import net.minecraft.server.packs.resources.ReloadInstance; -import net.minecraft.util.Mth; - @Mixin(LoadingOverlay.class) public abstract class MixinLoadingOverlay { @Shadow @@ -68,9 +66,9 @@ public abstract class MixinLoadingOverlay { .createCompositeState(false) ); - @Inject(method = "registerTextures", at = @At("HEAD")) - private static void registerTextures(Minecraft client, CallbackInfo ci) { - client.getTextureManager().register(SplashTexture.SPLASH, new SplashTexture()); + @Inject(method = "registerTextures", at = @At("TAIL")) + private static void registerTextures(TextureManager textureManager, CallbackInfo ci) { + textureManager.registerAndLoad(SplashTexture.SPLASH, new SplashTexture()); } @Inject(method = "render", at = @At("HEAD"), cancellable = true) From 1c0d6e86969c8100ae7580f499e088153a59c1dd Mon Sep 17 00:00:00 2001 From: Onako2 <79749977+Onako2@users.noreply.github.com> Date: Thu, 28 Nov 2024 19:17:36 +0100 Subject: [PATCH 03/12] Update to release candidate 1 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 62fcae8..9dee1d9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ org.gradle.jvmargs=-Xmx2G -minecraft_version=1.21.4-pre3 +minecraft_version=1.21.4-rc1 loader_version=0.16.9 #parchment_version=2024.05.01 # TODO: update when available fabric_version=0.110.2+1.21.4 From 50aa72b2a2ddcca4df34342c913c75daa2d13b81 Mon Sep 17 00:00:00 2001 From: Onako2 <79749977+Onako2@users.noreply.github.com> Date: Thu, 28 Nov 2024 23:58:39 +0100 Subject: [PATCH 04/12] Fix dragging --- build.gradle | 2 +- .../purpur/client/gui/screen/MobScreen.java | 57 ++++++++++--------- 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/build.gradle b/build.gradle index 74aa270..1ece050 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id 'com.github.johnrengelman.shadow' version '8.1.1' - id 'fabric-loom' version '1.7-SNAPSHOT' + id 'fabric-loom' version '1.8-SNAPSHOT' id "com.modrinth.minotaur" version "2.+" } diff --git a/src/main/java/org/purpurmc/purpur/client/gui/screen/MobScreen.java b/src/main/java/org/purpurmc/purpur/client/gui/screen/MobScreen.java index 6b24b02..b8fb15b 100644 --- a/src/main/java/org/purpurmc/purpur/client/gui/screen/MobScreen.java +++ b/src/main/java/org/purpurmc/purpur/client/gui/screen/MobScreen.java @@ -4,33 +4,17 @@ import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Axis; -import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; -import net.minecraft.client.renderer.CoreShaders; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.world.entity.EntitySpawnReason; -import org.joml.Matrix4fStack; -import org.joml.Quaternionf; -import org.purpurmc.purpur.client.PurpurClient; -import org.purpurmc.purpur.client.config.options.DoubleOption; -import org.purpurmc.purpur.client.entity.Mob; -import org.purpurmc.purpur.client.entity.Seat; -import org.purpurmc.purpur.client.fake.FakePlayer; -import org.purpurmc.purpur.client.gui.screen.widget.DoubleButton; -import org.purpurmc.purpur.client.mixin.accessor.AccessAbstractPiglin; -import org.purpurmc.purpur.client.mixin.accessor.AccessEntity; -import org.purpurmc.purpur.client.mixin.accessor.AccessHoglin; -import org.purpurmc.purpur.client.mixin.accessor.AccessMagmaCube; -import org.purpurmc.purpur.client.mixin.accessor.AccessSlime; - -import java.util.ArrayList; - import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.Renderable; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.client.renderer.CoreShaders; +import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.entity.EntityRenderDispatcher; import net.minecraft.network.chat.Component; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.ambient.Bat; import net.minecraft.world.entity.animal.WaterAnimal; import net.minecraft.world.entity.boss.enderdragon.EnderDragon; @@ -44,6 +28,21 @@ import net.minecraft.world.entity.monster.hoglin.Hoglin; import net.minecraft.world.entity.monster.piglin.AbstractPiglin; import net.minecraft.world.entity.monster.warden.Warden; +import org.joml.Matrix4fStack; +import org.joml.Quaternionf; +import org.purpurmc.purpur.client.PurpurClient; +import org.purpurmc.purpur.client.config.options.DoubleOption; +import org.purpurmc.purpur.client.entity.Mob; +import org.purpurmc.purpur.client.entity.Seat; +import org.purpurmc.purpur.client.fake.FakePlayer; +import org.purpurmc.purpur.client.gui.screen.widget.DoubleButton; +import org.purpurmc.purpur.client.mixin.accessor.AccessAbstractPiglin; +import org.purpurmc.purpur.client.mixin.accessor.AccessEntity; +import org.purpurmc.purpur.client.mixin.accessor.AccessHoglin; +import org.purpurmc.purpur.client.mixin.accessor.AccessMagmaCube; +import org.purpurmc.purpur.client.mixin.accessor.AccessSlime; + +import java.util.ArrayList; public class MobScreen extends AbstractScreen { private final Mob mob; @@ -261,14 +260,18 @@ public boolean mouseDragged(double mouseX, double mouseY, int button, double del // mouse was already down from previous screen, ignore return false; } - if (button == 0) { - this.previewYaw -= (float) (mouseX - this.mouseDownX); - this.previewPitch -= (float) (mouseY - this.mouseDownY); - clampYawPitch(); - } else if (button == 1) { - this.previewX += (mouseX - this.mouseDownX); - this.previewY += (mouseY - this.mouseDownY); + if (mouseDownX != 0 && mouseDownY != 0) { + // only move if the mouse wasn't just dragged + if (button == 0) { + this.previewYaw -= (float) (mouseX - this.mouseDownX); + this.previewPitch -= (float) (mouseY - this.mouseDownY); + clampYawPitch(); + } else if (button == 1) { + this.previewX += mouseX - this.mouseDownX; + this.previewY += mouseY - this.mouseDownY; + } } + this.mouseDownX = mouseX; this.mouseDownY = mouseY; return false; From 14876b18a20b5c0a3a1c1429e797db0b8862efac Mon Sep 17 00:00:00 2001 From: Onako2 <79749977+Onako2@users.noreply.github.com> Date: Fri, 29 Nov 2024 19:11:00 +0100 Subject: [PATCH 05/12] Update to release candidate 2 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 9dee1d9..6314451 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ org.gradle.jvmargs=-Xmx2G -minecraft_version=1.21.4-rc1 +minecraft_version=1.21.4-rc2 loader_version=0.16.9 #parchment_version=2024.05.01 # TODO: update when available fabric_version=0.110.2+1.21.4 From 55da225fd0cf6a8d2490e96b19cc742452b042b9 Mon Sep 17 00:00:00 2001 From: Onako2 <79749977+Onako2@users.noreply.github.com> Date: Sat, 30 Nov 2024 00:39:17 +0100 Subject: [PATCH 06/12] Update to release candidate 3 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 6314451..d3d2cc0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ org.gradle.jvmargs=-Xmx2G -minecraft_version=1.21.4-rc2 +minecraft_version=1.21.4-rc3 loader_version=0.16.9 #parchment_version=2024.05.01 # TODO: update when available fabric_version=0.110.2+1.21.4 From 7bfe838caedddad41d7d92819f81811021c8a486 Mon Sep 17 00:00:00 2001 From: granny Date: Wed, 4 Dec 2024 06:47:56 -0800 Subject: [PATCH 07/12] bump to 1.21.4 --- gradle.properties | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index d3d2cc0..724f610 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,10 +1,10 @@ org.gradle.jvmargs=-Xmx2G -minecraft_version=1.21.4-rc3 +minecraft_version=1.21.4 loader_version=0.16.9 #parchment_version=2024.05.01 # TODO: update when available -fabric_version=0.110.2+1.21.4 -modmenu_version=12.0.0-beta.1 +fabric_version=0.110.5+1.21.4 +modmenu_version=13.0.0-beta.1 configurate_version=4.1.2 maven_group=org.purpurmc.purpur.client From 71bb93fbd52ec3afc6c1f3420e654c2e066cf5e3 Mon Sep 17 00:00:00 2001 From: granny Date: Wed, 4 Dec 2024 06:48:07 -0800 Subject: [PATCH 08/12] update gradle wrapper to 8.10.2 --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9355b41..df97d72 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 46b1a3e31ae41f7fa0fb087ab7632921c9ff70ee Mon Sep 17 00:00:00 2001 From: granny Date: Wed, 4 Dec 2024 07:10:04 -0800 Subject: [PATCH 09/12] revert unnecessary import changes --- .../purpurmc/purpur/client/PurpurClient.java | 12 ++---- .../purpur/client/gui/SplashTexture.java | 15 +++++-- .../purpur/client/gui/screen/MobScreen.java | 39 ++++++++++--------- .../client/mixin/MixinLoadingOverlay.java | 14 ++++--- 4 files changed, 43 insertions(+), 37 deletions(-) diff --git a/src/main/java/org/purpurmc/purpur/client/PurpurClient.java b/src/main/java/org/purpurmc/purpur/client/PurpurClient.java index 6619ff9..0847b5b 100644 --- a/src/main/java/org/purpurmc/purpur/client/PurpurClient.java +++ b/src/main/java/org/purpurmc/purpur/client/PurpurClient.java @@ -2,28 +2,24 @@ import com.mojang.blaze3d.platform.IconSet; import com.mojang.blaze3d.platform.Window; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.List; import net.fabricmc.api.ClientModInitializer; -import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationConnectionEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationNetworking; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.screens.ShareToLanScreen; import net.minecraft.server.packs.VanillaPackResources; import net.minecraft.server.packs.resources.IoSupplier; import org.purpurmc.purpur.client.config.Config; import org.purpurmc.purpur.client.config.ConfigManager; -import org.purpurmc.purpur.client.gui.screen.OptionsScreen; import org.purpurmc.purpur.client.network.ClientboundBeehivePayload; import org.purpurmc.purpur.client.network.ServerboundBeehivePayload; import org.purpurmc.purpur.client.network.ServerboundPurpurClientHelloPayload; -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; -import java.util.List; - public class PurpurClient implements ClientModInitializer { private static PurpurClient instance; diff --git a/src/main/java/org/purpurmc/purpur/client/gui/SplashTexture.java b/src/main/java/org/purpurmc/purpur/client/gui/SplashTexture.java index f4865bd..9500b7a 100644 --- a/src/main/java/org/purpurmc/purpur/client/gui/SplashTexture.java +++ b/src/main/java/org/purpurmc/purpur/client/gui/SplashTexture.java @@ -1,16 +1,23 @@ package org.purpurmc.purpur.client.gui; +import java.io.FileNotFoundException; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.LoadingOverlay; +import net.minecraft.client.renderer.texture.TextureContents; +import net.minecraft.server.packs.PackType; +import net.minecraft.server.packs.VanillaPackResources; +import net.minecraft.server.packs.resources.IoSupplier; +import net.minecraft.server.packs.resources.ResourceProvider; +import org.purpurmc.purpur.client.PurpurClient; import com.mojang.blaze3d.platform.NativeImage; +import java.io.IOException; +import java.io.InputStream; import net.minecraft.client.renderer.texture.SimpleTexture; -import net.minecraft.client.renderer.texture.TextureContents; import net.minecraft.client.resources.metadata.texture.TextureMetadataSection; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.ResourceManager; import org.jetbrains.annotations.NotNull; -import org.purpurmc.purpur.client.PurpurClient; -import java.io.IOException; -import java.io.InputStream; public class SplashTexture extends SimpleTexture { public static final ResourceLocation SPLASH = ResourceLocation.fromNamespaceAndPath("purpurclient", "textures/splash.png"); diff --git a/src/main/java/org/purpurmc/purpur/client/gui/screen/MobScreen.java b/src/main/java/org/purpurmc/purpur/client/gui/screen/MobScreen.java index b8fb15b..a656501 100644 --- a/src/main/java/org/purpurmc/purpur/client/gui/screen/MobScreen.java +++ b/src/main/java/org/purpurmc/purpur/client/gui/screen/MobScreen.java @@ -4,17 +4,33 @@ import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Axis; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.client.renderer.CoreShaders; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.world.entity.EntitySpawnReason; +import org.joml.Matrix4fStack; +import org.joml.Quaternionf; +import org.purpurmc.purpur.client.PurpurClient; +import org.purpurmc.purpur.client.config.options.DoubleOption; +import org.purpurmc.purpur.client.entity.Mob; +import org.purpurmc.purpur.client.entity.Seat; +import org.purpurmc.purpur.client.fake.FakePlayer; +import org.purpurmc.purpur.client.gui.screen.widget.DoubleButton; +import org.purpurmc.purpur.client.mixin.accessor.AccessAbstractPiglin; +import org.purpurmc.purpur.client.mixin.accessor.AccessEntity; +import org.purpurmc.purpur.client.mixin.accessor.AccessHoglin; +import org.purpurmc.purpur.client.mixin.accessor.AccessMagmaCube; +import org.purpurmc.purpur.client.mixin.accessor.AccessSlime; + +import java.util.ArrayList; + import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.Renderable; import net.minecraft.client.gui.screens.Screen; -import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; -import net.minecraft.client.renderer.CoreShaders; -import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.entity.EntityRenderDispatcher; import net.minecraft.network.chat.Component; import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.ambient.Bat; import net.minecraft.world.entity.animal.WaterAnimal; import net.minecraft.world.entity.boss.enderdragon.EnderDragon; @@ -28,21 +44,6 @@ import net.minecraft.world.entity.monster.hoglin.Hoglin; import net.minecraft.world.entity.monster.piglin.AbstractPiglin; import net.minecraft.world.entity.monster.warden.Warden; -import org.joml.Matrix4fStack; -import org.joml.Quaternionf; -import org.purpurmc.purpur.client.PurpurClient; -import org.purpurmc.purpur.client.config.options.DoubleOption; -import org.purpurmc.purpur.client.entity.Mob; -import org.purpurmc.purpur.client.entity.Seat; -import org.purpurmc.purpur.client.fake.FakePlayer; -import org.purpurmc.purpur.client.gui.screen.widget.DoubleButton; -import org.purpurmc.purpur.client.mixin.accessor.AccessAbstractPiglin; -import org.purpurmc.purpur.client.mixin.accessor.AccessEntity; -import org.purpurmc.purpur.client.mixin.accessor.AccessHoglin; -import org.purpurmc.purpur.client.mixin.accessor.AccessMagmaCube; -import org.purpurmc.purpur.client.mixin.accessor.AccessSlime; - -import java.util.ArrayList; public class MobScreen extends AbstractScreen { private final Mob mob; diff --git a/src/main/java/org/purpurmc/purpur/client/mixin/MixinLoadingOverlay.java b/src/main/java/org/purpurmc/purpur/client/mixin/MixinLoadingOverlay.java index 378879a..ceb247f 100644 --- a/src/main/java/org/purpurmc/purpur/client/mixin/MixinLoadingOverlay.java +++ b/src/main/java/org/purpurmc/purpur/client/mixin/MixinLoadingOverlay.java @@ -2,16 +2,11 @@ import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.VertexFormat; -import net.minecraft.Util; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.gui.screens.LoadingOverlay; import net.minecraft.client.renderer.RenderStateShard; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.packs.resources.ReloadInstance; -import net.minecraft.util.Mth; + import net.minecraft.util.TriState; import org.purpurmc.purpur.client.PurpurClient; import org.purpurmc.purpur.client.gui.SplashTexture; @@ -27,6 +22,13 @@ import java.util.function.Consumer; import java.util.function.Function; +import net.minecraft.Util; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.LoadingOverlay; +import net.minecraft.server.packs.resources.ReloadInstance; +import net.minecraft.util.Mth; + @Mixin(LoadingOverlay.class) public abstract class MixinLoadingOverlay { @Shadow From f042b854ca695b9aa4197d5757e166665b84275d Mon Sep 17 00:00:00 2001 From: granny Date: Wed, 4 Dec 2024 07:13:07 -0800 Subject: [PATCH 10/12] remove hacky code --- src/main/java/org/purpurmc/purpur/client/PurpurClient.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/main/java/org/purpurmc/purpur/client/PurpurClient.java b/src/main/java/org/purpurmc/purpur/client/PurpurClient.java index 0847b5b..aa2fd40 100644 --- a/src/main/java/org/purpurmc/purpur/client/PurpurClient.java +++ b/src/main/java/org/purpurmc/purpur/client/PurpurClient.java @@ -54,13 +54,6 @@ public void onInitializeClient() { ClientConfigurationNetworking.send(new ServerboundPurpurClientHelloPayload()); }); - // Temporary so we can open the config screen without ModMenu TODO: Remove once ModMenu is updated - ClientTickEvents.END_CLIENT_TICK.register(client -> { - if (client.screen != null && client.screen.getClass().equals(ShareToLanScreen.class)) { - client.setScreen(new OptionsScreen(client.screen)); - } - }); - if (getConfig().useWindowTitle) { Minecraft.getInstance().execute(this::updateTitle); } From de71d927f704ff4cb428f8a9262fbe7c80dab145 Mon Sep 17 00:00:00 2001 From: granny Date: Wed, 4 Dec 2024 07:13:28 -0800 Subject: [PATCH 11/12] minor adjustments --- .../org/purpurmc/purpur/client/gui/SplashTexture.java | 10 +++------- .../purpur/client/mixin/MixinLoadingOverlay.java | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/purpurmc/purpur/client/gui/SplashTexture.java b/src/main/java/org/purpurmc/purpur/client/gui/SplashTexture.java index 9500b7a..3272e21 100644 --- a/src/main/java/org/purpurmc/purpur/client/gui/SplashTexture.java +++ b/src/main/java/org/purpurmc/purpur/client/gui/SplashTexture.java @@ -27,13 +27,9 @@ public SplashTexture() { } @Override - public @NotNull TextureContents loadContents(ResourceManager resourceManager) { - TextureContents data; - try (InputStream in = PurpurClient.class.getResourceAsStream("/assets/purpurclient/textures/splash.png")) { - data = new TextureContents(NativeImage.read(in), new TextureMetadataSection(true, true)); - } catch (IOException e) { - throw new RuntimeException("Failed to load splash texture", e); + public TextureContents loadContents(ResourceManager resourceManager) throws IOException { + try (InputStream inputStream = PurpurClient.class.getResourceAsStream("/assets/purpurclient/textures/splash.png")) { + return new TextureContents(NativeImage.read(inputStream), new TextureMetadataSection(true, true)); } - return data; } } diff --git a/src/main/java/org/purpurmc/purpur/client/mixin/MixinLoadingOverlay.java b/src/main/java/org/purpurmc/purpur/client/mixin/MixinLoadingOverlay.java index ceb247f..8398f83 100644 --- a/src/main/java/org/purpurmc/purpur/client/mixin/MixinLoadingOverlay.java +++ b/src/main/java/org/purpurmc/purpur/client/mixin/MixinLoadingOverlay.java @@ -68,7 +68,7 @@ public abstract class MixinLoadingOverlay { .createCompositeState(false) ); - @Inject(method = "registerTextures", at = @At("TAIL")) + @Inject(method = "registerTextures", at = @At("HEAD")) private static void registerTextures(TextureManager textureManager, CallbackInfo ci) { textureManager.registerAndLoad(SplashTexture.SPLASH, new SplashTexture()); } From 6a1ae2cd4754ac28ec803f86c79fcf9448197069 Mon Sep 17 00:00:00 2001 From: granny Date: Wed, 4 Dec 2024 07:14:32 -0800 Subject: [PATCH 12/12] more unnecessary imports --- .../org/purpurmc/purpur/client/gui/SplashTexture.java | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/main/java/org/purpurmc/purpur/client/gui/SplashTexture.java b/src/main/java/org/purpurmc/purpur/client/gui/SplashTexture.java index 3272e21..74f1e05 100644 --- a/src/main/java/org/purpurmc/purpur/client/gui/SplashTexture.java +++ b/src/main/java/org/purpurmc/purpur/client/gui/SplashTexture.java @@ -1,23 +1,14 @@ package org.purpurmc.purpur.client.gui; -import java.io.FileNotFoundException; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.screens.LoadingOverlay; -import net.minecraft.client.renderer.texture.TextureContents; -import net.minecraft.server.packs.PackType; -import net.minecraft.server.packs.VanillaPackResources; -import net.minecraft.server.packs.resources.IoSupplier; -import net.minecraft.server.packs.resources.ResourceProvider; import org.purpurmc.purpur.client.PurpurClient; import com.mojang.blaze3d.platform.NativeImage; import java.io.IOException; import java.io.InputStream; import net.minecraft.client.renderer.texture.SimpleTexture; +import net.minecraft.client.renderer.texture.TextureContents; import net.minecraft.client.resources.metadata.texture.TextureMetadataSection; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.ResourceManager; -import org.jetbrains.annotations.NotNull; - public class SplashTexture extends SimpleTexture { public static final ResourceLocation SPLASH = ResourceLocation.fromNamespaceAndPath("purpurclient", "textures/splash.png");