Merge pull request #24 from saturnclientmc/services-and-ui-tweaks
Services and UI tweaks
@@ -1,41 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* ================================================================
|
||||||
|
* Saturn Client - Fabric Mod Build Configuration
|
||||||
|
* ================================================================
|
||||||
|
*
|
||||||
|
* This build file configures:
|
||||||
|
* - Fabric Loom (Minecraft mod development)
|
||||||
|
* - Dependency management
|
||||||
|
* - Resource processing
|
||||||
|
* - Java toolchain (Java 21)
|
||||||
|
* - Publishing setup
|
||||||
|
*
|
||||||
|
* All version values are defined in gradle.properties.
|
||||||
|
* ================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
|
// Fabric mod development plugin
|
||||||
id 'fabric-loom' version '1.9-SNAPSHOT'
|
id 'fabric-loom' version '1.9-SNAPSHOT'
|
||||||
|
|
||||||
|
// Maven publishing support
|
||||||
id 'maven-publish'
|
id 'maven-publish'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ================================================================
|
||||||
|
* Project Metadata
|
||||||
|
* ================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
version = project.mod_version
|
version = project.mod_version
|
||||||
group = project.maven_group
|
group = project.maven_group
|
||||||
|
|
||||||
repositories {}
|
/*
|
||||||
|
* ================================================================
|
||||||
|
* Repositories
|
||||||
|
* ================================================================
|
||||||
|
* All dependency sources.
|
||||||
|
*/
|
||||||
|
repositories {
|
||||||
|
// Fabric
|
||||||
|
maven { url 'https://maven.fabricmc.net/' }
|
||||||
|
|
||||||
|
// JitPack (GitHub releases)
|
||||||
|
maven { url 'https://jitpack.io' }
|
||||||
|
|
||||||
|
// Parchment mappings (if needed later)
|
||||||
|
maven { url 'https://maven.parchmentmc.org' }
|
||||||
|
|
||||||
|
// Special Model Loader
|
||||||
|
maven { name = "FelNull Maven"; url = "https://maven.felnull.dev" }
|
||||||
|
|
||||||
|
// Player Animation Library
|
||||||
|
maven { name = "KosmX Maven"; url = 'https://maven.kosmx.dev/' }
|
||||||
|
|
||||||
|
// Central repository
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ================================================================
|
||||||
|
* Dependencies
|
||||||
|
* ================================================================
|
||||||
|
*/
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────
|
||||||
|
// Minecraft Core
|
||||||
|
// ─────────────────────────────────────────────
|
||||||
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
||||||
|
|
||||||
// Switch back to Yarn
|
// Yarn mappings (named mappings for dev environment)
|
||||||
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
|
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
|
||||||
|
|
||||||
|
// Fabric Loader
|
||||||
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
|
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
|
||||||
|
|
||||||
|
// Fabric API
|
||||||
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
||||||
|
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────
|
||||||
|
// Rendering / Model Libraries
|
||||||
|
// ─────────────────────────────────────────────
|
||||||
|
|
||||||
|
// Special Model Loader (included inside your mod jar)
|
||||||
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"
|
||||||
|
|
||||||
implementation 'com.github.selimaj-dev:session-java:0.1.4'
|
// SVG Rendering Library
|
||||||
|
implementation "com.formdev:svgSalamander:1.1.4"
|
||||||
|
|
||||||
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}")
|
// Animation
|
||||||
|
// ─────────────────────────────────────────────
|
||||||
|
|
||||||
|
// Player Animation Library (bundled into your mod)
|
||||||
|
include modImplementation(
|
||||||
|
"dev.kosmx.player-anim:player-animation-lib-fabric:${project.player_anim}"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Optional: BendyLib (only if you directly use it)
|
||||||
|
// include modRuntimeOnly(
|
||||||
|
// "io.github.kosmx.bendy-lib:bendy-lib-fabric:${project.bendylib_version}"
|
||||||
|
// )
|
||||||
|
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────
|
||||||
|
// External Libraries
|
||||||
|
// ─────────────────────────────────────────────
|
||||||
|
|
||||||
|
// Session Java (auth/session handling)
|
||||||
|
implementation "com.github.selimaj-dev:session-java:0.1.6"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
repositories {
|
/*
|
||||||
maven { url 'https://maven.fabricmc.net/' } // Fabric's official repo
|
* ================================================================
|
||||||
maven { url 'https://jitpack.io' }
|
* Resource Processing
|
||||||
maven { url "https://maven.parchmentmc.org" }
|
* ================================================================
|
||||||
maven { name = "FelNull Maven"; url = "https://maven.felnull.dev" }
|
* Injects version values into fabric.mod.json.
|
||||||
maven { name = "KosmX maven"; url = 'https://maven.kosmx.dev/' }
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
processResources {
|
processResources {
|
||||||
inputs.property "version", project.version
|
inputs.property "version", project.version
|
||||||
inputs.property "minecraft_version", project.minecraft_version
|
inputs.property "minecraft_version", project.minecraft_version
|
||||||
@@ -43,29 +128,42 @@ processResources {
|
|||||||
filteringCharset "UTF-8"
|
filteringCharset "UTF-8"
|
||||||
|
|
||||||
filesMatching("fabric.mod.json") {
|
filesMatching("fabric.mod.json") {
|
||||||
expand "version": project.version,
|
expand(
|
||||||
|
"version": project.version,
|
||||||
"minecraft_version": project.minecraft_version,
|
"minecraft_version": project.minecraft_version,
|
||||||
"loader_version": project.loader_version
|
"loader_version": project.loader_version
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ================================================================
|
||||||
|
* Java Configuration
|
||||||
|
* ================================================================
|
||||||
|
* Targeting Java 21.
|
||||||
|
*/
|
||||||
def targetJavaVersion = 21
|
def targetJavaVersion = 21
|
||||||
|
|
||||||
tasks.withType(JavaCompile).configureEach {
|
tasks.withType(JavaCompile).configureEach {
|
||||||
it.options.encoding = "UTF-8"
|
options.encoding = "UTF-8"
|
||||||
if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) {
|
options.release.set(targetJavaVersion)
|
||||||
it.options.release.set(targetJavaVersion)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
java {
|
java {
|
||||||
def javaVersion = JavaVersion.toVersion(targetJavaVersion)
|
|
||||||
if (JavaVersion.current() < javaVersion) {
|
|
||||||
toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion)
|
toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion)
|
||||||
}
|
|
||||||
archivesBaseName = project.archives_base_name
|
archivesBaseName = project.archives_base_name
|
||||||
withSourcesJar()
|
withSourcesJar()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ================================================================
|
||||||
|
* Jar Packaging
|
||||||
|
* ================================================================
|
||||||
|
* Includes LICENSE and NOTICE inside the final jar.
|
||||||
|
*/
|
||||||
jar {
|
jar {
|
||||||
from("LICENSE") {
|
from("LICENSE") {
|
||||||
rename { "${it}_${project.archivesBaseName}" }
|
rename { "${it}_${project.archivesBaseName}" }
|
||||||
@@ -75,6 +173,13 @@ jar {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ================================================================
|
||||||
|
* Publishing
|
||||||
|
* ================================================================
|
||||||
|
* Configured but no remote repository defined yet.
|
||||||
|
*/
|
||||||
publishing {
|
publishing {
|
||||||
publications {
|
publications {
|
||||||
mavenJava(MavenPublication) {
|
mavenJava(MavenPublication) {
|
||||||
@@ -82,5 +187,7 @@ publishing {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {}
|
repositories {
|
||||||
|
// Add publishing repository here when needed
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -9,46 +9,45 @@ import org.saturnclient.ui2.RenderScope;
|
|||||||
import org.saturnclient.modules.ModuleDetails;
|
import org.saturnclient.modules.ModuleDetails;
|
||||||
|
|
||||||
public class Keystrokes extends Module implements HudMod {
|
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);
|
|
||||||
|
|
||||||
// Cache key states to avoid repeated calls
|
private static final Property<Boolean> enabled = Property.bool(false);
|
||||||
private boolean w = false;
|
private static final Property<Boolean> showMouse = Property.bool(true);
|
||||||
private boolean a = false;
|
private static final Property<Boolean> showSpace = Property.bool(false);
|
||||||
private boolean s = false;
|
|
||||||
private boolean d = false;
|
|
||||||
private boolean lmb = false;
|
|
||||||
private boolean rmb = false;
|
|
||||||
private boolean space = false;
|
|
||||||
|
|
||||||
// Cache dimensions to avoid recalculation
|
private static final Property<Integer> clickBg = Property.color(0xFFCCCCCC);
|
||||||
private int cachedHeight = 54;
|
private static final Property<Integer> clickFg = Property.color(0xFFFFFFFF);
|
||||||
private boolean dimensionsDirty = true;
|
|
||||||
|
|
||||||
private static Property<Integer> clickBg = Property.color(0xFFCCCCCC);
|
private static final ModDimensions dimensions = new ModDimensions(78, 54);
|
||||||
private static Property<Integer> clickFg = Property.color(0xFFFFFFFF);
|
|
||||||
|
// Key states
|
||||||
|
private boolean w, a, s, d, lmb, rmb, space;
|
||||||
|
|
||||||
|
// Layout constants
|
||||||
|
private static final int KEY_SIZE = 24;
|
||||||
|
private static final int KEY_SPACING = 3;
|
||||||
|
private static final int MOUSE_WIDTH = 38;
|
||||||
|
private static final int MOUSE_HEIGHT = 24;
|
||||||
|
private static final int SPACE_HEIGHT = 19;
|
||||||
|
|
||||||
public Keystrokes() {
|
public Keystrokes() {
|
||||||
super(new ModuleDetails("Keystrokes", "keystrokes")
|
super(new ModuleDetails("Keystrokes", "keystrokes")
|
||||||
.description("Displays the keystrokes for movement")
|
.description("Displays movement keystrokes")
|
||||||
.version("v0.1.0")
|
.version("v0.2.0")
|
||||||
.tags("Utility"),
|
.tags("Utility"),
|
||||||
|
|
||||||
enabled.named("Enabled"),
|
enabled.named("Enabled"),
|
||||||
showMouse.named("Show mouse clicks"),
|
showMouse.named("Show mouse clicks"),
|
||||||
showSpace.named("Show space clicks"),
|
showSpace.named("Show space"),
|
||||||
dimensions.prop(),
|
dimensions.prop(),
|
||||||
clickFg.named("Clicked fg"),
|
clickFg.named("Clicked fg"),
|
||||||
clickBg.named("Clicked bg"));
|
clickBg.named("Clicked bg")
|
||||||
|
);
|
||||||
|
|
||||||
dimensions.renderBackground = false;
|
dimensions.renderBackground = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
// Cache key states to reduce method calls
|
|
||||||
w = SaturnClient.client.options.forwardKey.isPressed();
|
w = SaturnClient.client.options.forwardKey.isPressed();
|
||||||
a = SaturnClient.client.options.leftKey.isPressed();
|
a = SaturnClient.client.options.leftKey.isPressed();
|
||||||
s = SaturnClient.client.options.backKey.isPressed();
|
s = SaturnClient.client.options.backKey.isPressed();
|
||||||
@@ -57,103 +56,84 @@ public class Keystrokes extends Module implements HudMod {
|
|||||||
rmb = SaturnClient.client.options.useKey.isPressed();
|
rmb = SaturnClient.client.options.useKey.isPressed();
|
||||||
space = SaturnClient.client.options.jumpKey.isPressed();
|
space = SaturnClient.client.options.jumpKey.isPressed();
|
||||||
|
|
||||||
// Mark dimensions as dirty if mouse or space visibility changed
|
updateHeight();
|
||||||
if (dimensionsDirty) {
|
|
||||||
updateDimensions();
|
|
||||||
dimensionsDirty = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateDimensions() {
|
private void updateHeight() {
|
||||||
cachedHeight = 54; // base height with padding considered
|
int height = KEY_SIZE * 2 + KEY_SPACING;
|
||||||
|
|
||||||
if (showMouse.value) {
|
if (showSpace.value)
|
||||||
cachedHeight += 27;
|
height += SPACE_HEIGHT + KEY_SPACING;
|
||||||
}
|
|
||||||
|
|
||||||
if (showSpace.value) {
|
if (showMouse.value)
|
||||||
cachedHeight += 22;
|
height += MOUSE_HEIGHT + KEY_SPACING;
|
||||||
}
|
|
||||||
|
|
||||||
dimensions.height = cachedHeight;
|
dimensions.height = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderDummy(RenderScope scope) {
|
public void renderDummy(RenderScope scope) {
|
||||||
// Use cached dimensions
|
render(scope, false);
|
||||||
dimensions.height = cachedHeight;
|
|
||||||
|
|
||||||
// WASD keys (3px padding between each key)
|
|
||||||
renderKey(scope, false, '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, false, "LMB", 0, 54); // Below A/S/D
|
|
||||||
renderKeyM(scope, false, "RMB", 40, 54); // With 3px between
|
|
||||||
}
|
|
||||||
|
|
||||||
if (showSpace.value) {
|
|
||||||
renderKeySpace(scope, false, 0, cachedHeight - (showSpace.value ? 22 : 0));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderHud(RenderScope scope) {
|
public void renderHud(RenderScope scope) {
|
||||||
// Use cached dimensions
|
render(scope, true);
|
||||||
dimensions.height = cachedHeight;
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void render(RenderScope scope, boolean live) {
|
||||||
|
|
||||||
|
int yOffset = 0;
|
||||||
|
|
||||||
|
// --- W ---
|
||||||
|
renderKey(scope, live && w, 'W', KEY_SIZE + KEY_SPACING, yOffset);
|
||||||
|
|
||||||
|
// --- A S D ---
|
||||||
|
yOffset += KEY_SIZE + KEY_SPACING;
|
||||||
|
|
||||||
|
renderKey(scope, live && a, 'A', 0, yOffset);
|
||||||
|
renderKey(scope, live && s, 'S', KEY_SIZE + KEY_SPACING, yOffset);
|
||||||
|
renderKey(scope, live && d, 'D', (KEY_SIZE + KEY_SPACING) * 2, yOffset);
|
||||||
|
|
||||||
|
yOffset += KEY_SIZE + KEY_SPACING;
|
||||||
|
|
||||||
|
// --- SPACE ---
|
||||||
if (showSpace.value) {
|
if (showSpace.value) {
|
||||||
renderKeySpace(scope, space, 0, cachedHeight - (showSpace.value ? 22 : 0));
|
renderKeySpace(scope, live && space, 0, yOffset);
|
||||||
|
yOffset += SPACE_HEIGHT + KEY_SPACING;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- MOUSE ---
|
||||||
|
if (showMouse.value) {
|
||||||
|
renderKeyMouse(scope, live && lmb, "LMB", 0, yOffset);
|
||||||
|
renderKeyMouse(scope, live && rmb, "RMB", MOUSE_WIDTH + KEY_SPACING, yOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consistent 3px padding applied below:
|
private void renderKey(RenderScope scope, boolean pressed, char c, int x, int y) {
|
||||||
|
int bg = pressed ? clickBg.value : dimensions.bgColor.value;
|
||||||
|
int fg = pressed ? clickFg.value : dimensions.fgColor.value;
|
||||||
|
|
||||||
private void renderKeySpace(RenderScope scope, boolean isPressed, int x, int y) {
|
scope.drawRoundedRectangle(x, y, KEY_SIZE, KEY_SIZE, dimensions.radius.value, bg);
|
||||||
int height = 19;
|
scope.drawText(0.6f, String.valueOf(c), x + 9, y + 7, dimensions.font.value, fg);
|
||||||
int bgColor = isPressed ? clickBg.value : dimensions.bgColor.value;
|
|
||||||
int fgColor = isPressed ? clickFg.value : dimensions.fgColor.value;
|
|
||||||
|
|
||||||
scope.drawRoundedRectangle(x, y, dimensions.width, height, dimensions.radius.value, bgColor);
|
|
||||||
|
|
||||||
// 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, fgColor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderKeyM(RenderScope scope, boolean isPressed, String c, int x, int y) {
|
private void renderKeyMouse(RenderScope scope, boolean pressed, String text, int x, int y) {
|
||||||
int width = 38, height = 24;
|
int bg = pressed ? clickBg.value : dimensions.bgColor.value;
|
||||||
int bgColor = isPressed ? clickBg.value : dimensions.bgColor.value;
|
int fg = pressed ? clickFg.value : dimensions.fgColor.value;
|
||||||
int fgColor = isPressed ? clickFg.value : dimensions.fgColor.value;
|
|
||||||
|
|
||||||
scope.drawRoundedRectangle(x, y, width, height, dimensions.radius.value, bgColor);
|
scope.drawRoundedRectangle(x, y, MOUSE_WIDTH, MOUSE_HEIGHT, dimensions.radius.value, bg);
|
||||||
|
scope.drawText(0.6f, text, x + 9, y + 7, dimensions.font.value, fg);
|
||||||
// Apply padding: 3px top and left -> add slight offset to x/y
|
|
||||||
scope.drawText(0.6f, c, x + 9, y + 7, dimensions.font.value, fgColor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderKey(RenderScope scope, boolean isPressed, char c, int x, int y) {
|
private void renderKeySpace(RenderScope scope, boolean pressed, int x, int y) {
|
||||||
int size = 24;
|
int bg = pressed ? clickBg.value : dimensions.bgColor.value;
|
||||||
int bgColor = isPressed ? clickBg.value : dimensions.bgColor.value;
|
int fg = pressed ? clickFg.value : dimensions.fgColor.value;
|
||||||
int fgColor = isPressed ? clickFg.value : dimensions.fgColor.value;
|
|
||||||
|
|
||||||
scope.drawRoundedRectangle(x, y, size, size, dimensions.radius.value, bgColor);
|
scope.drawRoundedRectangle(x, y, dimensions.width, SPACE_HEIGHT, dimensions.radius.value, bg);
|
||||||
|
|
||||||
// Center the character with 3px top padding
|
int lineY = y + SPACE_HEIGHT / 2;
|
||||||
scope.drawText(0.6f, String.valueOf(c), x + 9, y + 7, dimensions.font.value, fgColor);
|
scope.drawRect(x + (dimensions.width - 30) / 2, lineY, 30, 1, fg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -169,6 +149,5 @@ public class Keystrokes extends Module implements HudMod {
|
|||||||
@Override
|
@Override
|
||||||
public void onEnabled(boolean e) {
|
public void onEnabled(boolean e) {
|
||||||
enabled.value = e;
|
enabled.value = e;
|
||||||
dimensionsDirty = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,8 +8,13 @@ import org.saturnclient.saturnclient.client.player.SaturnPlayer;
|
|||||||
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 dev.kosmx.playerAnim.api.layered.AnimationStack;
|
||||||
|
import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationAccess;
|
||||||
|
import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationRegistry;
|
||||||
import dev.selimaj.session.Session;
|
import dev.selimaj.session.Session;
|
||||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
|
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
|
||||||
|
import net.minecraft.client.network.AbstractClientPlayerEntity;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
public class ServiceClient {
|
public class ServiceClient {
|
||||||
private static Session session;
|
private static Session session;
|
||||||
@@ -17,7 +22,7 @@ public class ServiceClient {
|
|||||||
|
|
||||||
public static boolean connectTimeout() {
|
public static boolean connectTimeout() {
|
||||||
try {
|
try {
|
||||||
session = Session.connect("ws://127.0.0.1:8080", 10, TimeUnit.SECONDS);
|
session = Session.connect("wss://saturn-server.selimaj.dev", 10, TimeUnit.SECONDS);
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return false;
|
return false;
|
||||||
@@ -46,14 +51,15 @@ public class ServiceClient {
|
|||||||
uuid = mcSession.getUuidOrNull();
|
uuid = mcSession.getUuidOrNull();
|
||||||
String username = mcSession.getUsername();
|
String username = mcSession.getUsername();
|
||||||
|
|
||||||
SaturnClient.LOGGER.info("Authenticating with UUID: " + accessToken);
|
SaturnClient.LOGGER.info("Authenticating with UUID: " + uuid);
|
||||||
|
|
||||||
if (!connectTimeout()) {
|
if (!connectTimeout()) {
|
||||||
SaturnClient.LOGGER.error("Unable to authenticate: Session Server Timeout");
|
SaturnClient.LOGGER.error("Unable to authenticate: Session Server Timeout");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ServiceMethods.AuthResponse response = session.request(ServiceMethods.Authenticate, accessToken).get();
|
ServiceMethods.Types.Player response = session.request(ServiceMethods.Authenticate, accessToken)
|
||||||
|
.get();
|
||||||
|
|
||||||
for (String availableCloak : response.cloaks()) {
|
for (String availableCloak : response.cloaks()) {
|
||||||
Cloaks.availableCloaks.add(availableCloak);
|
Cloaks.availableCloaks.add(availableCloak);
|
||||||
@@ -63,7 +69,9 @@ public class ServiceClient {
|
|||||||
Hats.availableHats.add(availableHat);
|
Hats.availableHats.add(availableHat);
|
||||||
}
|
}
|
||||||
|
|
||||||
SaturnPlayer.set(uuid, username, new SaturnPlayer(uuid, username, response.cloak(), response.hat()));
|
eventHandlers();
|
||||||
|
|
||||||
|
SaturnPlayer.set(new SaturnPlayer(uuid, username, response.cloak(), response.hat()));
|
||||||
|
|
||||||
Cloaks.loadCloak(uuid);
|
Cloaks.loadCloak(uuid);
|
||||||
|
|
||||||
@@ -74,33 +82,67 @@ public class ServiceClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setCloak(String cloak) {
|
public static void setCloak(String itemId) {
|
||||||
try {
|
try {
|
||||||
session.request(ServiceMethods.SetCloak, cloak).get();
|
session.request(ServiceMethods.SetCloak, itemId).whenComplete((msg, throwable) -> {
|
||||||
|
if (throwable != null) {
|
||||||
|
throwable.printStackTrace();
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
session.request(ServiceMethods.SendPlayer,
|
||||||
|
new ServiceMethods.Types.SendPlayerRequest(SaturnPlayer.getExternalUUIDAsString()));
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
SaturnClient.LOGGER.error("Failed to set cloak (service): ", e);
|
SaturnClient.LOGGER.error("Failed to set cloak (service): ", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setHat(String hat) {
|
public static void setHat(String itemId) {
|
||||||
try {
|
try {
|
||||||
session.request(ServiceMethods.SetHat, hat).get();
|
session.request(ServiceMethods.SetHat, itemId).whenComplete((msg, throwable) -> {
|
||||||
|
if (throwable != null) {
|
||||||
|
throwable.printStackTrace();
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
session.request(ServiceMethods.SendPlayer,
|
||||||
|
new ServiceMethods.Types.SendPlayerRequest(SaturnPlayer.getExternalUUIDAsString()));
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
SaturnClient.LOGGER.error("Failed to set hat (service): ", e);
|
SaturnClient.LOGGER.error("Failed to set hat (service): ", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void buyCloak(String cloak) {
|
public static void buyCloak(String itemId) {
|
||||||
try {
|
try {
|
||||||
session.request(ServiceMethods.BuyCloak, cloak).get();
|
session.request(ServiceMethods.BuyCloak, itemId).whenComplete((msg, throwable) -> {
|
||||||
|
if (throwable != null) {
|
||||||
|
throwable.printStackTrace();
|
||||||
|
} else {
|
||||||
|
Cloaks.availableCloaks.add(itemId);
|
||||||
|
}
|
||||||
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
SaturnClient.LOGGER.error("Failed to buy cloak (service): ", e);
|
SaturnClient.LOGGER.error("Failed to buy cloak (service): ", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void buyHat(String hat) {
|
public static void buyHat(String itemId) {
|
||||||
try {
|
try {
|
||||||
session.request(ServiceMethods.BuyHat, hat).get();
|
session.request(ServiceMethods.BuyHat, itemId).whenComplete((msg, throwable) -> {
|
||||||
|
if (throwable != null) {
|
||||||
|
throwable.printStackTrace();
|
||||||
|
} else {
|
||||||
|
Hats.availableHats.add(itemId);
|
||||||
|
}
|
||||||
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
SaturnClient.LOGGER.error("Failed to buy hat (service): ", e);
|
SaturnClient.LOGGER.error("Failed to buy hat (service): ", e);
|
||||||
}
|
}
|
||||||
@@ -108,9 +150,56 @@ public class ServiceClient {
|
|||||||
|
|
||||||
public static void emote(String emote) {
|
public static void emote(String emote) {
|
||||||
try {
|
try {
|
||||||
session.request(ServiceMethods.Emote, emote).get();
|
session.request(ServiceMethods.Emote,
|
||||||
|
new ServiceMethods.Types.EmoteRequest(emote, SaturnPlayer.getExternalUUIDAsString()))
|
||||||
|
.whenComplete((msg, throwable) -> {
|
||||||
|
if (throwable != null) {
|
||||||
|
throwable.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
SaturnClient.LOGGER.error("Failed to emote (service): ", e);
|
SaturnClient.LOGGER.error("Failed to emote (service): ", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void eventHandlers() {
|
||||||
|
session.onNotification(ServiceMethods.EmoteEvent, (data) -> {
|
||||||
|
for (AbstractClientPlayerEntity player : SaturnClient.client.world.getPlayers()) {
|
||||||
|
if (player.getUuidAsString().equals(data.from())) {
|
||||||
|
AnimationStack animationStack = PlayerAnimationAccess.getPlayerAnimLayer(player);
|
||||||
|
if (data.emote() != null && !data.emote().isEmpty()) {
|
||||||
|
if (animationStack.isActive() && animationStack.getPriority() == 1000) {
|
||||||
|
animationStack.removeLayer(1000);
|
||||||
|
}
|
||||||
|
animationStack.addAnimLayer(1000,
|
||||||
|
PlayerAnimationRegistry
|
||||||
|
.getAnimation(Identifier.of("saturnclient", data.emote()))
|
||||||
|
.playAnimation());
|
||||||
|
} else {
|
||||||
|
animationStack.removeLayer(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
session.onNotification(ServiceMethods.Player, (player) -> {
|
||||||
|
System.out.println(player);
|
||||||
|
SaturnPlayer.set(player.toSaturnPlayer());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void player(UUID uuid, String name) {
|
||||||
|
try {
|
||||||
|
session.request(ServiceMethods.GetPlayer, uuid.toString())
|
||||||
|
.whenComplete((user, throwable) -> {
|
||||||
|
if (throwable != null) {
|
||||||
|
throwable.printStackTrace();
|
||||||
|
} else if (user != null) {
|
||||||
|
SaturnPlayer.set(user.toSaturnPlayer(uuid, name));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
SaturnClient.LOGGER.error("Failed to get player", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,113 @@
|
|||||||
package org.saturnclient.saturnclient.client;
|
package org.saturnclient.saturnclient.client;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.saturnclient.saturnclient.client.ServiceMethods.Types.SendPlayerRequest;
|
||||||
|
import org.saturnclient.saturnclient.client.player.SaturnPlayer;
|
||||||
|
|
||||||
import dev.selimaj.session.types.Method;
|
import dev.selimaj.session.types.Method;
|
||||||
|
|
||||||
public class ServiceMethods {
|
public class ServiceMethods {
|
||||||
public record AuthResponse(String cloak, String hat, String[] cloaks, String[] hats) {
|
|
||||||
|
// =========================
|
||||||
|
// Types (Rust structs)
|
||||||
|
// =========================
|
||||||
|
public static class Types {
|
||||||
|
|
||||||
|
public record EmoteRequest(String emote, String[] targets) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Method<String, AuthResponse, String> Authenticate = new Method<>("auth",
|
public record EmoteEvent(String emote, String from) {
|
||||||
String.class, AuthResponse.class, String.class);
|
}
|
||||||
|
|
||||||
// Equip
|
public record Player(
|
||||||
|
String cloak,
|
||||||
|
String hat,
|
||||||
|
String[] cloaks,
|
||||||
|
String[] hats) {
|
||||||
|
public SaturnPlayer toSaturnPlayer(UUID uuid, String name) {
|
||||||
|
return new SaturnPlayer(uuid, name, cloak, hat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record PlayerStream(Player player, String name, String uuid) {
|
||||||
|
public SaturnPlayer toSaturnPlayer() {
|
||||||
|
return new SaturnPlayer(UUID.fromString(uuid), name, this.player.cloak, this.player.hat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record SendPlayerRequest(String[] targets) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// AUTH
|
||||||
|
// =========================
|
||||||
|
public static final Method<String, Types.Player, String> Authenticate = new Method<>("auth",
|
||||||
|
String.class,
|
||||||
|
Types.Player.class,
|
||||||
|
String.class);
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// EQUIP
|
||||||
|
// =========================
|
||||||
public static final Method<String, String, String> SetCloak = new Method<>("set_cloak",
|
public static final Method<String, String, String> SetCloak = new Method<>("set_cloak",
|
||||||
String.class, String.class, String.class);
|
String.class,
|
||||||
|
String.class,
|
||||||
|
String.class);
|
||||||
|
|
||||||
public static final Method<String, String, String> SetHat = new Method<>("set_hat",
|
public static final Method<String, String, String> SetHat = new Method<>("set_hat",
|
||||||
String.class, String.class, String.class);
|
String.class,
|
||||||
|
String.class,
|
||||||
|
String.class);
|
||||||
|
|
||||||
// Buy
|
// =========================
|
||||||
|
// BUY
|
||||||
|
// =========================
|
||||||
public static final Method<String, String, String> BuyCloak = new Method<>("buy_cloak",
|
public static final Method<String, String, String> BuyCloak = new Method<>("buy_cloak",
|
||||||
String.class, String.class, String.class);
|
String.class,
|
||||||
public static final Method<String, String, String> BuyHat = new Method<>("buy_hat",
|
String.class,
|
||||||
String.class, String.class, String.class);
|
String.class);
|
||||||
|
|
||||||
// Emote
|
public static final Method<String, String, String> BuyHat = new Method<>("buy_hat",
|
||||||
public static final Method<String, String, String> Emote = new Method<>("emote",
|
String.class,
|
||||||
String.class, String.class, String.class);
|
String.class,
|
||||||
|
String.class);
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// EMOTE
|
||||||
|
// =========================
|
||||||
|
public static final Method<Types.EmoteRequest, Void, String> Emote = new Method<>("emote",
|
||||||
|
Types.EmoteRequest.class,
|
||||||
|
Void.class,
|
||||||
|
String.class);
|
||||||
|
|
||||||
|
public static final Method<Types.EmoteEvent, Void, Void> EmoteEvent = new Method<>("emote_event",
|
||||||
|
Types.EmoteEvent.class,
|
||||||
|
Void.class,
|
||||||
|
Void.class);
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// GET PLAYER
|
||||||
|
// =========================
|
||||||
|
public static final Method<String, Types.Player, String> GetPlayer = new Method<>("get_player",
|
||||||
|
String.class,
|
||||||
|
Types.Player.class,
|
||||||
|
String.class);
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// PLAYER (Server Notification)
|
||||||
|
// =========================
|
||||||
|
public static final Method<Types.PlayerStream, Void, Void> Player = new Method<>("player",
|
||||||
|
Types.PlayerStream.class,
|
||||||
|
Void.class,
|
||||||
|
Void.class);
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// SEND PLAYER
|
||||||
|
// =========================
|
||||||
|
public static final Method<SendPlayerRequest, Void, String> SendPlayer = new Method<>("send_player",
|
||||||
|
SendPlayerRequest.class,
|
||||||
|
Void.class,
|
||||||
|
String.class);
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,7 @@ package org.saturnclient.saturnclient.client.player;
|
|||||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
|
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
|
||||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||||
import org.saturnclient.saturnclient.SaturnClient;
|
import org.saturnclient.saturnclient.SaturnClient;
|
||||||
|
import org.saturnclient.saturnclient.client.ServiceClient;
|
||||||
|
|
||||||
import net.minecraft.client.network.PlayerListEntry;
|
import net.minecraft.client.network.PlayerListEntry;
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
@@ -46,7 +47,6 @@ public class PlayerTracker {
|
|||||||
|
|
||||||
private static void onPlayerJoin(MinecraftClient client, PlayerListEntry player) {
|
private static void onPlayerJoin(MinecraftClient client, PlayerListEntry player) {
|
||||||
GameProfile profile = player.getProfile();
|
GameProfile profile = player.getProfile();
|
||||||
UUID uuid = profile.getId();
|
ServiceClient.player(profile.getId(), profile.getName());
|
||||||
SaturnPlayer.player(uuid);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,18 +41,14 @@ public class SaturnPlayer {
|
|||||||
return PLAYERS.get(uuid);
|
return PLAYERS.get(uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void set(UUID uuid, String name, SaturnPlayer player) {
|
public static void set(SaturnPlayer player) {
|
||||||
PLAYER_NAMES.put(name, uuid);
|
PLAYER_NAMES.put(player.name, player.uuid);
|
||||||
PLAYERS.put(uuid, player);
|
PLAYERS.put(player.uuid, player);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void player(UUID uuid) {
|
public static String[] getExternalUUIDAsString() {
|
||||||
if (PLAYERS.containsKey(uuid)) {
|
return PLAYERS.keySet().stream().filter(id -> !id.equals(ServiceClient.uuid)).map(UUID::toString)
|
||||||
return;
|
.toArray(String[]::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If offline then leave
|
|
||||||
|
|
||||||
PLAYERS.put(uuid, null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ 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;
|
||||||
SaturnPlayer player = SaturnPlayer.get(state.name);
|
SaturnPlayer player = SaturnPlayer.get(state.name);
|
||||||
if (headItem.isEmpty() || state.invisible || player == null || player.hat.isEmpty()) {
|
|
||||||
|
if (!headItem.isEmpty() || state.invisible || player == null || player.hat.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,10 +24,7 @@ public class Hats {
|
|||||||
|
|
||||||
public static void setHat(UUID uuid, String hatName) {
|
public static void setHat(UUID uuid, String hatName) {
|
||||||
SaturnPlayer player = SaturnPlayer.get(uuid);
|
SaturnPlayer player = SaturnPlayer.get(uuid);
|
||||||
if (player == null) {
|
if (player != null) {
|
||||||
// Auth.players.put(uuid, new SaturnPlayer("", hatName));
|
|
||||||
// TODO: address this behaviour
|
|
||||||
} else {
|
|
||||||
player.hat = hatName;
|
player.hat = hatName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,10 +76,7 @@ public class Cloaks {
|
|||||||
public static void setCloak(UUID uuid, String cloakName) {
|
public static void setCloak(UUID uuid, String cloakName) {
|
||||||
SaturnPlayer player = SaturnPlayer.get(uuid);
|
SaturnPlayer player = SaturnPlayer.get(uuid);
|
||||||
|
|
||||||
if (player == null) {
|
if (player != null) {
|
||||||
// Auth.players.put(uuid, new SaturnPlayer(cloakName, null));
|
|
||||||
// TODO: Address this functionality
|
|
||||||
} else {
|
|
||||||
player.cloak = cloakName;
|
player.cloak = cloakName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,11 +9,14 @@ import java.util.function.Function;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.joml.Matrix4f;
|
import org.joml.Matrix4f;
|
||||||
import org.saturnclient.ui2.resources.Fonts;
|
import org.saturnclient.ui2.resources.Fonts;
|
||||||
|
import org.saturnclient.ui2.resources.SvgTexture;
|
||||||
|
|
||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
|
||||||
import org.saturnclient.saturnclient.SaturnClient;
|
import org.saturnclient.saturnclient.SaturnClient;
|
||||||
import org.saturnclient.saturnclient.mixin.DrawContextAccessor;
|
import org.saturnclient.saturnclient.mixin.DrawContextAccessor;
|
||||||
|
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.font.TextRenderer;
|
import net.minecraft.client.font.TextRenderer;
|
||||||
import net.minecraft.client.font.TextRenderer.TextLayerType;
|
import net.minecraft.client.font.TextRenderer.TextLayerType;
|
||||||
import net.minecraft.client.gui.DrawContext;
|
import net.minecraft.client.gui.DrawContext;
|
||||||
@@ -224,6 +227,11 @@ public class RenderScope {
|
|||||||
|
|
||||||
private void drawTexturedQuad(Identifier sprite, int x1, int x2, int y1, int y2, float u1, float u2, float v1,
|
private void drawTexturedQuad(Identifier sprite, int x1, int x2, int y1, int y2, float u1, float u2, float v1,
|
||||||
float v2, int color) {
|
float v2, int color) {
|
||||||
|
|
||||||
|
if (sprite.toString().endsWith(".svg")) {
|
||||||
|
sprite = SvgTexture.getSvg(MinecraftClient.getInstance(), sprite, (x2 - x1) * 2, (y2 - y1) * 2);
|
||||||
|
}
|
||||||
|
|
||||||
if (color == 0)
|
if (color == 0)
|
||||||
return;
|
return;
|
||||||
x1 *= 4;
|
x1 *= 4;
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ public class Utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static <T> T getOrNull(List<T> list, int index) {
|
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;
|
return (index >= 0 && index < list.size()) ? list.get(index) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,9 @@ package org.saturnclient.ui2.elements;
|
|||||||
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.SvgTexture;
|
||||||
|
|
||||||
import net.minecraft.client.render.RenderLayer;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
public class ImageTexture extends Element {
|
public class ImageTexture extends Element {
|
||||||
@@ -16,7 +17,16 @@ public class ImageTexture extends Element {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(RenderScope renderScope, ElementContext ctx) {
|
public void render(RenderScope renderScope, ElementContext ctx) {
|
||||||
renderScope.setRenderLayer(RenderLayer::getGuiTextured);
|
if (sprite.toString().endsWith(".svg")) {
|
||||||
|
MinecraftClient client = MinecraftClient.getInstance();
|
||||||
|
|
||||||
|
// Get the actual window pixel dimensions for the image
|
||||||
|
int renderWidth = (int) (width * client.getWindow().getFramebufferWidth() / client.getWindow().getWidth());
|
||||||
|
int renderHeight = (int) (height * client.getWindow().getFramebufferHeight() / client.getWindow().getHeight());
|
||||||
|
|
||||||
|
sprite = SvgTexture.getSvg(client, sprite, renderWidth * 2, renderHeight * 2);
|
||||||
|
}
|
||||||
|
|
||||||
renderScope.drawTexture(sprite, 0, 0, 0, 0, width, height);
|
renderScope.drawTexture(sprite, 0, 0, 0, 0, width, height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package org.saturnclient.ui2.resources;
|
||||||
|
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.RenderingHints;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.kitfox.svg.SVGDiagram;
|
||||||
|
import com.kitfox.svg.SVGUniverse;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.saturnclient.saturnclient.cosmetics.cloaks.utils.IdentifierUtils;
|
||||||
|
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
public class SvgTexture {
|
||||||
|
|
||||||
|
private static List<Identifier> svgCache = new ArrayList<>();
|
||||||
|
|
||||||
|
private static BufferedImage renderSvg(InputStream svgStream, int width, int height) throws Exception {
|
||||||
|
// Load SVG
|
||||||
|
SVGUniverse universe = new SVGUniverse();
|
||||||
|
java.net.URI uri = universe.loadSVG(svgStream, "tempSvg");
|
||||||
|
SVGDiagram diagram = universe.getDiagram(uri);
|
||||||
|
|
||||||
|
// Get intrinsic size of SVG
|
||||||
|
float svgWidth = (float) diagram.getWidth();
|
||||||
|
float svgHeight = (float) diagram.getHeight();
|
||||||
|
|
||||||
|
// Compute scale factors
|
||||||
|
float scaleX = width / svgWidth;
|
||||||
|
float scaleY = height / svgHeight;
|
||||||
|
|
||||||
|
// Create output image
|
||||||
|
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
Graphics2D g = image.createGraphics();
|
||||||
|
|
||||||
|
// Enable anti-aliasing for smooth scaling
|
||||||
|
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
|
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
|
||||||
|
|
||||||
|
// Apply scaling transform
|
||||||
|
g.scale(scaleX, scaleY);
|
||||||
|
|
||||||
|
// Render SVG
|
||||||
|
diagram.render(g);
|
||||||
|
|
||||||
|
g.dispose();
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static Identifier getSvg(MinecraftClient client, Identifier svgImage, int width, int height) {
|
||||||
|
Identifier id = Identifier
|
||||||
|
.of(svgImage.toString().replaceAll("\\.svg$", (width + "_" + height).toString() + ".png"));
|
||||||
|
|
||||||
|
if (svgCache.contains(id)) {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
try (InputStream svgStream = client
|
||||||
|
.getResourceManager()
|
||||||
|
.getResource(svgImage).get()
|
||||||
|
.getInputStream()) {
|
||||||
|
|
||||||
|
BufferedImage image = renderSvg(svgStream, width, height);
|
||||||
|
|
||||||
|
IdentifierUtils.registerBufferedImageTexture(id, image);
|
||||||
|
|
||||||
|
return id;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -53,7 +53,7 @@ public class Textures {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 + ".svg");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 675 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-shield-icon lucide-shield"><path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"/></svg>
|
||||||
|
After Width: | Height: | Size: 404 B |
|
Before Width: | Height: | Size: 526 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-move3d-icon lucide-move-3d"><path d="M5 3v16h16"/><path d="m5 19 6-6"/><path d="m2 6 3-3 3 3"/><path d="m18 16 3 3-3 3"/></svg>
|
||||||
|
After Width: | Height: | Size: 324 B |
|
Before Width: | Height: | Size: 1.0 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-plus-icon lucide-plus"><path d="M5 12h14"/><path d="M12 5v14"/></svg>
|
||||||
|
After Width: | Height: | Size: 266 B |
|
Before Width: | Height: | Size: 294 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-calendar-days-icon lucide-calendar-days"><path d="M8 2v4"/><path d="M16 2v4"/><rect width="18" height="18" x="3" y="4" rx="2"/><path d="M3 10h18"/><path d="M8 14h.01"/><path d="M12 14h.01"/><path d="M16 14h.01"/><path d="M8 18h.01"/><path d="M12 18h.01"/><path d="M16 18h.01"/></svg>
|
||||||
|
After Width: | Height: | Size: 480 B |
|
Before Width: | Height: | Size: 2.5 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-sparkles-icon lucide-sparkles"><path d="M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z"/><path d="M20 2v4"/><path d="M22 4h-4"/><circle cx="4" cy="20" r="2"/></svg>
|
||||||
|
After Width: | Height: | Size: 577 B |
|
Before Width: | Height: | Size: 478 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chart-area-icon lucide-chart-area"><path d="M3 3v16a2 2 0 0 0 2 2h16"/><path d="M7 11.207a.5.5 0 0 1 .146-.353l2-2a.5.5 0 0 1 .708 0l3.292 3.292a.5.5 0 0 0 .708 0l4.292-4.292a.5.5 0 0 1 .854.353V16a1 1 0 0 1-1 1H8a1 1 0 0 1-1-1z"/></svg>
|
||||||
|
After Width: | Height: | Size: 434 B |
|
Before Width: | Height: | Size: 959 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-switch-camera-icon lucide-switch-camera"><path d="M11 19H4a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2h5"/><path d="M13 5h7a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2h-5"/><circle cx="12" cy="12" r="3"/><path d="m18 22-3-3 3-3"/><path d="m6 2 3 3-3 3"/></svg>
|
||||||
|
After Width: | Height: | Size: 430 B |
|
Before Width: | Height: | Size: 697 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-sun-icon lucide-sun"><circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m6.34 17.66-1.41 1.41"/><path d="m19.07 4.93-1.41 1.41"/></svg>
|
||||||
|
After Width: | Height: | Size: 465 B |
|
Before Width: | Height: | Size: 962 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-heart-icon lucide-heart"><path d="M2 9.5a5.5 5.5 0 0 1 9.591-3.676.56.56 0 0 0 .818 0A5.49 5.49 0 0 1 22 9.5c0 2.29-1.5 4-3 5.5l-5.492 5.313a2 2 0 0 1-3 .019L5 15c-1.5-1.5-3-3.2-3-5.5"/></svg>
|
||||||
|
After Width: | Height: | Size: 389 B |
|
Before Width: | Height: | Size: 3.2 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-keyboard-icon lucide-keyboard"><path d="M10 8h.01"/><path d="M12 12h.01"/><path d="M14 8h.01"/><path d="M16 12h.01"/><path d="M18 8h.01"/><path d="M6 8h.01"/><path d="M7 16h10"/><path d="M8 12h.01"/><rect width="20" height="16" x="2" y="4" rx="2"/></svg>
|
||||||
|
After Width: | Height: | Size: 451 B |
|
Before Width: | Height: | Size: 282 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-cloud-fog-icon lucide-cloud-fog"><path d="M4 14.899A7 7 0 1 1 15.71 8h1.79a4.5 4.5 0 0 1 2.5 8.242"/><path d="M16 17H7"/><path d="M17 21H9"/></svg>
|
||||||
|
After Width: | Height: | Size: 344 B |
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-wand-sparkles-icon lucide-wand-sparkles"><path d="m21.64 3.64-1.28-1.28a1.21 1.21 0 0 0-1.72 0L2.36 18.64a1.21 1.21 0 0 0 0 1.72l1.28 1.28a1.2 1.2 0 0 0 1.72 0L21.64 5.36a1.2 1.2 0 0 0 0-1.72"/><path d="m14 7 3 3"/><path d="M5 6v4"/><path d="M19 14v4"/><path d="M10 2v2"/><path d="M7 8H3"/><path d="M21 16h-4"/><path d="M11 3H9"/></svg>
|
||||||
|
After Width: | Height: | Size: 533 B |
|
Before Width: | Height: | Size: 1.0 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-gauge-icon lucide-gauge"><path d="m12 14 4-4"/><path d="M3.34 19a10 10 0 1 1 17.32 0"/></svg>
|
||||||
|
After Width: | Height: | Size: 290 B |
|
Before Width: | Height: | Size: 961 B |
@@ -0,0 +1,35 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||||
|
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||||
|
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="1167.000000pt" height="1280.000000pt" viewBox="0 0 1167.000000 1280.000000"
|
||||||
|
preserveAspectRatio="xMidYMid meet">
|
||||||
|
<metadata>
|
||||||
|
Created by potrace 1.15, written by Peter Selinger 2001-2017
|
||||||
|
</metadata>
|
||||||
|
<g transform="translate(0.000000,1280.000000) scale(0.100000,-0.100000)"
|
||||||
|
fill="white" stroke="none">
|
||||||
|
<path d="M9270 12789 c-229 -29 -473 -124 -657 -256 -272 -194 -468 -494 -539
|
||||||
|
-825 -25 -114 -25 -369 -1 -491 94 -472 445 -861 918 -1021 167 -56 260 -70
|
||||||
|
459 -70 199 0 292 14 459 70 400 135 727 449 864 829 50 141 70 257 71 425 1
|
||||||
|
176 -11 259 -59 406 -165 505 -614 864 -1166 934 -96 12 -254 11 -349 -1z"/>
|
||||||
|
<path d="M5145 10889 c-80 -12 -193 -69 -252 -127 -42 -41 -1667 -2180 -1780
|
||||||
|
-2342 -24 -35 -54 -97 -69 -143 -23 -69 -27 -100 -27 -197 -1 -103 2 -124 29
|
||||||
|
-200 70 -200 212 -329 394 -362 128 -22 284 28 378 123 27 27 397 512 823
|
||||||
|
1078 l774 1030 443 0 443 1 -19 -27 c-11 -16 -769 -1026 -1684 -2246 l-1664
|
||||||
|
-2219 -1215 -1 -1214 -2 -68 -27 c-93 -38 -164 -87 -239 -166 -323 -343 -232
|
||||||
|
-974 171 -1186 134 -70 29 -66 1631 -66 1549 0 1541 0 1705 51 124 38 264 118
|
||||||
|
331 190 18 19 321 405 674 859 354 454 648 831 655 838 10 11 162 -154 768
|
||||||
|
-832 417 -465 757 -852 757 -860 0 -9 -140 -728 -311 -1598 -223 -1137 -312
|
||||||
|
-1611 -316 -1681 -21 -363 196 -688 508 -762 302 -71 612 129 718 465 11 36
|
||||||
|
180 886 376 1890 195 1004 376 1926 401 2049 40 196 45 239 46 355 0 197 -40
|
||||||
|
357 -124 486 -27 42 -731 859 -1325 1537 l-55 62 728 968 c400 532 728 969
|
||||||
|
729 971 1 1 211 -240 467 -535 256 -296 489 -560 517 -586 63 -59 178 -115
|
||||||
|
260 -127 144 -20 301 37 430 156 98 91 1610 1844 1649 1912 57 100 77 181 76
|
||||||
|
317 0 87 -5 137 -18 180 -49 163 -154 293 -292 361 -77 39 -79 39 -193 39
|
||||||
|
-104 -1 -122 -3 -174 -27 -32 -15 -77 -41 -100 -58 -24 -17 -328 -358 -677
|
||||||
|
-760 -349 -401 -638 -728 -641 -727 -4 1 -354 402 -780 891 -440 506 -796 907
|
||||||
|
-827 931 -30 24 -80 55 -111 71 -127 62 -38 58 -1401 60 -685 1 -1272 -2
|
||||||
|
-1305 -7z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-search-icon lucide-search"><path d="m21 21-4.34-4.34"/><circle cx="11" cy="11" r="8"/></svg>
|
||||||
|
After Width: | Height: | Size: 289 B |