Compare commits

..
Author SHA1 Message Date
selimaj-dev 2c64eed329 new version 2025-07-07 01:01:08 +02:00
selimaj-dev 66d7d7eab9 Disabled online emotes 2025-07-07 00:54:56 +02:00
selimaj-dev 21b1dcc997 saturn client branding 2025-07-05 05:20:34 +02:00
selimaj-dev c2470378e1 saturn client branding 2025-07-05 05:20:27 +02:00
selimaj-dev f57e773a44 fixed hat still visible when invisible 2025-07-05 04:02:30 +02:00
selimaj-dev 6c0575a03f Notifications 2025-06-23 17:03:18 -05:00
selimaj-dev 9f93ea923e Cosmetic preview slight improvement 2025-06-23 17:16:28 +02:00
selimaj-dev ecf5987434 sidebar gap 2025-06-23 17:04:03 +02:00
selimaj-dev 89a5b2437e fully functional store 2025-06-23 16:49:09 +02:00
selimaj-dev c8d28133a0 Crimson Mark 2025-06-23 07:12:54 +02:00
selimaj-dev 0980e3a5d4 semi working Store 2025-06-22 16:56:18 -05:00
selimaj-dev 420ba82b44 more emotes 2025-06-22 11:24:38 -05:00
selimaj-dev 2f3c125bba Keystrokes mouse and space options 2025-06-19 15:13:29 -05:00
selimaj-dev 9e64b2332e added keystrokes 2025-06-18 13:47:50 -05:00
selimaj-dev 089cf4778c freelook 2025-06-18 08:51:14 -05:00
selimaj-dev b9984c35a2 coord display methods 2025-06-18 05:10:15 -05:00
selimaj-dev b035381ba7 removed unnecessary resources 2025-06-18 04:30:17 -05:00
selimaj-dev 87b326ce9f coords 2025-06-18 04:26:39 -05:00
selimaj-dev 786f9cf6f7 small change 2025-06-18 00:29:57 +02:00
selimaj-dev 464d0b502b NONE key selection when backspace 2025-06-17 13:13:56 -05:00
selimaj-dev e38f4480a3 config save bug fix 2025-06-17 11:54:50 -05:00
selimaj-dev d178f1504b config for keybidnings 2025-06-17 11:42:19 -05:00
selimaj-dev 5b77ea7363 Small property refactor 2025-06-17 10:19:49 -05:00
selimaj-dev 78097b1d8f prep for module mixins 2025-06-17 09:54:03 -05:00
selimaj-dev 51040900cf potion display 2025-06-16 16:12:40 -05:00
selimaj-dev f06e2a0aaa updated icon 2025-06-16 16:06:19 -05:00
selimaj-dev 70fcd64f25 potion display (needs dummy and proper dimensions) 2025-06-16 11:49:56 -05:00
selimaj-dev b2c7e9f03e default transparent hud mod background 2025-06-16 07:31:56 -05:00
selimaj-dev 08155bd49a fixed armor display 2025-06-16 07:31:14 -05:00
selimaj-dev 67a5b219f5 better font management 2025-06-16 07:06:15 -05:00
selimaj-dev 6c608409e0 Added emote cancel (shift) 2025-06-15 09:53:50 -05:00
selimaj-dev 4c72f8e39f online emotes (todo: make the emotes cancel across the players) 2025-06-15 01:32:28 +02:00
selimaj-dev 3d9d01a28f fps display 2025-06-14 14:09:27 -05:00
selimaj-dev 7e39532d1d almost fully working emotes 2025-06-14 13:52:29 -05:00
selimaj-dev 76c20d8733 emotes (real) 2025-06-14 06:14:25 +02:00
selimaj-dev a1c68609d9 working emote test 2025-06-14 04:21:34 +02:00
selimaj-dev d49afbb981 updated mercedes flow 2025-05-18 23:03:16 +02:00
selimaj-dev fd0bf75750 beta2 2025-05-17 15:31:22 +02:00
102 changed files with 10090 additions and 523 deletions
+9
View File
@@ -19,6 +19,10 @@ dependencies {
modApi "dev.felnull:special-model-loader:1.4.0+pre.1" modApi "dev.felnull:special-model-loader:1.4.0+pre.1"
include "dev.felnull:special-model-loader:1.4.0+pre.1" include "dev.felnull:special-model-loader:1.4.0+pre.1"
include modImplementation("dev.kosmx.player-anim:player-animation-lib-fabric:${project.player_anim}")
//You might want bendy-lib. playerAnimator will wrap it.
// include modRuntimeOnly("io.github.kosmx.bendy-lib:bendy-lib-fabric:${project.bendylib_version}")
} }
@@ -28,6 +32,11 @@ repositories {
name = "FelNull Maven" name = "FelNull Maven"
url = "https://maven.felnull.dev" url = "https://maven.felnull.dev"
} }
maven {
name "KosmX's maven"
url 'https://maven.kosmx.dev/'
}
} }
processResources { processResources {
+8 -12
View File
@@ -1,17 +1,13 @@
# Done to increase the memory available to gradle. # Done to increase the memory available to gradle.
org.gradle.jvmargs=-Xmx1G org.gradle.jvmargs=-Xmx1G
# Fabric Properties minecraft_version=1.21.4
# check these on https://modmuss50.me/fabric.html yarn_mappings=1.21.4+build.7
minecraft_version=1.21.4 loader_version=0.16.10
yarn_mappings=1.21.4+build.7 fabric_version=0.114.0+1.21.4
loader_version=0.16.10
# Mod Properties mod_version = 0.0.3-beta0
mod_version = 0.0.1-alpha4 maven_group = org.saturnclient
maven_group = me.iipho3nix archives_base_name = saturnclient
archives_base_name = saturnclient
# Dependencies player_anim = 2.0.3+1.21.4
# check this on https://modmuss50.me/fabric.html
fabric_version=0.114.0+1.21.4
@@ -6,27 +6,32 @@ import org.saturnclient.saturnclient.config.NamedProperty;
import org.saturnclient.saturnclient.config.Property; import org.saturnclient.saturnclient.config.Property;
public class ModDimensions { public class ModDimensions {
public Property<Integer> x = new Property<>(0); public Property<Integer> x = Property.integer(0);
public Property<Integer> y = new Property<>(0); public Property<Integer> y = Property.integer(0);
public Property<Float> scale = new Property<>(1.0f); public Property<Float> scale = Property.floatProp(1.0f);
public Property<Integer> bgColor = new Property<>(0xFF000000, Property.PropertyType.HEX); public Property<Integer> bgColor = Property.color(0x00000000);
public Property<Integer> fgColor = new Property<>(0xFFffffff, Property.PropertyType.HEX); public Property<Integer> fgColor = Property.color(0xFFffffff);
public Property<Integer> radius = new Property<>(0); public Property<Integer> radius = Property.integer(0);
public Property<Integer> font = Property.font(0);
public boolean renderBackground = true;
public int width = 0; public int width = 0;
public int height = 0; public int height = 0;
public NamedProperty<Map<String, Property<?>>> prop() { public NamedProperty<Map<String, Property<?>>> prop() {
return new Property<Map<String, Property<?>>>(Map.of( return Property.namespace(Map.of(
"X", x, "X", x,
"Y", y, "Y", y,
"Scale", scale, "Scale", scale,
"Background Color", bgColor, "Background Color", bgColor,
"Foreground Color", fgColor, "Foreground Color", fgColor,
"Corner Radius", radius "Corner Radius", radius,
"Font", font
)).named("In-Game Display"); )).named("In-Game Display");
} }
public ModDimensions() {}
public ModDimensions(int width, int height) { public ModDimensions(int width, int height) {
this.width = width; this.width = width;
this.height = height; this.height = height;
@@ -3,6 +3,7 @@ package org.saturnclient.modules;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback;
import net.minecraft.client.font.TextRenderer; import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.render.RenderLayer;
import org.saturnclient.modules.mods.*; import org.saturnclient.modules.mods.*;
import org.saturnclient.saturnclient.SaturnClient; import org.saturnclient.saturnclient.SaturnClient;
@@ -14,7 +15,12 @@ public class ModManager {
public static Module[] MODS = { public static Module[] MODS = {
new Crosshair(), new Crosshair(),
new AutoSprint(), new AutoSprint(),
new ArmorDisplay() new ArmorDisplay(),
new Fps(),
new PotionDisplay(),
new Coordinates(),
new Freelook(),
new Keystrokes()
}; };
public static void init() { public static void init() {
@@ -44,7 +50,11 @@ public class ModManager {
renderScope.matrices.scale(dim.scale.value, dim.scale.value, 1.0f); renderScope.matrices.scale(dim.scale.value, dim.scale.value, 1.0f);
renderScope.drawRoundedRectangle(0, 0, dim.width, dim.height, dim.radius.value, dim.bgColor.value); if (dim.renderBackground) {
renderScope.drawRoundedRectangle(0, 0, dim.width, dim.height, dim.radius.value, dim.bgColor.value);
}
renderScope.setRenderLayer(RenderLayer::getGuiTextured);
((HudMod) m).renderHud(renderScope); ((HudMod) m).renderHud(renderScope);
@@ -0,0 +1,6 @@
# Credits
### Freelook
- https://github.com/Celibistrial/freelook
- https://modrinth.com/mod/freelook
**The other mods are coded by us, if you have a concern or we missed something feel free to submit a issue with the credits tag**
@@ -13,11 +13,12 @@ import net.minecraft.item.ItemStack;
import net.minecraft.item.Items; import net.minecraft.item.Items;
public class ArmorDisplay extends Module implements HudMod { public class ArmorDisplay extends Module implements HudMod {
private static Property<Boolean> enabled = new Property<>(true); private static Property<Boolean> enabled = Property.bool(false);
private static ModDimensions dimensions = new ModDimensions(40, 60); private static ModDimensions dimensions = new ModDimensions(40, 60);
public ArmorDisplay() { public ArmorDisplay() {
super(new ModuleDetails("Armor Display", "armor").description("Displays armor durability") super(new ModuleDetails("Armor Display", "armor")
.description("Displays armor durability")
.version("v0.1.0") .version("v0.1.0")
.tags("Utility"), .tags("Utility"),
enabled.named("Enabled"), enabled.named("Enabled"),
@@ -51,8 +52,10 @@ public class ArmorDisplay extends Module implements HudMod {
} }
} }
public void renderHealth(RenderScope scope, int i, int max, int current) { public void renderHealth(RenderScope scope, int i, int max_damage, int damage) {
scope.drawText(0.5f, String.valueOf(((double) current / max) * 100) + "%", 17, (15 * i) + 3, false, dimensions.fgColor.value); if (max_damage > 0 ) {
scope.drawText(0.5f, "" + (max_damage - damage), 17, (15 * i) + 3, dimensions.font.value, dimensions.fgColor.value);
}
} }
@Override @Override
@@ -8,7 +8,7 @@ import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.config.Property; import org.saturnclient.saturnclient.config.Property;
public class AutoSprint extends Module { public class AutoSprint extends Module {
private static Property<Boolean> enabled = new Property<>(true); private static Property<Boolean> enabled = Property.bool(false);
public AutoSprint() { public AutoSprint() {
super( super(
@@ -0,0 +1,75 @@
package org.saturnclient.modules.mods;
import org.saturnclient.modules.HudMod;
import org.saturnclient.modules.ModDimensions;
import org.saturnclient.modules.Module;
import org.saturnclient.modules.ModuleDetails;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.ui2.RenderScope;
import org.saturnclient.ui2.resources.Fonts;
import net.minecraft.util.math.Vec3d;
public class Coordinates extends Module implements HudMod {
private static Property<Boolean> enabled = Property.bool(false);
private static Property<Integer> displayMethod = Property.select(0, "Flat", "Flat annotated", "Newline", "Newline annotated");
private static ModDimensions dimensions = new ModDimensions(40, 18);
public Coordinates() {
super(new ModuleDetails("Coordinates", "coords")
.description("Displays your current coordinates")
.version("v0.1.0")
.tags("Utility"),
enabled.named("Enabled"),
displayMethod.named("Display Method"),
dimensions.prop()
);
}
@Override
public void renderDummy(RenderScope scope) {
renderCoords(532, 69, 253, scope);
}
@Override
public void renderHud(RenderScope scope) {
Vec3d pos = SaturnClient.client.player.getPos();
renderCoords((int) pos.x, (int) pos.y, (int) pos.z, scope);
}
public void renderCoords(int x, int y, int z, RenderScope scope) {
String f = "%d %d %d"; // Flat
switch (displayMethod.value) {
case 1: // Flat annotated
f = "X: %d Y: %d Z: %d";
break;
case 2: // Newline
f = "%d\n%d\n%d";
break;
case 3: // Newline annotated
f = "X: %d\nY: %d\nZ: %d";
break;
}
String text = String.format(f, x, y, z);
scope.drawText(text,
0, 0, dimensions.font.value, dimensions.fgColor.value);
dimensions.width = Fonts.getWidth(text, dimensions.font.value);
dimensions.height = 18 * text.split("\n").length;
}
@Override
public boolean isEnabled() {
return enabled.value;
}
@Override
public ModDimensions getDimensions() {
return dimensions;
}
@Override
public void setEnabled(boolean e) {
enabled.value = e;
}
}
@@ -10,8 +10,7 @@ import org.saturnclient.ui2.resources.Textures;
import net.minecraft.client.render.RenderLayer; import net.minecraft.client.render.RenderLayer;
public class Crosshair extends Module { public class Crosshair extends Module {
public static Property<Boolean> enabled = new Property<>(false); public static Property<Boolean> enabled = Property.bool(false);
public static Property<Boolean> range_indicator = new Property<>(false);
public Crosshair() { public Crosshair() {
super( super(
@@ -19,14 +18,12 @@ public class Crosshair extends Module {
.description("Changes the crosshair if you're aiming at a entity") .description("Changes the crosshair if you're aiming at a entity")
.tags("Visuals", "Utility") .tags("Visuals", "Utility")
.version("v0.1.0"), .version("v0.1.0"),
enabled.named("Enabled"), enabled.named("Enabled"));
range_indicator.named("Range Indicator"));
} }
@Override @Override
public void render(RenderScope scope) { public void render(RenderScope scope) {
if (enabled.value if (enabled.value
&& range_indicator.value
&& SaturnClient.client.targetedEntity != null && SaturnClient.client.targetedEntity != null
&& SaturnClient.client.targetedEntity.isAlive()) { && SaturnClient.client.targetedEntity.isAlive()) {
int scaledWidth = 15; int scaledWidth = 15;
@@ -0,0 +1,53 @@
package org.saturnclient.modules.mods;
import org.saturnclient.modules.HudMod;
import org.saturnclient.modules.ModDimensions;
import org.saturnclient.modules.Module;
import org.saturnclient.modules.ModuleDetails;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.ui2.RenderScope;
import org.saturnclient.ui2.resources.Fonts;
public class Fps extends Module implements HudMod {
private static Property<Boolean> enabled = Property.bool(false);
private static ModDimensions dimensions = new ModDimensions(60, Fonts.getHeight());
public Fps() {
super(new ModuleDetails("FPS Display", "fps")
.description("Displays current FPS")
.version("v0.1.0")
.tags("Utility"),
enabled.named("Enabled"),
dimensions.prop());
}
@Override
public void renderHud(RenderScope scope) {
String text = String.valueOf(SaturnClient.client.getCurrentFps()) + " FPS";
scope.drawText(text, 0, 0, dimensions.font.value, dimensions.fgColor.value);
dimensions.width = Fonts.getWidth(text, dimensions.font.value);
}
@Override
public void renderDummy(RenderScope scope) {
String text = "369 FPS";
scope.drawText(text, 0, 0, dimensions.font.value, dimensions.fgColor.value);
dimensions.width = Fonts.getWidth(text, dimensions.font.value);
}
@Override
public boolean isEnabled() {
return enabled.value;
}
@Override
public void setEnabled(boolean e) {
enabled.value = e;
}
@Override
public ModDimensions getDimensions() {
return dimensions;
}
}
@@ -0,0 +1,71 @@
package org.saturnclient.modules.mods;
import org.lwjgl.glfw.GLFW;
import org.saturnclient.modules.Module;
import org.saturnclient.modules.ModuleDetails;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.config.Property;
import net.minecraft.client.option.Perspective;
public class Freelook extends Module {
private static Property<Boolean> enabled = Property.bool(false);
private static Property<Boolean> toggle = Property.bool(true);
public static Property<Integer> freelookKey = Property.keybinding(GLFW.GLFW_KEY_H);
public static boolean isFreeLooking = false;
private static boolean was1stPerson = false;
public Freelook() {
super(
new ModuleDetails("Freelook", "freelook")
.description("Allows you to look around freely without moving your character")
.tags("Movement", "Camera")
.version("0.1.0"),
enabled.named("Enabled"),
toggle.named("Toggle freelook"),
freelookKey.named("Freelook Keybinding")
);
}
@Override
public void tick() {
if (toggle.value) {
if (freelookKey.wasKeyPressed()) {
if (isFreeLooking) {
stopFreelook();
} else {
startFreelook();
}
}
} else if (freelookKey.isKeyPressed()) {
if (!isFreeLooking) {
startFreelook();
}
} else if (isFreeLooking) {
stopFreelook();
}
}
private void startFreelook() {
isFreeLooking = true;
was1stPerson = SaturnClient.client.options.getPerspective() == Perspective.FIRST_PERSON;
SaturnClient.client.options.setPerspective(Perspective.THIRD_PERSON_BACK);
}
private void stopFreelook() {
if (was1stPerson) {
SaturnClient.client.options.setPerspective(Perspective.FIRST_PERSON);
}
isFreeLooking = false;
}
@Override
public void setEnabled(boolean e) {
enabled.value = e;
}
@Override
public boolean isEnabled() {
return enabled.value;
}
}
@@ -0,0 +1,139 @@
package org.saturnclient.modules.mods;
import org.saturnclient.modules.Module;
import org.saturnclient.modules.HudMod;
import org.saturnclient.modules.ModDimensions;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.ui2.RenderScope;
import org.saturnclient.modules.ModuleDetails;
public class Keystrokes extends Module implements HudMod {
public static Property<Boolean> enabled = Property.bool(false);
public static Property<Boolean> showMouse = Property.bool(true);
public static Property<Boolean> showSpace = Property.bool(false);
public static ModDimensions dimensions = new ModDimensions(78, 46);
private boolean w = false;
private boolean a = false;
private boolean s = false;
private boolean d = false;
private boolean lmb = false;
private boolean rmb = false;
private boolean space = false;
private static Property<Integer> clickBg = Property.color(0xFFCCCCCC);
private static Property<Integer> clickFg = Property.color(0xFFFFFFFF);
public Keystrokes() {
super(new ModuleDetails("Keystrokes", "keystrokes")
.description("Displays the keystrokes for movement")
.version("v0.1.0")
.tags("Utility"),
enabled.named("Enabled"),
showMouse.named("Show mouse clicks"),
showSpace.named("Show space clicks"),
dimensions.prop(),
clickFg.named("Clicked fg"),
clickBg.named("Clicked bg"));
dimensions.renderBackground = false;
}
@Override
public void tick() {
w = SaturnClient.client.options.forwardKey.isPressed();
a = SaturnClient.client.options.leftKey.isPressed();
s = SaturnClient.client.options.backKey.isPressed();
d = SaturnClient.client.options.rightKey.isPressed();
lmb = SaturnClient.client.options.attackKey.isPressed();
rmb = SaturnClient.client.options.useKey.isPressed();
space = SaturnClient.client.options.jumpKey.isPressed();
}
@Override
public void renderDummy(RenderScope scope) {
dimensions.height = 54; // base height with padding considered
// WASD keys (3px padding between each key)
renderKey(scope, true, 'W', 27, 0); // Top center
renderKey(scope, false, 'A', 0, 27); // Bottom left
renderKey(scope, false, 'S', 27, 27); // Bottom center
renderKey(scope, false, 'D', 54, 27); // Bottom right
if (showMouse.value) {
renderKeyM(scope, true, "LMB", 0, 54); // Below A/S/D
renderKeyM(scope, false, "RMB", 40, 54); // With 3px between
dimensions.height += 27;
}
if (showSpace.value) {
renderKeySpace(scope, false, 0, dimensions.height);
dimensions.height += 22;
}
}
@Override
public void renderHud(RenderScope scope) {
dimensions.height = 54; // base height with padding considered
// WASD keys (3px padding between each key)
renderKey(scope, w, 'W', 27, 0); // Top center
renderKey(scope, a, 'A', 0, 27); // Bottom left
renderKey(scope, s, 'S', 27, 27); // Bottom center
renderKey(scope, d, 'D', 54, 27); // Bottom right
if (showMouse.value) {
renderKeyM(scope, lmb, "LMB", 0, 54); // Below A/S/D
renderKeyM(scope, rmb, "RMB", 40, 54); // With 3px between
dimensions.height += 27;
}
if (showSpace.value) {
renderKeySpace(scope, space, 0, dimensions.height);
dimensions.height += 22;
}
}
// Consistent 3px padding applied below:
private void renderKeySpace(RenderScope scope, boolean isPressed, int x, int y) {
int height = 19;
scope.drawRoundedRectangle(x, y, dimensions.width, height, dimensions.radius.value, isPressed ? clickBg.value : dimensions.bgColor.value);
// A 30-pixel line centered vertically with 3px top padding
int lineY = y + (height - 1) / 2;
scope.drawRect(x + (dimensions.width - 30) / 2, lineY, 30, 1, isPressed ? clickFg.value : dimensions.fgColor.value);
}
private void renderKeyM(RenderScope scope, boolean isPressed, String c, int x, int y) {
int width = 38, height = 24;
scope.drawRoundedRectangle(x, y, width, height, dimensions.radius.value, isPressed ? clickBg.value : dimensions.bgColor.value);
// Apply padding: 3px top and left -> add slight offset to x/y
scope.drawText(0.6f, c, x + 9, y + 7, dimensions.font.value, isPressed ? clickFg.value : dimensions.fgColor.value);
}
private void renderKey(RenderScope scope, boolean isPressed, char c, int x, int y) {
int size = 24;
scope.drawRoundedRectangle(x, y, size, size, dimensions.radius.value, isPressed ? clickBg.value : dimensions.bgColor.value);
// Center the character with 3px top padding
scope.drawText(0.6f, String.valueOf(c), x + 9, y + 7, dimensions.font.value, isPressed ? clickFg.value : dimensions.fgColor.value);
}
@Override
public boolean isEnabled() {
return enabled.value;
}
@Override
public ModDimensions getDimensions() {
return dimensions;
}
@Override
public void setEnabled(boolean e) {
enabled.value = e;
}
}
@@ -0,0 +1,105 @@
package org.saturnclient.modules.mods;
import java.util.Arrays;
import org.saturnclient.modules.HudMod;
import org.saturnclient.modules.ModDimensions;
import org.saturnclient.modules.Module;
import org.saturnclient.modules.ModuleDetails;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.ui2.RenderScope;
import net.minecraft.client.resource.language.I18n;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.texture.StatusEffectSpriteManager;
import net.minecraft.entity.effect.StatusEffect;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.registry.Registries;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper;
public class PotionDisplay extends Module implements HudMod {
public static Property<Boolean> enabled = Property.bool(false);
private static ModDimensions dimensions = new ModDimensions(60, 0);
private final StatusEffectInstance[] dummyEffects = {
new StatusEffectInstance(Registries.STATUS_EFFECT.getEntry(Identifier.ofVanilla("speed")).get(), 12000, 2),
new StatusEffectInstance(Registries.STATUS_EFFECT.getEntry(Identifier.ofVanilla("strength")).get(), 12000, 2),
new StatusEffectInstance(Registries.STATUS_EFFECT.getEntry(Identifier.ofVanilla("fire_resistance")).get(), 12000, 2),
};
public PotionDisplay() {
super(new ModuleDetails("Potion Display", "potion")
.description("Displays potion effects")
.version("v0.1.0")
.tags("Utility"),
enabled.named("Enabled"),
dimensions.prop());
}
private void renderEffects(RenderScope scope, Iterable<StatusEffectInstance> effects) {
int row = 0;
StatusEffectSpriteManager statusEffectSpriteManager = SaturnClient.client.getStatusEffectSpriteManager();
for (StatusEffectInstance effect : effects) {
if (effect.shouldShowIcon()) {
RegistryEntry<StatusEffect> registryEntry = effect.getEffectType();
Sprite sprite = statusEffectSpriteManager.getSprite(registryEntry);
scope.drawSpriteStretched(sprite, 0, 18 * row, 16, 16);
scope.drawText(0.5f, getDurationAsString(effect), 18, 18 * row + 3, dimensions.font.value, -1);
row++;
}
}
dimensions.height = 18 * row;
}
@Override
public void renderHud(RenderScope scope) {
renderEffects(scope, SaturnClient.client.player.getStatusEffects());
}
@Override
public void renderDummy(RenderScope scope) {
renderEffects(scope, Arrays.asList(dummyEffects));
}
// This code was from: https://github.com/magicus/statuseffecttimer/blob/master/src/main/java/se/icus/mag/statuseffecttimer/mixin/StatusEffectTimerMixin.java
private String getDurationAsString(StatusEffectInstance statusEffectInstance) {
if (statusEffectInstance.isInfinite()) {
return I18n.translate("effect.duration.infinite");
}
int ticks = MathHelper.floor((float) statusEffectInstance.getDuration());
int totalSeconds = ticks / 20;
if (totalSeconds >= 3600) {
return totalSeconds / 3600 + "h";
} else if (totalSeconds >= 60) {
int minutes = totalSeconds / 60;
int seconds = totalSeconds % 60;
return String.format("%d:%02d", minutes, seconds);
} else {
return String.valueOf(totalSeconds) + "s";
}
}
@Override
public ModDimensions getDimensions() {
return dimensions;
}
@Override
public boolean isEnabled() {
return enabled.value;
}
@Override
public void setEnabled(boolean e) {
enabled.value = e;
}
}
@@ -0,0 +1,44 @@
package org.saturnclient.modules.mods.mixins;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.render.Camera;
import net.minecraft.entity.Entity;
import net.minecraft.world.BlockView;
import org.saturnclient.modules.mods.Freelook;
import org.saturnclient.modules.mods.utils.CameraOverriddenEntity;
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;
@Mixin(Camera.class)
public abstract class CameraMixin {
@Unique
boolean firstTime = true;
@Shadow
protected abstract void setRotation(float yaw, float pitch);
@Inject(method = "update", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/Camera;setRotation(FF)V", ordinal = 1, shift = At.Shift.AFTER))
public void lockRotation(BlockView focusedBlock, Entity cameraEntity, boolean isThirdPerson, boolean isFrontFacing, float tickDelta, CallbackInfo ci) {
if (Freelook.isFreeLooking && cameraEntity instanceof ClientPlayerEntity) {
CameraOverriddenEntity cameraOverriddenEntity = (CameraOverriddenEntity) cameraEntity;
if (firstTime && MinecraftClient.getInstance().player != null) {
cameraOverriddenEntity.freelook$setCameraPitch(MinecraftClient.getInstance().player.getPitch());
cameraOverriddenEntity.freelook$setCameraYaw(MinecraftClient.getInstance().player.getYaw());
firstTime = false;
}
this.setRotation(cameraOverriddenEntity.freelook$getCameraYaw(), cameraOverriddenEntity.freelook$getCameraPitch());
}
if (!Freelook.isFreeLooking && cameraEntity instanceof ClientPlayerEntity) {
firstTime = true;
}
}
}
@@ -0,0 +1,62 @@
package org.saturnclient.modules.mods.mixins;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.entity.Entity;
import net.minecraft.util.math.MathHelper;
import org.saturnclient.modules.mods.Freelook;
import org.saturnclient.modules.mods.utils.CameraOverriddenEntity;
import org.spongepowered.asm.mixin.Mixin;
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;
@Mixin(Entity.class)
public class EntityMixin implements CameraOverriddenEntity {
@Unique
private float cameraPitch;
@Unique
private float cameraYaw;
@Inject(method = "changeLookDirection", at = @At("HEAD"), cancellable = true)
public void changeCameraLookDirection(double xDelta, double yDelta, CallbackInfo ci) {
//noinspection ConstantValue// IntelliJ is incorrect here, this code block is reachable
if (Freelook.isFreeLooking && (Object) this instanceof ClientPlayerEntity) {
double pitchDelta = (yDelta * 0.15);
double yawDelta = (xDelta * 0.15);
this.cameraPitch = MathHelper.clamp(this.cameraPitch + (float) pitchDelta, -90.0f, 90.0f);
this.cameraYaw += (float) yawDelta;
ci.cancel();
}
}
@Override
@Unique
public float freelook$getCameraPitch() {
return this.cameraPitch;
}
@Override
@Unique
public float freelook$getCameraYaw() {
return this.cameraYaw;
}
@Override
@Unique
public void freelook$setCameraPitch(float pitch) {
this.cameraPitch = pitch;
}
@Override
@Unique
public void freelook$setCameraYaw(float yaw) {
this.cameraYaw = yaw;
}
}
@@ -0,0 +1,9 @@
package org.saturnclient.modules.mods.utils;
public interface CameraOverriddenEntity {
float freelook$getCameraPitch();
float freelook$getCameraYaw();
void freelook$setCameraPitch(float pitch);
void freelook$setCameraYaw(float yaw);
}
@@ -2,14 +2,23 @@ package org.saturnclient.saturnclient;
import net.fabricmc.api.ModInitializer; import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.util.math.MatrixStack;
import org.saturnclient.modules.ModManager; import org.saturnclient.modules.ModManager;
import org.saturnclient.saturnclient.auth.Auth; import org.saturnclient.saturnclient.auth.Auth;
import org.saturnclient.saturnclient.config.ConfigManager; import org.saturnclient.saturnclient.config.ConfigManager;
import org.saturnclient.saturnclient.cosmetics.Emotes;
import org.saturnclient.saturnclient.cosmetics.Hats; import org.saturnclient.saturnclient.cosmetics.Hats;
import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks; import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks;
import org.saturnclient.saturnclient.event.KeyInputHandler; import org.saturnclient.saturnclient.event.KeyInputHandler;
import org.saturnclient.saturnclient.mixin.DrawContextAccessor;
import org.saturnclient.ui2.RenderScope;
import org.saturnclient.ui2.SaturnScreen;
import org.saturnclient.ui2.elements.ImageTexture;
import org.saturnclient.ui2.resources.Textures;
import org.saturnclient.ui2.screens.TitleMenu;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -36,8 +45,35 @@ public class SaturnClient implements ModInitializer {
SpecialModelLoaderEvents.LOAD_SCOPE.register(() -> { SpecialModelLoaderEvents.LOAD_SCOPE.register(() -> {
return (resourceManager, location) -> MOD_ID.equals(location.getNamespace()); return (resourceManager, location) -> MOD_ID.equals(location.getNamespace());
}); });
ScreenEvents.AFTER_INIT.register((client, screen, scaledWidth, scaledHeight) -> {
if (screen != null && !(screen instanceof TitleMenu)) {
if (screen instanceof SaturnScreen) {
((SaturnScreen) screen).draw(new ImageTexture(Textures.LOGO_TEXT_BIG).dimensions(180, 18).position(screen.width - 180 - 20, screen.height - 18 - 20));
} else {
ScreenEvents.afterRender(screen).register((screen1, context, mouseX, mouseY, tickDelta) -> {
RenderScope renderScope = new RenderScope(context.getMatrices(),
((DrawContextAccessor) context).getVertexConsumers());
int width = context.getScaledWindowWidth();
int height = context.getScaledWindowHeight();
float scaleX = (float) screen1.width / width;
float scaleY = (float) screen1.height / height;
MatrixStack matrixStack = context.getMatrices();
matrixStack.push();
matrixStack.translate(width - 95, height - 14, 0);
matrixStack.scale(0.5f / scaleX, 0.5f / scaleY, 1.0f);
renderScope.drawTexture(Textures.LOGO_TEXT_BIG, 0, 0, 0, 0, 180, 18);
matrixStack.pop();
});
}
}
});
KeyInputHandler.register(); KeyInputHandler.register();
Emotes.initialize();
if (Auth.authenticate()) { if (Auth.authenticate()) {
Cloaks.initialize(); Cloaks.initialize();
Hats.initialize(); Hats.initialize();
@@ -1,6 +1,7 @@
package org.saturnclient.saturnclient; package org.saturnclient.saturnclient;
import org.saturnclient.saturnclient.config.Property; import org.saturnclient.saturnclient.config.Property;
import org.lwjgl.glfw.GLFW;
import org.saturnclient.saturnclient.config.ConfigManager; import org.saturnclient.saturnclient.config.ConfigManager;
import org.saturnclient.ui2.resources.Textures; import org.saturnclient.ui2.resources.Textures;
@@ -10,11 +11,10 @@ import net.minecraft.util.Identifier;
public class SaturnClientConfig { public class SaturnClientConfig {
public static ConfigManager config; public static ConfigManager config;
public static Property<Boolean> realisticLogo = public static Property<Boolean> realisticLogo = Property.bool(false);
new Property<>(false);
public static Property<Boolean> saturnTitleScreen = public static Property<Boolean> saturnTitleScreen = Property.bool(true);
new Property<>(true); public static Property<Integer> openEmoteWheel = Property.keybinding(GLFW.GLFW_KEY_B);
public static Identifier getLogo() { public static Identifier getLogo() {
return realisticLogo.value ? Textures.REALISTIC_LOGO : Textures.LOGO; return realisticLogo.value ? Textures.REALISTIC_LOGO : Textures.LOGO;
@@ -45,5 +45,6 @@ public class SaturnClientConfig {
config = new ConfigManager("Saturn Client"); config = new ConfigManager("Saturn Client");
config.property("Realistic logo", realisticLogo); config.property("Realistic logo", realisticLogo);
config.property("Saturn client title screen", saturnTitleScreen); config.property("Saturn client title screen", saturnTitleScreen);
config.property("Open Emote Wheel", openEmoteWheel);
} }
} }
@@ -5,6 +5,9 @@ import java.util.Map;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
import org.saturnclient.saturnclient.cosmetics.Hats; import org.saturnclient.saturnclient.cosmetics.Hats;
import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks; import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks;
import org.saturnclient.ui2.SaturnScreen;
import org.saturnclient.ui2.elements.Notification;
import org.saturnclient.ui2.elements.Notification.NotificationKind;
import org.saturnclient.saturnclient.SaturnClient; import org.saturnclient.saturnclient.SaturnClient;
public class Auth { public class Auth {
@@ -95,10 +98,25 @@ public class Auth {
playerNames.entrySet().removeIf(entry -> entry.getValue().equals(uuid)); playerNames.entrySet().removeIf(entry -> entry.getValue().equals(uuid));
} }
break; break;
case "successful_transaction":
String cloak = parser.getStringOrNull("cloak");
String hat = parser.getStringOrNull("hat");
if (cloak != null) {
Cloaks.availableCloaks.add(cloak);
}
if (hat != null) {
Hats.availableHats.add(hat);
}
default: default:
if (parser.error != null) { if (parser.error != null) {
SaturnClient.LOGGER.error("Error from the server: " + parser.error); SaturnClient.LOGGER.error("Error from the server: " + parser.error);
if (SaturnClient.client.currentScreen instanceof SaturnScreen) {
String[] a = parser.error.replace("!", "").split(": ");
((SaturnScreen) SaturnClient.client.currentScreen).draw(new Notification(SaturnClient.client.currentScreen.width, SaturnClient.client.currentScreen.height, NotificationKind.Error, a[0], a[1]));
}
} }
break; break;
} }
@@ -194,4 +212,44 @@ public class Auth {
} }
} }
} }
public static void sendEmote(String emote) {
String uuid = SaturnClient.client.player.getUuidAsString().replace("-", "");
for (Map.Entry<String, String> player : playerNames.entrySet()) {
if (players.containsKey(player.getValue()) && !player.getValue().equals(uuid)) {
SaturnClient.client.player.networkHandler
.sendChatCommand("msg " + player.getKey() + " "
+ "$SATURN_EMOTE&@"+uuid+"&@"+emote+"&@ if you are seeing this as a player, please report this to https://github.com/saturnclientmc/saturnclient/issues");
;
}
}
}
public static void cancelEmote() {
String uuid = SaturnClient.client.player.getUuidAsString().replace("-", "");
for (Map.Entry<String, String> player : playerNames.entrySet()) {
if (players.containsKey(player.getValue()) && !player.getValue().equals(uuid)) {
SaturnClient.client.player.networkHandler
.sendChatCommand("msg " + player.getKey() + " "
+ "$SATURN_CANCEL_EMOTE&@"+uuid+"&@ if you are seeing this as a player, please report this to https://github.com/saturnclientmc/saturnclient/issues");
;
}
}
}
public static void buyCloak(String name) {
try {
Network.write("buy_cloak@cloak=" + name);
} catch (Exception e) {
SaturnClient.LOGGER.error("Request failed", e);
}
}
public static void buyHat(String name) {
try {
Network.write("buy_hat@hat=" + name);
} catch (Exception e) {
SaturnClient.LOGGER.error("Request failed", e);
}
}
} }
@@ -43,6 +43,11 @@ public class SaturnParser {
} }
} }
public String getStringOrNull(String i) throws IOException {
String val = params.get(i);
return val;
}
public boolean getBool(String i) throws IOException { public boolean getBool(String i) throws IOException {
String val = params.get(i); String val = params.get(i);
if (val != null) { if (val != null) {
@@ -32,8 +32,7 @@ public class ConfigManager {
public ConfigManager(ConfigManager config, String namespace) { public ConfigManager(ConfigManager config, String namespace) {
currentMap = new LinkedHashMap<>(); currentMap = new LinkedHashMap<>();
Property<Map<String, Property<?>>> namespaceProperty = new Property<>(currentMap, Property<Map<String, Property<?>>> namespaceProperty = Property.namespace(currentMap);
Property.PropertyType.NAMESPACE);
config.property(namespace, namespaceProperty); config.property(namespace, namespaceProperty);
// Update the parent's state // Update the parent's state
config.currentMap.put(namespace, namespaceProperty); config.currentMap.put(namespace, namespaceProperty);
@@ -41,8 +40,7 @@ public class ConfigManager {
} }
public void sub(String namespace) { public void sub(String namespace) {
Property<Map<String, Property<?>>> namespaceProperty = new Property<>(currentMap, Property<Map<String, Property<?>>> namespaceProperty = Property.namespace(currentMap);
Property.PropertyType.NAMESPACE);
property(namespace, namespaceProperty); property(namespace, namespaceProperty);
} }
@@ -139,25 +137,17 @@ public class ConfigManager {
Map<String, Property<?>> nestedProperties = p.getNamespaceValue(); Map<String, Property<?>> nestedProperties = p.getNamespaceValue();
loadProperties(nestedConfig, nestedProperties); loadProperties(nestedConfig, nestedProperties);
} else { } else {
// Handle regular properties if (p.value instanceof Integer) {
switch (p.getType()) { ((Property<Integer>) p).value = c.getAsInt();
case BOOLEAN: } else if (p.value instanceof String) {
((Property<Boolean>) p).value = c.getAsBoolean(); ((Property<String>) p).value = c.getAsString();
break; } else if (p.value instanceof Float) {
case INTEGER: ((Property<Float>) p).value = c.getAsFloat();
((Property<Integer>) p).value = c.getAsInt(); } else if (p.value instanceof Boolean) {
break; ((Property<Boolean>) p).value = c.getAsBoolean();
case FLOAT: } else {
((Property<Float>) p).value = c.getAsFloat(); SaturnClient.LOGGER.warn(
break; "Unknown property type for: " + propertyName);
case STRING:
((Property<String>) p).value = c.getAsString();
break;
case HEX:
((Property<Integer>) p).value = c.getAsInt();
break;
default:
break;
} }
} }
} else { } else {
@@ -203,36 +193,29 @@ public class ConfigManager {
for (String propertyName : propertyMap.keySet()) { for (String propertyName : propertyMap.keySet()) {
Property<?> property = propertyMap.get(propertyName); Property<?> property = propertyMap.get(propertyName);
JsonElement propertyValue = null; JsonElement propertyValue = null;
// Convert the property value based on its type
if (property.getType() == Property.PropertyType.NAMESPACE) { switch (property.getType()) {
// Handle nested namespace case NAMESPACE:
JsonObject nestedConfig = new JsonObject(); // Handle nested namespace
Map<String, Property<?>> nestedProperties = (Map<String, Property<?>>) property.value; JsonObject nestedConfig = new JsonObject();
saveProperties(nestedConfig, nestedProperties); Map<String, Property<?>> nestedProperties = (Map<String, Property<?>>) property.value;
propertyValue = nestedConfig; saveProperties(nestedConfig, nestedProperties);
} else { propertyValue = nestedConfig;
// Convert the property value based on its type break;
switch (property.getType()) { default:
case BOOLEAN: if (property.value instanceof Integer) {
propertyValue = new JsonPrimitive((Boolean) property.value);
break;
case INTEGER:
propertyValue = new JsonPrimitive((Integer) property.value); propertyValue = new JsonPrimitive((Integer) property.value);
break; } else if (property.value instanceof String) {
case FLOAT:
propertyValue = new JsonPrimitive((Float) property.value);
break;
case STRING:
propertyValue = new JsonPrimitive((String) property.value); propertyValue = new JsonPrimitive((String) property.value);
break; } else if (property.value instanceof Float) {
case HEX: propertyValue = new JsonPrimitive((Float) property.value);
propertyValue = new JsonPrimitive((Integer) property.value); } else if (property.value instanceof Boolean) {
break; propertyValue = new JsonPrimitive((Boolean) property.value);
default: } else {
SaturnClient.LOGGER.warn( SaturnClient.LOGGER.warn(
"Unknown property type for: " + propertyName); "Unknown property type for: " + propertyName);
break; }
} break;
} }
if (propertyValue != null) { if (propertyValue != null) {
@@ -2,6 +2,9 @@ package org.saturnclient.saturnclient.config;
import java.util.Map; import java.util.Map;
import org.lwjgl.glfw.GLFW;
import org.saturnclient.saturnclient.SaturnClient;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive; import com.google.gson.JsonPrimitive;
@@ -13,62 +16,100 @@ public class Property<T> {
FLOAT, FLOAT,
STRING, STRING,
HEX, HEX,
NAMESPACE NAMESPACE,
SELECT,
KEYBINDING,
} }
public T value; public T value;
public boolean isReset = false; public boolean isReset = false;
private T defaultValue; private T defaultValue;
private String[] availableValues;
private PropertyType type; private PropertyType type;
private boolean wasPressedLastTick = false;
public Property(T value) { private Property(T value, PropertyType type) {
this.value = value;
this.defaultValue = value;
if (value instanceof Boolean) {
type = PropertyType.BOOLEAN;
} else if (value instanceof Integer) {
type = PropertyType.INTEGER;
} else if (value instanceof Float) {
type = PropertyType.FLOAT;
} else if (value instanceof String) {
type = PropertyType.STRING;
} else if (valueIsNamespace(value)) {
type = PropertyType.NAMESPACE;
}
}
public Property(T value, PropertyType type) {
this.value = value; this.value = value;
this.defaultValue = value; this.defaultValue = value;
this.type = type; this.type = type;
} }
public boolean getBool() { public static <T> Property<T> from(T value) {
if (value instanceof Boolean) { if (value instanceof Boolean) {
return (boolean) value; return new Property<>(value, PropertyType.BOOLEAN);
} else if (value instanceof Integer) {
return new Property<>(value, PropertyType.INTEGER);
} else if (value instanceof Float) {
return new Property<>(value, PropertyType.FLOAT);
} else if (value instanceof String) {
return new Property<>(value, PropertyType.STRING);
} else if (valueIsNamespace(value)) {
return new Property<>(value, PropertyType.NAMESPACE);
} else {
return null;
} }
throw new IllegalStateException("Property does not contain a boolean");
} }
public int getInt() { public static Property<Integer> font(int value) {
if (value instanceof Integer) { return select(value, "Default", "Inter", "Inter bold");
return (int) value;
}
throw new IllegalStateException("Property does not contain an int");
} }
public float getFloat() { public static Property<Integer> select(Integer value, String... availableValues) {
if (value instanceof Float) { Property<Integer> property = new Property<>(value, PropertyType.SELECT);
return (float) value; property.availableValues = availableValues;
} return property;
throw new IllegalStateException("Property does not contain a float");
} }
public String getString() { public static Property<Map<String, Property<?>>> namespace(Map<String, Property<?>> value) {
if (value instanceof String) { return new Property<>(value, PropertyType.NAMESPACE);
return (String) value; }
public static Property<Boolean> bool(boolean value) {
return new Property<>(value, PropertyType.BOOLEAN);
}
public static Property<Integer> integer(int value) {
return new Property<>(value, PropertyType.INTEGER);
}
public static Property<Float> floatProp(float value) {
return new Property<>(value, PropertyType.FLOAT);
}
public static Property<String> string(String value) {
return new Property<>(value, PropertyType.STRING);
}
public static Property<Integer> color(int value) {
return new Property<>(value, PropertyType.HEX);
}
public static Property<Integer> keybinding(int value) {
return new Property<>(value, PropertyType.KEYBINDING);
}
public void next() {
if ((Integer) value < availableValues.length-1) setValue((Integer)value+1);
else setValue(0);
}
public void prev() {
if ((Integer) value > 0) setValue((Integer)value-1);
else setValue(availableValues.length - 1);
}
public void setSelection(int selection) {
if (selection >= 0 && selection < availableValues.length && type == PropertyType.SELECT) {
setValue(selection);
}
}
public String getSelection() {
if (type == PropertyType.SELECT) {
return availableValues[(Integer) value];
} else {
return null;
} }
throw new IllegalStateException("Property does not contain a string");
} }
public void reset() { public void reset() {
@@ -154,4 +195,20 @@ public class Property<T> {
public NamedProperty<T> named(String name) { public NamedProperty<T> named(String name) {
return new NamedProperty<>(name, this); return new NamedProperty<>(name, this);
} }
public boolean isKeyPressed() {
return (Integer) value == -1 ? false : GLFW.glfwGetKey(SaturnClient.client.getWindow().getHandle(), (Integer) (Object) value) == GLFW.GLFW_PRESS;
}
public boolean wasKeyPressed() {
long window = SaturnClient.client.getWindow().getHandle();
int key = (Integer) value;
boolean isPressed = key != -1 && GLFW.glfwGetKey(window, key) == GLFW.GLFW_PRESS;
boolean wasJustPressed = isPressed && !wasPressedLastTick;
wasPressedLastTick = isPressed;
return wasJustPressed;
}
} }
@@ -51,7 +51,8 @@ public class ThemeManager {
} }
} else { } else {
for (Map.Entry<String, Property<?>> tProp : properties.get(namespace).entrySet()) { for (Map.Entry<String, Property<?>> tProp : properties.get(namespace).entrySet()) {
currentStyling.get(tProp.getKey()).setValue(tProp.getValue().value); Property<?> p = currentStyling.get(tProp.getKey());
if (p != null) p.setValue(tProp.getValue().value);
} }
} }
} }
@@ -61,7 +62,7 @@ public class ThemeManager {
for (Map.Entry<String, Property<?>> tProp : properties.get(namespace+"@"+state).entrySet()) { for (Map.Entry<String, Property<?>> tProp : properties.get(namespace+"@"+state).entrySet()) {
Property<?> p = currentStyling.get(tProp.getKey()); Property<?> p = currentStyling.get(tProp.getKey());
Property<?> currProp = properties.get(namespace).get(tProp.getKey()); Property<?> currProp = properties.get(namespace).get(tProp.getKey());
if (p.value.equals(currProp.value)) { if (currProp != null && p.value.equals(currProp.value)) {
p.setValue(tProp.getValue().value); p.setValue(tProp.getValue().value);
} }
} }
@@ -73,13 +74,13 @@ public class ThemeManager {
// Generic method to store any type of property // Generic method to store any type of property
public <T> Property<T> property(String name, Property<T> prop) { public <T> Property<T> property(String name, Property<T> prop) {
for (String state : states) { for (String state : states) {
Property<?> property = new Property<T>(prop.value); Property<?> property = Property.from(prop.value);
properties.get(namespace+"@"+state).put(name, property); properties.get(namespace+"@"+state).put(name, property);
loadProp(state, name, property); loadProp(state, name, property);
} }
loadProp(null, name, prop); loadProp(null, name, prop);
properties.get(namespace).put(name, new Property<T>(prop.value)); properties.get(namespace).put(name, Property.from(prop.value));
currentStyling.put(name, prop); currentStyling.put(name, prop);
return prop; return prop;
@@ -0,0 +1,17 @@
package org.saturnclient.saturnclient.cosmetics;
import java.util.ArrayList;
import java.util.List;
public class Emotes {
public static List<String> availableEmotes = new ArrayList<>();
public static void initialize() {
availableEmotes.add("tpose");
availableEmotes.add("back_flip");
availableEmotes.add("facepalm");
availableEmotes.add("cry");
availableEmotes.add("giga_chad");
availableEmotes.add("front_flip");
}
}
@@ -30,7 +30,7 @@ public class HatFeatureRenderer extends FeatureRenderer<PlayerEntityRenderState,
PlayerEntityRenderState state, float limbAngle, float limbDistance) { PlayerEntityRenderState state, float limbAngle, float limbDistance) {
ItemStack headItem = state.equippedHeadStack; ItemStack headItem = state.equippedHeadStack;
String uuid = Auth.playerNames.get(state.name); String uuid = Auth.playerNames.get(state.name);
if (headItem.isEmpty() && uuid != null) { if (headItem.isEmpty() && uuid != null && !state.invisible) {
SaturnPlayer player = Auth.players.get(uuid); SaturnPlayer player = Auth.players.get(uuid);
if (player == null || player.hat == null || player.hat.isEmpty()) { if (player == null || player.hat == null || player.hat.isEmpty()) {
return; return;
@@ -6,6 +6,7 @@ import org.saturnclient.saturnclient.auth.SaturnPlayer;
import org.saturnclient.saturnclient.auth.Auth; import org.saturnclient.saturnclient.auth.Auth;
public class Hats { public class Hats {
public static final String[] ALL_HATS = { "horns_black", "horns_white", "halo", "halo_black" };
public static List<String> availableHats = new ArrayList<>(); public static List<String> availableHats = new ArrayList<>();
public static void initialize() { public static void initialize() {
@@ -20,7 +20,8 @@ import org.saturnclient.saturnclient.SaturnClient;
* Originally created by IIpho3nix and modified for Saturn Client by leo. * Originally created by IIpho3nix and modified for Saturn Client by leo.
*/ */
public class Cloaks { public class Cloaks {
private static final String[] ANIMATED_CLOAKS = { "glitch" }; public static final String[] ALL_CLOAKS = { "glitch", "mercedes_flow", "crimson_mark", };
private static final String[] ANIMATED_CLOAKS = { "glitch", "mercedes_flow" };
private static final String CLOAKS_RESOURCE_PATH = "assets/saturnclient/textures/cloaks/"; private static final String CLOAKS_RESOURCE_PATH = "assets/saturnclient/textures/cloaks/";
public static final List<String> availableCloaks = new ArrayList<>(); public static final List<String> availableCloaks = new ArrayList<>();
@@ -48,6 +49,17 @@ public class Cloaks {
SaturnClient.LOGGER.info("Cloak set to " + cloakName); SaturnClient.LOGGER.info("Cloak set to " + cloakName);
} }
/**
* Sets cloak of the current player
*
* @param cloakName Name of the cloak file to load
*/
public static void setCloak(String cloakName) {
if (availableCloaks.contains(cloakName)) {
setCloak(Auth.uuid, cloakName);
}
}
/** /**
* Handles loading and caching of a new cloak texture, without connecting to the * Handles loading and caching of a new cloak texture, without connecting to the
* server. * server.
@@ -3,12 +3,17 @@ package org.saturnclient.saturnclient.event;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
import net.minecraft.client.option.KeyBinding; import net.minecraft.client.option.KeyBinding;
// import net.minecraft.client.option.Perspective;
import net.minecraft.client.util.InputUtil; import net.minecraft.client.util.InputUtil;
// import org.saturnclient.modules.mods.FreeLook; import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.SaturnClientConfig;
// import org.saturnclient.saturnclient.auth.Auth;
import org.saturnclient.ui2.screens.EmoteWheel;
import org.saturnclient.ui2.screens.ShiftMenu; import org.saturnclient.ui2.screens.ShiftMenu;
// import org.saturnclient.saturnclient.menus.SaturnMenu;
import dev.kosmx.playerAnim.api.layered.AnimationStack;
import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationAccess;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
/** /**
@@ -21,55 +26,30 @@ public class KeyInputHandler {
private static final int DEFAULT_MENU_KEY = GLFW.GLFW_KEY_RIGHT_SHIFT; private static final int DEFAULT_MENU_KEY = GLFW.GLFW_KEY_RIGHT_SHIFT;
private static KeyBinding mainMenuKeyBinding; private static KeyBinding mainMenuKeyBinding;
// private static final String FREELOOK_KEY_ID = "key.saturnclient.freelook";
// private static final int FREELOOK_KEY = GLFW.GLFW_KEY_M;
// private static KeyBinding freelookKeyBinding;
/**
* Registers all keybindings and their associated event handlers.
* Should be called during mod initialization.
*/
public static void register() { public static void register() {
// Register the main menu key binding
mainMenuKeyBinding = KeyBindingHelper.registerKeyBinding(new KeyBinding( mainMenuKeyBinding = KeyBindingHelper.registerKeyBinding(new KeyBinding(
MAIN_MENU_KEY_ID, MAIN_MENU_KEY_ID,
InputUtil.Type.KEYSYM, InputUtil.Type.KEYSYM,
DEFAULT_MENU_KEY, DEFAULT_MENU_KEY,
KEY_CATEGORY)); KEY_CATEGORY));
// freelookKeyBinding = KeyBindingHelper.registerKeyBinding(new KeyBinding(
// FREELOOK_KEY_ID,
// InputUtil.Type.KEYSYM,
// FREELOOK_KEY,
// KEY_CATEGORY));
// Register the event handler for the main menu key // Register the event handler for the main menu key
ClientTickEvents.END_CLIENT_TICK.register(client -> { ClientTickEvents.END_CLIENT_TICK.register(client -> {
if (mainMenuKeyBinding.wasPressed()) { if (mainMenuKeyBinding.wasPressed()) {
client.setScreen(new ShiftMenu()); client.setScreen(new ShiftMenu());
} }
// else if (freelookKeyBinding.wasPressed() && FreeLook.enabled.value && FreeLook.toggle.value) {
// FreeLook.isFreeLooking = !FreeLook.isFreeLooking; if (SaturnClientConfig.openEmoteWheel.wasKeyPressed()) {
// if (FreeLook.isFreeLooking) { client.setScreen(new EmoteWheel());
// FreeLook.lastPerspective = client.options.getPerspective(); }
// client.options.setPerspective(Perspective.THIRD_PERSON_BACK);
// } else if (FreeLook.lastPerspective != null) { if (SaturnClient.client.player != null && SaturnClient.client.player.isSneaking()) {
// client.options.setPerspective(FreeLook.lastPerspective); AnimationStack animationStack = PlayerAnimationAccess.getPlayerAnimLayer(SaturnClient.client.player);
// FreeLook.lastPerspective = null; if (animationStack.isActive() && animationStack.getPriority() == 1000) {
// } animationStack.removeLayer(1000);
// } else if (FreeLook.enabled.value && !FreeLook.toggle.value) { // Auth.cancelEmote();
// if (freelookKeyBinding.isPressed()) { }
// if (!FreeLook.isFreeLooking) { }
// FreeLook.lastPerspective = client.options.getPerspective();
// client.options.setPerspective(Perspective.THIRD_PERSON_BACK);
// FreeLook.isFreeLooking = true;
// }
// } else if (FreeLook.isFreeLooking && FreeLook.lastPerspective != null) {
// client.options.setPerspective(FreeLook.lastPerspective);
// FreeLook.isFreeLooking = false;
// FreeLook.lastPerspective = null;
// }
// }
}); });
} }
} }
@@ -1,33 +1,62 @@
package org.saturnclient.saturnclient.mixin; package org.saturnclient.saturnclient.mixin;
import java.util.Map; import java.util.Map;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.auth.Auth; import org.saturnclient.saturnclient.auth.Auth;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import dev.kosmx.playerAnim.api.layered.AnimationStack;
import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationAccess;
import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationRegistry;
import net.minecraft.client.gui.hud.ChatHud; import net.minecraft.client.gui.hud.ChatHud;
import net.minecraft.client.gui.hud.MessageIndicator; import net.minecraft.client.gui.hud.MessageIndicator;
import net.minecraft.client.network.AbstractClientPlayerEntity;
import net.minecraft.network.message.MessageSignatureData; import net.minecraft.network.message.MessageSignatureData;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
@Mixin(ChatHud.class) @Mixin(ChatHud.class)
public class SaturnReload { public class SaturnReload {
@Inject(method = "addMessage(Lnet/minecraft/text/Text;Lnet/minecraft/network/message/MessageSignatureData;Lnet/minecraft/client/gui/hud/MessageIndicator;)V", at = @At("HEAD"), cancellable = true) @Inject(method = "addMessage(Lnet/minecraft/text/Text;Lnet/minecraft/network/message/MessageSignatureData;Lnet/minecraft/client/gui/hud/MessageIndicator;)V", at = @At("HEAD"), cancellable = true)
public void onAddMessage(Text message, @Nullable MessageSignatureData signatureData, public void onAddMessage(Text message, @Nullable MessageSignatureData signatureData,
@Nullable MessageIndicator indicator, CallbackInfo ci) { @Nullable MessageIndicator indicator, CallbackInfo ci) {
String msg = message.toString(); try {
if (msg.contains("$SATURN_RELOAD")) { String msg = message.toString();
for (Map.Entry<String, String> player : Auth.playerNames.entrySet()) { if (msg.contains("$SATURN_RELOAD")) {
String name = player.getKey(); for (Map.Entry<String, String> player : Auth.playerNames.entrySet()) {
if (msg.contains(name)) { String name = player.getKey();
Auth.player(name, player.getValue()); if (msg.contains(name)) {
Auth.player(name, player.getValue());
}
ci.cancel();
} }
ci.cancel(); } else if (msg.contains("$SATURN_EMOTE")) {
String[] args = msg.split("&@");
for (AbstractClientPlayerEntity player : SaturnClient.client.world.getPlayers()) {
if (player.getUuidAsString().replace("-", "").equals(args[1])) {
AnimationStack animationStack = PlayerAnimationAccess.getPlayerAnimLayer(player);
animationStack.addAnimLayer(1000, PlayerAnimationRegistry.getAnimation(Identifier.of("saturnclient", args[2])).playAnimation());
ci.cancel();
break;
}
}
} else if (msg.contains("$SATURN_CANCEL_EMOTE")) {
String[] args = msg.split("&@");
for (AbstractClientPlayerEntity player : SaturnClient.client.world.getPlayers()) {
if (player.getUuidAsString().replace("-", "").equals(args[1])) {
AnimationStack animationStack = PlayerAnimationAccess.getPlayerAnimLayer(player);
animationStack.removeLayer(1000);
ci.cancel();
break;
}
}
} }
} catch (Exception e) {
e.printStackTrace();
} }
} }
} }
@@ -15,6 +15,7 @@ public class Element {
public Animation animation; public Animation animation;
public float scale = 1.0f; public float scale = 1.0f;
public Function<Double, Double> curve = Curve::easeInOutCubic; public Function<Double, Double> curve = Curve::easeInOutCubic;
public Integer duration = null; // Element duration, will fade out if not null
public void render(RenderScope renderScope, ElementContext ctx) { public void render(RenderScope renderScope, ElementContext ctx) {
} }
@@ -31,45 +32,45 @@ public class Element {
public void charTyped(char typedChar) { public void charTyped(char typedChar) {
} }
public final Element dimensions(int width, int height) { public Element dimensions(int width, int height) {
this.width = width; this.width = width;
this.height = height; this.height = height;
return this; return this;
} }
public final Element position(int x, int y) { public Element position(int x, int y) {
this.x = x; this.x = x;
this.y = y; this.y = y;
return this; return this;
} }
public final Element centerHorizontal(int w, int h, int offsetX, int offsetY) { public Element centerHorizontal(int w, int h, int offsetX, int offsetY) {
this.x = (w - (int) (width * scale)) / 2 + offsetX; this.x = (w - (int) (width * scale)) / 2 + offsetX;
this.y = offsetY; this.y = offsetY;
return this; return this;
} }
public final Element center(int w, int h) { public Element center(int w, int h) {
this.centerOffset(w, h, 0, 0); this.centerOffset(w, h, 0, 0);
return this; return this;
} }
public final Element centerOffset(int w, int h, int offsetX, int offsetY) { public Element centerOffset(int w, int h, int offsetX, int offsetY) {
this.x = (w - (int) (width * scale)) / 2 + offsetX; this.x = (w - (int) (width * scale)) / 2 + offsetX;
this.y = (h - (int) (height * scale)) / 2 + offsetY; this.y = (h - (int) (height * scale)) / 2 + offsetY;
return this; return this;
} }
public final Element animation(Animation animation) { public Element animation(Animation animation) {
this.animation = animation; this.animation = animation;
return this; return this;
} }
public final Element animation(Animation animation, Function<Double, Double> curve) { public Element animation(Animation animation, Function<Double, Double> curve) {
this.animation = animation; this.animation = animation;
this.curve = curve; this.curve = curve;
return this; return this;
@@ -21,6 +21,7 @@ import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.item.ItemRenderState; import net.minecraft.client.render.item.ItemRenderState;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.util.Window; import net.minecraft.client.util.Window;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
@@ -36,7 +37,7 @@ import net.minecraft.world.World;
public class RenderScope { public class RenderScope {
public MatrixStack matrices; public MatrixStack matrices;
public VertexConsumerProvider.Immediate vertexConsumers; public VertexConsumerProvider.Immediate vertexConsumers;
private Function<Identifier, RenderLayer> renderLayers; // private Function<Identifier, RenderLayer> renderLayers;
private ScissorStack scissorStack = new ScissorStack(); private ScissorStack scissorStack = new ScissorStack();
private int opacity = 255 << 24; private int opacity = 255 << 24;
private final ItemRenderState itemRenderState; private final ItemRenderState itemRenderState;
@@ -60,7 +61,7 @@ public class RenderScope {
} }
public void setRenderLayer(Function<Identifier, RenderLayer> renderLayers) { public void setRenderLayer(Function<Identifier, RenderLayer> renderLayers) {
this.renderLayers = renderLayers; // this.renderLayers = renderLayers;
} }
public void drawRect(int x, int y, int width, int height, int color) { public void drawRect(int x, int y, int width, int height, int color) {
@@ -92,20 +93,22 @@ public class RenderScope {
vertexConsumer.vertex(matrix4f, (float) x2, (float) y1, 0).color(color); vertexConsumer.vertex(matrix4f, (float) x2, (float) y1, 0).color(color);
} }
public void drawText(String text, int x, int y, boolean bold, int color) { public void drawText(String text, int x, int y, int font, int color) {
drawText(1.0f, text, x, y, bold, color); drawText(1.0f, text, x, y, font, color);
} }
public void drawText(float scale, String text, int x, int y, boolean bold, int color) { public void drawText(float scale, String text, int x, int y, int font, int color) {
if (font == 0) {
scale *= 2;
}
int i = 0; int i = 0;
for (String line : text.split("\n")) { for (String line : text.split("\n")) {
color = getColor(color); color = getColor(color);
Identifier font = bold ? Fonts.INTER_BOLD : Fonts.INTER;
matrices.push(); matrices.push();
matrices.translate(x, y + (i * Fonts.getHeight()), 0); matrices.translate(x, y + (i * Fonts.getHeight()), 0);
matrices.scale(scale, scale, 1.0f); matrices.scale(scale, scale, 1.0f);
TextRenderer textRenderer = SaturnClient.client.textRenderer; TextRenderer textRenderer = SaturnClient.client.textRenderer;
textRenderer.draw(Fonts.setFont(line, font), 0, 7, color, false, this.matrices.peek().getPositionMatrix(), textRenderer.draw(Fonts.setFont(line, Fonts.getFont(font)), 0, font == 0 ? 1: 7, color, false, this.matrices.peek().getPositionMatrix(),
this.vertexConsumers, TextLayerType.NORMAL, 0, 15728880); this.vertexConsumers, TextLayerType.NORMAL, 0, 15728880);
matrices.pop(); matrices.pop();
i++; i++;
@@ -179,7 +182,7 @@ public class RenderScope {
public int getScaledWindowWidth() { public int getScaledWindowWidth() {
return SaturnClient.client.getWindow().getScaledWidth(); return SaturnClient.client.getWindow().getScaledWidth();
} }
public int getScaledWindowHeight() { public int getScaledWindowHeight() {
return SaturnClient.client.getWindow().getScaledHeight(); return SaturnClient.client.getWindow().getScaledHeight();
@@ -209,31 +212,31 @@ public class RenderScope {
matrices.push(); matrices.push();
matrices.scale(0.25f, 0.25f, 1.0f); matrices.scale(0.25f, 0.25f, 1.0f);
RenderSystem.setShaderTexture(0, sprite); RenderSystem.setShaderTexture(0, sprite);
RenderLayer renderLayer = (RenderLayer)renderLayers.apply(sprite); RenderLayer renderLayer = (RenderLayer)RenderLayer.getGuiTextured(sprite);
Matrix4f matrix4f = this.matrices.peek().getPositionMatrix(); Matrix4f matrix4f = this.matrices.peek().getPositionMatrix();
VertexConsumer vertexConsumer = this.vertexConsumers.getBuffer(renderLayer); VertexConsumer vertexConsumer = this.vertexConsumers.getBuffer(renderLayer);
vertexConsumer.vertex(matrix4f, (float)x1, (float)y1, 0.0F).texture(u1, v1).color(color); vertexConsumer.vertex(matrix4f, (float)x1, (float)y1, 0.0F).texture(u1, v1).color(color);
vertexConsumer.vertex(matrix4f, (float)x1, (float)y2, 0.0F).texture(u1, v2).color(color); vertexConsumer.vertex(matrix4f, (float)x1, (float)y2, 0.0F).texture(u1, v2).color(color);
vertexConsumer.vertex(matrix4f, (float)x2, (float)y2, 0.0F).texture(u2, v2).color(color); vertexConsumer.vertex(matrix4f, (float)x2, (float)y2, 0.0F).texture(u2, v2).color(color);
vertexConsumer.vertex(matrix4f, (float)x2, (float)y1, 0.0F).texture(u2, v1).color(color); vertexConsumer.vertex(matrix4f, (float)x2, (float)y1, 0.0F).texture(u2, v1).color(color);
matrices.pop(); matrices.pop();
} }
public void enableScissor(int x1, int y1, int x2, int y2) { public void enableScissor(int x1, int y1, int x2, int y2) {
ScreenRect screenRect = (new ScreenRect(x1, y1, x2 - x1, y2 - y1)).transform(this.matrices.peek().getPositionMatrix()); ScreenRect screenRect = (new ScreenRect(x1, y1, x2 - x1, y2 - y1)).transform(this.matrices.peek().getPositionMatrix());
this.setScissor(this.scissorStack.push(screenRect)); this.setScissor(this.scissorStack.push(screenRect));
} }
public void disableScissor() { public void disableScissor() {
this.setScissor(this.scissorStack.pop()); this.setScissor(this.scissorStack.pop());
} }
public boolean scissorContains(int x, int y) { public boolean scissorContains(int x, int y) {
return this.scissorStack.containsPoint(x, y); return this.scissorStack.containsPoint(x, y);
} }
private void setScissor(@Nullable ScreenRect rect) { private void setScissor(@Nullable ScreenRect rect) {
this.draw(); this.draw();
if (rect != null) { if (rect != null) {
Window window = SaturnClient.client.getWindow(); Window window = SaturnClient.client.getWindow();
@@ -290,68 +293,78 @@ public class RenderScope {
} }
public void drawItem(ItemStack item, int x, int y) { public void drawItem(ItemStack item, int x, int y) {
this.drawItem(SaturnClient.client.player, SaturnClient.client.world, item, x, y, 0); this.drawItem(SaturnClient.client.player, SaturnClient.client.world, item, x, y, 0);
} }
public void drawItem(ItemStack stack, int x, int y, int seed) { public void drawItem(ItemStack stack, int x, int y, int seed) {
this.drawItem(SaturnClient.client.player, SaturnClient.client.world, stack, x, y, seed); this.drawItem(SaturnClient.client.player, SaturnClient.client.world, stack, x, y, seed);
} }
public void drawItem(ItemStack stack, int x, int y, int seed, int z) { public void drawItem(ItemStack stack, int x, int y, int seed, int z) {
this.drawItem(SaturnClient.client.player, SaturnClient.client.world, stack, x, y, seed, z); this.drawItem(SaturnClient.client.player, SaturnClient.client.world, stack, x, y, seed, z);
} }
public void drawItemWithoutEntity(ItemStack stack, int x, int y) { public void drawItemWithoutEntity(ItemStack stack, int x, int y) {
this.drawItemWithoutEntity(stack, x, y, 0); this.drawItemWithoutEntity(stack, x, y, 0);
} }
public void drawItemWithoutEntity(ItemStack stack, int x, int y, int seed) { public void drawItemWithoutEntity(ItemStack stack, int x, int y, int seed) {
this.drawItem((LivingEntity)null, SaturnClient.client.world, stack, x, y, seed); this.drawItem((LivingEntity)null, SaturnClient.client.world, stack, x, y, seed);
} }
public void drawItem(LivingEntity entity, ItemStack stack, int x, int y, int seed) { public void drawItem(LivingEntity entity, ItemStack stack, int x, int y, int seed) {
this.drawItem(entity, entity.getWorld(), stack, x, y, seed); this.drawItem(entity, entity.getWorld(), stack, x, y, seed);
} }
private void drawItem(@Nullable LivingEntity entity, @Nullable World world, ItemStack stack, int x, int y, int seed) { private void drawItem(@Nullable LivingEntity entity, @Nullable World world, ItemStack stack, int x, int y, int seed) {
this.drawItem(entity, world, stack, x, y, seed, 0); this.drawItem(entity, world, stack, x, y, seed, 0);
} }
private void drawItem(@Nullable LivingEntity entity, @Nullable World world, ItemStack stack, int x, int y, int seed, int z) { private void drawItem(@Nullable LivingEntity entity, @Nullable World world, ItemStack stack, int x, int y, int seed, int z) {
if (!stack.isEmpty()) { if (!stack.isEmpty()) {
SaturnClient.client.getItemModelManager().update(this.itemRenderState, stack, ModelTransformationMode.GUI, false, world, entity, seed); SaturnClient.client.getItemModelManager().update(this.itemRenderState, stack, ModelTransformationMode.GUI, false, world, entity, seed);
this.matrices.push(); this.matrices.push();
this.matrices.translate((float)(x + 8), (float)(y + 8), (float)(150 + (this.itemRenderState.hasDepth() ? z : 0))); this.matrices.translate((float)(x + 8), (float)(y + 8), (float)(150 + (this.itemRenderState.hasDepth() ? z : 0)));
try { try {
this.matrices.scale(16.0F, -16.0F, 16.0F); this.matrices.scale(16.0F, -16.0F, 16.0F);
boolean bl = !this.itemRenderState.isSideLit(); boolean bl = !this.itemRenderState.isSideLit();
if (bl) { if (bl) {
this.draw(); this.draw();
DiffuseLighting.disableGuiDepthLighting(); DiffuseLighting.disableGuiDepthLighting();
}
this.itemRenderState.render(this.matrices, this.vertexConsumers, 15728880, OverlayTexture.DEFAULT_UV);
this.draw();
if (bl) {
DiffuseLighting.enableGuiDepthLighting();
}
} catch (Throwable var11) {
CrashReport crashReport = CrashReport.create(var11, "Rendering item");
CrashReportSection crashReportSection = crashReport.addElement("Item being rendered");
crashReportSection.add("Item Type", () -> {
return String.valueOf(stack.getItem());
});
crashReportSection.add("Item Components", () -> {
return String.valueOf(stack.getComponents());
});
crashReportSection.add("Item Foil", () -> {
return String.valueOf(stack.hasGlint());
});
throw new CrashException(crashReport);
} }
this.itemRenderState.render(this.matrices, this.vertexConsumers, 15728880, OverlayTexture.DEFAULT_UV); this.matrices.pop();
this.draw(); }
if (bl) { }
DiffuseLighting.enableGuiDepthLighting();
}
} catch (Throwable var11) {
CrashReport crashReport = CrashReport.create(var11, "Rendering item");
CrashReportSection crashReportSection = crashReport.addElement("Item being rendered");
crashReportSection.add("Item Type", () -> {
return String.valueOf(stack.getItem());
});
crashReportSection.add("Item Components", () -> {
return String.valueOf(stack.getComponents());
});
crashReportSection.add("Item Foil", () -> {
return String.valueOf(stack.hasGlint());
});
throw new CrashException(crashReport);
}
this.matrices.pop(); public void drawSpriteStretched(Sprite sprite, int x, int y, int width, int height) {
} this.drawSpriteStretched(sprite, x, y, width, height, -1);
} }
public void drawSpriteStretched(Sprite sprite, int x, int y, int width, int height, int color) {
if (width != 0 && height != 0) {
this.drawTexturedQuad(sprite.getAtlasId(), x, x + width, y, y + height, sprite.getMinU(), sprite.getMaxU(), sprite.getMinV(), sprite.getMaxV(), color);
}
}
} }
@@ -5,6 +5,7 @@ import java.util.List;
import org.saturnclient.saturnclient.mixin.DrawContextAccessor; import org.saturnclient.saturnclient.mixin.DrawContextAccessor;
import org.saturnclient.ui2.anim.Animation; import org.saturnclient.ui2.anim.Animation;
import org.saturnclient.ui2.anim.SlideXAbsolute;
import org.saturnclient.ui2.components.ElementRenderer; import org.saturnclient.ui2.components.ElementRenderer;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
@@ -50,6 +51,25 @@ public abstract class SaturnScreen extends Screen {
element.animation.tick(progress, element); element.animation.tick(progress, element);
}, element.animation.duration); }, element.animation.duration);
} }
if (element.duration != null) {
new Thread(() -> {
try {
Animation fadeOut = new SlideXAbsolute(700, -(width - element.x));
Thread.sleep(element.duration);
fadeOut.init(element);
Animation.executeSync((Float progress) -> {
fadeOut.tick(progress, element);
}, fadeOut.duration);
synchronized (elements) {
elements.remove(element);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
} }
@Override @Override
@@ -93,7 +113,7 @@ public abstract class SaturnScreen extends Screen {
renderScope.matrices.scale(0.5f, 0.5f, 0.5f); renderScope.matrices.scale(0.5f, 0.5f, 0.5f);
ElementRenderer.render(elements, renderScope, mouseX, mouseY); ElementRenderer.render(new ArrayList<>(elements), renderScope, mouseX, mouseY);
renderScope.matrices.pop(); renderScope.matrices.pop();
} }
@@ -1,6 +1,9 @@
package org.saturnclient.ui2; package org.saturnclient.ui2;
import java.util.List;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
import org.saturnclient.saturnclient.SaturnClient;
public class Utils { public class Utils {
public static boolean isHovering(int mouseX, int mouseY, int elementWidth, int elementHeight, float elementScale) { public static boolean isHovering(int mouseX, int mouseY, int elementWidth, int elementHeight, float elementScale) {
@@ -44,4 +47,9 @@ public class Utils {
default -> '\0'; default -> '\0';
}; };
} }
public static <T> T getOrNull(List<T> list, int index) {
SaturnClient.LOGGER.info("Accessing index {} in list of size {}", index, list.size());
return (index >= 0 && index < list.size()) ? list.get(index) : null;
}
} }
@@ -44,4 +44,32 @@ public abstract class Animation {
} }
}).start(); }).start();
} }
public static void executeSync(Consumer<Float> tick, int duration) {
Function<Double, Double> curveFunction = Curve::easeInOutCubic;
float progress = 0.0f;
double incremental = (1000 - duration) / 10000.0;
for (int i = 0; i <= 100; i++) {
float newProgress = (float) (double) curveFunction.apply(i / 100.0);
while (Math.abs(newProgress - progress) > 1e-6) {
if (progress < newProgress) {
progress += incremental;
if (progress > newProgress) progress = newProgress;
} else {
progress -= incremental;
if (progress < newProgress) progress = newProgress;
}
tick.accept(newProgress);
try {
Thread.sleep(duration / 100);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
} }
@@ -0,0 +1,22 @@
package org.saturnclient.ui2.anim;
import org.saturnclient.ui2.Element;
public class FadeOut extends Animation {
float targetOpacity;
public FadeOut(int duration) {
super(duration);
}
@Override
public void tick(float progress, Element element) {
element.opacity = targetOpacity - progress;
}
@Override
public void init(Element element) {
targetOpacity = element.opacity;
// element.opacity = 1.0f;
}
}
@@ -0,0 +1,36 @@
package org.saturnclient.ui2.anim;
import org.saturnclient.ui2.Element;
public class SlideX extends Animation {
int offset = 20;
int maxOffset = 20;
int elementX;
public SlideX(int duration) {
super(duration);
}
public SlideX(int duration, int offset) {
super(duration);
this.offset = offset;
this.maxOffset = offset;
}
public SlideX(int duration, int offset, int maxOffset) {
super(duration);
this.offset = offset;
this.maxOffset = maxOffset; // ✅ fixed
}
@Override
public void tick(float progress, Element element) {
element.x = elementX + (int) (offset * progress);
}
@Override
public void init(Element element) {
element.x -= offset;
elementX = element.x;
}
}
@@ -0,0 +1,35 @@
package org.saturnclient.ui2.anim;
import org.saturnclient.ui2.Element;
public class SlideXAbsolute extends Animation {
int offset = 20;
int maxOffset = 20;
int elementX;
public SlideXAbsolute(int duration) {
super(duration);
}
public SlideXAbsolute(int duration, int offset) {
super(duration);
this.offset = offset;
this.maxOffset = offset;
}
public SlideXAbsolute(int duration, int offset, int maxOffset) {
super(duration);
this.offset = offset;
this.maxOffset = maxOffset;
}
@Override
public void tick(float progress, Element element) {
element.x = elementX + (int) (offset * progress);
}
@Override
public void init(Element element) {
elementX = element.x;
}
}
@@ -11,10 +11,10 @@ import net.minecraft.util.Identifier;
public class CosmeticPreview extends Element { public class CosmeticPreview extends Element {
private static ThemeManager theme = new ThemeManager("CosmeticPreview", "selected", "hovering"); private static ThemeManager theme = new ThemeManager("CosmeticPreview", "selected", "hovering");
private static Property<Integer> bgColor = theme.property("bg-color", new Property<Integer>(0xAA000000)); private static Property<Integer> bgColor = theme.property("bg-color", Property.color(0x89000000));
private static Property<Integer> fgColor = theme.property("fg-color", new Property<Integer>(0xFFFFFFFF)); private static Property<Integer> fgColor = theme.property("fg-color", Property.color(0xFFFFFFFF));
private static Property<Integer> padding = theme.property("padding", new Property<Integer>(14)); private static Property<Integer> padding = theme.property("padding", Property.integer(14));
private static Property<Integer> cornerRadius = theme.property("corner-radius", new Property<Integer>(10)); private static Property<Integer> cornerRadius = theme.property("corner-radius", Property.integer(10));
static {} static {}
@@ -16,13 +16,14 @@ import net.minecraft.client.render.RenderLayer;
public class SaturnModule extends Element { public class SaturnModule extends Element {
private static ThemeManager theme = new ThemeManager("Module", "enabled", "hovering"); private static ThemeManager theme = new ThemeManager("Module", "enabled", "hovering");
private static Property<Integer> bgColor = theme.property("bg", new Property<>(0xFF1d202d)); private static Property<Integer> bgColor = theme.property("bg", Property.color(0xFF1d202d));
private static Property<Integer> fgColor = theme.property("fg", new Property<>(0xFFA1A2B8)); private static Property<Integer> fgColor = theme.property("fg", Property.color(0xFFA1A2B8));
private static Property<Integer> iconFg = theme.property("icon-fg", new Property<>(0xFFA1A2B8)); private static Property<Integer> iconFg = theme.property("icon-fg", Property.color(0xFFA1A2B8));
private static Property<Integer> iconBg = theme.property("icon-bg", new Property<>(0xFF2e3248)); private static Property<Integer> iconBg = theme.property("icon-bg", Property.color(0xFF2e3248));
private static Property<Integer> tagBg = theme.property("tag-bg", new Property<>(0xFF2e3248)); private static Property<Integer> tagBg = theme.property("tag-bg", Property.color(0xFF2e3248));
private static Property<Integer> iconRadius = theme.property("icon-radius", new Property<>(10)); private static Property<Integer> iconRadius = theme.property("icon-radius", Property.color(10));
private static Property<Integer> radius = theme.property("radius", new Property<>(10)); private static Property<Integer> font = theme.property("font", Property.font(1));
private static Property<Integer> radius = theme.property("radius", Property.color(10));
static { static {
theme.propertyStateDefault("enabled", "bg", 0xFF1d202d); theme.propertyStateDefault("enabled", "bg", 0xFF1d202d);
@@ -64,15 +65,15 @@ public class SaturnModule extends Element {
renderScope.drawTexture(mod.getIconTexture(), p + (p / 2), p + (p / 2), 0, 0, h - p, h - p, iconFg.value); renderScope.drawTexture(mod.getIconTexture(), p + (p / 2), p + (p / 2), 0, 0, h - p, h - p, iconFg.value);
renderScope.drawText(0.6f, mod.getName(), p+h+4, p + 1, true, fgColor.value); renderScope.drawText(0.6f, mod.getName(), p+h+4, p + 1, font.value, fgColor.value);
renderScope.drawText(0.35f, mod.getVersion(), width - p - (int) (Fonts.getWidth(mod.getVersion(), false) * 0.35f), p + 1, false, fgColor.value); renderScope.drawText(0.35f, mod.getVersion(), width - p - (int) (Fonts.getWidth(mod.getVersion(), font.value) * 0.35f), p + 1, font.value, fgColor.value);
int xt = p + h + 4; int xt = p + h + 4;
for (String tag : mod.getTags()) { for (String tag : mod.getTags()) {
int xtb = (int) (Fonts.getWidth(tag, false) * 0.4f); int xtb = (int) (Fonts.getWidth(tag, font.value) * 0.4f);
renderScope.drawRoundedRectangle(xt, p + (h/2), xtb + 6, 12, 5, tagBg.value); renderScope.drawRoundedRectangle(xt, p + (h/2), xtb + 6, 12, 5, tagBg.value);
renderScope.drawText(0.4f, tag, xt+2, p + (h/2) + 3, false, fgColor.value); renderScope.drawText(0.4f, tag, xt+2, p + (h/2) + 3, font.value, fgColor.value);
xt += xtb + 9; xt += xtb + 9;
} }
@@ -1,6 +1,7 @@
package org.saturnclient.ui2.components; package org.saturnclient.ui2.components;
import org.saturnclient.saturnclient.SaturnClient; import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.saturnclient.config.Property; import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.saturnclient.config.ThemeManager; import org.saturnclient.saturnclient.config.ThemeManager;
import org.saturnclient.ui2.resources.Textures; import org.saturnclient.ui2.resources.Textures;
@@ -8,23 +9,23 @@ import org.saturnclient.ui2.Element;
import org.saturnclient.ui2.ElementContext; import org.saturnclient.ui2.ElementContext;
import org.saturnclient.ui2.RenderScope; import org.saturnclient.ui2.RenderScope;
import org.saturnclient.ui2.Utils; import org.saturnclient.ui2.Utils;
import org.saturnclient.ui2.screens.CloakMenu; import org.saturnclient.ui2.screens.ConfigEditor;
import org.saturnclient.ui2.screens.HatMenu;
import org.saturnclient.ui2.screens.ModMenu; import org.saturnclient.ui2.screens.ModMenu;
import org.saturnclient.ui2.screens.SaturnConfigEditor; import org.saturnclient.ui2.screens.cosmetics.CloakMenu;
import org.saturnclient.ui2.screens.store.CloakStore;
import net.minecraft.client.render.RenderLayer; import net.minecraft.client.render.RenderLayer;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
public class Sidebar extends Element { public class Sidebar extends Element {
private static ThemeManager theme = new ThemeManager("SideBar", "hovering"); private static ThemeManager theme = new ThemeManager("SideBar", "hovering");
private static Property<Integer> bgColor = theme.property("bg-color", new Property<Integer>(0x90000000)); private static Property<Integer> bgColor = theme.property("bg-color", Property.color(0x90000000));
private static Property<Integer> iconFg = theme.property("icon-fg", new Property<Integer>(-1)); private static Property<Integer> iconFg = theme.property("icon-fg", Property.color(0xFFFFFFFF));
private static Property<Integer> iconBg = theme.property("icon-bg", new Property<Integer>(0x00000000)); private static Property<Integer> iconBg = theme.property("icon-bg", Property.color(0x00000000));
private static Property<Integer> cornerRadius = theme.property("corner-radius", new Property<Integer>(10)); private static Property<Integer> cornerRadius = theme.property("corner-radius", Property.integer(10));
private static Property<Integer> iconRadius = theme.property("icon-radius", new Property<Integer>(10)); private static Property<Integer> iconRadius = theme.property("icon-radius", Property.integer(10));
private static Property<Integer> padding = theme.property("padding", new Property<Integer>(10)); private static Property<Integer> padding = theme.property("padding", Property.integer(10));
static { static {
theme.propertyStateDefault("hovering", "icon-bg", -7643914); theme.propertyStateDefault("hovering", "icon-bg", -7643914);
@@ -48,20 +49,20 @@ public class Sidebar extends Element {
SaturnClient.client.setScreen(new ModMenu()); SaturnClient.client.setScreen(new ModMenu());
}, false), }, false),
new Sidebar.SidebarComponent(Textures.SETTINGS, () -> { new Sidebar.SidebarComponent(Textures.SETTINGS, () -> {
SaturnClient.client.setScreen(new SaturnConfigEditor()); SaturnClient.client.setScreen(new ConfigEditor(SaturnClientConfig.config));
}, false), }, false),
new Sidebar.SidebarComponent(Textures.CLOAK, () -> { new Sidebar.SidebarComponent(Textures.SHIRT, () -> {
SaturnClient.client.setScreen(new CloakMenu()); SaturnClient.client.setScreen(new CloakMenu());
}, false), }, false),
new Sidebar.SidebarComponent(Textures.HAT, () -> {
SaturnClient.client.setScreen(new HatMenu());
}, false),
new Sidebar.SidebarComponent(Textures.CLOSE, () -> { new Sidebar.SidebarComponent(Textures.CLOSE, () -> {
onClose.run(); onClose.run();
}, true) }, true),
new Sidebar.SidebarComponent(Textures.STORE, () -> {
SaturnClient.client.setScreen(new CloakStore());
}, true),
}; };
int active = 0; int active = 0;
@@ -77,9 +78,9 @@ public class Sidebar extends Element {
int topRow = 0; int topRow = 0;
int bottomRow = 0; int bottomRow = 0;
int sp = 30 - padding.value; int gap = 5; // 5px gap between icons
int sp = 30 - padding.value + gap;
int s = 30 - (padding.value * 2); int s = 30 - (padding.value * 2);
int s2 = s + padding.value; int s2 = s + padding.value;
renderScope.setRenderLayer(RenderLayer::getGuiTextured); renderScope.setRenderLayer(RenderLayer::getGuiTextured);
@@ -100,7 +101,7 @@ public class Sidebar extends Element {
renderScope.drawTexture(component.sprite, padding.value, y, 0, 0, s, s, iconFg.value); renderScope.drawTexture(component.sprite, padding.value, y, 0, 0, s, s, iconFg.value);
bottomRow += 1; bottomRow += 1;
} else { } else {
int y = padding.value + ((sp) * topRow); int y = padding.value + (sp * topRow);
if (ctx.isHovering(0, y - (padding.value / 2), s2, s2) || active == i) { if (ctx.isHovering(0, y - (padding.value / 2), s2, s2) || active == i) {
theme.setState("hovering"); theme.setState("hovering");
} else { } else {
@@ -120,19 +121,22 @@ public class Sidebar extends Element {
int topRow = 0; int topRow = 0;
int bottomRow = 0; int bottomRow = 0;
int sp = 30 - padding.value; int gap = 5; // same 5px gap here
int sp = 30 - padding.value + gap;
int s = 30 - (padding.value * 2); int s = 30 - (padding.value * 2);
int s2 = s + padding.value; int s2 = s + padding.value;
for (SidebarComponent component : components) { for (SidebarComponent component : components) {
if (component.end) { if (component.end) {
if (Utils.isHovering(mouseX, mouseY - (height - (sp * bottomRow) - (s * 2)), s2, s2, scale)) { int y = (height - (sp * bottomRow)) - (s * 2);
if (Utils.isHovering(mouseX - (padding.value / 2), mouseY - (y - (padding.value / 2)), s2, s2, scale)) {
component.onClick.run(); component.onClick.run();
break; break;
} }
bottomRow += 1; bottomRow += 1;
} else { } else {
if (Utils.isHovering(mouseX, mouseY - (padding.value + ((sp) * topRow)), s2, s2, scale)) { int y = padding.value + (sp * topRow);
if (Utils.isHovering(mouseX - (padding.value / 2), mouseY - (y - (padding.value / 2)), s2, s2, scale)) {
component.onClick.run(); component.onClick.run();
break; break;
} }
@@ -2,12 +2,17 @@ package org.saturnclient.ui2.components.inputs;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
import org.saturnclient.saturnclient.SaturnClient; import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.saturnclient.config.ThemeManager;
import org.saturnclient.ui2.Element; import org.saturnclient.ui2.Element;
import org.saturnclient.ui2.ElementContext; import org.saturnclient.ui2.ElementContext;
import org.saturnclient.ui2.RenderScope; import org.saturnclient.ui2.RenderScope;
import org.saturnclient.ui2.resources.Fonts; import org.saturnclient.ui2.resources.Fonts;
public abstract class Input extends Element { public abstract class Input extends Element {
private static ThemeManager theme = new ThemeManager("Input");
private static Property<Integer> font = theme.property("font", Property.font(1));
String text = ""; String text = "";
public int cursorPosition = 0; public int cursorPosition = 0;
public abstract void checkReset(); public abstract void checkReset();
@@ -66,12 +71,11 @@ public abstract class Input extends Element {
int scrollOffset = getScrollOffset(); int scrollOffset = getScrollOffset();
String visibleText = getVisibleText(scrollOffset); String visibleText = getVisibleText(scrollOffset);
int textColor = focused ? 0xFFFFFF : 0xAAAAAA; int textColor = focused ? 0xFFFFFF : 0xAAAAAA;
renderScope.drawText(0.6f, visibleText, 4, 4, false, textColor); renderScope.drawText(0.6f, visibleText, 4, 4, font.value, textColor);
if (focused) { if (focused) {
int cursorX = 4 + int cursorX = 4 +
(int) (SaturnClient.client.textRenderer.getWidth( (int) (Fonts.getWidth(visibleText.substring(0, cursorPosition - scrollOffset), font.value) * 0.6f);
Fonts.setFont(visibleText.substring(0, cursorPosition - scrollOffset))) * 0.6f);
renderScope.drawRect(cursorX, 2, 1, height - 4, 0xFFFFFFFF); renderScope.drawRect(cursorX, 2, 1, height - 4, 0xFFFFFFFF);
} }
@@ -86,7 +90,7 @@ public abstract class Input extends Element {
int maxWidth = width - 4; // Available width for text int maxWidth = width - 4; // Available width for text
while (offset < cursorPosition) { // Ensure cursor remains visible while (offset < cursorPosition) { // Ensure cursor remains visible
String visibleText = text.substring(offset, cursorPosition); String visibleText = text.substring(offset, cursorPosition);
if (SaturnClient.client.textRenderer.getWidth(Fonts.setFont(visibleText)) > maxWidth) { if (Fonts.getWidth(visibleText, font.value) > maxWidth) {
offset++; offset++;
} else { } else {
break; break;
@@ -100,8 +104,7 @@ public abstract class Input extends Element {
// Ensure text does not overflow past the available width // Ensure text does not overflow past the available width
for (int i = 1; i <= visibleText.length(); i++) { for (int i = 1; i <= visibleText.length(); i++) {
if (SaturnClient.client.textRenderer.getWidth( if (Fonts.getWidth(visibleText.substring(0, i), font.value) > width - 4) {
Fonts.setFont(visibleText.substring(0, i))) > width - 4) {
return visibleText.substring(0, i - 1); // Trim overflow return visibleText.substring(0, i - 1); // Trim overflow
} }
} }
@@ -0,0 +1,40 @@
package org.saturnclient.ui2.components.inputs;
import org.lwjgl.glfw.GLFW;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.saturnclient.config.ThemeManager;
import org.saturnclient.ui2.Element;
import org.saturnclient.ui2.ElementContext;
import org.saturnclient.ui2.RenderScope;
import org.saturnclient.ui2.resources.Fonts;
public class KeybindingSelector extends Element {
private static ThemeManager theme = new ThemeManager("Input");
private static Property<Integer> font = theme.property("font", Property.font(1));
Property<Integer> prop;
public KeybindingSelector(Property<Integer> prop) {
this.prop = prop;
this.width = 120;
this.height = Fonts.getHeight();
}
@Override
public void render(RenderScope renderScope, ElementContext ctx) {
int textColor = focused ? 0xFFFFFF : 0xAAAAAA;
renderScope.drawRoundedRectangle(0, 0, width, height, 10, 0xFF000000);
renderScope.drawText(0.6f, prop.value == -1 ? "<NONE>" :
GLFW.glfwGetKeyName(prop.value, GLFW.glfwGetKeyScancode(prop.value)).toUpperCase(),
4, 4, font.value, textColor);
}
@Override
public void keyPressed(int keyCode, int scanCode, int modifiers) {
if (keyCode == GLFW.GLFW_KEY_BACKSPACE) {
prop.value = -1;
} else {
prop.value = keyCode;
}
focused = false;
}
}
@@ -0,0 +1,49 @@
package org.saturnclient.ui2.components.inputs;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.saturnclient.config.ThemeManager;
import org.saturnclient.ui2.Element;
import org.saturnclient.ui2.ElementContext;
import org.saturnclient.ui2.RenderScope;
import org.saturnclient.ui2.Utils;
import org.saturnclient.ui2.resources.Fonts;
import net.minecraft.client.render.RenderLayer;
public class Select extends Element {
private static ThemeManager theme = new ThemeManager("Toggle");
private static Property<Integer> fgColor = theme.property("fg-color", Property.color(0xAAAAAA));
private static Property<Integer> arrowColor = theme.property("arrow-color", Property.color(0xff8B5CF6));
private static Property<Integer> font = theme.property("font", Property.font(1));
private Property<Integer> prop;
public Select(Property<Integer> prop) {
this.prop = prop;
this.width = 150;
this.height = 15;
}
@Override
public void render(RenderScope renderScope, ElementContext ctx) {
renderScope.setRenderLayer(RenderLayer::getGuiTextured);
renderScope.drawText(0.8f, "<", 0, 0, font.value, arrowColor.value);
String text = prop.getSelection();
renderScope.drawText(0.6f, text, (int) (width - ((float) Fonts.getWidth(text, font.value) * 0.6f)) / 2, 1, font.value, fgColor.value);
renderScope.drawText(0.8f, ">", width - 10, 0, font.value, arrowColor.value);
theme.setState(null);
}
@Override
public void click(int mouseX, int mouseY) {
if (Utils.isHovering(mouseX - (width - 10), mouseY, 10, height, 1.0f)) {
prop.next();
} else if (Utils.isHovering(mouseX, mouseY, 10, height, 1.0f)) {
prop.prev();
}
}
}
@@ -8,9 +8,9 @@ import org.saturnclient.ui2.RenderScope;
public class Toggle extends Element { public class Toggle extends Element {
private static ThemeManager theme = new ThemeManager("Toggle", "hovering", "enabled"); private static ThemeManager theme = new ThemeManager("Toggle", "hovering", "enabled");
private static Property<Integer> bgColor = theme.property("bg-color", new Property<Integer>(0xFF808080)); private static Property<Integer> bgColor = theme.property("bg-color", Property.color(0xFF808080));
private static Property<Integer> fgColor = theme.property("fg-color", new Property<Integer>(0xFF909090)); private static Property<Integer> fgColor = theme.property("fg-color", Property.color(0xFF909090));
private static Property<Integer> cornerRadius = theme.property("corner-radius", new Property<Integer>(30)); private static Property<Integer> cornerRadius = theme.property("corner-radius", Property.integer(30));
static { static {
theme.propertyStateDefault("enabled", "bg-color", 0xaf8B5CF6); theme.propertyStateDefault("enabled", "bg-color", 0xaf8B5CF6);
@@ -9,10 +9,10 @@ import org.saturnclient.ui2.resources.Fonts;
public class Button extends Element { public class Button extends Element {
private static ThemeManager theme = new ThemeManager("Button", "hovering"); private static ThemeManager theme = new ThemeManager("Button", "hovering");
private static Property<Integer> bgColor = theme.property("bg-color", new Property<Integer>(0xFF000000)); private static Property<Integer> bgColor = theme.property("bg-color", Property.color(0xFF000000));
private static Property<Integer> fgColor = theme.property("fg-color", new Property<Integer>(0xFFFFFFFF)); private static Property<Integer> fgColor = theme.property("fg-color", Property.color(0xFFFFFFFF));
private static Property<Integer> cornerRadius = theme.property("corner-radius", new Property<Integer>(10)); private static Property<Integer> cornerRadius = theme.property("corner-radius", Property.integer(10));
private static Property<Boolean> bold = theme.property("fg-bold", new Property<Boolean>(false)); private static Property<Integer> font = theme.property("font", Property.font(1));
static { static {
theme.propertyStateDefault("hovering", "fg-color", 0xFF845eee); theme.propertyStateDefault("hovering", "fg-color", 0xFF845eee);
@@ -24,7 +24,7 @@ public class Button extends Element {
public Button(String text, Runnable onClick) { public Button(String text, Runnable onClick) {
this.text = text; this.text = text;
this.onClick = onClick; this.onClick = onClick;
this.dimensions(Fonts.getWidth(text, bold.value) + 50, 38); this.dimensions(Fonts.getWidth(text, font.value) + 50, 38);
} }
@Override @Override
@@ -37,7 +37,7 @@ public class Button extends Element {
renderScope.drawRoundedRectangle(0, 0, width, height, cornerRadius.value, bgColor.value); renderScope.drawRoundedRectangle(0, 0, width, height, cornerRadius.value, bgColor.value);
// renderScope.drawText(text, (width - Fonts.getWidth(text, font)) / 2, (height - Fonts.getHeight()) / 2, bold.value, fgColor.value); // renderScope.drawText(text, (width - Fonts.getWidth(text, font)) / 2, (height - Fonts.getHeight()) / 2, bold.value, fgColor.value);
renderScope.drawText(text, Fonts.centerX(width, text, bold.value), Fonts.centerY(height), bold.value, fgColor.value); renderScope.drawText(text, Fonts.centerX(width, text, font.value), Fonts.centerY(height), font.value, fgColor.value);
} }
@Override @Override
@@ -11,7 +11,7 @@ import net.minecraft.util.Identifier;
public class ClickableTexture extends Element { public class ClickableTexture extends Element {
private static ThemeManager theme = new ThemeManager("ClickableTexture", "hovering"); private static ThemeManager theme = new ThemeManager("ClickableTexture", "hovering");
private static Property<Integer> fgColor = theme.property("fg-color", new Property<Integer>(0xFFFFFFFF)); private static Property<Integer> fgColor = theme.property("fg-color", Property.color(0xFFFFFFFF));
Identifier sprite; Identifier sprite;
private Runnable onClick; private Runnable onClick;
@@ -0,0 +1,60 @@
package org.saturnclient.ui2.elements;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.saturnclient.config.ThemeManager;
import org.saturnclient.ui2.Element;
import org.saturnclient.ui2.ElementContext;
import org.saturnclient.ui2.RenderScope;
import org.saturnclient.ui2.anim.SlideX;
import org.saturnclient.ui2.resources.Fonts;
import org.saturnclient.ui2.resources.Textures;
public class Notification extends Element {
private static ThemeManager theme = new ThemeManager("Notification");
private static Property<Integer> bgColor = theme.property("bg-color", Property.color(0xFF000000));
private static Property<Integer> error = theme.property("error", Property.color(0xFFbf212f));
private static Property<Integer> info = theme.property("info", Property.color(0xFF264b96));
private static Property<Integer> success = theme.property("success", Property.color(0xFF27b376));
public static enum NotificationKind {
Error,
Info,
Success,
}
NotificationKind kind;
String text;
String title;
public Notification(int width, int height, NotificationKind kind, String title, String text) {
this.kind = kind;
this.text = text;
this.title = title;
this.width = (int) Math.max(Fonts.getWidth(text, 1) * 0.6f, Fonts.getWidth(title, 1)) + 20;
this.height = 50;
this.x = width - this.width - 15;
this.y = height - this.height - 15;
this.animation = new SlideX(700, -width);
this.duration = 3000;
}
@Override
public void render(RenderScope renderScope, ElementContext ctx) {
renderScope.drawRoundedRectangle(0, 0, width, height, 10, bgColor.value);
switch (kind) {
case Error:
renderScope.drawTexture(Textures.CIRCLE_X, 9, 9, 0, 0, 15, 15, error.value);
break;
case Info:
renderScope.drawTexture(Textures.INFO, 9, 9, 0, 0, 15, 15, info.value);
break;
case Success:
renderScope.drawTexture(Textures.CHECK, 9, 9, 0, 0, 15, 15, success.value);
break;
}
renderScope.drawText(0.7f, title, 32, 10, 1, -1);
renderScope.drawText(0.5f, text, 32, 28, 1, -1);
}
}
@@ -12,13 +12,13 @@ import org.saturnclient.ui2.components.ElementRenderer;
public class Scroll extends Element { public class Scroll extends Element {
private static ThemeManager theme = new ThemeManager("Scroll"); private static ThemeManager theme = new ThemeManager("Scroll");
private static Property<Integer> bgColor = theme.property("bg-color", new Property<Integer>(0x90000000)); private static Property<Integer> bgColor = theme.property("bg-color", Property.color(0x90000000));
private static Property<Integer> scrollBarColor = theme.property("scrollbar-color", new Property<Integer>(-7643914)); private static Property<Integer> scrollBarColor = theme.property("scrollbar-color", Property.color(-7643914));
private static Property<Integer> scrollBarRadius = theme.property("scrollbar-radius", new Property<Integer>(10)); private static Property<Integer> scrollBarRadius = theme.property("scrollbar-radius", Property.integer(10));
private static Property<Integer> scrollBarWidth = theme.property("scrollbar-width", new Property<Integer>(5)); private static Property<Integer> scrollBarWidth = theme.property("scrollbar-width", Property.integer(5));
private static Property<Integer> scrollBarPadding = theme.property("scrollbar-padding", new Property<Integer>(5)); private static Property<Integer> scrollBarPadding = theme.property("scrollbar-padding", Property.integer(5));
private static Property<Integer> cornerRadius = theme.property("corner-radius", new Property<Integer>(10)); private static Property<Integer> cornerRadius = theme.property("corner-radius", Property.integer(10));
int padding = 0; int padding = 0;
@@ -61,16 +61,14 @@ public class Scroll extends Element {
public void draw(Element element) { public void draw(Element element) {
children.add(element); children.add(element);
}
if (element.width > width) { @Override
width = element.width; public Element dimensions(int width, int height) {
for (Element element : children) {
maxScroll = Math.max(maxScroll, element.y + element.height - height);
} }
return super.dimensions(width, height);
if (element.height > height) {
height = element.height;
}
maxScroll = Math.max(maxScroll, element.y - maxScroll);
} }
int calculateScrollBarHeight() { int calculateScrollBarHeight() {
@@ -0,0 +1,73 @@
package org.saturnclient.ui2.elements;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.saturnclient.config.ThemeManager;
import org.saturnclient.ui2.Element;
import org.saturnclient.ui2.ElementContext;
import org.saturnclient.ui2.RenderScope;
import org.saturnclient.ui2.Utils;
import net.minecraft.util.Identifier;
public class TabMenu extends Element {
private static ThemeManager theme = new ThemeManager("TabMenu", "hovering", "selected");
private static Property<Integer> bgColor = theme.property("bg-color", Property.color(0x90000000));
private static Property<Integer> iconFg = theme.property("icon-fg", Property.color(0xFFFFFFFF));
private static Property<Integer> iconBg = theme.property("icon-bg", Property.color(0x00000000));
private static Property<Integer> cornerRadius = theme.property("corner-radius", Property.integer(10));
static {
theme.propertyStateDefault("hovering", "icon-bg", -7643914);
}
public static class TabMenuComponent {
Runnable onClick;
Identifier sprite;
public TabMenuComponent(Identifier sprite, Runnable onClick) {
this.onClick = onClick;
this.sprite = sprite;
}
}
TabMenuComponent[] components;
public int selectedScreen = 0;
public TabMenu(int active, TabMenuComponent... components) {
this.components = components;
width = 25 * components.length + 6;
height = 30;
this.selectedScreen = active;
}
@Override
public void render(RenderScope renderScope, ElementContext ctx) {
renderScope.drawRoundedRectangle(0, 0, width, height, cornerRadius.value, bgColor.value);
int col = 0;
for (TabMenuComponent component : components) {
int x = 25 * col + 5;
if (ctx.isHovering(x, 5, 20, 20) || selectedScreen == col) {
theme.setState("hovering");
}
renderScope.drawRoundedRectangle(x, 5, 20, 20, cornerRadius.value, iconBg.value);
renderScope.drawTexture(component.sprite, x + 5, 10, 0, 0, 10, 10, iconFg.value);
theme.setState(null);
col++;
}
}
@Override
public void click(int mouseX, int mouseY) {
int col = 0;
for (TabMenuComponent component : components) {
int x = 25 * col + 5;
if (Utils.isHovering(mouseX - x, mouseY - 5, 20, 20, 1.0f)) {
component.onClick.run();
}
col++;
}
}
}
@@ -5,19 +5,23 @@ import org.saturnclient.saturnclient.config.ThemeManager;
import org.saturnclient.ui2.Element; import org.saturnclient.ui2.Element;
import org.saturnclient.ui2.ElementContext; import org.saturnclient.ui2.ElementContext;
import org.saturnclient.ui2.RenderScope; import org.saturnclient.ui2.RenderScope;
import org.saturnclient.ui2.resources.Fonts;
public class Text extends Element { public class Text extends Element {
private static ThemeManager theme = new ThemeManager("Text"); private static ThemeManager theme = new ThemeManager("Text");
private static Property<Integer> fgColor = theme.property("fg-color", new Property<Integer>(0xFFFFFFFF)); private static Property<Integer> fgColor = theme.property("fg-color", Property.color(0xFFFFFFFF));
public static Property<Integer> font = theme.property("font", Property.font(1));
private String text; private String text;
public Text(String text) { public Text(String text) {
this.text = text; this.text = text;
width = Fonts.getWidth(text, font.value);
height = Fonts.getHeight();
} }
@Override @Override
public void render(RenderScope renderScope, ElementContext ctx) { public void render(RenderScope renderScope, ElementContext ctx) {
renderScope.drawText(this.text, 0, 0, false, fgColor.value); renderScope.drawText(this.text, 0, 0, font.value, fgColor.value);
} }
} }
@@ -11,10 +11,10 @@ import net.minecraft.util.Identifier;
public class TextureButton extends Element { public class TextureButton extends Element {
private static ThemeManager theme = new ThemeManager("TextureButton", "hovering"); private static ThemeManager theme = new ThemeManager("TextureButton", "hovering");
private static Property<Integer> bgColor = theme.property("bg-color", new Property<Integer>(0xFF000000)); private static Property<Integer> bgColor = theme.property("bg-color", Property.color(0xFF000000));
private static Property<Integer> fgColor = theme.property("fg-color", new Property<Integer>(0xFFFFFFFF)); private static Property<Integer> fgColor = theme.property("fg-color", Property.color(0xFFFFFFFF));
private static Property<Integer> padding = theme.property("padding", new Property<Integer>(14)); private static Property<Integer> padding = theme.property("padding", Property.integer(14));
private static Property<Integer> cornerRadius = theme.property("corner-radius", new Property<Integer>(10)); private static Property<Integer> cornerRadius = theme.property("corner-radius", Property.integer(10));
static { static {
@@ -8,12 +8,16 @@ import net.minecraft.util.Identifier;
public class Fonts { public class Fonts {
public static final Identifier INTER = Identifier.of("saturnclient", "inter"); public static final Identifier INTER = Identifier.of("saturnclient", "inter");
public static final Identifier INTER_BOLD = Identifier.of("saturnclient", "inter_bold"); public static final Identifier INTER_BOLD = Identifier.of("saturnclient", "inter_bold");
public static final Identifier DEFAULT = Identifier.ofVanilla("default");
public static Identifier getFont(boolean bold) { public static Identifier getFont(int font) {
if (bold) { switch (font) {
return INTER_BOLD; case 0:
} else { return DEFAULT;
return INTER; case 1:
return INTER;
default:
return INTER_BOLD;
} }
} }
@@ -22,35 +26,28 @@ public class Fonts {
Style.EMPTY.withFont(font)); Style.EMPTY.withFont(font));
} }
public static Text setFont(String text, boolean bold) { public static int getWidth(String text, int font) {
return Text.literal(text).setStyle( int w = 0;
Style.EMPTY.withFont(bold ? INTER_BOLD : INTER)); for (String line : text.split("\n")) {
w = Math.max(w, getWidth(line, getFont(font)));
}
if (font == 0) {
return w * 2;
} else {
return w;
}
} }
public static Text setFont(String text) { private static int getWidth(String text, Identifier font) {
return Text.literal(text).setStyle( return SaturnClient.client.textRenderer.getWidth(setFont(text, font));
Style.EMPTY.withFont(INTER));
}
// public static int getWidth(String text, Identifier font) {
// return SaturnClient.client.textRenderer.getWidth(Text.literal(text).setStyle(
// Style.EMPTY.withFont(font)));
// }
// public static int getHeight() {
// return SaturnClient.client.textRenderer.fontHeight;
// }
public static int getWidth(String text, boolean bold) {
return SaturnClient.client.textRenderer.getWidth(setFont(text, getFont(bold)));
} }
public static int getHeight() { public static int getHeight() {
return 18; return 18;
} }
public static int centerX(int w, String text, boolean bold) { public static int centerX(int w, String text, int font) {
return (w - Fonts.getWidth(text, bold)) / 2; return (w - Fonts.getWidth(text, font)) / 2;
} }
public static int centerY(int h) { public static int centerY(int h) {
@@ -15,11 +15,19 @@ public class Textures {
public static final Identifier RESET = Identifier.of("saturnclient", "textures/gui/components/reset.png"); public static final Identifier RESET = Identifier.of("saturnclient", "textures/gui/components/reset.png");
public static final Identifier TOGGLE_INDICATOR = Identifier.of("saturnclient", public static final Identifier TOGGLE_INDICATOR = Identifier.of("saturnclient",
"textures/gui/components/toggle_indicator.png"); "textures/gui/components/toggle_indicator.png");
public static final Identifier TOGGLE_BG = Identifier.of("saturnclient", "textures/gui/components/toggle_bg.png"); public static final Identifier LEFT = Identifier.of("saturnclient", "textures/gui/components/left.png");
public static final Identifier RIGHT = Identifier.of("saturnclient", "textures/gui/components/right.png");
public static final Identifier STORE = Identifier.of("saturnclient", "textures/gui/components/store.png");
public static final Identifier COINS = Identifier.of("saturnclient", "textures/gui/components/coins.png");
public static final Identifier SHIRT = Identifier.of("saturnclient", "textures/gui/components/shirt.png");
public static final Identifier CIRCLE_X = Identifier.of("saturnclient", "textures/gui/components/circle_x.png");
public static final Identifier INFO = Identifier.of("saturnclient", "textures/gui/components/info.png");
public static final Identifier CHECK = Identifier.of("saturnclient", "textures/gui/components/check.png");
public static final Identifier LOGO = Identifier.of("saturnclient", "textures/logo/logo.png"); public static final Identifier LOGO = Identifier.of("saturnclient", "textures/logo/logo.png");
public static final Identifier REALISTIC_LOGO = Identifier.of("saturnclient", "textures/logo/realistic.png"); public static final Identifier REALISTIC_LOGO = Identifier.of("saturnclient", "textures/logo/realistic.png");
public static final Identifier LOGO_TEXT = Identifier.of("saturnclient", "textures/logo/text.png"); public static final Identifier LOGO_TEXT = Identifier.of("saturnclient", "textures/logo/text.png");
public static final Identifier LOGO_TEXT_BIG = Identifier.of("saturnclient", "textures/logo/text_big.png");
// Widgets // Widgets
public static final Identifier BUTTON_BORDER = Identifier.of("saturnclient", "button_border"); public static final Identifier BUTTON_BORDER = Identifier.of("saturnclient", "button_border");
@@ -39,7 +47,12 @@ public class Textures {
return Identifier.of("saturnclient", "textures/gui/hat/" + (hat.isEmpty() ? "none" : hat) + ".png"); return Identifier.of("saturnclient", "textures/gui/hat/" + (hat.isEmpty() ? "none" : hat) + ".png");
} }
public static Identifier getEmotePreview(String emote) {
return Identifier.of("saturnclient", "textures/gui/emote/" + (emote == null ? "none" : emote) + ".png");
}
public static Identifier getModIcon(String modId) { public static Identifier getModIcon(String modId) {
return Identifier.of("saturnclient", "textures/gui/mod/" + modId + ".png"); return Identifier.of("saturnclient", "textures/gui/mod/" + modId + ".png");
} }
} }
@@ -9,6 +9,8 @@ import org.saturnclient.ui2.components.Sidebar;
import org.saturnclient.ui2.components.inputs.FloatInput; import org.saturnclient.ui2.components.inputs.FloatInput;
import org.saturnclient.ui2.components.inputs.HexInput; import org.saturnclient.ui2.components.inputs.HexInput;
import org.saturnclient.ui2.components.inputs.IntInput; import org.saturnclient.ui2.components.inputs.IntInput;
import org.saturnclient.ui2.components.inputs.KeybindingSelector;
import org.saturnclient.ui2.components.inputs.Select;
import org.saturnclient.ui2.components.inputs.Toggle; import org.saturnclient.ui2.components.inputs.Toggle;
import org.saturnclient.ui2.elements.Scroll; import org.saturnclient.ui2.elements.Scroll;
import org.saturnclient.ui2.elements.Text; import org.saturnclient.ui2.elements.Text;
@@ -36,7 +38,7 @@ public class ConfigEditor extends SaturnScreen {
draw(scroll.dimensions(scrollWidth, 350).center(width, height)); draw(scroll.dimensions(scrollWidth, 350).center(width, height));
draw(new Sidebar(0, this::close).centerOffset(width, height, -(scrollWidth / 2 + 20), 0)); draw(new Sidebar(1, this::close).centerOffset(width, height, -(scrollWidth / 2 + 20), 0));
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -59,7 +61,7 @@ public class ConfigEditor extends SaturnScreen {
configScroll.draw( configScroll.draw(
new Text( new Text(
propName propName
).position(Fonts.centerX(520, propName, false), modY + 1).scale(0.7f)); ).position(Fonts.centerX(520, propName, Text.font.value), modY + 1).scale(0.7f));
} else { } else {
configScroll.draw( configScroll.draw(
new Text( new Text(
@@ -91,6 +93,15 @@ public class ConfigEditor extends SaturnScreen {
Map<String, Property<?>> nestedProperties = (Map<String, Property<?>>) prop.value; Map<String, Property<?>> nestedProperties = (Map<String, Property<?>>) prop.value;
row = drawProperties(configScroll, nestedProperties, row + 1, col, w); row = drawProperties(configScroll, nestedProperties, row + 1, col, w);
break; break;
case SELECT:
configScroll.draw(new Select((Property<Integer>) prop).position(w / 2, modY));
break;
case KEYBINDING:
configScroll.draw(new KeybindingSelector((Property<Integer>) prop).position(w / 2, modY));
break;
case STRING: case STRING:
} }
@@ -0,0 +1,87 @@
package org.saturnclient.ui2.screens;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.SaturnClientConfig;
// import org.saturnclient.saturnclient.auth.Auth;
import org.saturnclient.saturnclient.cosmetics.Emotes;
import org.saturnclient.ui2.SaturnScreen;
import org.saturnclient.ui2.Utils;
import org.saturnclient.ui2.anim.Fade;
import org.saturnclient.ui2.anim.SlideY;
import org.saturnclient.ui2.elements.ImageTexture;
import org.saturnclient.ui2.elements.TextureButton;
import org.saturnclient.ui2.resources.Textures;
import dev.kosmx.playerAnim.api.layered.AnimationStack;
import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationAccess;
import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationRegistry;
import net.minecraft.util.Identifier;
public class EmoteWheel extends SaturnScreen {
int page = 1;
public EmoteWheel() {
super("Emote Wheel");
}
@Override
public void ui() {
int row = 0;
int col = 0;
draw(new ImageTexture(Textures.LOGO_TEXT).dimensions(98, 10).centerOffset(width, height, 0, -105).animation(new Fade(700)));
draw(new ImageTexture(SaturnClientConfig.getLogo()).dimensions(98, 98).centerOffset(width, height, 0, -149).animation(new SlideY(700, -20)));
draw(new TextureButton(Textures.LEFT, () -> {
if (page > 1) {
page--;
elements.clear();
ui();
}
}).dimensions(30, 30).centerOffset(width, height, -20, 45).animation(new Fade(700)));
draw(new TextureButton(Textures.RIGHT, () -> {
if ((8 * page) < Emotes.availableEmotes.size()) {
page++;
elements.clear();
ui();
}
}).dimensions(30, 30).centerOffset(width, height, 20, 45).animation(new Fade(700)));
while (row < 3) {
int idx = (row * 3 + col) * page;
if (row == 1 && col == 1) {
col++;
}
String emote = Utils.getOrNull(Emotes.availableEmotes, idx);
draw(new TextureButton(Textures.getEmotePreview(emote), () -> {
if (emote == null) {
return;
}
AnimationStack animationStack = PlayerAnimationAccess.getPlayerAnimLayer(SaturnClient.client.player);
if (animationStack.isActive() && animationStack.getPriority() == 1000) {
animationStack.removeLayer(1000);
// Auth.cancelEmote();
}
animationStack.addAnimLayer(1000, PlayerAnimationRegistry.getAnimation(Identifier.of("saturnclient", emote)).playAnimation());
// Auth.sendEmote(emote);
close();
}).dimensions(70, 70).centerOffset(width, height, -80 + (col * 80), -35 + (row * 80)).animation(new Fade(700)));
if (col < 2) {
col++;
} else {
col = 0;
row++;
}
}
}
@Override
public boolean shouldPause() {
return false;
}
}
@@ -5,7 +5,9 @@ import org.saturnclient.modules.Module;
import org.saturnclient.ui2.SaturnScreen; import org.saturnclient.ui2.SaturnScreen;
import org.saturnclient.ui2.components.SaturnModule; import org.saturnclient.ui2.components.SaturnModule;
import org.saturnclient.ui2.components.Sidebar; import org.saturnclient.ui2.components.Sidebar;
import org.saturnclient.ui2.elements.ImageTexture;
import org.saturnclient.ui2.elements.Scroll; import org.saturnclient.ui2.elements.Scroll;
import org.saturnclient.ui2.resources.Textures;
public class ModMenu extends SaturnScreen { public class ModMenu extends SaturnScreen {
public ModMenu() { public ModMenu() {
@@ -38,5 +40,7 @@ public class ModMenu extends SaturnScreen {
draw(scroll.dimensions(scrollWidth, 350).center(width, height)); draw(scroll.dimensions(scrollWidth, 350).center(width, height));
draw(new Sidebar(0, this::close).centerOffset(width, height, -(scrollWidth / 2 + 20), 0)); draw(new Sidebar(0, this::close).centerOffset(width, height, -(scrollWidth / 2 + 20), 0));
draw(new ImageTexture(Textures.LOGO_TEXT_BIG).dimensions(180, 18).position(width - 180 - 20, height - 18 - 20));
} }
} }
@@ -1,117 +0,0 @@
package org.saturnclient.ui2.screens;
import java.util.Map;
import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.ui2.SaturnScreen;
import org.saturnclient.ui2.components.Sidebar;
import org.saturnclient.ui2.components.inputs.FloatInput;
import org.saturnclient.ui2.components.inputs.HexInput;
import org.saturnclient.ui2.components.inputs.IntInput;
import org.saturnclient.ui2.components.inputs.Toggle;
import org.saturnclient.ui2.elements.Scroll;
import org.saturnclient.ui2.elements.Text;
import org.saturnclient.ui2.resources.Fonts;
public class SaturnConfigEditor extends SaturnScreen {
public SaturnConfigEditor() {
super("Saturn Config Editor");
}
@Override
public void ui() {
int p = 10;
int g = 10;
Scroll scroll = new Scroll(p);
drawProperties(scroll, SaturnClientConfig.config.getProperties(), 0, 0, 480 + 10 + (g * 2));
int scrollWidth = 480 + 10 + (g * 2) + (p * 2);
draw(scroll.dimensions(scrollWidth, 350).center(width, height));
draw(new Sidebar(1, this::close).centerOffset(width, height, -(scrollWidth / 2 + 20), 0));
}
@SuppressWarnings("unchecked")
private int drawProperties(Scroll configScroll, Map<String, Property<?>> properties, int row, int col, int w) {
for (Map.Entry<String, Property<?>> propEntry : properties.entrySet()) {
Property<?> prop = propEntry.getValue();
String propName = propEntry.getKey();
boolean full = isFull(prop);
// Always reset to col 0 if full-width component needs to be drawn mid-row
if (full && col != 0) {
col = 0;
row++;
}
int modX = (w / 2) * col; // two-column layout
int modY = 25 * row;
if (prop.getType() == Property.PropertyType.NAMESPACE) {
configScroll.draw(
new Text(
propName
).position(Fonts.centerX(520, propName, false), modY + 1).scale(0.7f));
} else {
configScroll.draw(
new Text(
propName
).position(modX, modY + 1).scale(0.7f));
}
switch (prop.getType()) {
case BOOLEAN:
configScroll.draw(
new Toggle((Property<Boolean>) prop)
.position(modX + (w / 2) - 40, modY)
.scale(0.5f));
break;
case HEX:
configScroll.draw(new HexInput((Property<Integer>) prop, this).position(w / 2, modY));
break;
case INTEGER:
configScroll.draw(new IntInput((Property<Integer>) prop).position(w / 2, modY));
break;
case FLOAT:
configScroll.draw(new FloatInput((Property<Float>) prop).position(w / 2, modY));
break;
case NAMESPACE:
Map<String, Property<?>> nestedProperties = (Map<String, Property<?>>) prop.value;
row = drawProperties(configScroll, nestedProperties, row + 1, col, w);
break;
case STRING:
}
if (full) {
row++; // full-width takes a whole row
col = 0;
} else {
col++;
if (col > 1) { // max 2 columns
col = 0;
row++;
}
}
}
return row;
}
public static boolean isFull(Property<?> prop) {
switch (prop.getType()) {
case BOOLEAN:
return false;
default:
return true;
}
}
}
@@ -4,6 +4,7 @@ import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.SaturnClientConfig; import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.saturnclient.menus.HudEditor; import org.saturnclient.saturnclient.menus.HudEditor;
import org.saturnclient.ui2.resources.Textures; import org.saturnclient.ui2.resources.Textures;
import org.saturnclient.ui2.screens.cosmetics.CloakMenu;
import org.saturnclient.ui2.Element; import org.saturnclient.ui2.Element;
import org.saturnclient.ui2.SaturnScreen; import org.saturnclient.ui2.SaturnScreen;
import org.saturnclient.ui2.elements.Button; import org.saturnclient.ui2.elements.Button;
@@ -4,6 +4,7 @@ import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.SaturnClientConfig; import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.saturnclient.menus.HudEditor; import org.saturnclient.saturnclient.menus.HudEditor;
import org.saturnclient.ui2.resources.Textures; import org.saturnclient.ui2.resources.Textures;
import org.saturnclient.ui2.screens.cosmetics.CloakMenu;
import org.saturnclient.ui2.SaturnScreen; import org.saturnclient.ui2.SaturnScreen;
import org.saturnclient.ui2.anim.Fade; import org.saturnclient.ui2.anim.Fade;
import org.saturnclient.ui2.anim.SlideY; import org.saturnclient.ui2.anim.SlideY;
@@ -1,5 +1,6 @@
package org.saturnclient.ui2.screens; package org.saturnclient.ui2.screens.cosmetics;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.auth.Auth; import org.saturnclient.saturnclient.auth.Auth;
import org.saturnclient.saturnclient.auth.SaturnPlayer; import org.saturnclient.saturnclient.auth.SaturnPlayer;
import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks; import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks;
@@ -9,6 +10,8 @@ import org.saturnclient.ui2.components.CosmeticPreview;
import org.saturnclient.ui2.components.Sidebar; import org.saturnclient.ui2.components.Sidebar;
import org.saturnclient.ui2.components.SkinPreview; import org.saturnclient.ui2.components.SkinPreview;
import org.saturnclient.ui2.elements.Scroll; import org.saturnclient.ui2.elements.Scroll;
import org.saturnclient.ui2.elements.TabMenu;
import org.saturnclient.ui2.elements.TabMenu.TabMenuComponent;
public class CloakMenu extends SaturnScreen { public class CloakMenu extends SaturnScreen {
public CloakMenu() { public CloakMenu() {
@@ -30,7 +33,7 @@ public class CloakMenu extends SaturnScreen {
if (player != null) { if (player != null) {
for (String cloak : Cloaks.availableCloaks) { for (String cloak : Cloaks.availableCloaks) {
scroll.draw(new CosmeticPreview(cloak == player.cloak, Textures.getCloakPreview(cloak), () -> { scroll.draw(new CosmeticPreview(cloak == player.cloak, Textures.getCloakPreview(cloak), () -> {
Cloaks.setCloak(Auth.uuid, cloak); Cloaks.setCloak(cloak);
}).position((50 + g) * col, (111 + g) * row)); }).position((50 + g) * col, (111 + g) * row));
if (col == 5) { if (col == 5) {
@@ -49,5 +52,12 @@ public class CloakMenu extends SaturnScreen {
draw(new SkinPreview(-30.0f, false).scale(3.5f).position(scroll.x + (scrollWidth - 220), scroll.y+40)); draw(new SkinPreview(-30.0f, false).scale(3.5f).position(scroll.x + (scrollWidth - 220), scroll.y+40));
draw(new Sidebar(2, this::close).centerOffset(width, height, -(scrollWidth / 2 + 20), 0)); draw(new Sidebar(2, this::close).centerOffset(width, height, -(scrollWidth / 2 + 20), 0));
draw(new TabMenu(0,
new TabMenuComponent(Textures.CLOAK, () -> {}),
new TabMenuComponent(Textures.HAT, () -> {
SaturnClient.client.setScreen(new HatMenu());
})
).centerOffset(width, height, 0, -195));
} }
} }
@@ -1,5 +1,6 @@
package org.saturnclient.ui2.screens; package org.saturnclient.ui2.screens.cosmetics;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.auth.Auth; import org.saturnclient.saturnclient.auth.Auth;
import org.saturnclient.saturnclient.auth.SaturnPlayer; import org.saturnclient.saturnclient.auth.SaturnPlayer;
import org.saturnclient.saturnclient.cosmetics.Hats; import org.saturnclient.saturnclient.cosmetics.Hats;
@@ -9,6 +10,8 @@ import org.saturnclient.ui2.components.CosmeticPreview;
import org.saturnclient.ui2.components.Sidebar; import org.saturnclient.ui2.components.Sidebar;
import org.saturnclient.ui2.components.SkinPreview; import org.saturnclient.ui2.components.SkinPreview;
import org.saturnclient.ui2.elements.Scroll; import org.saturnclient.ui2.elements.Scroll;
import org.saturnclient.ui2.elements.TabMenu;
import org.saturnclient.ui2.elements.TabMenu.TabMenuComponent;
public class HatMenu extends SaturnScreen { public class HatMenu extends SaturnScreen {
public HatMenu() { public HatMenu() {
@@ -48,6 +51,13 @@ public class HatMenu extends SaturnScreen {
draw(new SkinPreview(170f, true).scale(3.5f).position(scroll.x + (scrollWidth - 220), scroll.y+40)); draw(new SkinPreview(170f, true).scale(3.5f).position(scroll.x + (scrollWidth - 220), scroll.y+40));
draw(new Sidebar(3, this::close).centerOffset(width, height, -(scrollWidth / 2 + 20), 0)); draw(new Sidebar(2, this::close).centerOffset(width, height, -(scrollWidth / 2 + 20), 0));
draw(new TabMenu(1,
new TabMenuComponent(Textures.CLOAK, () -> {
SaturnClient.client.setScreen(new CloakMenu());
}),
new TabMenuComponent(Textures.HAT, () -> {})
).centerOffset(width, height, 0, -195));
} }
} }
@@ -0,0 +1,75 @@
package org.saturnclient.ui2.screens.store;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.auth.Auth;
import org.saturnclient.saturnclient.auth.SaturnPlayer;
import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks;
import org.saturnclient.ui2.SaturnScreen;
import org.saturnclient.ui2.components.CosmeticPreview;
import org.saturnclient.ui2.components.Sidebar;
import org.saturnclient.ui2.elements.ImageTexture;
import org.saturnclient.ui2.elements.Scroll;
import org.saturnclient.ui2.elements.TabMenu;
import org.saturnclient.ui2.elements.TabMenu.TabMenuComponent;
import org.saturnclient.ui2.elements.Text;
import org.saturnclient.ui2.resources.Fonts;
import org.saturnclient.ui2.resources.Textures;
public class CloakStore extends SaturnScreen {
public CloakStore() {
super("Hat Store");
}
@Override
public void ui() {
int p = 10;
int gx = 10;
int gy = 20;
Scroll scroll = new Scroll(p);
int row = 0;
int col = 0;
SaturnPlayer player = Auth.players.get(Auth.uuid);
if (player != null) {
for (String cloak : Cloaks.ALL_CLOAKS) {
if (!Cloaks.availableCloaks.contains(cloak)) {
int x = (50 + gx) * col;
int y = (111 + gy) * row;
scroll.draw(new CosmeticPreview(cloak == player.cloak, Textures.getCloakPreview(cloak), () -> {
Auth.buyCloak(cloak);
SaturnClient.client.setScreen(new CloakStore());
}).position(x, y));
String t = "100";
scroll.draw(new Text(t).position(x + Fonts.centerX(50, t, Text.font.value), y + 113).scale(0.5f));
scroll.draw(new ImageTexture(Textures.COINS).dimensions(16, 16).position(x + Fonts.getWidth(t, Text.font.value) - 1, y + 112).scale(0.5f));
if (col == 8) {
col = 0;
row++;
} else {
col++;
}
}
}
}
int scrollWidth = 480 + 40 + (gx * 2) + (p * 2);
draw(scroll.dimensions(scrollWidth, 350).centerOffset(width, height, 15, 0));
draw(new Sidebar(5, this::close).centerOffset(width, height, -((scrollWidth - 30) / 2 + 20), 0));
draw(new TabMenu(0,
new TabMenuComponent(Textures.CLOAK, () -> {}),
new TabMenuComponent(Textures.HAT, () -> {
SaturnClient.client.setScreen(new HatStore());
})
).centerOffset(width, height, 0, -195));
}
}
@@ -0,0 +1,75 @@
package org.saturnclient.ui2.screens.store;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.auth.Auth;
import org.saturnclient.saturnclient.auth.SaturnPlayer;
import org.saturnclient.saturnclient.cosmetics.Hats;
import org.saturnclient.ui2.SaturnScreen;
import org.saturnclient.ui2.components.CosmeticPreview;
import org.saturnclient.ui2.components.Sidebar;
import org.saturnclient.ui2.elements.ImageTexture;
import org.saturnclient.ui2.elements.Scroll;
import org.saturnclient.ui2.elements.TabMenu;
import org.saturnclient.ui2.elements.TabMenu.TabMenuComponent;
import org.saturnclient.ui2.elements.Text;
import org.saturnclient.ui2.resources.Fonts;
import org.saturnclient.ui2.resources.Textures;
public class HatStore extends SaturnScreen {
public HatStore() {
super("Hat Store");
}
@Override
public void ui() {
int p = 10;
int gx = 10;
int gy = 20;
Scroll scroll = new Scroll(p);
int row = 0;
int col = 0;
SaturnPlayer player = Auth.players.get(Auth.uuid);
if (player != null) {
for (String hat : Hats.ALL_HATS) {
if (!Hats.availableHats.contains(hat)) {
int x = (50 + gx) * col;
int y = (50 + gy) * row;
scroll.draw(new CosmeticPreview(hat == player.hat, Textures.getHatPreview(hat), () -> {
Auth.buyHat(hat);
SaturnClient.client.setScreen(new HatStore());
}).dimensions(50, 50).position(x, y));
String t = "50";
scroll.draw(new Text(t).position(x + Fonts.centerX(50, t, Text.font.value), y + 53).scale(0.5f));
scroll.draw(new ImageTexture(Textures.COINS).dimensions(16, 16).position(x + Fonts.getWidth(t, Text.font.value) + 4, y + 52).scale(0.5f));
if (col == 8) {
col = 0;
row++;
} else {
col++;
}
}
}
}
int scrollWidth = 480 + 40 + (gx * 2) + (p * 2);
draw(scroll.dimensions(scrollWidth, 350).centerOffset(width, height, 15, 0));
draw(new Sidebar(5, this::close).centerOffset(width, height, -((scrollWidth - 30) / 2 + 20), 0));
draw(new TabMenu(1,
new TabMenuComponent(Textures.CLOAK, () -> {
SaturnClient.client.setScreen(new CloakStore());
}),
new TabMenuComponent(Textures.HAT, () -> {})
).centerOffset(width, height, 0, -195));
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 368 KiB

After

Width:  |  Height:  |  Size: 419 KiB

File diff suppressed because it is too large Load Diff
@@ -0,0 +1,305 @@
{
"version": 1,
"valid": true,
"name": "cry",
"description": "T_T",
"author": "dsty",
"emote": {
"beginTick": 0,
"endTick": 60,
"stopTick": 61,
"isLoop": true,
"returnTick": 5,
"nsfw": false,
"degrees": false,
"moves": [
{
"tick": 5,
"easing": "INOUTQUAD",
"head": {
"x": -0.0
}
},
{
"tick": 60,
"easing": "INOUTQUAD",
"head": {
"x": -0.0
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"head": {
"y": -0.0
}
},
{
"tick": 60,
"easing": "INOUTQUAD",
"head": {
"y": -0.0
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"head": {
"z": -0.0
}
},
{
"tick": 60,
"easing": "INOUTQUAD",
"head": {
"z": -0.0
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"head": {
"pitch": 0.34134695
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"head": {
"pitch": 0.22808763
}
},
{
"tick": 25,
"easing": "INOUTQUAD",
"head": {
"pitch": 0.21269174
}
},
{
"tick": 35,
"easing": "INOUTQUAD",
"head": {
"pitch": 0.32248768
}
},
{
"tick": 45,
"easing": "INOUTQUAD",
"head": {
"pitch": 0.0874397
}
},
{
"tick": 55,
"easing": "INOUTQUAD",
"head": {
"pitch": 0.17582592
}
},
{
"tick": 60,
"easing": "INOUTQUAD",
"head": {
"pitch": 0.21476103
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"head": {
"yaw": -0.0
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"head": {
"yaw": -6.320644E-4
}
},
{
"tick": 25,
"easing": "INOUTQUAD",
"head": {
"yaw": 0.029434478
}
},
{
"tick": 35,
"easing": "INOUTQUAD",
"head": {
"yaw": -0.039604172
}
},
{
"tick": 45,
"easing": "INOUTQUAD",
"head": {
"yaw": 0.037607383
}
},
{
"tick": 55,
"easing": "INOUTQUAD",
"head": {
"yaw": 0.050604735
}
},
{
"tick": 60,
"easing": "INOUTQUAD",
"head": {
"yaw": -0.0
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"head": {
"roll": 0.0
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"head": {
"roll": -0.00930274
}
},
{
"tick": 25,
"easing": "INOUTQUAD",
"head": {
"roll": 0.0010032838
}
},
{
"tick": 35,
"easing": "INOUTQUAD",
"head": {
"roll": -0.009209918
}
},
{
"tick": 45,
"easing": "INOUTQUAD",
"head": {
"roll": -0.012478679
}
},
{
"tick": 55,
"easing": "INOUTQUAD",
"head": {
"roll": 0.031160546
}
},
{
"tick": 60,
"easing": "INOUTQUAD",
"head": {
"roll": 0.0
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"rightArm": {
"x": -5.0
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"rightArm": {
"y": 2.0
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"rightArm": {
"z": -0.0
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"rightArm": {
"pitch": -1.8700758
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"rightArm": {
"yaw": -0.4349194
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"rightArm": {
"roll": 0.4970688
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"rightArm": {
"bend": -0.9622451
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"leftArm": {
"x": 5.0
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"leftArm": {
"y": 2.0
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"leftArm": {
"z": -0.0
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"leftArm": {
"pitch": -1.9203311
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"leftArm": {
"yaw": 0.6307226
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"leftArm": {
"roll": -0.2971223
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"leftArm": {
"bend": -0.8864816
}
}
]
}
}
@@ -0,0 +1,389 @@
{
"version": 1,
"valid": true,
"name": "facepalm",
"description": "just facepalm",
"author": "dsty",
"emote": {
"beginTick": 0,
"endTick": 60,
"stopTick": 61,
"isLoop": false,
"returnTick": 2,
"nsfw": false,
"degrees": false,
"moves": [
{
"tick": 10,
"easing": "INOUTQUAD",
"head": {
"x": -0.0
}
},
{
"tick": 60,
"easing": "INOUTQUAD",
"head": {
"x": -0.0
}
},
{
"tick": 10,
"easing": "INOUTQUAD",
"head": {
"y": -0.0
}
},
{
"tick": 60,
"easing": "INOUTQUAD",
"head": {
"y": -0.0
}
},
{
"tick": 10,
"easing": "INOUTQUAD",
"head": {
"z": -0.0
}
},
{
"tick": 60,
"easing": "INOUTQUAD",
"head": {
"z": -0.0
}
},
{
"tick": 10,
"easing": "INOUTQUAD",
"head": {
"pitch": 0.067995355
}
},
{
"tick": 20,
"easing": "INOUTQUAD",
"head": {
"pitch": 0.14453278
}
},
{
"tick": 30,
"easing": "INOUTQUAD",
"head": {
"pitch": 0.11871816
}
},
{
"tick": 40,
"easing": "INOUTQUAD",
"head": {
"pitch": 0.19018666
}
},
{
"tick": 50,
"easing": "INOUTQUAD",
"head": {
"pitch": 0.20064461
}
},
{
"tick": 60,
"easing": "INOUTQUAD",
"head": {
"pitch": -0.0
}
},
{
"tick": 10,
"easing": "INOUTQUAD",
"head": {
"yaw": 0.060454715
}
},
{
"tick": 20,
"easing": "INOUTQUAD",
"head": {
"yaw": -0.086299464
}
},
{
"tick": 30,
"easing": "INOUTQUAD",
"head": {
"yaw": -0.087619215
}
},
{
"tick": 40,
"easing": "INOUTQUAD",
"head": {
"yaw": -0.083825104
}
},
{
"tick": 50,
"easing": "INOUTQUAD",
"head": {
"yaw": 0.036273066
}
},
{
"tick": 60,
"easing": "INOUTQUAD",
"head": {
"yaw": -0.0
}
},
{
"tick": 10,
"easing": "INOUTQUAD",
"head": {
"roll": 0.0041144555
}
},
{
"tick": 20,
"easing": "INOUTQUAD",
"head": {
"roll": 0.12942825
}
},
{
"tick": 30,
"easing": "INOUTQUAD",
"head": {
"roll": -0.050149817
}
},
{
"tick": 40,
"easing": "INOUTQUAD",
"head": {
"roll": 0.08701207
}
},
{
"tick": 50,
"easing": "INOUTQUAD",
"head": {
"roll": 0.08676299
}
},
{
"tick": 60,
"easing": "INOUTQUAD",
"head": {
"roll": 0.0
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"rightArm": {
"x": -3.8523226
}
},
{
"tick": 50,
"easing": "INOUTQUAD",
"rightArm": {
"x": -3.8523226
}
},
{
"tick": 60,
"easing": "INOUTQUAD",
"rightArm": {
"x": -5.0
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"rightArm": {
"y": 2.0
}
},
{
"tick": 60,
"easing": "INOUTQUAD",
"rightArm": {
"y": 2.0
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"rightArm": {
"z": -0.0
}
},
{
"tick": 60,
"easing": "INOUTQUAD",
"rightArm": {
"z": -0.0
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"rightArm": {
"pitch": -2.0664942
}
},
{
"tick": 20,
"easing": "INOUTQUAD",
"rightArm": {
"pitch": -2.074402
}
},
{
"tick": 30,
"easing": "INOUTQUAD",
"rightArm": {
"pitch": -2.074402
}
},
{
"tick": 40,
"easing": "INOUTQUAD",
"rightArm": {
"pitch": -2.02932
}
},
{
"tick": 50,
"easing": "INOUTQUAD",
"rightArm": {
"pitch": -2.02932
}
},
{
"tick": 60,
"easing": "INOUTQUAD",
"rightArm": {
"pitch": -0.0
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"rightArm": {
"yaw": -0.47555572
}
},
{
"tick": 20,
"easing": "INOUTQUAD",
"rightArm": {
"yaw": -0.5093512
}
},
{
"tick": 30,
"easing": "INOUTQUAD",
"rightArm": {
"yaw": -0.5093512
}
},
{
"tick": 40,
"easing": "INOUTQUAD",
"rightArm": {
"yaw": -0.38563538
}
},
{
"tick": 50,
"easing": "INOUTQUAD",
"rightArm": {
"yaw": -0.38563538
}
},
{
"tick": 60,
"easing": "INOUTQUAD",
"rightArm": {
"yaw": -0.0
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"rightArm": {
"roll": 0.20147677
}
},
{
"tick": 20,
"easing": "INOUTQUAD",
"rightArm": {
"roll": 0.20521602
}
},
{
"tick": 30,
"easing": "INOUTQUAD",
"rightArm": {
"roll": 0.3274244
}
},
{
"tick": 40,
"easing": "INOUTQUAD",
"rightArm": {
"roll": 0.30787703
}
},
{
"tick": 50,
"easing": "INOUTQUAD",
"rightArm": {
"roll": 0.40478125
}
},
{
"tick": 60,
"easing": "INOUTQUAD",
"rightArm": {
"roll": -0.0
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"rightArm": {
"bend": -0.49199954
}
},
{
"tick": 20,
"easing": "INOUTQUAD",
"rightArm": {
"bend": -0.54730254
}
},
{
"tick": 40,
"easing": "INOUTQUAD",
"rightArm": {
"bend": -0.52019864
}
},
{
"tick": 60,
"easing": "INOUTQUAD",
"rightArm": {
"bend": -0.0
}
}
]
}
}
@@ -0,0 +1,697 @@
{
"version": 1,
"valid": true,
"name": "front_flip",
"description": "Parkour!!!!1",
"author": "DKinchik",
"emote": {
"beginTick": 0,
"endTick": 17,
"stopTick": 18,
"isLoop": false,
"returnTick": 1,
"nsfw": false,
"degrees": false,
"moves": [
{
"tick": 2,
"easing": "INOUTQUAD",
"head": {
"x": -0.0
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"head": {
"x": -0.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"head": {
"y": -0.0
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"head": {
"y": -0.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"head": {
"z": -0.0
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"head": {
"z": -0.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"head": {
"pitch": -0.0
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"head": {
"pitch": 0.7020477
}
},
{
"tick": 10,
"easing": "INOUTQUAD",
"head": {
"pitch": 0.7020477
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"head": {
"pitch": -0.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"head": {
"yaw": -0.0
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"head": {
"yaw": -0.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"head": {
"roll": 0.0
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"head": {
"roll": 0.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"rightLeg": {
"x": -1.9
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"rightLeg": {
"x": -1.9
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"rightLeg": {
"y": 11.169379
}
},
{
"tick": 3,
"easing": "INOUTQUAD",
"rightLeg": {
"y": 12.0
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"rightLeg": {
"y": 12.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"rightLeg": {
"z": -0.39214998
}
},
{
"tick": 3,
"easing": "INOUTQUAD",
"rightLeg": {
"z": 0.1
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"rightLeg": {
"z": 0.1
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"rightLeg": {
"pitch": -0.0
}
},
{
"tick": 3,
"easing": "INOUTQUAD",
"rightLeg": {
"pitch": -0.0
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"rightLeg": {
"pitch": -1.9707682
}
},
{
"tick": 10,
"easing": "INOUTQUAD",
"rightLeg": {
"pitch": -1.9707682
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"rightLeg": {
"pitch": -0.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"rightLeg": {
"yaw": -0.0
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"rightLeg": {
"yaw": -0.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"rightLeg": {
"roll": -0.0
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"rightLeg": {
"roll": -0.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"rightLeg": {
"bend": -0.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"rightArm": {
"x": -5.0
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"rightArm": {
"x": -5.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"rightArm": {
"y": 2.0
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"rightArm": {
"y": 2.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"rightArm": {
"z": -0.0
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"rightArm": {
"z": -0.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"rightArm": {
"pitch": -0.0
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"rightArm": {
"pitch": -1.3665518
}
},
{
"tick": 10,
"easing": "INOUTQUAD",
"rightArm": {
"pitch": -1.3665518
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"rightArm": {
"pitch": -0.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"rightArm": {
"yaw": -0.0
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"rightArm": {
"yaw": -0.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"rightArm": {
"roll": -0.0
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"rightArm": {
"roll": -0.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"rightArm": {
"bend": -0.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"leftArm": {
"x": 5.0
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"leftArm": {
"x": 5.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"leftArm": {
"y": 2.0
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"leftArm": {
"y": 2.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"leftArm": {
"z": -0.0
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"leftArm": {
"z": -0.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"leftArm": {
"pitch": 0.0
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"leftArm": {
"pitch": -1.0793308
}
},
{
"tick": 10,
"easing": "INOUTQUAD",
"leftArm": {
"pitch": -1.0793308
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"leftArm": {
"pitch": 0.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"leftArm": {
"yaw": -0.0
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"leftArm": {
"yaw": -0.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"leftArm": {
"roll": 0.0
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"leftArm": {
"roll": 0.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"leftArm": {
"bend": -0.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"leftLeg": {
"x": 1.9
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"leftLeg": {
"x": 1.9
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"leftLeg": {
"y": 10.861001
}
},
{
"tick": 3,
"easing": "INOUTQUAD",
"leftLeg": {
"y": 12.0
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"leftLeg": {
"y": 12.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"leftLeg": {
"z": -0.5082285
}
},
{
"tick": 3,
"easing": "INOUTQUAD",
"leftLeg": {
"z": -0.1
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"leftLeg": {
"z": -0.1
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"leftLeg": {
"pitch": -0.0
}
},
{
"tick": 3,
"easing": "INOUTQUAD",
"leftLeg": {
"pitch": -0.0
}
},
{
"tick": 5,
"easing": "INOUTQUAD",
"leftLeg": {
"pitch": -1.9850811
}
},
{
"tick": 10,
"easing": "INOUTQUAD",
"leftLeg": {
"pitch": -1.9850811
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"leftLeg": {
"pitch": -0.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"leftLeg": {
"yaw": -0.0
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"leftLeg": {
"yaw": -0.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"leftLeg": {
"roll": -0.0
}
},
{
"tick": 15,
"easing": "INOUTQUAD",
"leftLeg": {
"roll": 0.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"leftLeg": {
"bend": -0.0
}
},
{
"tick": 2,
"easing": "INQUAD",
"body": {
"x": 0.0
}
},
{
"tick": 16,
"easing": "INQUAD",
"body": {
"x": 0.0
}
},
{
"tick": 2,
"easing": "INQUAD",
"body": {
"y": -0.061333913
}
},
{
"tick": 7,
"easing": "OUTQUAD",
"body": {
"y": 0.48852682
}
},
{
"tick": 15,
"easing": "CONSTANT",
"body": {
"y": 0.0
}
},
{
"tick": 16,
"easing": "INQUAD",
"body": {
"y": 0.0
}
},
{
"tick": 2,
"easing": "INQUAD",
"body": {
"z": -0.0
}
},
{
"tick": 16,
"easing": "INQUAD",
"body": {
"z": -0.0
}
},
{
"tick": 2,
"easing": "INQUAD",
"body": {
"pitch": 0.0
}
},
{
"tick": 7,
"easing": "OUTQUAD",
"body": {
"pitch": -2.8362873
}
},
{
"tick": 15,
"easing": "CONSTANT",
"body": {
"pitch": -6.2831855
}
},
{
"tick": 16,
"easing": "INQUAD",
"body": {
"pitch": 0.0
}
},
{
"tick": 2,
"easing": "INQUAD",
"body": {
"yaw": 0.0
}
},
{
"tick": 16,
"easing": "INQUAD",
"body": {
"yaw": 0.0
}
},
{
"tick": 2,
"easing": "INQUAD",
"body": {
"roll": -0.0
}
},
{
"tick": 16,
"easing": "INQUAD",
"body": {
"roll": 0.0
}
},
{
"tick": 2,
"easing": "INOUTQUAD",
"body": {
"bend": -0.0
}
}
]
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,354 @@
{
"version": 1,
"valid": true,
"name": "tpose",
"description": "MENACING",
"author": "stephanieisdumb",
"emote": {
"beginTick": 0,
"endTick": 80,
"stopTick": 81,
"isLoop": true,
"returnTick": 20,
"nsfw": false,
"degrees": false,
"moves": [
{
"tick": 10,
"easing": "INOUTQUAD",
"rightArm": {
"x": -5.0
}
},
{
"tick": 20,
"easing": "INOUTQUAD",
"rightArm": {
"x": -6.0
}
},
{
"tick": 80,
"easing": "INOUTQUAD",
"rightArm": {
"x": -6.0
}
},
{
"tick": 10,
"easing": "INOUTQUAD",
"rightArm": {
"y": 2.0
}
},
{
"tick": 20,
"easing": "INOUTQUAD",
"rightArm": {
"y": 3.0
}
},
{
"tick": 80,
"easing": "INOUTQUAD",
"rightArm": {
"y": 3.0
}
},
{
"tick": 10,
"easing": "INOUTQUAD",
"rightArm": {
"z": -0.0
}
},
{
"tick": 20,
"easing": "INOUTQUAD",
"rightArm": {
"z": -0.0
}
},
{
"tick": 80,
"easing": "INOUTQUAD",
"rightArm": {
"z": -0.0
}
},
{
"tick": 10,
"easing": "INOUTQUAD",
"rightArm": {
"pitch": -1.0704756
}
},
{
"tick": 20,
"easing": "INOUTQUAD",
"rightArm": {
"pitch": -0.0
}
},
{
"tick": 50,
"easing": "INOUTQUAD",
"rightArm": {
"pitch": 0.059108086
}
},
{
"tick": 80,
"easing": "INOUTQUAD",
"rightArm": {
"pitch": -0.0
}
},
{
"tick": 10,
"easing": "INOUTQUAD",
"rightArm": {
"yaw": -0.61077195
}
},
{
"tick": 20,
"easing": "INOUTQUAD",
"rightArm": {
"yaw": -0.0
}
},
{
"tick": 50,
"easing": "INOUTQUAD",
"rightArm": {
"yaw": -0.008776078
}
},
{
"tick": 80,
"easing": "INOUTQUAD",
"rightArm": {
"yaw": -0.0
}
},
{
"tick": 10,
"easing": "INOUTQUAD",
"rightArm": {
"roll": 0.6060502
}
},
{
"tick": 20,
"easing": "INOUTQUAD",
"rightArm": {
"roll": 1.5707964
}
},
{
"tick": 50,
"easing": "INOUTQUAD",
"rightArm": {
"roll": 1.5765934
}
},
{
"tick": 80,
"easing": "INOUTQUAD",
"rightArm": {
"roll": 1.5707964
}
},
{
"tick": 10,
"easing": "INOUTQUAD",
"rightArm": {
"bend": -1.3806202
}
},
{
"tick": 20,
"easing": "INOUTQUAD",
"rightArm": {
"bend": -0.0
}
},
{
"tick": 10,
"easing": "INOUTQUAD",
"leftArm": {
"x": 5.0
}
},
{
"tick": 20,
"easing": "INOUTQUAD",
"leftArm": {
"x": 6.0
}
},
{
"tick": 80,
"easing": "INOUTQUAD",
"leftArm": {
"x": 6.0
}
},
{
"tick": 10,
"easing": "INOUTQUAD",
"leftArm": {
"y": 2.0
}
},
{
"tick": 20,
"easing": "INOUTQUAD",
"leftArm": {
"y": 3.0
}
},
{
"tick": 80,
"easing": "INOUTQUAD",
"leftArm": {
"y": 3.0
}
},
{
"tick": 10,
"easing": "INOUTQUAD",
"leftArm": {
"z": -0.0
}
},
{
"tick": 20,
"easing": "INOUTQUAD",
"leftArm": {
"z": -0.0
}
},
{
"tick": 80,
"easing": "INOUTQUAD",
"leftArm": {
"z": -0.0
}
},
{
"tick": 10,
"easing": "INOUTQUAD",
"leftArm": {
"pitch": -1.0045553
}
},
{
"tick": 20,
"easing": "INOUTQUAD",
"leftArm": {
"pitch": 0.0
}
},
{
"tick": 50,
"easing": "INOUTQUAD",
"leftArm": {
"pitch": 0.010133168
}
},
{
"tick": 80,
"easing": "INOUTQUAD",
"leftArm": {
"pitch": 0.0
}
},
{
"tick": 10,
"easing": "INOUTQUAD",
"leftArm": {
"yaw": 0.44322997
}
},
{
"tick": 20,
"easing": "INOUTQUAD",
"leftArm": {
"yaw": -0.0
}
},
{
"tick": 50,
"easing": "INOUTQUAD",
"leftArm": {
"yaw": 0.038214765
}
},
{
"tick": 80,
"easing": "INOUTQUAD",
"leftArm": {
"yaw": -0.0
}
},
{
"tick": 10,
"easing": "INOUTQUAD",
"leftArm": {
"roll": -0.5571526
}
},
{
"tick": 20,
"easing": "INOUTQUAD",
"leftArm": {
"roll": -1.5707964
}
},
{
"tick": 50,
"easing": "INOUTQUAD",
"leftArm": {
"roll": -1.5692185
}
},
{
"tick": 80,
"easing": "INOUTQUAD",
"leftArm": {
"roll": -1.5707964
}
},
{
"tick": 10,
"easing": "INOUTQUAD",
"leftArm": {
"bend": -1.3810014
}
},
{
"tick": 20,
"easing": "INOUTQUAD",
"leftArm": {
"bend": -0.0
}
},
{
"tick": 80,
"easing": "INOUTQUAD",
"leftLeg": {
"pitch": 0.0
}
},
{
"tick": 80,
"easing": "INOUTQUAD",
"rightLeg": {
"pitch": 0.0
}
}
]
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 357 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 884 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 958 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 672 B

@@ -1,10 +0,0 @@
{
"gui": {
"scaling": {
"type": "nine_slice",
"width": 80,
"height": 80,
"border": 16
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 753 B

@@ -1,10 +0,0 @@
{
"gui": {
"scaling": {
"type": "nine_slice",
"width": 80,
"height": 80,
"border": 16
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

@@ -1,10 +0,0 @@
{
"gui": {
"scaling": {
"type": "nine_slice",
"width": 228,
"height": 228,
"border": 13
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

@@ -1,10 +0,0 @@
{
"gui": {
"scaling": {
"type": "nine_slice",
"width": 228,
"height": 228,
"border": 13
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Some files were not shown because too many files have changed in this diff Show More