Compare commits
31
Commits
0.1.1-beta
...
771ed93992
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
771ed93992 | ||
|
|
a8e6f14022 | ||
|
|
84270c023a | ||
|
|
25a19d7951 | ||
|
|
c5665548a0 | ||
|
|
22142be7b5 | ||
|
|
a949c18ec1 | ||
|
|
6f122b5237 | ||
|
|
85e5ef3f59 | ||
|
|
0bf4fc6808 | ||
|
|
a44b4f4e90 | ||
|
|
f2d30e6611 | ||
|
|
242653054d | ||
|
|
95e4dff448 | ||
|
|
a30cf4d3ab | ||
|
|
eebfe8fa4d | ||
|
|
019e5cfb43 | ||
|
|
6ed2ac1b60 | ||
|
|
1853b09443 | ||
|
|
9126faa11c | ||
|
|
090e5132b2 | ||
|
|
bbe6d02568 | ||
|
|
04e7064790 | ||
|
|
ff0bce4d24 | ||
|
|
2ecb4f80ea | ||
|
|
41f9be8595 | ||
|
|
f73f7e733c | ||
|
|
91b53daac9 | ||
|
|
5bcdc72b83 | ||
|
|
3f0670ea9d | ||
|
|
c54b5ae6d7 |
@@ -0,0 +1,164 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
// Publish the jars attached to a Gitea release to Modrinth.
|
||||||
|
//
|
||||||
|
// Creates one Modrinth version per jar (saturn-client-<version>+<mc>.jar), for
|
||||||
|
// that Minecraft version, with Fabric API as a required dependency and the
|
||||||
|
// Gitea release notes as the changelog. Versions that already exist on
|
||||||
|
// Modrinth are skipped, so the script is safe to re-run.
|
||||||
|
//
|
||||||
|
// Runs on plain Node (>= 18: fetch, FormData, Blob) with no dependencies, since
|
||||||
|
// every Gitea Actions runner has Node to run JavaScript actions.
|
||||||
|
//
|
||||||
|
// Environment:
|
||||||
|
// TAG release tag, e.g. 0.1.1-beta
|
||||||
|
// SERVER_URL public Gitea URL, e.g. https://git.selimaj.dev
|
||||||
|
// REPO owner/name, e.g. saturnclientmc/saturnclient
|
||||||
|
// MODRINTH_TOKEN Modrinth PAT with the "Create versions" scope
|
||||||
|
// DRY_RUN "true" to check everything and print what would be
|
||||||
|
// published without uploading (no token needed)
|
||||||
|
|
||||||
|
const MODRINTH_API = "https://api.modrinth.com/v2";
|
||||||
|
const MODRINTH_PROJECT_ID = "i6JDSY9x"; // saturnclient
|
||||||
|
const FABRIC_API_PROJECT_ID = "P7dR8mSH";
|
||||||
|
const USER_AGENT =
|
||||||
|
"saturnclientmc/saturnclient release workflow (https://git.selimaj.dev/saturnclientmc/saturnclient)";
|
||||||
|
|
||||||
|
const JAR_NAME = /^saturn-client-(?<version>.+)\+(?<mc>\d+\.\d+(?:\.\d+)?)\.jar$/;
|
||||||
|
|
||||||
|
function fail(message) {
|
||||||
|
console.error(message);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function http(url, options = {}) {
|
||||||
|
const res = await fetch(url, {
|
||||||
|
...options,
|
||||||
|
headers: { "User-Agent": USER_AGENT, ...options.headers },
|
||||||
|
});
|
||||||
|
if (!res.ok) {
|
||||||
|
const error = new Error(`${options.method ?? "GET"} ${url} returned ${res.status}: ${await res.text()}`);
|
||||||
|
error.status = res.status;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getJson(url) {
|
||||||
|
return (await http(url)).json();
|
||||||
|
}
|
||||||
|
|
||||||
|
function versionType(tag) {
|
||||||
|
const t = tag.toLowerCase();
|
||||||
|
if (t.includes("alpha")) return "alpha";
|
||||||
|
if (t.includes("beta") || t.includes("rc") || t.includes("pre")) return "beta";
|
||||||
|
return "release";
|
||||||
|
}
|
||||||
|
|
||||||
|
function compareMc(a, b) {
|
||||||
|
const pa = a.split(".").map(Number);
|
||||||
|
const pb = b.split(".").map(Number);
|
||||||
|
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
||||||
|
const diff = (pa[i] ?? 0) - (pb[i] ?? 0);
|
||||||
|
if (diff !== 0) return diff;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const { TAG: tag, SERVER_URL, REPO: repo } = process.env;
|
||||||
|
const serverUrl = (SERVER_URL ?? "").replace(/\/+$/, "");
|
||||||
|
const dryRun = (process.env.DRY_RUN ?? "").toLowerCase() === "true";
|
||||||
|
const token = process.env.MODRINTH_TOKEN ?? "";
|
||||||
|
|
||||||
|
if (!tag || !serverUrl || !repo) fail("TAG, SERVER_URL and REPO must be set.");
|
||||||
|
if (!token && !dryRun) {
|
||||||
|
fail("MODRINTH_TOKEN is not set. Add it as a repository secret (Settings → Actions → Secrets).");
|
||||||
|
}
|
||||||
|
|
||||||
|
let release;
|
||||||
|
try {
|
||||||
|
release = await getJson(`${serverUrl}/api/v1/repos/${repo}/releases/tags/${encodeURIComponent(tag)}`);
|
||||||
|
} catch (e) {
|
||||||
|
if (e.status === 404) fail(`No Gitea release with tag ${tag}.`);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
const changelog = release.body ?? "";
|
||||||
|
|
||||||
|
const jars = (release.assets ?? [])
|
||||||
|
.map((asset) => ({ name: asset.name, match: JAR_NAME.exec(asset.name) }))
|
||||||
|
.filter(({ match }) => match)
|
||||||
|
.map(({ name, match }) => ({ name, version: match.groups.version, mc: match.groups.mc }))
|
||||||
|
.sort((a, b) => compareMc(a.mc, b.mc));
|
||||||
|
|
||||||
|
if (jars.length === 0) fail(`Release ${tag} has no saturn-client-*.jar assets. Run the Release workflow first.`);
|
||||||
|
|
||||||
|
for (const jar of jars) {
|
||||||
|
if (jar.version !== tag.replace(/^v/, "")) fail(`${jar.name} is version ${jar.version}, but the release tag is ${tag}.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const knownGameVersions = new Set((await getJson(`${MODRINTH_API}/tag/game_version`)).map((g) => g.version));
|
||||||
|
const unknown = [...new Set(jars.map((j) => j.mc))].filter((mc) => !knownGameVersions.has(mc));
|
||||||
|
if (unknown.length > 0) fail(`Modrinth doesn't know these Minecraft versions: ${unknown.join(", ")}`);
|
||||||
|
|
||||||
|
const existing = new Set(
|
||||||
|
(await getJson(`${MODRINTH_API}/project/${MODRINTH_PROJECT_ID}/version`)).map((v) => v.version_number),
|
||||||
|
);
|
||||||
|
const kind = versionType(tag);
|
||||||
|
const failed = [];
|
||||||
|
|
||||||
|
for (const { name, version, mc } of jars) {
|
||||||
|
const versionNumber = `${version}+${mc}`;
|
||||||
|
|
||||||
|
if (existing.has(versionNumber)) {
|
||||||
|
console.log(`skip ${versionNumber}: already on Modrinth`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gitea's own download URLs use its internal ROOT_URL, so build a public one.
|
||||||
|
const downloadUrl = `${serverUrl}/${repo}/releases/download/${encodeURIComponent(tag)}/${encodeURIComponent(name)}`;
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
project_id: MODRINTH_PROJECT_ID,
|
||||||
|
name: `Saturn Client ${versionNumber}`,
|
||||||
|
version_number: versionNumber,
|
||||||
|
changelog,
|
||||||
|
dependencies: [{ project_id: FABRIC_API_PROJECT_ID, dependency_type: "required" }],
|
||||||
|
game_versions: [mc],
|
||||||
|
version_type: kind,
|
||||||
|
loaders: ["fabric"],
|
||||||
|
featured: false,
|
||||||
|
status: "listed",
|
||||||
|
file_parts: ["file"],
|
||||||
|
primary_file: "file",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (dryRun) {
|
||||||
|
const probe = await http(downloadUrl, { headers: { Range: "bytes=0-0" } });
|
||||||
|
await probe.arrayBuffer();
|
||||||
|
console.log(`would publish ${versionNumber} (${kind}, Minecraft ${mc}) from ${downloadUrl} [reachable]`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const jarBytes = await (await http(downloadUrl)).arrayBuffer();
|
||||||
|
|
||||||
|
const form = new FormData();
|
||||||
|
form.append("data", JSON.stringify(data));
|
||||||
|
form.append("file", new Blob([jarBytes], { type: "application/java-archive" }), name);
|
||||||
|
|
||||||
|
await http(`${MODRINTH_API}/version`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: { Authorization: token },
|
||||||
|
body: form,
|
||||||
|
});
|
||||||
|
console.log(`publish ${versionNumber}: done (${(jarBytes.byteLength / 1_000_000).toFixed(1)} MB)`);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`publish ${versionNumber}: FAILED ${e.message}`);
|
||||||
|
failed.push(versionNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failed.length > 0) fail(`Failed to publish: ${failed.join(", ")}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((e) => fail(e.stack ?? String(e)));
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
name: Check
|
||||||
|
|
||||||
|
# Compiles every Minecraft version on pull requests, so a change that breaks
|
||||||
|
# one version (e.g. a missed or bad port) fails before it's merged instead of
|
||||||
|
# in the release build. Merges to master aren't re-checked: the PR already
|
||||||
|
# checked that code.
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
compile:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
|
||||||
|
# The JDK comes from the runner's tool cache. `cache: gradle` stores Gradle's
|
||||||
|
# dependencies, Loom's Minecraft cache and the build cache in the runner's
|
||||||
|
# actions cache.
|
||||||
|
- name: Set up Java 21
|
||||||
|
uses: actions/setup-java@v5
|
||||||
|
with:
|
||||||
|
distribution: temurin
|
||||||
|
java-version: 21
|
||||||
|
cache: gradle
|
||||||
|
|
||||||
|
- name: Compile all versions
|
||||||
|
run: |
|
||||||
|
chmod +x gradlew
|
||||||
|
# --continue reports every version that fails, not just the first.
|
||||||
|
./gradlew compileJava --no-daemon --stacktrace --continue
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
name: Publish to Modrinth
|
||||||
|
|
||||||
|
# Publishes the jars already attached to a Gitea release (built by the Release
|
||||||
|
# workflow) to Modrinth, one version per Minecraft version. Run it manually
|
||||||
|
# after smoke-testing the release. It doesn't rebuild anything, and versions
|
||||||
|
# already on Modrinth are skipped, so re-running is safe.
|
||||||
|
#
|
||||||
|
# Needs a MODRINTH_TOKEN repository secret: a Modrinth PAT with the
|
||||||
|
# "Create versions" scope.
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
tag:
|
||||||
|
description: Tag of the Gitea release to publish
|
||||||
|
required: true
|
||||||
|
dry_run:
|
||||||
|
description: Only check and print what would be published
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Publish to Modrinth
|
||||||
|
env:
|
||||||
|
TAG: ${{ inputs.tag }}
|
||||||
|
DRY_RUN: ${{ inputs.dry_run }}
|
||||||
|
SERVER_URL: ${{ github.server_url }}
|
||||||
|
REPO: ${{ github.repository }}
|
||||||
|
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
|
||||||
|
# Node is always available on Gitea runners (it runs JavaScript actions).
|
||||||
|
run: node .gitea/scripts/publish_modrinth.mjs
|
||||||
@@ -44,8 +44,11 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
echo "Building Saturn Client $MOD_VERSION"
|
echo "Building Saturn Client $MOD_VERSION"
|
||||||
|
|
||||||
|
# The JDK comes from the runner's tool cache. `cache: gradle` stores Gradle's
|
||||||
|
# dependencies, Loom's Minecraft cache and the build cache in the runner's
|
||||||
|
# actions cache.
|
||||||
- name: Set up Java 21
|
- name: Set up Java 21
|
||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v5
|
||||||
with:
|
with:
|
||||||
distribution: temurin
|
distribution: temurin
|
||||||
java-version: 21
|
java-version: 21
|
||||||
@@ -54,7 +57,8 @@ jobs:
|
|||||||
- name: Build all versions
|
- name: Build all versions
|
||||||
run: |
|
run: |
|
||||||
chmod +x gradlew
|
chmod +x gradlew
|
||||||
# buildAll remaps every versions/* project in parallel into build/allJars.
|
# buildAll remaps every Minecraft version (two at a time, to stay within the
|
||||||
|
# Gradle heap) into build/allJars.
|
||||||
./gradlew buildAll --no-daemon --stacktrace
|
./gradlew buildAll --no-daemon --stacktrace
|
||||||
|
|
||||||
- name: Upload jars to the release
|
- name: Upload jars to the release
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="https://raw.github.com/saturnclientmc/common/master/src/main/resources/assets/saturnclient/textures/logo/logo.png" alt="Saturn Client Logo" width="150px"/>
|
<img src="logo.png" alt="Saturn Client Logo" width="150px"/>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h1 align="center">Saturn Client</h1>
|
<h1 align="center">Saturn Client</h1>
|
||||||
@@ -13,27 +13,47 @@
|
|||||||
<img src="screenshot.png" alt="Saturn Client Screenshot"/>
|
<img src="screenshot.png" alt="Saturn Client Screenshot"/>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
---
|
## About
|
||||||
|
|
||||||
## ✨ About
|
|
||||||
|
|
||||||
Saturn Client is a free, open-source Minecraft client designed to enhance the gameplay experience while staying lightweight and customizable.
|
Saturn Client is a free, open-source Minecraft client designed to enhance the gameplay experience while staying lightweight and customizable.
|
||||||
Our goal is to build a clean, optimized client that the community can contribute to and improve together.
|
Our goal is to build a clean, optimized client that the community can contribute to and improve together.
|
||||||
|
|
||||||
Saturn is currently trying to support multiple versions of minecraft, so please report any issues you are experiencing.
|
Saturn runs on Fabric and supports **Minecraft 1.21.4 to 1.21.11**, with one build per version. If something doesn't work on your version, please open an issue.
|
||||||
|
|
||||||
---
|
## Features
|
||||||
|
|
||||||
## 🚀 Features
|
- Free cosmetics that don't require real money: cloaks, including animated ones, and hats
|
||||||
|
- 18 built-in mods: Armor Display, Auto Sprint, Clock, Coordinates, Crosshair, Day Counter, FPS Display, Freelook, Fullbright, Health Display, Keystrokes, Nametags, No Fog, Ping Display, Speedometer, Status Effects, TPS Display and Zoom
|
||||||
- Free cosmetics that don't require real money
|
|
||||||
- Clean and modern UI with animations
|
- Clean and modern UI with animations
|
||||||
- Ongoing performance improvements
|
- Ongoing performance improvements
|
||||||
- Open-source and community-driven
|
- Open-source and community-driven
|
||||||
|
|
||||||
---
|
## Installation
|
||||||
|
|
||||||
## 🤝 Contributing
|
1. Install [Fabric Loader](https://fabricmc.net/use/) and [Fabric API](https://modrinth.com/mod/fabric-api) for your Minecraft version.
|
||||||
|
2. Download the Saturn Client jar for the same version from [Modrinth](https://modrinth.com/mod/saturnclient) or the [releases page](https://git.selimaj.dev/saturnclientmc/saturnclient/releases).
|
||||||
|
3. Put it in your `mods` folder.
|
||||||
|
|
||||||
|
### Network use
|
||||||
|
|
||||||
|
For cosmetics, Saturn Client connects to the Saturn server (`saturn-server.selimaj.dev`). You're signed in the same way as on an online-mode Minecraft server: your client proves who you are to Mojang's session server, and the Saturn server asks Mojang to confirm it. **Your Minecraft access token is only ever sent to Mojang, never to the Saturn server.**
|
||||||
|
|
||||||
|
## Building from source
|
||||||
|
|
||||||
|
The version-independent code lives in the `common` submodule, so clone with submodules:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone --recurse-submodules https://git.selimaj.dev/saturnclientmc/saturnclient.git
|
||||||
|
cd saturnclient
|
||||||
|
|
||||||
|
./gradlew buildAll # every version → build/allJars/
|
||||||
|
./gradlew :1.21.11:build # a single version
|
||||||
|
./gradlew :1.21.11:runClient # launch a development client
|
||||||
|
```
|
||||||
|
|
||||||
|
Building needs Java 21.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
We welcome contributions of all kinds:
|
We welcome contributions of all kinds:
|
||||||
|
|
||||||
@@ -43,27 +63,23 @@ We welcome contributions of all kinds:
|
|||||||
- Cosmetic designs
|
- Cosmetic designs
|
||||||
- Suggestions and feedback
|
- Suggestions and feedback
|
||||||
|
|
||||||
If you're an artist or designer interested in helping with cosmetics or visual assets, we’d love to collaborate.
|
If you're an artist or designer interested in helping with cosmetics or visual assets, we'd love to collaborate.
|
||||||
|
|
||||||
---
|
Most features belong in `common`, which every Minecraft version shares. For code that differs between versions, see the [version guide](VERSION_GUIDE.md): it covers how the versions share one copy of the code with Stonecutter, writing version-specific code, and adding a new Minecraft version. Every pull request is compiled for all versions automatically.
|
||||||
|
|
||||||
## 🙌 Credits
|
## Credits
|
||||||
|
|
||||||
- **Cloak Rendering:** `IIpho3nix` & Saturn
|
- **Cloak Rendering:** `IIpho3nix` & Saturn
|
||||||
- **Who Am I:** `FokshaWasTaken`
|
- **Who Am I:** `FokshaWasTaken`
|
||||||
- **Panorama:**
|
- **Panorama:**
|
||||||
https://www.planetminecraft.com/texture-pack/minecraft-cavesand-cliffs-part-ii-main-menu-panorama/
|
https://www.planetminecraft.com/texture-pack/minecraft-cavesand-cliffs-part-ii-main-menu-panorama/
|
||||||
|
|
||||||
If any code or assets belong to you and you would like them removed, please open an issue.
|
If any code or assets belong to you and you would like them removed, please open an issue.
|
||||||
We aim to properly credit all contributors and respect original creators of their respective art.
|
We aim to properly credit all contributors and respect original creators of their respective art.
|
||||||
|
|
||||||
---
|
## License
|
||||||
|
|
||||||
## 📜 License
|
Saturn Client is free and open-source under the **Apache-2.0** license.
|
||||||
|
|
||||||
Saturn Client is free and open-source using **Apache-2.0**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
Made with ❤️ by the Saturn Client team
|
Made with ❤️ by the Saturn Client team
|
||||||
|
|||||||
+66
-1
@@ -1,3 +1,68 @@
|
|||||||
# Version guide
|
# Version guide
|
||||||
|
|
||||||
This guide will help you to add or edit minecraft versions.
|
How Saturn Client supports several Minecraft versions, and how to change or add one.
|
||||||
|
|
||||||
|
## Layout
|
||||||
|
|
||||||
|
Every supported Minecraft version (1.21.4 to 1.21.11) builds from one copy of the version-specific code with [Stonecutter](https://stonecutter.kikugie.dev/):
|
||||||
|
|
||||||
|
- `common/`: all version-independent code (mods, UI, cosmetics, the server client). It has no Minecraft dependency and reaches the game only through the interfaces in `org.saturnclient.common`.
|
||||||
|
- `src/`: the version-specific code (providers, refs, mixins and the three mixin configs), one copy for every version. Where Minecraft's API differs between versions, the code goes behind version comments (see below).
|
||||||
|
- `versions/<mc>/`: each version's `gradle.properties` (Minecraft, Yarn, Fabric Loader and Fabric API versions), plus its `build/` and `run/` folders. Each version is the Gradle project `:<mc>`.
|
||||||
|
|
||||||
|
`settings.gradle.kts` lists the versions in `stonecutterVersions`. The root `build.gradle.kts` builds each version, and `stonecutter.gradle.kts` configures the root project (shared repositories, the `common` wiring and `buildAll`). Loom's version is `loom_version` in the root `gradle.properties`.
|
||||||
|
|
||||||
|
## Version-specific code with Stonecutter
|
||||||
|
|
||||||
|
The code in `src/` is always plain Java for the **active** version (1.21.11, set in `stonecutter.gradle.kts`). Code for other versions sits in comments that Stonecutter swaps before building each version:
|
||||||
|
|
||||||
|
```java
|
||||||
|
//? if >=1.21.9 {
|
||||||
|
public void render(MatrixStack matrices, OrderedRenderCommandQueue queue, int light, PlayerEntityRenderState state, float limbAngle, float limbDistance) {
|
||||||
|
//?} else
|
||||||
|
//public void render(MatrixStack matrices, VertexConsumerProvider consumers, int light, PlayerEntityRenderState state, float limbAngle, float limbDistance) {
|
||||||
|
```
|
||||||
|
|
||||||
|
A condition without braces covers the next line only. For several lines, use braces and wrap the inactive block in `/* … */`:
|
||||||
|
|
||||||
|
```java
|
||||||
|
//? if >=1.21.11 {
|
||||||
|
import net.minecraft.client.render.RenderLayers;
|
||||||
|
import net.minecraft.client.render.RenderSetup;
|
||||||
|
//?} else {
|
||||||
|
/*import net.minecraft.client.render.RenderPhase.Textures;
|
||||||
|
*///?}
|
||||||
|
```
|
||||||
|
|
||||||
|
Stonecutter rewrites inactive code into its own layout when switching versions (a single inactive line becomes `//code`), so write it that way to begin with, or run a switch and a reset before committing.
|
||||||
|
|
||||||
|
When a newer version leaves something out that an older one implements, keep the older version's code behind a condition and mark the newer branch with a `TODO`, rather than dropping it for every version. `WorldFeatureImpl.getWorldAge` and `SaturnScreenFabric.resize` are examples. Search for `TODO` to find what newer versions still lack.
|
||||||
|
|
||||||
|
A whole class that only exists for some versions (such as `NametagsMixin`, which hooks a method that 1.21.9 changed) can keep an empty class body on the other versions. An empty mixin changes nothing, and it keeps the mixin configs the same for every version, since JSON can't hold version comments.
|
||||||
|
|
||||||
|
Inactive code sits inside a `/* … */` comment, so it can't contain `/* … */` comments itself: use `//` comments in code that's only active for some versions. For the same reason, don't nest multi-line version blocks; use `//?} else if <condition> {` for more than two version ranges, as in `PlayerEntityRendererMixin` and `SaturnRenderState`.
|
||||||
|
|
||||||
|
- `./gradlew "Set active project to <mc>"` (or the Stonecutter IntelliJ plugin) rewrites `src/` so that version's code is the uncommented one, for editing it in the IDE.
|
||||||
|
- `./gradlew "Reset active project"` switches back to 1.21.11. **Run it before committing**, so `src/` is always committed with 1.21.11 active.
|
||||||
|
- Each version's processed copy is compiled from `versions/<mc>/build/generated/stonecutter/`, which is also where to look when a non-active version fails to compile.
|
||||||
|
|
||||||
|
The `emotes` repository uses the same setup, and its `BentCubeRenderer` and `PlayerModelMixin` are small examples of version comments.
|
||||||
|
|
||||||
|
## Checking a change on every version
|
||||||
|
|
||||||
|
Since every version shares `src/`, a change applies to all of them at once. Code that uses the Minecraft API may still only compile on some, so build them all:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./gradlew compileJava
|
||||||
|
```
|
||||||
|
|
||||||
|
The **Check** workflow runs the same compile on every pull request, so a version a change doesn't compile on fails before merging. Mixins whose target changed fail at startup rather than at compile time, so launch the versions a change touches with `./gradlew :<mc>:runClient`.
|
||||||
|
|
||||||
|
For bigger changes, `./gradlew buildAll` builds every version's jar into `build/allJars/`.
|
||||||
|
|
||||||
|
## Adding a Minecraft version
|
||||||
|
|
||||||
|
1. Create `versions/<new>/gradle.properties` with `minecraft_version`, `yarn_mappings`, `loader_version` and `fabric_api_version` (copy 1.21.11's and change the values; they're listed at <https://fabricmc.net/develop>). Loom's version is shared, in the root `gradle.properties`.
|
||||||
|
2. Add `<new>` to `stonecutterVersions` in `settings.gradle.kts`.
|
||||||
|
3. Build it with `./gradlew :<new>:compileJava` and put what Minecraft changed behind version comments. Check the mixin configs in `src/main/resources/*.mixins.json` as well: a mixin whose target changed fails at startup, not at compile time, so launch it with `./gradlew :<new>:runClient`.
|
||||||
|
4. The release workflow builds everything through `buildAll`, and "Publish to Modrinth" takes the game version from each jar's name, so neither needs changing.
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
subprojects {
|
|
||||||
apply plugin: "java"
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
maven { url "https://maven.fabricmc.net/" }
|
|
||||||
maven { url "https://git.selimaj.dev/api/packages/selimaj-dev/maven" }
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation "de.javagl:obj:0.4.0"
|
|
||||||
implementation "com.formdev:svgSalamander:1.1.4"
|
|
||||||
implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.0'
|
|
||||||
implementation 'com.fasterxml.jackson.core:jackson-annotations:2.17.0'
|
|
||||||
implementation 'com.fasterxml.jackson.core:jackson-core:2.17.0'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
configure(subprojects.findAll { it.name != "common" }) {
|
|
||||||
dependencies {
|
|
||||||
implementation project(":common")
|
|
||||||
|
|
||||||
sourceSets {
|
|
||||||
main {
|
|
||||||
resources {
|
|
||||||
srcDir project(":common").file("src/main/resources")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register("buildAll") {
|
|
||||||
group = "build"
|
|
||||||
description = "Builds all subprojects and collects their remapped jars"
|
|
||||||
|
|
||||||
// Only build remapped jars (not full build)
|
|
||||||
dependsOn subprojects.collect { proj ->
|
|
||||||
proj.tasks.matching { it.name == "remapJar" }
|
|
||||||
}
|
|
||||||
|
|
||||||
doLast {
|
|
||||||
def outputDir = file("$buildDir/allJars")
|
|
||||||
outputDir.mkdirs()
|
|
||||||
|
|
||||||
subprojects.each { proj ->
|
|
||||||
def remapTask = proj.tasks.findByName("remapJar")
|
|
||||||
|
|
||||||
if (remapTask != null) {
|
|
||||||
def jarFile = remapTask.archiveFile.get().asFile
|
|
||||||
|
|
||||||
if (jarFile.exists() && !jarFile.name.contains("sources")) {
|
|
||||||
copy {
|
|
||||||
from jarFile
|
|
||||||
into outputDir
|
|
||||||
rename { "${jarFile.name}" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
println "All remapped jars collected in: $outputDir"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
// Builds one Minecraft version from the shared src/. Stonecutter runs this for each version in
|
||||||
|
// stonecutterVersions (settings.gradle.kts), with that version's versions/<v>/gradle.properties.
|
||||||
|
plugins {
|
||||||
|
id("net.fabricmc.fabric-loom-remap")
|
||||||
|
`maven-publish`
|
||||||
|
}
|
||||||
|
|
||||||
|
val minecraftVersion = property("minecraft_version") as String
|
||||||
|
val loaderVersion = property("loader_version") as String
|
||||||
|
|
||||||
|
version = "${property("mod_version")}+$minecraftVersion"
|
||||||
|
group = property("maven_group") as String
|
||||||
|
|
||||||
|
base {
|
||||||
|
archivesName = property("archives_base_name") as String
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
minecraft("com.mojang:minecraft:$minecraftVersion")
|
||||||
|
mappings("net.fabricmc:yarn:${property("yarn_mappings")}:v2")
|
||||||
|
modImplementation("net.fabricmc:fabric-loader:$loaderVersion")
|
||||||
|
modImplementation("net.fabricmc.fabric-api:fabric-api:${property("fabric_api_version")}")
|
||||||
|
|
||||||
|
// Saturn's emote library (limb bending, Emotecraft emotes)
|
||||||
|
include(modImplementation("org.saturnclient:emotes-fabric:${property("emotes_version")}+$minecraftVersion")!!)
|
||||||
|
|
||||||
|
implementation(project(":common"))
|
||||||
|
|
||||||
|
for (library in listOf(
|
||||||
|
"dev.selimaj:session-java:0.2.0",
|
||||||
|
"de.javagl:obj:0.4.0",
|
||||||
|
"com.formdev:svgSalamander:1.1.4",
|
||||||
|
"com.fasterxml.jackson.core:jackson-databind:2.17.0",
|
||||||
|
"com.fasterxml.jackson.core:jackson-annotations:2.17.0",
|
||||||
|
"com.fasterxml.jackson.core:jackson-core:2.17.0",
|
||||||
|
)) {
|
||||||
|
include(implementation(library)!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Injects the version values into fabric.mod.json.
|
||||||
|
tasks.processResources {
|
||||||
|
val values = mapOf(
|
||||||
|
"version" to project.version.toString(),
|
||||||
|
"minecraft_version" to minecraftVersion,
|
||||||
|
"loader_version" to loaderVersion,
|
||||||
|
)
|
||||||
|
inputs.properties(values)
|
||||||
|
filteringCharset = "UTF-8"
|
||||||
|
filesMatching("fabric.mod.json") { expand(values) }
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType<JavaCompile>().configureEach {
|
||||||
|
options.release = 21
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
// Loom attaches the sources jar to remapSourcesJar and build.
|
||||||
|
withSourcesJar()
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_21
|
||||||
|
targetCompatibility = JavaVersion.VERSION_21
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.jar {
|
||||||
|
val archivesName = base.archivesName
|
||||||
|
inputs.property("archivesName", archivesName)
|
||||||
|
from("LICENSE") {
|
||||||
|
rename { "${it}_${archivesName.get()}" }
|
||||||
|
}
|
||||||
|
from(project(":common").extensions.getByType<SourceSetContainer>()["main"].output)
|
||||||
|
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||||
|
}
|
||||||
|
|
||||||
|
publishing {
|
||||||
|
publications {
|
||||||
|
create<MavenPublication>("mavenJava") {
|
||||||
|
artifactId = property("archives_base_name") as String
|
||||||
|
from(components["java"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
Submodule common updated: 5df42e2b7c...15fa973553
@@ -1,7 +1,15 @@
|
|||||||
org.gradle.jvmargs=-Xmx3G
|
org.gradle.jvmargs=-Xmx3G
|
||||||
org.gradle.parallel=true
|
org.gradle.parallel=true
|
||||||
|
# Reuse task outputs (e.g. compiled classes) when inputs haven't changed.
|
||||||
|
org.gradle.caching=true
|
||||||
|
|
||||||
# IntelliJ IDEA is not yet fully compatible with configuration cache, see: https://github.com/FabricMC/fabric-loom/issues/1349
|
# IntelliJ IDEA is not yet fully compatible with configuration cache, see: https://github.com/FabricMC/fabric-loom/issues/1349
|
||||||
org.gradle.configuration-cache=false
|
org.gradle.configuration-cache=false
|
||||||
|
|
||||||
mod_version=0.1.1-beta
|
mod_version=0.1.1-beta
|
||||||
|
|
||||||
|
# Saturn's emote library (git.selimaj.dev/saturnclientmc/emotes)
|
||||||
|
emotes_version=0.1.0
|
||||||
|
|
||||||
|
# Loom, for every Minecraft version (read in settings.gradle.kts).
|
||||||
|
loom_version=1.17.21
|
||||||
|
|||||||
Vendored
BIN
Binary file not shown.
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.0-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-9.8.0-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
# Gradle start up script for POSIX generated by Gradle.
|
# gradlew start up script for POSIX generated by Gradle.
|
||||||
#
|
#
|
||||||
# Important for running:
|
# Important for running:
|
||||||
#
|
#
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
# bash, then to run this script, type that shell name before the whole
|
# bash, then to run this script, type that shell name before the whole
|
||||||
# command line, like:
|
# command line, like:
|
||||||
#
|
#
|
||||||
# ksh Gradle
|
# ksh gradlew
|
||||||
#
|
#
|
||||||
# Busybox and similar reduced shells will NOT work, because this script
|
# Busybox and similar reduced shells will NOT work, because this script
|
||||||
# requires all of these POSIX shell features:
|
# requires all of these POSIX shell features:
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
# Darwin, MinGW, and NonStop.
|
# Darwin, MinGW, and NonStop.
|
||||||
#
|
#
|
||||||
# (3) This script is generated from the Groovy template
|
# (3) This script is generated from the Groovy template
|
||||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
# within the Gradle project.
|
# within the Gradle project.
|
||||||
#
|
#
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
|
|||||||
Vendored
+52
-33
@@ -19,12 +19,39 @@
|
|||||||
@if "%DEBUG%"=="" @echo off
|
@if "%DEBUG%"=="" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
@rem
|
@rem
|
||||||
@rem Gradle startup script for Windows
|
@rem gradlew startup script for Windows
|
||||||
@rem
|
@rem
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
|
|
||||||
@rem Set local scope for the variables with windows NT shell
|
@rem Set local scope for the variables, and ensure extensions are enabled
|
||||||
if "%OS%"=="Windows_NT" setlocal
|
setlocal EnableExtensions
|
||||||
|
|
||||||
|
@rem Catch executions from older scripts and ensure they exit cleanly.
|
||||||
|
@rem This can be removed once we can be reasonably confident that few people
|
||||||
|
@rem will be migrating directly to this new wrapper.
|
||||||
|
goto afterSafetyNet
|
||||||
|
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||||
|
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||||
|
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||||
|
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||||
|
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||||
|
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||||
|
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||||
|
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||||
|
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||||
|
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||||
|
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||||
|
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||||
|
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||||
|
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||||
|
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||||
|
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||||
|
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||||
|
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||||
|
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||||
|
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||||
|
goto exitWithErrorLevel
|
||||||
|
:afterSafetyNet
|
||||||
|
|
||||||
set DIRNAME=%~dp0
|
set DIRNAME=%~dp0
|
||||||
if "%DIRNAME%"=="" set DIRNAME=.
|
if "%DIRNAME%"=="" set DIRNAME=.
|
||||||
@@ -45,13 +72,14 @@ set JAVA_EXE=java.exe
|
|||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if %ERRORLEVEL% equ 0 goto execute
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
echo. 1>&2
|
1>&2 echo.
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
1>&2 echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
echo. 1>&2
|
1>&2 echo.
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
1>&2 echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
echo location of your Java installation. 1>&2
|
1>&2 echo location of your Java installation.
|
||||||
|
|
||||||
goto fail
|
"%COMSPEC%" /c exit 1
|
||||||
|
goto exitWithErrorLevel
|
||||||
|
|
||||||
:findJavaFromJavaHome
|
:findJavaFromJavaHome
|
||||||
set JAVA_HOME=%JAVA_HOME:"=%
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
@@ -59,35 +87,26 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|||||||
|
|
||||||
if exist "%JAVA_EXE%" goto execute
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
echo. 1>&2
|
1>&2 echo.
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
1>&2 echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
echo. 1>&2
|
1>&2 echo.
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
1>&2 echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
echo location of your Java installation. 1>&2
|
1>&2 echo location of your Java installation.
|
||||||
|
|
||||||
goto fail
|
"%COMSPEC%" /c exit 1
|
||||||
|
goto exitWithErrorLevel
|
||||||
|
|
||||||
:execute
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
@rem Execute gradlew
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
|
||||||
|
@rem which allows us to clear the local environment before executing the java command
|
||||||
|
endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel & goto exitWithErrorLevel
|
||||||
|
|
||||||
:end
|
@rem This label must not be changed. We rely on old scripts being able to jump to this point.
|
||||||
@rem End local scope for the variables with windows NT shell
|
:exitWithErrorLevel
|
||||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
|
||||||
|
"%COMSPEC%" /c exit %ERRORLEVEL%
|
||||||
:fail
|
|
||||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
|
||||||
rem the _cmd.exe /c_ return code!
|
|
||||||
set EXIT_CODE=%ERRORLEVEL%
|
|
||||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
|
||||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
|
||||||
exit /b %EXIT_CODE%
|
|
||||||
|
|
||||||
:mainEnd
|
|
||||||
if "%OS%"=="Windows_NT" endlocal
|
|
||||||
|
|
||||||
:omega
|
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
pluginManagement {
|
|
||||||
repositories {
|
|
||||||
maven { url "https://maven.fabricmc.net/" }
|
|
||||||
gradlePluginPortal()
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rootProject.name = "saturn-client"
|
|
||||||
|
|
||||||
include("common")
|
|
||||||
|
|
||||||
def versionsDir = file("versions")
|
|
||||||
|
|
||||||
versionsDir.eachDir { dir ->
|
|
||||||
def version = dir.name
|
|
||||||
def projectName = "mc-${version}"
|
|
||||||
|
|
||||||
include(projectName)
|
|
||||||
project(":${projectName}").projectDir = dir
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
maven("https://maven.fabricmc.net/")
|
||||||
|
maven("https://maven.kikugie.dev/releases")
|
||||||
|
gradlePluginPortal()
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loom's version for build.gradle.kts, which can't read properties in its plugins block.
|
||||||
|
val loom_version: String by settings
|
||||||
|
plugins {
|
||||||
|
id("net.fabricmc.fabric-loom-remap") version loom_version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("dev.kikugie.stonecutter") version "0.9.8"
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.name = "saturn-client"
|
||||||
|
|
||||||
|
include("common")
|
||||||
|
|
||||||
|
// Versions built by Stonecutter from the shared src/ (see stonecutter.gradle.kts). Each one's
|
||||||
|
// versions/<v>/gradle.properties holds its Minecraft, Yarn and Fabric API versions.
|
||||||
|
val stonecutterVersions = listOf("1.21.4", "1.21.5", "1.21.6", "1.21.7", "1.21.8", "1.21.9", "1.21.10", "1.21.11")
|
||||||
|
|
||||||
|
stonecutter {
|
||||||
|
create(rootProject) {
|
||||||
|
versions(stonecutterVersions)
|
||||||
|
vcsVersion = "1.21.11"
|
||||||
|
}
|
||||||
|
}
|
||||||
+19
-3
@@ -15,7 +15,10 @@ import org.saturnclient.saturnclient.SaturnRenderState;
|
|||||||
|
|
||||||
import net.minecraft.client.render.OverlayTexture;
|
import net.minecraft.client.render.OverlayTexture;
|
||||||
import net.minecraft.client.render.VertexConsumer;
|
import net.minecraft.client.render.VertexConsumer;
|
||||||
|
//? if >=1.21.9 {
|
||||||
import net.minecraft.client.render.command.OrderedRenderCommandQueue;
|
import net.minecraft.client.render.command.OrderedRenderCommandQueue;
|
||||||
|
//?} else
|
||||||
|
//import net.minecraft.client.render.VertexConsumerProvider;
|
||||||
import net.minecraft.client.render.entity.equipment.EquipmentModel;
|
import net.minecraft.client.render.entity.equipment.EquipmentModel;
|
||||||
import net.minecraft.client.render.entity.equipment.EquipmentModelLoader;
|
import net.minecraft.client.render.entity.equipment.EquipmentModelLoader;
|
||||||
import net.minecraft.client.render.entity.equipment.EquipmentModel.LayerType;
|
import net.minecraft.client.render.entity.equipment.EquipmentModel.LayerType;
|
||||||
@@ -394,14 +397,24 @@ public class CloakFeatureRenderer extends FeatureRenderer<PlayerEntityRenderStat
|
|||||||
private long lastUpdate = 0;
|
private long lastUpdate = 0;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(MatrixStack matrices, OrderedRenderCommandQueue queue, int light, PlayerEntityRenderState state,
|
public void render(MatrixStack matrices,
|
||||||
float limbAngle, float limbDistance) {
|
//? if >=1.21.9 {
|
||||||
|
OrderedRenderCommandQueue output,
|
||||||
|
//?} else
|
||||||
|
//VertexConsumerProvider output,
|
||||||
|
int light, PlayerEntityRenderState state, float limbAngle, float limbDistance) {
|
||||||
if (state.invisible || !state.capeVisible
|
if (state.invisible || !state.capeVisible
|
||||||
|
//? if >=1.21.9 {
|
||||||
|| state.skinTextures.cape() != null) {
|
|| state.skinTextures.cape() != null) {
|
||||||
|
//?} else
|
||||||
|
//|| state.skinTextures.capeTexture() != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//? if >=1.21.8 {
|
||||||
SaturnPlayer player = state.getData(SaturnRenderState.saturnDataKey);
|
SaturnPlayer player = state.getData(SaturnRenderState.saturnDataKey);
|
||||||
|
//?} else
|
||||||
|
//SaturnPlayer player = SaturnPlayer.get(state.name);
|
||||||
|
|
||||||
if (player == null) {
|
if (player == null) {
|
||||||
return;
|
return;
|
||||||
@@ -454,9 +467,12 @@ public class CloakFeatureRenderer extends FeatureRenderer<PlayerEntityRenderStat
|
|||||||
|
|
||||||
horizontalCurve = MathHelper.clamp(state.field_53537 / 150.0f, -1.0f, 1.0f);
|
horizontalCurve = MathHelper.clamp(state.field_53537 / 150.0f, -1.0f, 1.0f);
|
||||||
|
|
||||||
queue.submitCustom(matrices, ShaderUtils.getRenderLayer(customCape), (entry, vertexConsumer) -> {
|
//? if >=1.21.9 {
|
||||||
|
output.submitCustom(matrices, ShaderUtils.getRenderLayer(customCape), (entry, vertexConsumer) -> {
|
||||||
renderCape(entry, vertexConsumer, state, l, OverlayTexture.DEFAULT_UV);
|
renderCape(entry, vertexConsumer, state, l, OverlayTexture.DEFAULT_UV);
|
||||||
});
|
});
|
||||||
|
//?} else
|
||||||
|
//renderCape(matrices.peek(), output.getBuffer(ShaderUtils.getRenderLayer(customCape)), state, l, OverlayTexture.DEFAULT_UV);
|
||||||
|
|
||||||
matrices.pop();
|
matrices.pop();
|
||||||
}
|
}
|
||||||
+16
-3
@@ -7,7 +7,10 @@ import org.saturnclient.impl.cosmetics.obj.ObjModel;
|
|||||||
import org.saturnclient.saturnclient.SaturnRenderState;
|
import org.saturnclient.saturnclient.SaturnRenderState;
|
||||||
|
|
||||||
import net.minecraft.client.render.OverlayTexture;
|
import net.minecraft.client.render.OverlayTexture;
|
||||||
|
//? if >=1.21.9 {
|
||||||
import net.minecraft.client.render.command.OrderedRenderCommandQueue;
|
import net.minecraft.client.render.command.OrderedRenderCommandQueue;
|
||||||
|
//?} else
|
||||||
|
//import net.minecraft.client.render.VertexConsumerProvider;
|
||||||
import net.minecraft.client.render.entity.feature.FeatureRenderer;
|
import net.minecraft.client.render.entity.feature.FeatureRenderer;
|
||||||
import net.minecraft.client.render.entity.feature.FeatureRendererContext;
|
import net.minecraft.client.render.entity.feature.FeatureRendererContext;
|
||||||
import net.minecraft.client.render.entity.model.PlayerEntityModel;
|
import net.minecraft.client.render.entity.model.PlayerEntityModel;
|
||||||
@@ -21,9 +24,16 @@ public class HatFeatureRenderer extends FeatureRenderer<PlayerEntityRenderState,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(MatrixStack matrices, OrderedRenderCommandQueue queue, int light, PlayerEntityRenderState state,
|
public void render(MatrixStack matrices,
|
||||||
float limbAngle, float limbDistance) {
|
//? if >=1.21.9 {
|
||||||
|
OrderedRenderCommandQueue output,
|
||||||
|
//?} else
|
||||||
|
//VertexConsumerProvider output,
|
||||||
|
int light, PlayerEntityRenderState state, float limbAngle, float limbDistance) {
|
||||||
|
//? if >=1.21.8 {
|
||||||
SaturnPlayer player = state.getData(SaturnRenderState.saturnDataKey);
|
SaturnPlayer player = state.getData(SaturnRenderState.saturnDataKey);
|
||||||
|
//?} else
|
||||||
|
//SaturnPlayer player = SaturnPlayer.get(state.name);
|
||||||
|
|
||||||
if (state.invisible || player == null || player.hat.isEmpty()) {
|
if (state.invisible || player == null || player.hat.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
@@ -31,11 +41,14 @@ public class HatFeatureRenderer extends FeatureRenderer<PlayerEntityRenderState,
|
|||||||
|
|
||||||
matrices.push();
|
matrices.push();
|
||||||
|
|
||||||
|
//? if >=1.21.5 {
|
||||||
ModelPart head = this.getContextModel().head;
|
ModelPart head = this.getContextModel().head;
|
||||||
matrices.multiply(new Quaternionf().rotationZYX(head.roll, head.yaw, head.pitch));
|
matrices.multiply(new Quaternionf().rotationZYX(head.roll, head.yaw, head.pitch));
|
||||||
|
//?} else
|
||||||
|
//this.getContextModel().head.rotate(matrices);
|
||||||
|
|
||||||
ObjModel.cosmetic("hat", player.hat).render(MtlLoader.cosmetic(player.hat),
|
ObjModel.cosmetic("hat", player.hat).render(MtlLoader.cosmetic(player.hat),
|
||||||
matrices, queue, light,
|
matrices, output, light,
|
||||||
OverlayTexture.DEFAULT_UV);
|
OverlayTexture.DEFAULT_UV);
|
||||||
|
|
||||||
matrices.pop();
|
matrices.pop();
|
||||||
+10
-3
@@ -13,7 +13,10 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||||||
import de.javagl.obj.Mtl;
|
import de.javagl.obj.Mtl;
|
||||||
import de.javagl.obj.Obj;
|
import de.javagl.obj.Obj;
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
//? if >=1.21.9 {
|
||||||
import net.minecraft.client.render.command.OrderedRenderCommandQueue;
|
import net.minecraft.client.render.command.OrderedRenderCommandQueue;
|
||||||
|
//?} else
|
||||||
|
//import net.minecraft.client.render.VertexConsumerProvider;
|
||||||
import net.minecraft.client.util.math.MatrixStack;
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
import net.minecraft.resource.Resource;
|
import net.minecraft.resource.Resource;
|
||||||
import net.minecraft.resource.ResourceManager;
|
import net.minecraft.resource.ResourceManager;
|
||||||
@@ -78,8 +81,12 @@ public class ObjModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void render(Map<String, Mtl> mtlMap, MatrixStack matrices, OrderedRenderCommandQueue queue, int light,
|
public void render(Map<String, Mtl> mtlMap, MatrixStack matrices,
|
||||||
int overlay) {
|
//? if >=1.21.9 {
|
||||||
|
OrderedRenderCommandQueue output,
|
||||||
|
//?} else
|
||||||
|
//VertexConsumerProvider output,
|
||||||
|
int light, int overlay) {
|
||||||
matrices.push();
|
matrices.push();
|
||||||
|
|
||||||
matrices.multiply(net.minecraft.util.math.RotationAxis.POSITIVE_X.rotationDegrees(180.0f));
|
matrices.multiply(net.minecraft.util.math.RotationAxis.POSITIVE_X.rotationDegrees(180.0f));
|
||||||
@@ -95,7 +102,7 @@ public class ObjModel {
|
|||||||
matrices.multiply(net.minecraft.util.math.RotationAxis.POSITIVE_Z.rotationDegrees(config.rotation.z));
|
matrices.multiply(net.minecraft.util.math.RotationAxis.POSITIVE_Z.rotationDegrees(config.rotation.z));
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjRenderer.renderObj(this.obj, mtlMap, matrices, queue, light, overlay);
|
ObjRenderer.renderObj(this.obj, mtlMap, matrices, output, light, overlay);
|
||||||
|
|
||||||
matrices.pop();
|
matrices.pop();
|
||||||
}
|
}
|
||||||
+23
-11
@@ -12,7 +12,10 @@ import de.javagl.obj.*;
|
|||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.render.RenderLayer;
|
import net.minecraft.client.render.RenderLayer;
|
||||||
import net.minecraft.client.render.VertexConsumer;
|
import net.minecraft.client.render.VertexConsumer;
|
||||||
|
//? if >=1.21.9 {
|
||||||
import net.minecraft.client.render.command.OrderedRenderCommandQueue;
|
import net.minecraft.client.render.command.OrderedRenderCommandQueue;
|
||||||
|
//?} else
|
||||||
|
//import net.minecraft.client.render.VertexConsumerProvider;
|
||||||
import net.minecraft.client.util.math.MatrixStack;
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
@@ -28,7 +31,10 @@ public class ObjRenderer {
|
|||||||
public static void renderObj(Obj obj,
|
public static void renderObj(Obj obj,
|
||||||
Map<String, Mtl> mtlMap,
|
Map<String, Mtl> mtlMap,
|
||||||
MatrixStack matrices,
|
MatrixStack matrices,
|
||||||
OrderedRenderCommandQueue queue,
|
//? if >=1.21.9 {
|
||||||
|
OrderedRenderCommandQueue output,
|
||||||
|
//?} else
|
||||||
|
//VertexConsumerProvider output,
|
||||||
int light,
|
int light,
|
||||||
int overlay) {
|
int overlay) {
|
||||||
|
|
||||||
@@ -64,19 +70,25 @@ public class ObjRenderer {
|
|||||||
final float fr = r, fg = g, fb = b;
|
final float fr = r, fg = g, fb = b;
|
||||||
final Obj finalObj = groupObj;
|
final Obj finalObj = groupObj;
|
||||||
|
|
||||||
queue.submitCustom(matrices, layer, (e, vertexConsumer) -> {
|
//? if >=1.21.9 {
|
||||||
|
output.submitCustom(matrices, layer,
|
||||||
|
(entry, consumer) -> drawGroup(finalObj, consumer, entry, light, overlay, fr, fg, fb));
|
||||||
|
//?} else
|
||||||
|
//drawGroup(finalObj, output.getBuffer(layer), matrices.peek(), light, overlay, fr, fg, fb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int faces = finalObj.getNumFaces();
|
private static void drawGroup(Obj obj, VertexConsumer consumer, MatrixStack.Entry entry, int light, int overlay,
|
||||||
|
float r, float g, float b) {
|
||||||
|
int faces = obj.getNumFaces();
|
||||||
|
|
||||||
for (int f = 0; f < faces; f++) {
|
for (int f = 0; f < faces; f++) {
|
||||||
ObjFace face = finalObj.getFace(f);
|
ObjFace face = obj.getFace(f);
|
||||||
int verts = face.getNumVertices();
|
int verts = face.getNumVertices();
|
||||||
|
|
||||||
for (int i = verts - 1; i >= 0; i--) {
|
for (int i = verts - 1; i >= 0; i--) {
|
||||||
writeVertex(finalObj, face, i, vertexConsumer, e, light, overlay, fr, fg, fb);
|
writeVertex(obj, face, i, consumer, entry, light, overlay, r, g, b);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
+3
@@ -43,9 +43,12 @@ public class IdentifierUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SaturnClient.client.execute(() -> {
|
SaturnClient.client.execute(() -> {
|
||||||
|
//? if >=1.21.5 {
|
||||||
NativeImageBackedTexture texture = new NativeImageBackedTexture(
|
NativeImageBackedTexture texture = new NativeImageBackedTexture(
|
||||||
() -> identifier.toString(),
|
() -> identifier.toString(),
|
||||||
nativeImage);
|
nativeImage);
|
||||||
|
//?} else
|
||||||
|
//NativeImageBackedTexture texture = new NativeImageBackedTexture(nativeImage);
|
||||||
|
|
||||||
SaturnClient.client.getTextureManager().registerTexture(identifier, texture);
|
SaturnClient.client.getTextureManager().registerTexture(identifier, texture);
|
||||||
});
|
});
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
package org.saturnclient.impl.cosmetics.utils;
|
||||||
|
|
||||||
|
import org.saturnclient.common.ref.asset.IdentifierRef;
|
||||||
|
import org.saturnclient.cosmetics.utils.GifUtils;
|
||||||
|
|
||||||
|
//? if >=1.21.5
|
||||||
|
import com.mojang.blaze3d.pipeline.RenderPipeline;
|
||||||
|
|
||||||
|
//? if >=1.21.5
|
||||||
|
import net.minecraft.client.gl.RenderPipelines;
|
||||||
|
import net.minecraft.client.render.RenderLayer;
|
||||||
|
//? if <1.21.5 {
|
||||||
|
/*import net.minecraft.client.render.RenderPhase;
|
||||||
|
import net.minecraft.client.render.VertexFormat.DrawMode;
|
||||||
|
import net.minecraft.client.render.VertexFormats;
|
||||||
|
*///?}
|
||||||
|
//? if >=1.21.11 {
|
||||||
|
import net.minecraft.client.render.RenderLayers;
|
||||||
|
import net.minecraft.client.render.RenderSetup;
|
||||||
|
import net.minecraft.client.render.block.entity.AbstractEndPortalBlockEntityRenderer;
|
||||||
|
//?} else {
|
||||||
|
/*import net.minecraft.client.render.RenderPhase.Textures;
|
||||||
|
import net.minecraft.client.render.block.entity.EndPortalBlockEntityRenderer;
|
||||||
|
*///?}
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
public class ShaderUtils {
|
||||||
|
// Render pipelines exist from 1.21.5; before that the layer names a shader program directly.
|
||||||
|
//? if >=1.21.5 {
|
||||||
|
public static final RenderPipeline END_GATEWAY_PIPELINE = RenderPipelines.register(
|
||||||
|
RenderPipeline.builder(new RenderPipeline.Snippet[] {
|
||||||
|
RenderPipelines.RENDERTYPE_END_PORTAL_SNIPPET })
|
||||||
|
.withLocation("pipeline/end_gateway")
|
||||||
|
.withShaderDefine("PORTAL_LAYERS", 16)
|
||||||
|
.withCull(false)
|
||||||
|
.build());
|
||||||
|
//?}
|
||||||
|
|
||||||
|
//? if >=1.21.11 {
|
||||||
|
public static final RenderLayer END_GATEWAY = RenderLayer.of("end_gateway",
|
||||||
|
RenderSetup.builder(END_GATEWAY_PIPELINE)
|
||||||
|
.texture("Sampler0", AbstractEndPortalBlockEntityRenderer.SKY_TEXTURE)
|
||||||
|
.texture("Sampler1", AbstractEndPortalBlockEntityRenderer.PORTAL_TEXTURE).build());
|
||||||
|
//?} else if >=1.21.6 {
|
||||||
|
/*public static final RenderLayer END_GATEWAY = RenderLayer.of("end_gateway", 1536, false, false,
|
||||||
|
END_GATEWAY_PIPELINE,
|
||||||
|
RenderLayer.MultiPhaseParameters.builder()
|
||||||
|
.texture(Textures.create().add(EndPortalBlockEntityRenderer.SKY_TEXTURE, false)
|
||||||
|
.add(EndPortalBlockEntityRenderer.PORTAL_TEXTURE, false).build())
|
||||||
|
.build(false));
|
||||||
|
*///?} else if >=1.21.5 {
|
||||||
|
/*public static final RenderLayer END_GATEWAY = RenderLayer.of("end_gateway", 1536, false, false,
|
||||||
|
END_GATEWAY_PIPELINE,
|
||||||
|
RenderLayer.MultiPhaseParameters.builder()
|
||||||
|
.texture(Textures.create().add(EndPortalBlockEntityRenderer.SKY_TEXTURE, false, false)
|
||||||
|
.add(EndPortalBlockEntityRenderer.PORTAL_TEXTURE, false, false).build())
|
||||||
|
.build(false));
|
||||||
|
*///?} else {
|
||||||
|
/*public static final RenderLayer END_GATEWAY = RenderLayer.of(
|
||||||
|
"end_gateway",
|
||||||
|
VertexFormats.POSITION,
|
||||||
|
DrawMode.QUADS,
|
||||||
|
1536,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
RenderLayer.MultiPhaseParameters.builder()
|
||||||
|
.program(RenderLayer.END_GATEWAY_PROGRAM)
|
||||||
|
.texture(Textures.create()
|
||||||
|
.add(EndPortalBlockEntityRenderer.SKY_TEXTURE, false, false)
|
||||||
|
.add(EndPortalBlockEntityRenderer.PORTAL_TEXTURE, false, false)
|
||||||
|
.build())
|
||||||
|
.cull(RenderPhase.DISABLE_CULLING)
|
||||||
|
.build(false));
|
||||||
|
*///?}
|
||||||
|
|
||||||
|
public static RenderLayer getRenderLayer(IdentifierRef texture) {
|
||||||
|
String path = texture.toString();
|
||||||
|
if (path.endsWith(".gif")) {
|
||||||
|
return entityAlpha((Identifier) (Object) GifUtils.get(texture));
|
||||||
|
} else if (path.endsWith("end.png")) {
|
||||||
|
return END_GATEWAY;
|
||||||
|
} else {
|
||||||
|
return entityAlpha((Identifier) (Object) texture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RenderLayer entityAlpha(Identifier texture) {
|
||||||
|
//? if >=1.21.11 {
|
||||||
|
return RenderLayers.entityAlpha(texture);
|
||||||
|
//?} else
|
||||||
|
//return RenderLayer.getEntityAlpha(texture);
|
||||||
|
}
|
||||||
|
}
|
||||||
+6
@@ -13,7 +13,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||||||
import net.minecraft.client.network.ClientPlayerEntity;
|
import net.minecraft.client.network.ClientPlayerEntity;
|
||||||
import net.minecraft.client.render.Camera;
|
import net.minecraft.client.render.Camera;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
|
//? if >=1.21.11 {
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
//?} else
|
||||||
|
//import net.minecraft.world.BlockView;
|
||||||
|
|
||||||
@Mixin(Camera.class)
|
@Mixin(Camera.class)
|
||||||
public abstract class CameraMixin {
|
public abstract class CameraMixin {
|
||||||
@@ -25,7 +28,10 @@ public abstract class CameraMixin {
|
|||||||
|
|
||||||
@Inject(method = "update", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/Camera;setRotation(FF)V", ordinal = 1, shift = At.Shift.AFTER))
|
@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(
|
public void lockRotation(
|
||||||
|
//? if >=1.21.11 {
|
||||||
World focusedBlock,
|
World focusedBlock,
|
||||||
|
//?} else
|
||||||
|
//BlockView focusedBlock,
|
||||||
Entity cameraEntity,
|
Entity cameraEntity,
|
||||||
boolean isThirdPerson,
|
boolean isThirdPerson,
|
||||||
boolean isFrontFacing,
|
boolean isFrontFacing,
|
||||||
+10
-4
@@ -1,7 +1,9 @@
|
|||||||
package org.saturnclient.impl.features.mixins.misc;
|
package org.saturnclient.impl.features.mixins.misc;
|
||||||
|
|
||||||
import net.minecraft.client.render.VertexConsumerProvider;
|
|
||||||
import net.minecraft.client.render.entity.EntityRenderer;
|
import net.minecraft.client.render.entity.EntityRenderer;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
//? if <1.21.9 {
|
||||||
|
/*import net.minecraft.client.render.VertexConsumerProvider;
|
||||||
import net.minecraft.client.render.entity.state.EntityRenderState;
|
import net.minecraft.client.render.entity.state.EntityRenderState;
|
||||||
import net.minecraft.client.render.entity.state.LivingEntityRenderState;
|
import net.minecraft.client.render.entity.state.LivingEntityRenderState;
|
||||||
import net.minecraft.client.util.math.MatrixStack;
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
@@ -11,12 +13,12 @@ import org.saturnclient.impl.features.entity.EntityFeatureImpl;
|
|||||||
import org.saturnclient.impl.features.entity.HealthRenderState;
|
import org.saturnclient.impl.features.entity.HealthRenderState;
|
||||||
import org.saturnclient.impl.features.mixins.render.LivingEntityRenderStateMixin;
|
import org.saturnclient.impl.features.mixins.render.LivingEntityRenderStateMixin;
|
||||||
import org.saturnclient.mod.mods.NametagsMod;
|
import org.saturnclient.mod.mods.NametagsMod;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
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;
|
||||||
|
*///?}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Intercepts nametag rendering and replaces the displayed text with
|
* Intercepts nametag rendering and replaces the displayed text with
|
||||||
@@ -44,8 +46,11 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||||||
*/
|
*/
|
||||||
@Mixin(EntityRenderer.class)
|
@Mixin(EntityRenderer.class)
|
||||||
public abstract class NametagsMixin {
|
public abstract class NametagsMixin {
|
||||||
|
// TODO: 1.21.9 moved label rendering to the render queue (renderLabelIfPresent no longer takes a
|
||||||
/** Guards against the recursive call we make with the replacement text. */
|
// VertexConsumerProvider), so custom nametags only work on older versions. On 1.21.9+ this mixin is
|
||||||
|
// empty but stays registered, so features.mixins.json is the same for every version.
|
||||||
|
//? if <1.21.9 {
|
||||||
|
/*// Guards against the recursive call we make with the replacement text.
|
||||||
@Unique
|
@Unique
|
||||||
private static final ThreadLocal<Boolean> saturn$rendering = ThreadLocal.withInitial(() -> false);
|
private static final ThreadLocal<Boolean> saturn$rendering = ThreadLocal.withInitial(() -> false);
|
||||||
|
|
||||||
@@ -92,4 +97,5 @@ public abstract class NametagsMixin {
|
|||||||
saturn$rendering.set(false);
|
saturn$rendering.set(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*///?}
|
||||||
}
|
}
|
||||||
+6
@@ -1,13 +1,19 @@
|
|||||||
package org.saturnclient.impl.features.mixins.render;
|
package org.saturnclient.impl.features.mixins.render;
|
||||||
|
|
||||||
|
//? if >=1.21.6 {
|
||||||
import net.minecraft.client.render.fog.FogRenderer;
|
import net.minecraft.client.render.fog.FogRenderer;
|
||||||
|
//?} else
|
||||||
|
//import net.minecraft.client.render.BackgroundRenderer;
|
||||||
|
|
||||||
import org.saturnclient.mod.mods.NoFogMod;
|
import org.saturnclient.mod.mods.NoFogMod;
|
||||||
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.ModifyVariable;
|
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||||
|
|
||||||
|
//? if >=1.21.6 {
|
||||||
@Mixin(FogRenderer.class)
|
@Mixin(FogRenderer.class)
|
||||||
|
//?} else
|
||||||
|
//@Mixin(BackgroundRenderer.class)
|
||||||
public class BackgroundRendererMixin {
|
public class BackgroundRendererMixin {
|
||||||
// fog
|
// fog
|
||||||
@ModifyVariable(method = "applyFog", at = @At("HEAD"), ordinal = 0, argsOnly = true)
|
@ModifyVariable(method = "applyFog", at = @At("HEAD"), ordinal = 0, argsOnly = true)
|
||||||
+12
@@ -169,22 +169,34 @@ public class PlayerFeatureImpl implements PlayerFeature {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemStackRef getHelmet() {
|
public ItemStackRef getHelmet() {
|
||||||
|
//? if >=1.21.5 {
|
||||||
return wrap(hasPlayer() ? player().getEquippedStack(EquipmentSlot.HEAD) : ItemStack.EMPTY);
|
return wrap(hasPlayer() ? player().getEquippedStack(EquipmentSlot.HEAD) : ItemStack.EMPTY);
|
||||||
|
//?} else
|
||||||
|
//return wrap(hasPlayer() ? player().getInventory().armor.get(3) : ItemStack.EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemStackRef getChestplate() {
|
public ItemStackRef getChestplate() {
|
||||||
|
//? if >=1.21.5 {
|
||||||
return wrap(hasPlayer() ? player().getEquippedStack(EquipmentSlot.CHEST) : ItemStack.EMPTY);
|
return wrap(hasPlayer() ? player().getEquippedStack(EquipmentSlot.CHEST) : ItemStack.EMPTY);
|
||||||
|
//?} else
|
||||||
|
//return wrap(hasPlayer() ? player().getInventory().armor.get(2) : ItemStack.EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemStackRef getLeggings() {
|
public ItemStackRef getLeggings() {
|
||||||
|
//? if >=1.21.5 {
|
||||||
return wrap(hasPlayer() ? player().getEquippedStack(EquipmentSlot.LEGS) : ItemStack.EMPTY);
|
return wrap(hasPlayer() ? player().getEquippedStack(EquipmentSlot.LEGS) : ItemStack.EMPTY);
|
||||||
|
//?} else
|
||||||
|
//return wrap(hasPlayer() ? player().getInventory().armor.get(1) : ItemStack.EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemStackRef getBoots() {
|
public ItemStackRef getBoots() {
|
||||||
|
//? if >=1.21.5 {
|
||||||
return wrap(hasPlayer() ? player().getEquippedStack(EquipmentSlot.FEET) : ItemStack.EMPTY);
|
return wrap(hasPlayer() ? player().getEquippedStack(EquipmentSlot.FEET) : ItemStack.EMPTY);
|
||||||
|
//?} else
|
||||||
|
//return wrap(hasPlayer() ? player().getInventory().armor.get(0) : ItemStack.EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------
|
// ---------------------------------------------------------------
|
||||||
+4
-1
@@ -31,7 +31,10 @@ public class WorldFeatureImpl implements WorldFeature {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public long getWorldAge() {
|
public long getWorldAge() {
|
||||||
// return hasWorld() ? mc.world.getTime() : 0L;
|
//? if >=1.21.11 {
|
||||||
|
// TODO: not implemented on 1.21.11 yet.
|
||||||
return 0L;
|
return 0L;
|
||||||
|
//?} else
|
||||||
|
//return hasWorld() ? mc.world.getTime() : 0L;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+25
-6
@@ -1,14 +1,25 @@
|
|||||||
package org.saturnclient.impl.mixins;
|
package org.saturnclient.impl.mixins;
|
||||||
|
|
||||||
import org.joml.Quaternionfc;
|
|
||||||
import org.saturnclient.common.ref.render.MatrixStackRef;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import net.minecraft.client.util.math.MatrixStack;
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
//? if <1.21.6 {
|
||||||
|
/*import org.saturnclient.common.ref.render.MatrixStackRef;
|
||||||
|
//? if >=1.21.5
|
||||||
|
import org.joml.Quaternionfc;
|
||||||
|
//? if <1.21.5
|
||||||
|
//import org.joml.Quaternionf;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
import net.minecraft.util.math.RotationAxis;
|
import net.minecraft.util.math.RotationAxis;
|
||||||
|
*///?}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes MatrixStack a MatrixStackRef, for GUI drawing before 1.21.6. From 1.21.6 the GUI uses a 2D
|
||||||
|
* Matrix3x2fStack (Matrix3x2fStackRef) instead, so this mixin is empty but stays registered, keeping
|
||||||
|
* impl.mixins.json the same for every version.
|
||||||
|
*/
|
||||||
@Mixin(MatrixStack.class)
|
@Mixin(MatrixStack.class)
|
||||||
public abstract class MatrixStackMixin implements MatrixStackRef {
|
//? if <1.21.6 {
|
||||||
|
/*public abstract class MatrixStackMixin implements MatrixStackRef {
|
||||||
@Shadow
|
@Shadow
|
||||||
public abstract void push();
|
public abstract void push();
|
||||||
|
|
||||||
@@ -22,10 +33,16 @@ public abstract class MatrixStackMixin implements MatrixStackRef {
|
|||||||
public abstract void scale(float x, float y, float z);
|
public abstract void scale(float x, float y, float z);
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
|
//? if >=1.21.5
|
||||||
public abstract void multiply(Quaternionfc quaternion);
|
public abstract void multiply(Quaternionfc quaternion);
|
||||||
|
//? if <1.21.5
|
||||||
|
//public abstract void multiply(Quaternionf quaternion);
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
|
//? if >=1.21.5
|
||||||
public abstract void multiply(Quaternionfc quaternion, float originX, float originY, float originZ);
|
public abstract void multiply(Quaternionfc quaternion, float originX, float originY, float originZ);
|
||||||
|
//? if <1.21.5
|
||||||
|
//public abstract void multiply(Quaternionf quaternion, float originX, float originY, float originZ);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(float x, float y) {
|
public void translate(float x, float y) {
|
||||||
@@ -46,4 +63,6 @@ public abstract class MatrixStackMixin implements MatrixStackRef {
|
|||||||
public void rotate(float angle) {
|
public void rotate(float angle) {
|
||||||
multiply(RotationAxis.NEGATIVE_Z.rotationDegrees(angle));
|
multiply(RotationAxis.NEGATIVE_Z.rotationDegrees(angle));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*///?} else
|
||||||
|
public abstract class MatrixStackMixin {}
|
||||||
+6
@@ -141,7 +141,10 @@ public abstract class MinecraftClientMixin implements MinecraftClientRef {
|
|||||||
if (entry == null)
|
if (entry == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
//? if >=1.21.9 {
|
||||||
return entry.getProfile().name();
|
return entry.getProfile().name();
|
||||||
|
//?} else
|
||||||
|
//return entry.getProfile().getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -157,6 +160,9 @@ public abstract class MinecraftClientMixin implements MinecraftClientRef {
|
|||||||
if (entry == null)
|
if (entry == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
//? if >=1.21.9 {
|
||||||
return entry.getProfile().id();
|
return entry.getProfile().id();
|
||||||
|
//?} else
|
||||||
|
//return entry.getProfile().getId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+11
@@ -3,6 +3,8 @@ package org.saturnclient.impl.mixins;
|
|||||||
import org.saturnclient.common.ref.asset.IdentifierRef;
|
import org.saturnclient.common.ref.asset.IdentifierRef;
|
||||||
import org.saturnclient.common.ref.asset.SpriteRef;
|
import org.saturnclient.common.ref.asset.SpriteRef;
|
||||||
import org.saturnclient.common.ref.game.EffectRef;
|
import org.saturnclient.common.ref.game.EffectRef;
|
||||||
|
//? if <1.21.9
|
||||||
|
//import org.saturnclient.saturnclient.SaturnClient;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
|
||||||
@@ -29,15 +31,24 @@ public abstract class StatusEffectMixin implements EffectRef {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SpriteRef getIcon() {
|
public SpriteRef getIcon() {
|
||||||
|
// 1.21.9 changed the GUI atlas, so newer versions draw the effect's texture (getIconId) instead.
|
||||||
|
//? if >=1.21.9 {
|
||||||
return null;
|
return null;
|
||||||
|
//?} else if >=1.21.6 {
|
||||||
|
//return (SpriteRef) SaturnClient.client.getGuiAtlasManager().getSprite((InGameHud.getEffectTexture(getEffectType())));
|
||||||
|
//?} else
|
||||||
|
//return (SpriteRef) SaturnClient.client.getStatusEffectSpriteManager().getSprite(getEffectType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Before 1.21.6 there's no InGameHud.getEffectTexture; getIcon's sprite is used there instead.
|
||||||
|
//? if >=1.21.6 {
|
||||||
@Override
|
@Override
|
||||||
public IdentifierRef getIconId() {
|
public IdentifierRef getIconId() {
|
||||||
Identifier id = InGameHud.getEffectTexture(getEffectType());
|
Identifier id = InGameHud.getEffectTexture(getEffectType());
|
||||||
|
|
||||||
return IdentifierRef.of(id.getNamespace(), "textures/" + id.getPath() + ".png");
|
return IdentifierRef.of(id.getNamespace(), "textures/" + id.getPath() + ".png");
|
||||||
}
|
}
|
||||||
|
//?}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getInfiniteText() {
|
public String getInfiniteText() {
|
||||||
+4
@@ -7,6 +7,7 @@ import org.spongepowered.asm.mixin.Mixin;
|
|||||||
|
|
||||||
import net.minecraft.text.Style;
|
import net.minecraft.text.Style;
|
||||||
import net.minecraft.text.Text;
|
import net.minecraft.text.Text;
|
||||||
|
//? if >=1.21.9
|
||||||
import net.minecraft.text.StyleSpriteSource.Font;
|
import net.minecraft.text.StyleSpriteSource.Font;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
@@ -15,7 +16,10 @@ public interface TextMixin extends TextRef {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public default TextRef withFont(IdentifierRef font) {
|
public default TextRef withFont(IdentifierRef font) {
|
||||||
|
//? if >=1.21.9 {
|
||||||
return (TextRef) (Text) (((Text) this).copy().setStyle(Style.EMPTY.withFont(new Font((Identifier) (Object) font))));
|
return (TextRef) (Text) (((Text) this).copy().setStyle(Style.EMPTY.withFont(new Font((Identifier) (Object) font))));
|
||||||
|
//?} else
|
||||||
|
//return (TextRef) (((Text) this).copy().setStyle(Style.EMPTY.withFont((Identifier) (Object) font)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
+8
-25
@@ -11,6 +11,7 @@ import net.minecraft.text.Text;
|
|||||||
import org.saturnclient.common.provider.SaturnProvider;
|
import org.saturnclient.common.provider.SaturnProvider;
|
||||||
import org.saturnclient.common.ref.asset.IdentifierRef;
|
import org.saturnclient.common.ref.asset.IdentifierRef;
|
||||||
import org.saturnclient.common.ref.game.MinecraftClientRef;
|
import org.saturnclient.common.ref.game.MinecraftClientRef;
|
||||||
|
import org.saturnclient.cosmetics.Emotes;
|
||||||
import org.saturnclient.impl.cosmetics.utils.IdentifierUtils;
|
import org.saturnclient.impl.cosmetics.utils.IdentifierUtils;
|
||||||
import org.saturnclient.saturnclient.SaturnClient;
|
import org.saturnclient.saturnclient.SaturnClient;
|
||||||
|
|
||||||
@@ -22,31 +23,13 @@ public class SaturnProviderImpl implements SaturnProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void playEmote(UUID fromPlayerUuid, String emoteIdOrNull) {
|
public void playEmote(UUID fromPlayerUuid, String emoteIdOrNull) {
|
||||||
// if (SaturnClient.client == null || SaturnClient.client.world == null) {
|
if (fromPlayerUuid == null) {
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
|
// An empty or unknown ID stops whatever the player is playing.
|
||||||
// for (AbstractClientPlayerEntity player : SaturnClient.client.world.getPlayers()) {
|
Emotes.get(emoteIdOrNull == null ? "" : emoteIdOrNull).ifPresentOrElse(
|
||||||
// if (!player.getUuid().equals(fromPlayerUuid)) {
|
emote -> org.saturnclient.emotes.fabric.Emotes.play(fromPlayerUuid, emote.animation()),
|
||||||
// continue;
|
() -> org.saturnclient.emotes.fabric.Emotes.stop(fromPlayerUuid));
|
||||||
// }
|
|
||||||
|
|
||||||
// AnimationStack animationStack = PlayerAnimationAccess.getPlayerAnimLayer(player);
|
|
||||||
|
|
||||||
// if (emoteIdOrNull != null && !emoteIdOrNull.isEmpty()) {
|
|
||||||
// if (animationStack.isActive() && animationStack.getPriority() == 1000) {
|
|
||||||
// animationStack.removeLayer(1000);
|
|
||||||
// }
|
|
||||||
// animationStack.addAnimLayer(1000,
|
|
||||||
// PlayerAnimationRegistry
|
|
||||||
// .getAnimation(Identifier.of("saturnclient", emoteIdOrNull))
|
|
||||||
// .playAnimation());
|
|
||||||
// } else {
|
|
||||||
// animationStack.removeLayer(1000);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -0,0 +1,177 @@
|
|||||||
|
package org.saturnclient.impl.ui;
|
||||||
|
|
||||||
|
// Entities in the UI are drawn through the GUI render state from 1.21.6, and straight into vertex
|
||||||
|
// consumers before. This file has one implementation for each side.
|
||||||
|
//? if >=1.21.6 {
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.joml.Quaternionf;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
import org.saturnclient.saturnclient.SaturnClient;
|
||||||
|
import org.saturnclient.ui.ElementContext;
|
||||||
|
import org.saturnclient.ui.RenderScope;
|
||||||
|
import org.saturnclient.ui.components.SkinPreview.EntityDrawer;
|
||||||
|
|
||||||
|
//? if >=1.21.9 {
|
||||||
|
import net.minecraft.client.render.entity.EntityRenderManager;
|
||||||
|
//?} else
|
||||||
|
//import net.minecraft.client.render.entity.EntityRenderDispatcher;
|
||||||
|
import net.minecraft.client.render.entity.EntityRenderer;
|
||||||
|
import net.minecraft.client.render.entity.state.EntityRenderState;
|
||||||
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
|
||||||
|
public class EntityDrawerImpl implements EntityDrawer {
|
||||||
|
@Override
|
||||||
|
public void render(RenderScope renderScope, boolean negativeAngle, float angle, float scale, ElementContext ctx) {
|
||||||
|
LivingEntity entity = SaturnClient.client.player;
|
||||||
|
|
||||||
|
if (entity != null) {
|
||||||
|
drawEntity(renderScope, 0, 0, 75, 78, 30, 0.0625F, ctx.mouseX / scale, ctx.mouseY / scale,
|
||||||
|
SaturnClient.client.player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void drawEntity(RenderScope renderScope, int x1, int y1, int x2, int y2, int size, float scale,
|
||||||
|
float mouseX, float mouseY, LivingEntity entity) {
|
||||||
|
float f = (float) (x1 + x2) / 2.0F;
|
||||||
|
float g = (float) (y1 + y2) / 2.0F;
|
||||||
|
renderScope.enableScissor(x1, y1, x2, y2);
|
||||||
|
float h = (float) Math.atan((double) ((f - mouseX) / 40.0F));
|
||||||
|
float i = (float) Math.atan((double) ((g - mouseY) / 40.0F));
|
||||||
|
Quaternionf quaternionf = (new Quaternionf()).rotateZ((float) Math.PI);
|
||||||
|
Quaternionf quaternionf2 = (new Quaternionf()).rotateX(i * 20.0F * ((float) Math.PI / 180F));
|
||||||
|
quaternionf.mul(quaternionf2);
|
||||||
|
float j = entity.bodyYaw;
|
||||||
|
float k = entity.getYaw();
|
||||||
|
float l = entity.getPitch();
|
||||||
|
float m = entity.lastHeadYaw;
|
||||||
|
float n = entity.headYaw;
|
||||||
|
entity.bodyYaw = 180.0F + h * 20.0F;
|
||||||
|
entity.setYaw(180.0F + h * 40.0F);
|
||||||
|
entity.setPitch(-i * 20.0F);
|
||||||
|
entity.headYaw = entity.getYaw();
|
||||||
|
entity.lastHeadYaw = entity.getYaw();
|
||||||
|
float o = entity.getScale();
|
||||||
|
Vector3f vector3f = new Vector3f(0.0F, entity.getHeight() / 2.0F + scale * o, 0.0F);
|
||||||
|
float p = (float) size / o;
|
||||||
|
drawEntity(renderScope, x1, y1, x2, y2, p, vector3f, quaternionf, quaternionf2, entity);
|
||||||
|
entity.bodyYaw = j;
|
||||||
|
entity.setYaw(k);
|
||||||
|
entity.setPitch(l);
|
||||||
|
entity.lastHeadYaw = m;
|
||||||
|
entity.headYaw = n;
|
||||||
|
renderScope.disableScissor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void drawEntity(RenderScope renderScope, int x1, int y1, int x2, int y2, float scale,
|
||||||
|
Vector3f translation, Quaternionf rotation, @Nullable Quaternionf overrideCameraAngle,
|
||||||
|
LivingEntity entity) {
|
||||||
|
//? if >=1.21.9 {
|
||||||
|
EntityRenderManager entityRenderDispatcher = SaturnClient.client.getEntityRenderDispatcher();
|
||||||
|
//?} else
|
||||||
|
//EntityRenderDispatcher entityRenderDispatcher = SaturnClient.client.getEntityRenderDispatcher();
|
||||||
|
EntityRenderer<? super LivingEntity, ?> entityRenderer = entityRenderDispatcher.getRenderer(entity);
|
||||||
|
EntityRenderState entityRenderState = entityRenderer.getAndUpdateRenderState(entity, 1.0F);
|
||||||
|
//? if <1.21.11
|
||||||
|
//entityRenderState.hitbox = null;
|
||||||
|
|
||||||
|
if (renderScope instanceof RenderScopeImpl i)
|
||||||
|
i.addEntity(entityRenderState, scale, translation, rotation, overrideCameraAngle, x1, y1, x2, y2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//?} else {
|
||||||
|
/*import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.joml.Quaternionf;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
import org.saturnclient.saturnclient.SaturnClient;
|
||||||
|
import org.saturnclient.ui.ElementContext;
|
||||||
|
import org.saturnclient.ui.RenderScope;
|
||||||
|
import org.saturnclient.ui.components.SkinPreview.EntityDrawer;
|
||||||
|
|
||||||
|
import net.minecraft.client.render.DiffuseLighting;
|
||||||
|
import net.minecraft.client.render.entity.EntityRenderDispatcher;
|
||||||
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
|
||||||
|
public class EntityDrawerImpl implements EntityDrawer {
|
||||||
|
public static void drawEntity(RenderScope renderScope, int x1, int y1, int x2, int y2, int size, float f,
|
||||||
|
float mouseX,
|
||||||
|
float mouseY, LivingEntity entity, float angle, boolean negativeAngle) {
|
||||||
|
float g = (float) (x1 + x2) / 2.0F;
|
||||||
|
float h = (float) (y1 + y2) / 2.0F;
|
||||||
|
renderScope.enableScissor(0, 6, x2, y2);
|
||||||
|
float i = (float) Math.atan((double) ((g - mouseX) / 40.0F));
|
||||||
|
float j = (float) Math.atan((double) ((h - mouseY) / 40.0F));
|
||||||
|
Quaternionf quaternionf = (new Quaternionf()).rotateZ(3.1415927F);
|
||||||
|
float k = entity.bodyYaw;
|
||||||
|
float l = entity.getYaw();
|
||||||
|
float m = entity.getPitch();
|
||||||
|
//? if >=1.21.5
|
||||||
|
float n = entity.lastHeadYaw;
|
||||||
|
//? if <1.21.5
|
||||||
|
//float n = entity.prevHeadYaw;
|
||||||
|
float o = entity.headYaw;
|
||||||
|
entity.setYaw(angle);
|
||||||
|
entity.bodyYaw = angle;
|
||||||
|
entity.setPitch(-(j * 20.0F));
|
||||||
|
entity.headYaw = negativeAngle ? (i * 40.0F) + 180f : -(i * 40.0F);
|
||||||
|
//? if >=1.21.5
|
||||||
|
entity.lastHeadYaw = entity.getHeadYaw();
|
||||||
|
//? if <1.21.5
|
||||||
|
//entity.prevHeadYaw = entity.getHeadYaw();
|
||||||
|
entity.setCustomNameVisible(false);
|
||||||
|
|
||||||
|
float p = entity.getScale();
|
||||||
|
Vector3f vector3f = new Vector3f(0.0F, entity.getHeight() / 2.0F + f * p, 0.0F);
|
||||||
|
float q = (float) size / p;
|
||||||
|
drawEntity(renderScope, g, h, q, vector3f, quaternionf, null, entity);
|
||||||
|
|
||||||
|
entity.setCustomNameVisible(true);
|
||||||
|
entity.bodyYaw = k;
|
||||||
|
entity.setYaw(l);
|
||||||
|
entity.setPitch(m);
|
||||||
|
//? if >=1.21.5
|
||||||
|
entity.lastHeadYaw = n;
|
||||||
|
//? if <1.21.5
|
||||||
|
//entity.prevHeadYaw = n;
|
||||||
|
entity.headYaw = o;
|
||||||
|
renderScope.disableScissor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void drawEntity(RenderScope renderScope, float x, float y, float size, Vector3f vector3f,
|
||||||
|
Quaternionf quaternionf, @Nullable Quaternionf quaternionf2, LivingEntity entity) {
|
||||||
|
if (renderScope instanceof RenderScopeImpl scopeImpl) {
|
||||||
|
scopeImpl.matrices.push();
|
||||||
|
scopeImpl.matrices.translate((double) x, (double) y, 0);
|
||||||
|
scopeImpl.matrices.scale(size, size, -size);
|
||||||
|
scopeImpl.matrices.translate(vector3f.x, vector3f.y, vector3f.z);
|
||||||
|
scopeImpl.matrices.multiply(quaternionf);
|
||||||
|
scopeImpl.draw();
|
||||||
|
//? if >=1.21.5
|
||||||
|
DiffuseLighting.disableGuiDepthLighting();
|
||||||
|
//? if <1.21.5
|
||||||
|
//DiffuseLighting.method_34742();
|
||||||
|
EntityRenderDispatcher entityRenderDispatcher = SaturnClient.client.getEntityRenderDispatcher();
|
||||||
|
|
||||||
|
entityRenderDispatcher.setRenderShadows(false);
|
||||||
|
scopeImpl.draw((vertexConsumers) -> {
|
||||||
|
entityRenderDispatcher.render(entity, 0.0, 0.0, 0.0, 1.0F,
|
||||||
|
scopeImpl.matrices, vertexConsumers, 15728880);
|
||||||
|
});
|
||||||
|
|
||||||
|
scopeImpl.draw();
|
||||||
|
entityRenderDispatcher.setRenderShadows(true);
|
||||||
|
scopeImpl.getMatrixStack().pop();
|
||||||
|
DiffuseLighting.enableGuiDepthLighting();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(RenderScope renderScope, boolean negativeAngle, float angle, float scale, ElementContext ctx) {
|
||||||
|
LivingEntity entity = SaturnClient.client.player;
|
||||||
|
if (entity != null) {
|
||||||
|
drawEntity(renderScope, 0, 0, 75, 78, 30, 0.0625F, ctx.mouseX / scale, ctx.mouseY / scale, entity, angle,
|
||||||
|
negativeAngle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*///?}
|
||||||
@@ -0,0 +1,786 @@
|
|||||||
|
package org.saturnclient.impl.ui;
|
||||||
|
|
||||||
|
// 1.21.6 rewrote GUI rendering: render states and a 2D matrix stack (Matrix3x2fStack) instead of
|
||||||
|
// drawing into vertex consumers with a MatrixStack. This file has one implementation for each side.
|
||||||
|
//? if >=1.21.6 {
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.Deque;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.joml.Matrix3x2f;
|
||||||
|
import org.joml.Matrix3x2fStack;
|
||||||
|
import org.joml.Quaternionf;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.textures.GpuTextureView;
|
||||||
|
|
||||||
|
import org.saturnclient.common.ref.asset.IdentifierRef;
|
||||||
|
import org.saturnclient.common.ref.asset.SpriteRef;
|
||||||
|
import org.saturnclient.common.ref.game.ItemStackRef;
|
||||||
|
import org.saturnclient.common.ref.render.MatrixStackRef;
|
||||||
|
import org.saturnclient.impl.ref.Matrix3x2fStackRef;
|
||||||
|
import org.saturnclient.saturnclient.SaturnClient;
|
||||||
|
import org.saturnclient.saturnclient.mixin.DrawContextAccessor;
|
||||||
|
import org.saturnclient.ui.RenderScope;
|
||||||
|
import org.saturnclient.ui.resources.Fonts;
|
||||||
|
import org.saturnclient.ui.resources.SvgTexture;
|
||||||
|
|
||||||
|
import net.minecraft.client.gl.RenderPipelines;
|
||||||
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
import net.minecraft.client.gui.ScreenRect;
|
||||||
|
import net.minecraft.client.gui.render.state.ColoredQuadGuiElementRenderState;
|
||||||
|
import net.minecraft.client.gui.render.state.GuiRenderState;
|
||||||
|
import net.minecraft.client.gui.render.state.ItemGuiElementRenderState;
|
||||||
|
import net.minecraft.client.gui.render.state.TextGuiElementRenderState;
|
||||||
|
import net.minecraft.client.gui.render.state.TexturedQuadGuiElementRenderState;
|
||||||
|
import net.minecraft.client.gui.render.state.special.EntityGuiElementRenderState;
|
||||||
|
import net.minecraft.client.render.entity.state.EntityRenderState;
|
||||||
|
//? if >=1.21.7 {
|
||||||
|
import net.minecraft.client.render.item.KeyedItemRenderState;
|
||||||
|
//?} else
|
||||||
|
//import net.minecraft.client.render.item.ItemRenderState;
|
||||||
|
//? if >=1.21.11
|
||||||
|
import net.minecraft.client.texture.AbstractTexture;
|
||||||
|
import net.minecraft.client.texture.Sprite;
|
||||||
|
import net.minecraft.client.texture.TextureSetup;
|
||||||
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
import net.minecraft.item.ItemDisplayContext;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.crash.CrashException;
|
||||||
|
import net.minecraft.util.crash.CrashReport;
|
||||||
|
import net.minecraft.util.crash.CrashReportSection;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
public class RenderScopeImpl implements RenderScope {
|
||||||
|
|
||||||
|
public final Matrix3x2fStackRef matrices;
|
||||||
|
public final GuiRenderState state;
|
||||||
|
|
||||||
|
private ScissorStack scissorStack;
|
||||||
|
private int opacity = 0xFF << 24;
|
||||||
|
|
||||||
|
public RenderScopeImpl(DrawContext context) {
|
||||||
|
this(context.getMatrices(), ((DrawContextAccessor) (Object) context).getState());
|
||||||
|
}
|
||||||
|
|
||||||
|
public RenderScopeImpl(Matrix3x2fStack matrices, GuiRenderState state) {
|
||||||
|
this.matrices = new Matrix3x2fStackRef(matrices);
|
||||||
|
this.state = state;
|
||||||
|
this.scissorStack = new ScissorStack();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MatrixStackRef getMatrixStack() {
|
||||||
|
return matrices;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOpacity(float alpha) {
|
||||||
|
this.opacity = ((int) (alpha * 255)) << 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getColor(int color) {
|
||||||
|
int originalAlpha = (color >>> 24) & 0xFF;
|
||||||
|
int newAlpha = (opacity >>> 24) & 0xFF;
|
||||||
|
int mixedAlpha = (originalAlpha * newAlpha) / 255;
|
||||||
|
return (mixedAlpha << 24) | (color & 0x00FFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fill(int x1, int y1, int x2, int y2, int color) {
|
||||||
|
this.state.addSimpleElement(
|
||||||
|
new ColoredQuadGuiElementRenderState(
|
||||||
|
RenderPipelines.GUI,
|
||||||
|
TextureSetup.empty(),
|
||||||
|
new Matrix3x2f(this.matrices.stack),
|
||||||
|
x1, y1, x2, y2, color, color,
|
||||||
|
this.scissorStack.peekLast()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawRectangle(int x, int y, int width, int height, int color) {
|
||||||
|
if (color == 0)
|
||||||
|
return;
|
||||||
|
color = getColor(color);
|
||||||
|
|
||||||
|
int x1 = x;
|
||||||
|
int x2 = x + width;
|
||||||
|
int y1 = y;
|
||||||
|
int y2 = y + height;
|
||||||
|
|
||||||
|
if (x2 < x1) {
|
||||||
|
int tmp = x1;
|
||||||
|
x1 = x2;
|
||||||
|
x2 = tmp;
|
||||||
|
}
|
||||||
|
if (y2 < y1) {
|
||||||
|
int tmp = y1;
|
||||||
|
y1 = y2;
|
||||||
|
y2 = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.fill(x1, y1, x2, y2, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawText(String text, int x, int y, int font, int color) {
|
||||||
|
drawText(1.0f, text, x, y, font, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawText(float scale, String text, int x, int y, int font, int color) {
|
||||||
|
if (color == 0)
|
||||||
|
return;
|
||||||
|
if (font == 0)
|
||||||
|
scale *= 2;
|
||||||
|
|
||||||
|
int lineIndex = 0;
|
||||||
|
for (String line : text.split("\n")) {
|
||||||
|
int finalColor = getColor(color);
|
||||||
|
|
||||||
|
matrices.push();
|
||||||
|
matrices.translate(x, y + (lineIndex * Fonts.getHeight()));
|
||||||
|
matrices.scale(scale, scale);
|
||||||
|
|
||||||
|
this.state.addText(
|
||||||
|
new TextGuiElementRenderState(
|
||||||
|
SaturnClient.client.textRenderer,
|
||||||
|
((Text) Fonts.setFont(line, font)).asOrderedText(),
|
||||||
|
new Matrix3x2f(this.matrices.stack),
|
||||||
|
0, font == 0 ? 1 : 8,
|
||||||
|
//? if >=1.21.11 {
|
||||||
|
finalColor, 0, false, false, this.scissorStack.peekLast()));
|
||||||
|
//?} else
|
||||||
|
//finalColor, 0, false, this.scissorStack.peekLast()));
|
||||||
|
|
||||||
|
matrices.pop();
|
||||||
|
|
||||||
|
lineIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getScaledWindowWidth() {
|
||||||
|
return SaturnClient.client.getWindow().getScaledWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getScaledWindowHeight() {
|
||||||
|
return SaturnClient.client.getWindow().getScaledHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Texture rendering
|
||||||
|
@Override
|
||||||
|
public void drawTexture(IdentifierRef sprite, int x, int y, float u, float v, int width, int height) {
|
||||||
|
drawTexture(sprite, x, y, u, v, width, height, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawTexture(IdentifierRef sprite, int x, int y, float u, float v, int width, int height, int color) {
|
||||||
|
drawTexture(sprite, x, y, u, v, width, height, width, height, width, height, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawTexture(IdentifierRef sprite, int x, int y, float u, float v, int width, int height,
|
||||||
|
int regionWidth, int regionHeight, int textureWidth, int textureHeight) {
|
||||||
|
drawTexture(sprite, x, y, u, v, width, height, regionWidth, regionHeight, textureWidth, textureHeight, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawTexture(IdentifierRef sprite, int x, int y, float u, float v, int width, int height,
|
||||||
|
int regionWidth, int regionHeight, int textureWidth, int textureHeight, int color) {
|
||||||
|
drawTexturedQuad((Identifier) (Object) sprite, x, x + width, y, y + height,
|
||||||
|
(u + 0f) / textureWidth,
|
||||||
|
(u + regionWidth) / textureWidth,
|
||||||
|
(v + 0f) / textureHeight,
|
||||||
|
(v + regionHeight) / textureHeight,
|
||||||
|
color);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawTexturedQuad(Identifier sprite, int x1, int x2, int y1, int y2,
|
||||||
|
float u1, float u2, float v1, float v2, int color) {
|
||||||
|
if (color == 0)
|
||||||
|
return;
|
||||||
|
color = getColor(color);
|
||||||
|
|
||||||
|
if (sprite.getPath().endsWith(".svg")) {
|
||||||
|
sprite = (Identifier) (Object) SvgTexture.getSvg(
|
||||||
|
(IdentifierRef) (Object) sprite,
|
||||||
|
(x2 - x1) * 2, (y2 - y1) * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
GpuTextureView gpuTextureView = SaturnClient.client.getTextureManager()
|
||||||
|
.getTexture(sprite).getGlTextureView();
|
||||||
|
|
||||||
|
//? if >=1.21.11
|
||||||
|
AbstractTexture abstractTexture = SaturnClient.client.getTextureManager().getTexture(sprite);
|
||||||
|
|
||||||
|
this.state.addSimpleElement(new TexturedQuadGuiElementRenderState(
|
||||||
|
RenderPipelines.GUI_TEXTURED,
|
||||||
|
//? if >=1.21.11 {
|
||||||
|
TextureSetup.of(gpuTextureView, abstractTexture.getSampler()),
|
||||||
|
//?} else
|
||||||
|
//TextureSetup.withoutGlTexture(gpuTextureView),
|
||||||
|
new Matrix3x2f(this.matrices.stack),
|
||||||
|
x1, y1, x2, y2, u1, u2, v1, v2, color,
|
||||||
|
this.scissorStack.peekLast()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scissor management
|
||||||
|
@Override
|
||||||
|
public void enableScissor(int x1, int y1, int x2, int y2) {
|
||||||
|
ScreenRect rect = new ScreenRect(x1, y1, x2 - x1, y2 - y1).transform(this.matrices.stack);
|
||||||
|
scissorStack.push(rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disableScissor() {
|
||||||
|
scissorStack.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean scissorContains(int x, int y) {
|
||||||
|
return scissorStack.contains(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ScissorStack {
|
||||||
|
private final Deque<ScreenRect> stack = new ArrayDeque<>();
|
||||||
|
|
||||||
|
public ScreenRect push(ScreenRect rect) {
|
||||||
|
ScreenRect last = stack.peekLast();
|
||||||
|
if (last != null) {
|
||||||
|
ScreenRect intersection = Objects.requireNonNullElse(rect.intersection(last), ScreenRect.empty());
|
||||||
|
stack.addLast(intersection);
|
||||||
|
return intersection;
|
||||||
|
} else {
|
||||||
|
stack.addLast(rect);
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public ScreenRect pop() {
|
||||||
|
if (stack.isEmpty())
|
||||||
|
throw new IllegalStateException("Scissor stack underflow");
|
||||||
|
stack.removeLast();
|
||||||
|
return stack.peekLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public ScreenRect peekLast() {
|
||||||
|
return stack.peekLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean contains(int x, int y) {
|
||||||
|
return stack.isEmpty() || stack.peekLast().contains(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Item rendering
|
||||||
|
@Override
|
||||||
|
public void drawItem(ItemStackRef stack, int x, int y) {
|
||||||
|
drawItem(null, SaturnClient.client.world, stack, x, y, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawItem(@Nullable LivingEntity entity, @Nullable World world, ItemStackRef stack, int x, int y,
|
||||||
|
int seed) {
|
||||||
|
drawItem(entity, world, (ItemStack) (Object) stack, x, y, seed, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawItem(@Nullable LivingEntity entity, @Nullable World world, ItemStack stack, int x, int y, int seed,
|
||||||
|
int z) {
|
||||||
|
if (!stack.isEmpty()) {
|
||||||
|
//? if >=1.21.7 {
|
||||||
|
KeyedItemRenderState keyedItemRenderState = new KeyedItemRenderState();
|
||||||
|
//?} else
|
||||||
|
//ItemRenderState keyedItemRenderState = new ItemRenderState();
|
||||||
|
SaturnClient.client.getItemModelManager().clearAndUpdate(keyedItemRenderState, stack,
|
||||||
|
ItemDisplayContext.GUI, world,
|
||||||
|
entity, seed);
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.state.addItem(new ItemGuiElementRenderState(stack.getItem().getName().toString(),
|
||||||
|
new Matrix3x2f(this.matrices.stack), keyedItemRenderState, x, y,
|
||||||
|
this.scissorStack.peekLast()));
|
||||||
|
} catch (Throwable throwable) {
|
||||||
|
CrashReport crashReport = CrashReport.create(throwable, "Rendering item");
|
||||||
|
CrashReportSection crashReportSection = crashReport.addElement("Item being rendered");
|
||||||
|
crashReportSection.add("Item Type", () -> String.valueOf(stack.getItem()));
|
||||||
|
crashReportSection.add("Item Components", () -> String.valueOf(stack.getComponents()));
|
||||||
|
crashReportSection.add("Item Foil", () -> String.valueOf(stack.hasGlint()));
|
||||||
|
throw new CrashException(crashReport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawSpriteStretched(SpriteRef sprite, int x, int y, int width, int height) {
|
||||||
|
drawSpriteStretched(sprite, x, y, width, height, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawSpriteStretched(SpriteRef sprite, int x, int y, int width, int height, int color) {
|
||||||
|
Sprite mcSprite = (Sprite) sprite;
|
||||||
|
if (color == 0 || width == 0 || height == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
drawTexturedQuad(mcSprite.getAtlasId(), x, x + width, y, y + height,
|
||||||
|
mcSprite.getMinU(), mcSprite.getMaxU(), mcSprite.getMinV(), mcSprite.getMaxV(), color);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw() {
|
||||||
|
// No-op for now
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawBorder(int x, int y, int width, int height, int color) {
|
||||||
|
fill(x, y, x + width, y + 1, color);
|
||||||
|
fill(x, y + height - 1, x + width, y + height, color);
|
||||||
|
fill(x, y + 1, x + 1, y + height - 1, color);
|
||||||
|
fill(x + width - 1, y + 1, x + width, y + height - 1, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addEntity(EntityRenderState entityState, float scale, Vector3f translation, Quaternionf rotation,
|
||||||
|
@Nullable Quaternionf overrideCameraAngle, int x1, int y1, int x2, int y2) {
|
||||||
|
|
||||||
|
Matrix3x2f mat = this.matrices.stack;
|
||||||
|
float offsetX = mat.m20;
|
||||||
|
float offsetY = mat.m21;
|
||||||
|
float scaleX = mat.m00; // current matrix X scale
|
||||||
|
float scaleY = mat.m11; // current matrix Y scale
|
||||||
|
|
||||||
|
int adjustedX1 = (int) (x1 * scaleX + offsetX);
|
||||||
|
int adjustedY1 = (int) (y1 * scaleY + offsetY);
|
||||||
|
int adjustedX2 = (int) (x2 * scaleX + offsetX);
|
||||||
|
int adjustedY2 = (int) (y2 * scaleY + offsetY);
|
||||||
|
|
||||||
|
float adjustedScale = scale * scaleX; // apply matrix scale to entity scale too
|
||||||
|
|
||||||
|
this.state.addSpecialElement(new EntityGuiElementRenderState(entityState, translation, rotation,
|
||||||
|
overrideCameraAngle, adjustedX1, adjustedY1, adjustedX2, adjustedY2, adjustedScale,
|
||||||
|
this.scissorStack.peekLast()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//?} else {
|
||||||
|
/*import java.util.ArrayDeque;
|
||||||
|
import java.util.Deque;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.joml.Matrix4f;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
|
||||||
|
import org.saturnclient.common.ref.asset.IdentifierRef;
|
||||||
|
import org.saturnclient.common.ref.asset.SpriteRef;
|
||||||
|
import org.saturnclient.common.ref.game.ItemStackRef;
|
||||||
|
import org.saturnclient.common.ref.render.MatrixStackRef;
|
||||||
|
import org.saturnclient.saturnclient.SaturnClient;
|
||||||
|
import org.saturnclient.saturnclient.mixin.DrawContextAccessor;
|
||||||
|
import org.saturnclient.ui.RenderScope;
|
||||||
|
import org.saturnclient.ui.resources.Fonts;
|
||||||
|
import org.saturnclient.ui.resources.SvgTexture;
|
||||||
|
|
||||||
|
import net.minecraft.client.font.TextRenderer;
|
||||||
|
import net.minecraft.client.font.TextRenderer.TextLayerType;
|
||||||
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
import net.minecraft.client.gui.ScreenRect;
|
||||||
|
import net.minecraft.client.render.DiffuseLighting;
|
||||||
|
import net.minecraft.client.render.OverlayTexture;
|
||||||
|
import net.minecraft.client.render.RenderLayer;
|
||||||
|
import net.minecraft.client.render.VertexConsumer;
|
||||||
|
import net.minecraft.client.render.VertexConsumerProvider;
|
||||||
|
import net.minecraft.client.render.item.ItemRenderState;
|
||||||
|
import net.minecraft.client.texture.Sprite;
|
||||||
|
import net.minecraft.client.util.Window;
|
||||||
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
//? if >=1.21.5
|
||||||
|
import net.minecraft.item.ItemDisplayContext;
|
||||||
|
//? if <1.21.5
|
||||||
|
//import net.minecraft.item.ModelTransformationMode;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.crash.CrashException;
|
||||||
|
import net.minecraft.util.crash.CrashReport;
|
||||||
|
import net.minecraft.util.crash.CrashReportSection;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
public class RenderScopeImpl implements RenderScope {
|
||||||
|
// ----------------------------
|
||||||
|
// Fields
|
||||||
|
// ----------------------------
|
||||||
|
public MatrixStack matrices;
|
||||||
|
public VertexConsumerProvider.Immediate vertexConsumers;
|
||||||
|
private ScissorStack scissorStack = new ScissorStack();
|
||||||
|
private int opacity = 255 << 24;
|
||||||
|
private final ItemRenderState itemRenderState;
|
||||||
|
|
||||||
|
// ----------------------------
|
||||||
|
// Constructors
|
||||||
|
// ----------------------------
|
||||||
|
public RenderScopeImpl(DrawContext context) {
|
||||||
|
this(context.getMatrices(), ((DrawContextAccessor) context).getVertexConsumers());
|
||||||
|
}
|
||||||
|
|
||||||
|
public RenderScopeImpl(MatrixStack matrices, VertexConsumerProvider.Immediate vertexConsumers) {
|
||||||
|
this.matrices = matrices;
|
||||||
|
this.vertexConsumers = vertexConsumers;
|
||||||
|
this.scissorStack = new ScissorStack();
|
||||||
|
this.itemRenderState = new ItemRenderState();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------
|
||||||
|
// Matrix & Transform
|
||||||
|
// ----------------------------
|
||||||
|
@Override
|
||||||
|
public MatrixStackRef getMatrixStack() {
|
||||||
|
return (MatrixStackRef) matrices;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------
|
||||||
|
// Color & Opacity
|
||||||
|
// ----------------------------
|
||||||
|
@Override
|
||||||
|
public void setOpacity(float alpha) {
|
||||||
|
this.opacity = (int) (alpha * 255) << 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getColor(int color) {
|
||||||
|
int originalAlpha = (color >>> 24) & 0xFF;
|
||||||
|
int newAlpha = (opacity >>> 24) & 0xFF;
|
||||||
|
int mixedAlpha = (originalAlpha * newAlpha) / 255;
|
||||||
|
return (mixedAlpha << 24) | (color & 0x00FFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------
|
||||||
|
// Draw / Window Info
|
||||||
|
// ----------------------------
|
||||||
|
@Override
|
||||||
|
public void draw() {
|
||||||
|
this.vertexConsumers.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getScaledWindowWidth() {
|
||||||
|
return SaturnClient.client.getWindow().getScaledWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getScaledWindowHeight() {
|
||||||
|
return SaturnClient.client.getWindow().getScaledHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void draw(Consumer<VertexConsumerProvider> drawer) {
|
||||||
|
drawer.accept(this.vertexConsumers);
|
||||||
|
this.vertexConsumers.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------
|
||||||
|
// Shapes
|
||||||
|
// ----------------------------
|
||||||
|
@Override
|
||||||
|
public void drawRectangle(int x, int y, int width, int height, int color) {
|
||||||
|
if (color == 0)
|
||||||
|
return;
|
||||||
|
color = getColor(color);
|
||||||
|
|
||||||
|
Matrix4f matrix4f = this.matrices.peek().getPositionMatrix();
|
||||||
|
|
||||||
|
int x1 = x;
|
||||||
|
int x2 = x + width;
|
||||||
|
int y1 = y;
|
||||||
|
int y2 = y + height;
|
||||||
|
|
||||||
|
if (x1 < x2) {
|
||||||
|
int tmp = x1;
|
||||||
|
x1 = x2;
|
||||||
|
x2 = tmp;
|
||||||
|
}
|
||||||
|
if (y1 < y2) {
|
||||||
|
int tmp = y1;
|
||||||
|
y1 = y2;
|
||||||
|
y2 = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
VertexConsumer vertexConsumer = this.vertexConsumers.getBuffer(RenderLayer.getGui());
|
||||||
|
vertexConsumer.vertex(matrix4f, x1, y1, 0).color(color);
|
||||||
|
vertexConsumer.vertex(matrix4f, x1, y2, 0).color(color);
|
||||||
|
vertexConsumer.vertex(matrix4f, x2, y2, 0).color(color);
|
||||||
|
vertexConsumer.vertex(matrix4f, x2, y1, 0).color(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fill(int x1, int y1, int x2, int y2, int color) {
|
||||||
|
fill(x1, y1, x2, y2, 0, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fill(int x1, int y1, int x2, int y2, int z, int color) {
|
||||||
|
fill(RenderLayer.getGui(), x1, y1, x2, y2, z, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fill(RenderLayer layer, int x1, int y1, int x2, int y2, int color) {
|
||||||
|
fill(layer, x1, y1, x2, y2, 0, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fill(RenderLayer layer, int x1, int y1, int x2, int y2, int z, int color) {
|
||||||
|
Matrix4f matrix4f = this.matrices.peek().getPositionMatrix();
|
||||||
|
if (x1 < x2) {
|
||||||
|
int tmp = x1;
|
||||||
|
x1 = x2;
|
||||||
|
x2 = tmp;
|
||||||
|
}
|
||||||
|
if (y1 < y2) {
|
||||||
|
int tmp = y1;
|
||||||
|
y1 = y2;
|
||||||
|
y2 = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
VertexConsumer vertexConsumer = this.vertexConsumers.getBuffer(layer);
|
||||||
|
vertexConsumer.vertex(matrix4f, x1, y1, z).color(color);
|
||||||
|
vertexConsumer.vertex(matrix4f, x1, y2, z).color(color);
|
||||||
|
vertexConsumer.vertex(matrix4f, x2, y2, z).color(color);
|
||||||
|
vertexConsumer.vertex(matrix4f, x2, y1, z).color(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawBorder(int x, int y, int width, int height, int color) {
|
||||||
|
fill(x, y, x + width, y + 1, color);
|
||||||
|
fill(x, y + height - 1, x + width, y + height, color);
|
||||||
|
fill(x, y + 1, x + 1, y + height - 1, color);
|
||||||
|
fill(x + width - 1, y + 1, x + width, y + height - 1, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------
|
||||||
|
// Text
|
||||||
|
// ----------------------------
|
||||||
|
@Override
|
||||||
|
public void drawText(String text, int x, int y, int font, int color) {
|
||||||
|
drawText(1.0f, text, x, y, font, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawText(float scale, String text, int x, int y, int font, int color) {
|
||||||
|
if (color == 0)
|
||||||
|
return;
|
||||||
|
if (font == 0)
|
||||||
|
scale *= 2;
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (String line : text.split("\n")) {
|
||||||
|
color = getColor(color);
|
||||||
|
matrices.push();
|
||||||
|
matrices.translate(x, y + i * Fonts.getHeight(), 0);
|
||||||
|
matrices.scale(scale, scale, 1.0f);
|
||||||
|
TextRenderer textRenderer = SaturnClient.client.textRenderer;
|
||||||
|
textRenderer.draw((Text) Fonts.setFont(line, font), 0, font == 0 ? 1 : 7, color, false,
|
||||||
|
matrices.peek().getPositionMatrix(), vertexConsumers, TextLayerType.NORMAL, 0, 15728880);
|
||||||
|
matrices.pop();
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------
|
||||||
|
// Textures & Sprites
|
||||||
|
// ----------------------------
|
||||||
|
@Override
|
||||||
|
public void drawTexture(IdentifierRef sprite, int x, int y, float u, float v, int width, int height) {
|
||||||
|
drawTexture(sprite, x, y, u, v, width, height, width, height, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawTexture(IdentifierRef sprite, int x, int y, float u, float v, int width, int height, int color) {
|
||||||
|
drawTexture(sprite, x, y, u, v, width, height, width, height, width, height, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawTexture(IdentifierRef sprite, int x, int y, float u, float v, int width, int height,
|
||||||
|
int regionWidth, int regionHeight, int textureWidth, int textureHeight) {
|
||||||
|
drawTexture(sprite, x, y, u, v, width, height, regionWidth, regionHeight, textureWidth, textureHeight, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawTexture(IdentifierRef sprite, int x, int y, float u, float v, int width, int height,
|
||||||
|
int regionWidth, int regionHeight, int textureWidth, int textureHeight, int color) {
|
||||||
|
drawTexturedQuad((Identifier) (Object) sprite, x, x + width, y, y + height,
|
||||||
|
(u + 0.0f) / textureWidth, (u + regionWidth) / textureWidth,
|
||||||
|
(v + 0.0f) / textureHeight, (v + regionHeight) / textureHeight, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawSpriteStretched(SpriteRef sprite, int x, int y, int width, int height) {
|
||||||
|
drawSpriteStretched(sprite, x, y, width, height, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawSpriteStretched(SpriteRef saturnSprite, int x, int y, int width, int height, int color) {
|
||||||
|
Sprite sprite = (Sprite) saturnSprite;
|
||||||
|
if (color == 0)
|
||||||
|
return;
|
||||||
|
if (width != 0 && height != 0) {
|
||||||
|
drawTexturedQuad(sprite.getAtlasId(), x, x + width, y, y + height,
|
||||||
|
sprite.getMinU(), sprite.getMaxU(), sprite.getMinV(), sprite.getMaxV(), color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawTexturedQuad(Identifier sprite, int x1, int x2, int y1, int y2,
|
||||||
|
float u1, float u2, float v1, float v2, int color) {
|
||||||
|
if (sprite.toString().endsWith(".svg")) {
|
||||||
|
sprite = (Identifier) (Object) SvgTexture.getSvg((IdentifierRef) (Object) sprite, (x2 - x1) * 2,
|
||||||
|
(y2 - y1) * 2);
|
||||||
|
}
|
||||||
|
if (color == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
x1 *= 4;
|
||||||
|
x2 *= 4;
|
||||||
|
y1 *= 4;
|
||||||
|
y2 *= 4;
|
||||||
|
color = getColor(color);
|
||||||
|
|
||||||
|
matrices.push();
|
||||||
|
matrices.scale(0.25f, 0.25f, 1.0f);
|
||||||
|
//? if <1.21.5
|
||||||
|
//RenderSystem.setShaderTexture(0, sprite);
|
||||||
|
RenderLayer renderLayer = RenderLayer.getGuiTextured(sprite);
|
||||||
|
Matrix4f matrix4f = matrices.peek().getPositionMatrix();
|
||||||
|
VertexConsumer vertexConsumer = vertexConsumers.getBuffer(renderLayer);
|
||||||
|
vertexConsumer.vertex(matrix4f, x1, y1, 0).texture(u1, v1).color(color);
|
||||||
|
vertexConsumer.vertex(matrix4f, x1, y2, 0).texture(u1, v2).color(color);
|
||||||
|
vertexConsumer.vertex(matrix4f, x2, y2, 0).texture(u2, v2).color(color);
|
||||||
|
vertexConsumer.vertex(matrix4f, x2, y1, 0).texture(u2, v1).color(color);
|
||||||
|
matrices.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------
|
||||||
|
// Items
|
||||||
|
// ----------------------------
|
||||||
|
@Override
|
||||||
|
public void drawItem(ItemStackRef item, int x, int y) {
|
||||||
|
drawItem(SaturnClient.client.player, SaturnClient.client.world, item, x, y, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawItem(@Nullable LivingEntity entity, @Nullable World world, ItemStackRef stack, int x, int y,
|
||||||
|
int seed) {
|
||||||
|
drawItem(entity, world, (ItemStack) (Object) stack, x, y, seed, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawItem(@Nullable LivingEntity entity, @Nullable World world, ItemStack stack, int x, int y, int seed,
|
||||||
|
int z) {
|
||||||
|
if (stack.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
//? if >=1.21.5
|
||||||
|
SaturnClient.client.getItemModelManager().update(itemRenderState, stack, ItemDisplayContext.GUI, world, entity, seed);
|
||||||
|
//? if >=1.21.5
|
||||||
|
SaturnClient.client.getItemModelManager().clearAndUpdate(this.itemRenderState, stack, ItemDisplayContext.GUI, world, entity, seed);
|
||||||
|
//? if <1.21.5
|
||||||
|
//SaturnClient.client.getItemModelManager().update(itemRenderState, stack, ModelTransformationMode.GUI, false, world, entity, seed);
|
||||||
|
|
||||||
|
this.matrices.push();
|
||||||
|
//? if >=1.21.5
|
||||||
|
this.matrices.translate((float) (x + 8), (float) (y + 8), (float) (150 + z));
|
||||||
|
//? if <1.21.5
|
||||||
|
//this.matrices.translate(x + 8, y + 8, 150 + (itemRenderState.hasDepth() ? z : 0));
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.matrices.scale(16.0F, -16.0F, 16.0F);
|
||||||
|
boolean bl = !this.itemRenderState.isSideLit();
|
||||||
|
if (bl) {
|
||||||
|
this.draw();
|
||||||
|
DiffuseLighting.disableGuiDepthLighting();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.itemRenderState.render(this.matrices, this.vertexConsumers, 15728880, OverlayTexture.DEFAULT_UV);
|
||||||
|
this.draw();
|
||||||
|
if (bl) {
|
||||||
|
DiffuseLighting.enableGuiDepthLighting();
|
||||||
|
}
|
||||||
|
} catch (Throwable throwable) {
|
||||||
|
CrashReport crashReport = CrashReport.create(throwable, "Rendering item");
|
||||||
|
CrashReportSection crashReportSection = crashReport.addElement("Item being rendered");
|
||||||
|
crashReportSection.add("Item Type", () -> String.valueOf(stack.getItem()));
|
||||||
|
crashReportSection.add("Item Components", () -> String.valueOf(stack.getComponents()));
|
||||||
|
crashReportSection.add("Item Foil", () -> String.valueOf(stack.hasGlint()));
|
||||||
|
throw new CrashException(crashReport);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.matrices.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------
|
||||||
|
// Scissor / Clipping
|
||||||
|
// ----------------------------
|
||||||
|
@Override
|
||||||
|
public void enableScissor(int x1, int y1, int x2, int y2) {
|
||||||
|
ScreenRect screenRect = new ScreenRect(x1, y1, x2 - x1, y2 - y1)
|
||||||
|
.transform(matrices.peek().getPositionMatrix());
|
||||||
|
setScissor(scissorStack.push(screenRect));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disableScissor() {
|
||||||
|
setScissor(scissorStack.pop());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean scissorContains(int x, int y) {
|
||||||
|
return scissorStack.containsPoint(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setScissor(@Nullable ScreenRect rect) {
|
||||||
|
draw();
|
||||||
|
if (rect != null) {
|
||||||
|
Window window = SaturnClient.client.getWindow();
|
||||||
|
int framebufferHeight = window.getFramebufferHeight();
|
||||||
|
double scaleFactor = window.getScaleFactor();
|
||||||
|
RenderSystem.enableScissor(
|
||||||
|
(int) (rect.getLeft() * scaleFactor),
|
||||||
|
(int) (framebufferHeight - rect.getBottom() * scaleFactor),
|
||||||
|
Math.max(0, (int) (rect.width() * scaleFactor)),
|
||||||
|
Math.max(0, (int) (rect.height() * scaleFactor)));
|
||||||
|
} else {
|
||||||
|
RenderSystem.disableScissor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ScissorStack {
|
||||||
|
private final Deque<ScreenRect> stack = new ArrayDeque<>();
|
||||||
|
|
||||||
|
public ScreenRect push(ScreenRect p_281812_) {
|
||||||
|
ScreenRect screenrectangle = this.stack.peekLast();
|
||||||
|
if (screenrectangle != null) {
|
||||||
|
ScreenRect screenrectangle1 = Objects.requireNonNullElse(p_281812_.intersection(screenrectangle),
|
||||||
|
ScreenRect.empty());
|
||||||
|
this.stack.addLast(screenrectangle1);
|
||||||
|
return screenrectangle1;
|
||||||
|
} else {
|
||||||
|
this.stack.addLast(p_281812_);
|
||||||
|
return p_281812_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public ScreenRect pop() {
|
||||||
|
if (this.stack.isEmpty()) {
|
||||||
|
throw new IllegalStateException("Scissor stack underflow");
|
||||||
|
} else {
|
||||||
|
this.stack.removeLast();
|
||||||
|
return this.stack.peekLast();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containsPoint(int p_329411_, int p_333404_) {
|
||||||
|
return this.stack.isEmpty() ? true : this.stack.peek().contains(p_329411_, p_333404_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*///?}
|
||||||
+72
-15
@@ -3,21 +3,26 @@ package org.saturnclient.impl.ui;
|
|||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
|
||||||
import org.saturnclient.saturnclient.mixin.DrawContextAccessor;
|
|
||||||
import org.saturnclient.ui.RenderScope;
|
import org.saturnclient.ui.RenderScope;
|
||||||
import org.saturnclient.ui.SaturnScreen;
|
import org.saturnclient.ui.SaturnScreen;
|
||||||
import org.saturnclient.ui.SaturnScreen.ScreenProvider;
|
import org.saturnclient.ui.SaturnScreen.ScreenProvider;
|
||||||
|
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.gl.PostEffectProcessor;
|
//? if >=1.21.9
|
||||||
|
import net.minecraft.client.gui.Click;
|
||||||
import net.minecraft.client.gui.CubeMapRenderer;
|
import net.minecraft.client.gui.CubeMapRenderer;
|
||||||
import net.minecraft.client.gui.DrawContext;
|
import net.minecraft.client.gui.DrawContext;
|
||||||
import net.minecraft.client.gui.RotatingCubeMapRenderer;
|
import net.minecraft.client.gui.RotatingCubeMapRenderer;
|
||||||
import net.minecraft.client.gui.screen.Screen;
|
import net.minecraft.client.gui.screen.Screen;
|
||||||
|
//? if >=1.21.9
|
||||||
|
import net.minecraft.client.input.KeyInput;
|
||||||
|
//? if <1.21.6 {
|
||||||
|
/*import net.minecraft.client.gl.PostEffectProcessor;
|
||||||
import net.minecraft.client.render.DefaultFramebufferSet;
|
import net.minecraft.client.render.DefaultFramebufferSet;
|
||||||
|
import net.minecraft.client.util.Pool;
|
||||||
|
*///?}
|
||||||
import net.minecraft.client.texture.ResourceTexture;
|
import net.minecraft.client.texture.ResourceTexture;
|
||||||
import net.minecraft.client.texture.TextureManager;
|
import net.minecraft.client.texture.TextureManager;
|
||||||
import net.minecraft.client.util.Pool;
|
|
||||||
import net.minecraft.text.Text;
|
import net.minecraft.text.Text;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
@@ -32,7 +37,8 @@ public class SaturnScreenFabric extends Screen implements ScreenProvider {
|
|||||||
ROTATING_PANORAMA_RENDERER = new RotatingCubeMapRenderer(PANORAMA_RENDERER);
|
ROTATING_PANORAMA_RENDERER = new RotatingCubeMapRenderer(PANORAMA_RENDERER);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Pool pool = new Pool(3);
|
//? if <1.21.6
|
||||||
|
//private final Pool pool = new Pool(3);
|
||||||
public final SaturnScreen screen;
|
public final SaturnScreen screen;
|
||||||
|
|
||||||
public static void preload(MinecraftClient client) {
|
public static void preload(MinecraftClient client) {
|
||||||
@@ -56,7 +62,8 @@ public class SaturnScreenFabric extends Screen implements ScreenProvider {
|
|||||||
screen.init();
|
screen.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
//? if <1.21.6
|
||||||
|
//@SuppressWarnings("deprecation")
|
||||||
@Override
|
@Override
|
||||||
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||||
if (screen.start == null) {
|
if (screen.start == null) {
|
||||||
@@ -67,30 +74,65 @@ public class SaturnScreenFabric extends Screen implements ScreenProvider {
|
|||||||
mouseX *= 2;
|
mouseX *= 2;
|
||||||
mouseY *= 2;
|
mouseY *= 2;
|
||||||
|
|
||||||
|
// TODO: the panorama and the background blur (screen.backgroundBlur) are only drawn before
|
||||||
|
// 1.21.6 so far. See also issue #23.
|
||||||
if (client.world == null && client.getCurrentServerEntry() == null) {
|
if (client.world == null && client.getCurrentServerEntry() == null) {
|
||||||
ROTATING_PANORAMA_RENDERER.render(context, this.width, this.height, screen.backgroundOpacity, delta);
|
//? if <1.21.6
|
||||||
|
//ROTATING_PANORAMA_RENDERER.render(context, this.width, this.height, screen.backgroundOpacity, delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
PostEffectProcessor postEffectProcessor = this.client.getShaderLoader().loadPostEffect(
|
//? if <1.21.6 {
|
||||||
|
/*PostEffectProcessor postEffectProcessor = this.client.getShaderLoader().loadPostEffect(
|
||||||
Identifier.ofVanilla("blur"),
|
Identifier.ofVanilla("blur"),
|
||||||
DefaultFramebufferSet.MAIN_ONLY);
|
DefaultFramebufferSet.MAIN_ONLY);
|
||||||
|
|
||||||
if (postEffectProcessor != null) {
|
if (postEffectProcessor != null) {
|
||||||
float radius = screen.backgroundBlur * Math.min((float) elapsed / 700, 1.0f);
|
float radius = screen.backgroundBlur * Math.min((float) elapsed / 700, 1.0f);
|
||||||
postEffectProcessor.render(
|
//? if >=1.21.5
|
||||||
this.client.getFramebuffer(),
|
postEffectProcessor.render(this.client.getFramebuffer(), this.pool, pass -> pass.setUniform("Radius", radius));
|
||||||
this.pool,
|
//? if <1.21.5
|
||||||
pass -> pass.setUniform("Radius", radius)
|
//postEffectProcessor.setUniforms("Radius", radius);
|
||||||
);
|
//? if <1.21.5
|
||||||
|
//postEffectProcessor.render(this.client.getFramebuffer(), this.pool);
|
||||||
}
|
}
|
||||||
|
*///?}
|
||||||
|
|
||||||
RenderScope renderScope = new RenderScopeImpl(context.getMatrices(),
|
RenderScope renderScope = new RenderScopeImpl(context);
|
||||||
((DrawContextAccessor) context).getVertexConsumers());
|
|
||||||
|
|
||||||
screen.render(renderScope, mouseX, mouseY, delta, elapsed);
|
screen.render(renderScope, mouseX, mouseY, delta, elapsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 1.21.9 moved mouse and key events to Click and KeyInput.
|
||||||
|
//? if >=1.21.9 {
|
||||||
@Override
|
@Override
|
||||||
|
public boolean mouseClicked(Click click, boolean doubled) {
|
||||||
|
if (screen.mouseClicked(click.x(), click.y(), click.button())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.mouseClicked(click, doubled);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseDragged(Click click, double offsetX, double offsetY) {
|
||||||
|
// TODO: 1.21.8 passes the drag deltas; check whether offsetX/offsetY are the same on 1.21.9+.
|
||||||
|
if (screen.mouseDragged(click.x(), click.y(), click.button(), 0.0, 0.0)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.mouseDragged(click, offsetX, offsetY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseReleased(Click click) {
|
||||||
|
if (screen.mouseReleased(click.x(), click.y(), click.button())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.mouseReleased(click);
|
||||||
|
}
|
||||||
|
//?} else {
|
||||||
|
/*@Override
|
||||||
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
||||||
if (screen.mouseClicked(mouseX, mouseY, button)) {
|
if (screen.mouseClicked(mouseX, mouseY, button)) {
|
||||||
return true;
|
return true;
|
||||||
@@ -113,6 +155,7 @@ public class SaturnScreenFabric extends Screen implements ScreenProvider {
|
|||||||
}
|
}
|
||||||
return super.mouseReleased(mouseX, mouseY, button);
|
return super.mouseReleased(mouseX, mouseY, button);
|
||||||
}
|
}
|
||||||
|
*///?}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) {
|
public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) {
|
||||||
@@ -122,19 +165,33 @@ public class SaturnScreenFabric extends Screen implements ScreenProvider {
|
|||||||
return super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount);
|
return super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//? if >=1.21.9 {
|
||||||
@Override
|
@Override
|
||||||
|
public boolean keyPressed(KeyInput input) {
|
||||||
|
if (screen.keyPressed(input.getKeycode(), input.scancode(), input.modifiers())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.keyPressed(input);
|
||||||
|
}
|
||||||
|
//?} else {
|
||||||
|
/*@Override
|
||||||
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
|
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
|
||||||
if (screen.keyPressed(keyCode, scanCode, modifiers)) {
|
if (screen.keyPressed(keyCode, scanCode, modifiers)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return super.keyPressed(keyCode, scanCode, modifiers);
|
return super.keyPressed(keyCode, scanCode, modifiers);
|
||||||
}
|
}
|
||||||
|
*///?}
|
||||||
|
|
||||||
@Override
|
// TODO: resize isn't hooked on 1.21.11 yet.
|
||||||
|
//? if <1.21.11 {
|
||||||
|
/*@Override
|
||||||
public void resize(MinecraftClient client, int width, int height) {
|
public void resize(MinecraftClient client, int width, int height) {
|
||||||
screen.resize(width, height);
|
screen.resize(width, height);
|
||||||
super.resize(client, width, height);
|
super.resize(client, width, height);
|
||||||
}
|
}
|
||||||
|
*///?}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package org.saturnclient.saturnclient;
|
||||||
|
|
||||||
|
//? if >=1.21.11
|
||||||
|
import org.jspecify.annotations.NonNull;
|
||||||
|
//? if >=1.21.8 {
|
||||||
|
import org.saturnclient.client.player.SaturnPlayer;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.client.rendering.v1.RenderStateDataKey;
|
||||||
|
//?}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The key PlayerEntityRendererMixin stores each player's SaturnPlayer under in their render state.
|
||||||
|
* Fabric API's render state data only exists from 1.21.8, so older versions look players up by name.
|
||||||
|
*/
|
||||||
|
public class SaturnRenderState {
|
||||||
|
//? if >=1.21.11 {
|
||||||
|
@NonNull
|
||||||
|
public static RenderStateDataKey<SaturnPlayer> saturnDataKey = RenderStateDataKey
|
||||||
|
.create(() -> "saturn-client-player");
|
||||||
|
//?} else if >=1.21.8 {
|
||||||
|
/*public static RenderStateDataKey<SaturnPlayer> saturnDataKey = RenderStateDataKey
|
||||||
|
.create(() -> "saturn-client-player");
|
||||||
|
*///?}
|
||||||
|
}
|
||||||
+22
-10
@@ -4,17 +4,17 @@ 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.util.InputUtil;
|
import net.minecraft.client.util.InputUtil;
|
||||||
|
//? if >=1.21.9
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
import org.saturnclient.config.Config;
|
import org.saturnclient.config.Config;
|
||||||
import org.saturnclient.saturnclient.SaturnClient;
|
import org.saturnclient.saturnclient.SaturnClient;
|
||||||
import org.saturnclient.common.provider.Providers;
|
import org.saturnclient.common.provider.Providers;
|
||||||
|
import org.saturnclient.client.ServiceClient;
|
||||||
|
import org.saturnclient.emotes.fabric.Emotes;
|
||||||
import org.saturnclient.ui.screens.EmoteWheel;
|
import org.saturnclient.ui.screens.EmoteWheel;
|
||||||
import org.saturnclient.ui.screens.ShiftMenu;
|
import org.saturnclient.ui.screens.ShiftMenu;
|
||||||
|
|
||||||
// import dev.kosmx.playerAnim.api.layered.AnimationStack;
|
|
||||||
// import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationAccess;
|
|
||||||
|
|
||||||
import org.lwjgl.glfw.GLFW;
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -22,17 +22,28 @@ import org.lwjgl.glfw.GLFW;
|
|||||||
* Manages keybindings and their associated actions.
|
* Manages keybindings and their associated actions.
|
||||||
*/
|
*/
|
||||||
public class KeyInputHandler {
|
public class KeyInputHandler {
|
||||||
|
//? if >=1.21.9 {
|
||||||
private static final Identifier KEY_CATEGORY = Identifier.of("saturnclient", "key.category.saturnclient");
|
private static final Identifier KEY_CATEGORY = Identifier.of("saturnclient", "key.category.saturnclient");
|
||||||
|
//?} else
|
||||||
|
//private static final String KEY_CATEGORY = "key.category.saturnclient";
|
||||||
private static final String MAIN_MENU_KEY_ID = "key.saturnclient.main_menu";
|
private static final String MAIN_MENU_KEY_ID = "key.saturnclient.main_menu";
|
||||||
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;
|
||||||
|
|
||||||
public static void register() {
|
public static void register() {
|
||||||
|
//? if >=1.21.9 {
|
||||||
mainMenuKeyBinding = KeyBindingHelper.registerKeyBinding(
|
mainMenuKeyBinding = KeyBindingHelper.registerKeyBinding(
|
||||||
new KeyBinding(
|
new KeyBinding(
|
||||||
MAIN_MENU_KEY_ID,
|
MAIN_MENU_KEY_ID,
|
||||||
DEFAULT_MENU_KEY,
|
DEFAULT_MENU_KEY,
|
||||||
KeyBinding.Category.create(KEY_CATEGORY)));
|
KeyBinding.Category.create(KEY_CATEGORY)));
|
||||||
|
//?} else {
|
||||||
|
/*mainMenuKeyBinding = KeyBindingHelper.registerKeyBinding(new KeyBinding(
|
||||||
|
MAIN_MENU_KEY_ID,
|
||||||
|
InputUtil.Type.KEYSYM,
|
||||||
|
DEFAULT_MENU_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 -> {
|
||||||
@@ -41,17 +52,18 @@ public class KeyInputHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Config.openEmoteWheel.wasKeyPressed() && client.currentScreen == null
|
if (Config.openEmoteWheel.wasKeyPressed() && client.currentScreen == null
|
||||||
|
//? if >=1.21.9 {
|
||||||
&& !InputUtil.isKeyPressed(client.getWindow(), GLFW.GLFW_KEY_F3)) {
|
&& !InputUtil.isKeyPressed(client.getWindow(), GLFW.GLFW_KEY_F3)) {
|
||||||
|
//?} else
|
||||||
|
//&& !InputUtil.isKeyPressed(client.getWindow().getHandle(), GLFW.GLFW_KEY_F3)) {
|
||||||
Providers.saturn.getClient().setScreen(new EmoteWheel());
|
Providers.saturn.getClient().setScreen(new EmoteWheel());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SaturnClient.client.player != null && SaturnClient.client.player.isSneaking()) {
|
// Sneaking cancels your own emote, for everyone.
|
||||||
// AnimationStack animationStack =
|
if (SaturnClient.client.player != null && SaturnClient.client.player.isSneaking()
|
||||||
// PlayerAnimationAccess.getPlayerAnimLayer(SaturnClient.client.player);
|
&& Emotes.playing(SaturnClient.client.player.getUuid()).isPresent()) {
|
||||||
// if (animationStack.isActive() && animationStack.getPriority() == 1000) {
|
Emotes.stop(SaturnClient.client.player.getUuid());
|
||||||
// animationStack.removeLayer(1000);
|
ServiceClient.emote("");
|
||||||
// ServiceClient.emote("");
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
+8
@@ -1,12 +1,20 @@
|
|||||||
package org.saturnclient.saturnclient.mixin;
|
package org.saturnclient.saturnclient.mixin;
|
||||||
|
|
||||||
import net.minecraft.client.gui.DrawContext;
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
//? if >=1.21.6 {
|
||||||
import net.minecraft.client.gui.render.state.GuiRenderState;
|
import net.minecraft.client.gui.render.state.GuiRenderState;
|
||||||
|
//?} else
|
||||||
|
//import net.minecraft.client.render.VertexConsumerProvider;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||||
|
|
||||||
@Mixin(DrawContext.class)
|
@Mixin(DrawContext.class)
|
||||||
public interface DrawContextAccessor {
|
public interface DrawContextAccessor {
|
||||||
|
//? if >=1.21.6 {
|
||||||
@Accessor("state")
|
@Accessor("state")
|
||||||
GuiRenderState getState();
|
GuiRenderState getState();
|
||||||
|
//?} else {
|
||||||
|
/*@Accessor("vertexConsumers")
|
||||||
|
VertexConsumerProvider.Immediate getVertexConsumers();
|
||||||
|
*///?}
|
||||||
}
|
}
|
||||||
+23
-3
@@ -1,12 +1,16 @@
|
|||||||
package org.saturnclient.saturnclient.mixin;
|
package org.saturnclient.saturnclient.mixin;
|
||||||
|
|
||||||
|
//? if >=1.21.9 {
|
||||||
import net.minecraft.client.network.ClientPlayerLikeEntity;
|
import net.minecraft.client.network.ClientPlayerLikeEntity;
|
||||||
|
import net.minecraft.entity.PlayerLikeEntity;
|
||||||
|
//?} else
|
||||||
|
//import net.minecraft.client.network.AbstractClientPlayerEntity;
|
||||||
import net.minecraft.client.render.entity.EntityRendererFactory;
|
import net.minecraft.client.render.entity.EntityRendererFactory;
|
||||||
import net.minecraft.client.render.entity.LivingEntityRenderer;
|
import net.minecraft.client.render.entity.LivingEntityRenderer;
|
||||||
import net.minecraft.client.render.entity.PlayerEntityRenderer;
|
import net.minecraft.client.render.entity.PlayerEntityRenderer;
|
||||||
import net.minecraft.client.render.entity.model.PlayerEntityModel;
|
import net.minecraft.client.render.entity.model.PlayerEntityModel;
|
||||||
import net.minecraft.client.render.entity.state.PlayerEntityRenderState;
|
import net.minecraft.client.render.entity.state.PlayerEntityRenderState;
|
||||||
import net.minecraft.entity.PlayerLikeEntity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.text.MutableText;
|
import net.minecraft.text.MutableText;
|
||||||
import net.minecraft.text.Text;
|
import net.minecraft.text.Text;
|
||||||
@@ -36,10 +40,25 @@ public abstract class PlayerEntityRendererMixin
|
|||||||
this.addFeature(new CloakFeatureRenderer(this, ctx.getEquipmentModelLoader()));
|
this.addFeature(new CloakFeatureRenderer(this, ctx.getEquipmentModelLoader()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stores the SaturnPlayer in the render state and adds the role icon to the name. Render state
|
||||||
|
// data only exists from 1.21.8.
|
||||||
|
// TODO: 1.21.6 and 1.21.7 don't show the role icon in player names.
|
||||||
|
//? if >=1.21.9 {
|
||||||
@Inject(method = "updateRenderState", at = @At("TAIL"))
|
@Inject(method = "updateRenderState", at = @At("TAIL"))
|
||||||
public <A extends PlayerLikeEntity & ClientPlayerLikeEntity> void updateRenderState(
|
public <A extends PlayerLikeEntity & ClientPlayerLikeEntity> void updateRenderState(
|
||||||
A entity, PlayerEntityRenderState state,
|
A entity, PlayerEntityRenderState state, float f, CallbackInfo ci) {
|
||||||
float f, CallbackInfo ci) {
|
saturn$applyPlayer(entity, state);
|
||||||
|
}
|
||||||
|
//?} else if >=1.21.8 {
|
||||||
|
/*@Inject(method = "updateRenderState", at = @At("TAIL"))
|
||||||
|
public void updateRenderState(
|
||||||
|
AbstractClientPlayerEntity entity, PlayerEntityRenderState state, float f, CallbackInfo ci) {
|
||||||
|
saturn$applyPlayer(entity, state);
|
||||||
|
}
|
||||||
|
*///?}
|
||||||
|
|
||||||
|
//? if >=1.21.8 {
|
||||||
|
private void saturn$applyPlayer(Entity entity, PlayerEntityRenderState state) {
|
||||||
if (entity == null) {
|
if (entity == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -58,4 +77,5 @@ public abstract class PlayerEntityRendererMixin
|
|||||||
.append(state.displayName.copy());
|
.append(state.displayName.copy());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//?}
|
||||||
}
|
}
|
||||||
+8
-2
@@ -15,6 +15,7 @@ import org.spongepowered.asm.mixin.Final;
|
|||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.gui.DrawContext;
|
import net.minecraft.client.gui.DrawContext;
|
||||||
import net.minecraft.client.gui.screen.SplashOverlay;
|
import net.minecraft.client.gui.screen.SplashOverlay;
|
||||||
|
//? if >=1.21.11
|
||||||
import net.minecraft.client.util.Window;
|
import net.minecraft.client.util.Window;
|
||||||
import net.minecraft.resource.ResourceReload;
|
import net.minecraft.resource.ResourceReload;
|
||||||
import net.minecraft.util.Util;
|
import net.minecraft.util.Util;
|
||||||
@@ -125,8 +126,9 @@ public abstract class SplashOverlayMixin {
|
|||||||
private void renderProgressBar(RenderScope scope, DrawContext context, int screenWidth, int screenHeight,
|
private void renderProgressBar(RenderScope scope, DrawContext context, int screenWidth, int screenHeight,
|
||||||
int alpha) {
|
int alpha) {
|
||||||
int progressY = ((screenHeight - 5) / 2) + 25;
|
int progressY = ((screenHeight - 5) / 2) + 25;
|
||||||
// context.drawBorder((screenWidth - 120) / 2, progressY, 120, 5,
|
// TODO: the loading bar's border isn't drawn on 1.21.9+ yet.
|
||||||
// Theme.withAlpha(alpha, 0xFFFFFFFF));
|
//? if <1.21.9
|
||||||
|
//context.drawBorder((screenWidth - 120) / 2, progressY, 120, 5, Theme.withAlpha(alpha, 0xFFFFFFFF));
|
||||||
|
|
||||||
int progressWidth = Math.min((int) (progress * 120), 120);
|
int progressWidth = Math.min((int) (progress * 120), 120);
|
||||||
int progressX = (screenWidth - 120) / 2;
|
int progressX = (screenWidth - 120) / 2;
|
||||||
@@ -155,9 +157,13 @@ public abstract class SplashOverlayMixin {
|
|||||||
|
|
||||||
reloadCompleteTime = Util.getMeasuringTimeMs();
|
reloadCompleteTime = Util.getMeasuringTimeMs();
|
||||||
|
|
||||||
|
//? if >=1.21.11
|
||||||
Window window = client.getWindow();
|
Window window = client.getWindow();
|
||||||
if (client.currentScreen != null) {
|
if (client.currentScreen != null) {
|
||||||
|
//? if >=1.21.11 {
|
||||||
client.currentScreen.init(window.getScaledWidth(), window.getScaledHeight());
|
client.currentScreen.init(window.getScaledWidth(), window.getScaledHeight());
|
||||||
|
//?} else
|
||||||
|
//client.currentScreen.init(client, context.getScaledWindowWidth(), context.getScaledWindowHeight());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+5
@@ -27,8 +27,13 @@ public abstract class TabListMixin {
|
|||||||
private void saturn$addSaturnIcon(CallbackInfoReturnable<Text> cir) {
|
private void saturn$addSaturnIcon(CallbackInfoReturnable<Text> cir) {
|
||||||
PlayerListEntry entry = (PlayerListEntry) (Object) this;
|
PlayerListEntry entry = (PlayerListEntry) (Object) this;
|
||||||
GameProfile profile = entry.getProfile();
|
GameProfile profile = entry.getProfile();
|
||||||
|
//? if >=1.21.9 {
|
||||||
String name = profile.name();
|
String name = profile.name();
|
||||||
UUID uuid = profile.id();
|
UUID uuid = profile.id();
|
||||||
|
//?} else {
|
||||||
|
/*String name = profile.getName();
|
||||||
|
UUID uuid = profile.getId();
|
||||||
|
*///?}
|
||||||
|
|
||||||
if (SaturnPlayer.get(name, uuid) == null) {
|
if (SaturnPlayer.get(name, uuid) == null) {
|
||||||
return;
|
return;
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
plugins {
|
||||||
|
id("dev.kikugie.stonecutter")
|
||||||
|
}
|
||||||
|
|
||||||
|
// The version whose code is uncommented in src/. Switch with "Set active project to <v>", and run
|
||||||
|
// "Reset active project" before committing.
|
||||||
|
stonecutter active "1.21.11"
|
||||||
|
|
||||||
|
subprojects {
|
||||||
|
apply(plugin = "java")
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
maven("https://maven.fabricmc.net/")
|
||||||
|
maven("https://git.selimaj.dev/api/packages/selimaj-dev/maven")
|
||||||
|
maven("https://git.selimaj.dev/api/packages/saturnclientmc/maven")
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
"implementation"("de.javagl:obj:0.4.0")
|
||||||
|
"implementation"("com.formdev:svgSalamander:1.1.4")
|
||||||
|
"implementation"("com.fasterxml.jackson.core:jackson-databind:2.17.0")
|
||||||
|
"implementation"("com.fasterxml.jackson.core:jackson-annotations:2.17.0")
|
||||||
|
"implementation"("com.fasterxml.jackson.core:jackson-core:2.17.0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Every Minecraft version builds on common and ships its resources.
|
||||||
|
configure(subprojects.filter { it.name != "common" }) {
|
||||||
|
dependencies {
|
||||||
|
"implementation"(project(":common"))
|
||||||
|
}
|
||||||
|
|
||||||
|
extensions.configure<SourceSetContainer> {
|
||||||
|
named("main") {
|
||||||
|
resources.srcDir(project(":common").file("src/main/resources"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remapJar loads a whole Minecraft classpath and remaps a ~50 MB jar. Eight at once don't fit in the
|
||||||
|
// daemon's heap (org.gradle.jvmargs) and the build stalls in garbage collection, so only two run
|
||||||
|
// together. Everything else still builds in parallel.
|
||||||
|
abstract class RemapLimit : BuildService<BuildServiceParameters.None>
|
||||||
|
|
||||||
|
val remapLimit = gradle.sharedServices.registerIfAbsent("remapLimit", RemapLimit::class) {
|
||||||
|
maxParallelUsages = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
subprojects {
|
||||||
|
tasks.matching { it.name == "remapJar" }.configureEach {
|
||||||
|
usesService(remapLimit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register("buildAll") {
|
||||||
|
group = "build"
|
||||||
|
description = "Builds every Minecraft version's remapped jar and collects them in build/allJars"
|
||||||
|
|
||||||
|
val remapJars = subprojects.flatMap { it.tasks.matching { task -> task.name == "remapJar" } }
|
||||||
|
dependsOn(remapJars)
|
||||||
|
|
||||||
|
doLast {
|
||||||
|
val outputDir = layout.buildDirectory.dir("allJars").get().asFile
|
||||||
|
outputDir.mkdirs()
|
||||||
|
remapJars.map { (it as AbstractArchiveTask).archiveFile.get().asFile }
|
||||||
|
.filter { it.exists() && !it.name.contains("sources") }
|
||||||
|
.forEach { it.copyTo(outputDir.resolve(it.name), overwrite = true) }
|
||||||
|
println("All remapped jars collected in: $outputDir")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id 'net.fabricmc.fabric-loom-remap' version "${loom_version}"
|
|
||||||
id 'maven-publish'
|
|
||||||
}
|
|
||||||
|
|
||||||
version = "${project.mod_version}+${project.minecraft_version}"
|
|
||||||
group = project.maven_group
|
|
||||||
|
|
||||||
base {
|
|
||||||
archivesName = project.archives_base_name
|
|
||||||
}
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
// maven { name = "KoSmX Maven"; url = 'https://maven.kosmx.dev/' }
|
|
||||||
maven { name = "Selimaj"; url = 'https://git.selimaj.dev/api/packages/selimaj-dev/maven' }
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
// To change the versions see the gradle.properties file
|
|
||||||
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
|
||||||
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
|
|
||||||
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
|
|
||||||
|
|
||||||
// Fabric API. This is technically optional, but you probably want it anyway.
|
|
||||||
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_version}"
|
|
||||||
|
|
||||||
// Player Animation Library
|
|
||||||
// include modImplementation(
|
|
||||||
// "dev.kosmx.player-anim:player-animation-lib-fabric:${project.player_anim}"
|
|
||||||
// )
|
|
||||||
|
|
||||||
implementation project(":common")
|
|
||||||
|
|
||||||
include implementation("dev.selimaj:session-java:0.2.0")
|
|
||||||
include implementation("de.javagl:obj:0.4.0")
|
|
||||||
include implementation("com.formdev:svgSalamander:1.1.4")
|
|
||||||
include implementation("com.fasterxml.jackson.core:jackson-databind:2.17.0")
|
|
||||||
include implementation("com.fasterxml.jackson.core:jackson-annotations:2.17.0")
|
|
||||||
include implementation("com.fasterxml.jackson.core:jackson-core:2.17.0")
|
|
||||||
|
|
||||||
// Optional: BendyLib
|
|
||||||
// include modRuntimeOnly(
|
|
||||||
// "io.github.kosmx.bendy-lib:bendy-lib-fabric:${project.bendylib_version}"
|
|
||||||
// )
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ================================================================
|
|
||||||
* Resource Processing
|
|
||||||
* ================================================================
|
|
||||||
* Injects version values into fabric.mod.json.
|
|
||||||
*/
|
|
||||||
processResources {
|
|
||||||
inputs.property "version", project.version
|
|
||||||
inputs.property "minecraft_version", project.minecraft_version
|
|
||||||
inputs.property "loader_version", project.loader_version
|
|
||||||
filteringCharset "UTF-8"
|
|
||||||
|
|
||||||
filesMatching("fabric.mod.json") {
|
|
||||||
expand(
|
|
||||||
"version": project.version,
|
|
||||||
"minecraft_version": project.minecraft_version,
|
|
||||||
"loader_version": project.loader_version
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.withType(JavaCompile).configureEach {
|
|
||||||
it.options.release = 21
|
|
||||||
}
|
|
||||||
|
|
||||||
java {
|
|
||||||
// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task
|
|
||||||
// if it is present.
|
|
||||||
// If you remove this line, sources will not be generated.
|
|
||||||
withSourcesJar()
|
|
||||||
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_21
|
|
||||||
targetCompatibility = JavaVersion.VERSION_21
|
|
||||||
}
|
|
||||||
|
|
||||||
jar {
|
|
||||||
inputs.property "archivesName", project.base.archivesName
|
|
||||||
|
|
||||||
from("LICENSE") {
|
|
||||||
rename { "${it}_${inputs.properties.archivesName}"}
|
|
||||||
}
|
|
||||||
|
|
||||||
from project(":common").sourceSets.main.output
|
|
||||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
|
||||||
}
|
|
||||||
|
|
||||||
// configure the maven publication
|
|
||||||
publishing {
|
|
||||||
publications {
|
|
||||||
create("mavenJava", MavenPublication) {
|
|
||||||
artifactId = project.archives_base_name
|
|
||||||
from components.java
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.
|
|
||||||
repositories {
|
|
||||||
// Add repositories to publish to here.
|
|
||||||
// Notice: This block does NOT have the same function as the block in the top level.
|
|
||||||
// The repositories here will be used for publishing your artifact, not for
|
|
||||||
// retrieving dependencies.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,12 +10,9 @@ org.gradle.configuration-cache=false
|
|||||||
minecraft_version=1.21.10
|
minecraft_version=1.21.10
|
||||||
yarn_mappings=1.21.10+build.3
|
yarn_mappings=1.21.10+build.3
|
||||||
loader_version=0.19.0
|
loader_version=0.19.0
|
||||||
loom_version=1.15-SNAPSHOT
|
|
||||||
|
|
||||||
fabric_api_version=0.138.4+1.21.10
|
fabric_api_version=0.138.4+1.21.10
|
||||||
|
|
||||||
# Mod Properties
|
# Mod Properties
|
||||||
maven_group=org.saturnclient
|
maven_group=org.saturnclient
|
||||||
archives_base_name=saturn-client
|
archives_base_name=saturn-client
|
||||||
|
|
||||||
# player_anim = 2.0.2+1.21.5
|
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
pluginManagement {
|
|
||||||
repositories {
|
|
||||||
maven {
|
|
||||||
name = 'Fabric'
|
|
||||||
url = 'https://maven.fabricmc.net/'
|
|
||||||
}
|
|
||||||
mavenCentral()
|
|
||||||
gradlePluginPortal()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-462
@@ -1,462 +0,0 @@
|
|||||||
package org.saturnclient.impl.cosmetics;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import org.joml.Matrix3f;
|
|
||||||
import org.joml.Matrix4f;
|
|
||||||
import org.joml.Vector3f;
|
|
||||||
import org.joml.Vector4f;
|
|
||||||
import org.saturnclient.client.player.SaturnPlayer;
|
|
||||||
import org.saturnclient.common.ref.asset.IdentifierRef;
|
|
||||||
import org.saturnclient.config.Config;
|
|
||||||
import org.saturnclient.cosmetics.Cloaks;
|
|
||||||
import org.saturnclient.impl.cosmetics.utils.ShaderUtils;
|
|
||||||
import org.saturnclient.saturnclient.SaturnRenderState;
|
|
||||||
|
|
||||||
import net.minecraft.client.render.OverlayTexture;
|
|
||||||
import net.minecraft.client.render.VertexConsumer;
|
|
||||||
import net.minecraft.client.render.command.OrderedRenderCommandQueue;
|
|
||||||
import net.minecraft.client.render.entity.equipment.EquipmentModel;
|
|
||||||
import net.minecraft.client.render.entity.equipment.EquipmentModelLoader;
|
|
||||||
import net.minecraft.client.render.entity.equipment.EquipmentModel.LayerType;
|
|
||||||
import net.minecraft.client.render.entity.feature.FeatureRenderer;
|
|
||||||
import net.minecraft.client.render.entity.feature.FeatureRendererContext;
|
|
||||||
import net.minecraft.client.render.entity.model.PlayerEntityModel;
|
|
||||||
import net.minecraft.client.render.entity.state.PlayerEntityRenderState;
|
|
||||||
import net.minecraft.client.util.math.MatrixStack;
|
|
||||||
import net.minecraft.component.DataComponentTypes;
|
|
||||||
import net.minecraft.component.type.EquippableComponent;
|
|
||||||
import net.minecraft.item.ItemStack;
|
|
||||||
import net.minecraft.item.equipment.EquipmentAsset;
|
|
||||||
import net.minecraft.registry.RegistryKey;
|
|
||||||
import net.minecraft.util.math.MathHelper;
|
|
||||||
import net.minecraft.util.math.RotationAxis;
|
|
||||||
import net.minecraft.util.math.Vec3d;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The cloak renderer
|
|
||||||
* - **Efficient**: uses a image only consisting of the cloak texture, 16x8
|
|
||||||
* whitespace.
|
|
||||||
* - **Curving**: Curves when player velocity increases.
|
|
||||||
* - **Wavey**: Makes the cloak feel like wind, when jump sprinting.
|
|
||||||
*/
|
|
||||||
public class CloakFeatureRenderer extends FeatureRenderer<PlayerEntityRenderState, PlayerEntityModel> {
|
|
||||||
private final EquipmentModelLoader equipmentModelLoader;
|
|
||||||
private static final int PARTS = 24;
|
|
||||||
private final float[] segmentValues = new float[PARTS];
|
|
||||||
private static final int H_PARTS = 6;
|
|
||||||
private float horizontalCurve = 0.0f;
|
|
||||||
|
|
||||||
private static final float TEX_W = 176f;
|
|
||||||
private static final float TEX_H = 138f;
|
|
||||||
|
|
||||||
private static final class PxRect {
|
|
||||||
final int x, y, w, h;
|
|
||||||
|
|
||||||
PxRect(int x, int y, int w, int h) {
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
this.w = w;
|
|
||||||
this.h = h;
|
|
||||||
}
|
|
||||||
|
|
||||||
float u1() {
|
|
||||||
return x / TEX_W;
|
|
||||||
}
|
|
||||||
|
|
||||||
float v1() {
|
|
||||||
return y / TEX_H;
|
|
||||||
}
|
|
||||||
|
|
||||||
float u2() {
|
|
||||||
return (x + w) / TEX_W;
|
|
||||||
}
|
|
||||||
|
|
||||||
float v2() {
|
|
||||||
return (y + h) / TEX_H;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final PxRect FRONT_RECT = new PxRect(8, 8, 80, 128);
|
|
||||||
private static final PxRect BACK_RECT = new PxRect(96, 8, 80, 128);
|
|
||||||
private static final PxRect LEFT_EDGE_RECT = new PxRect(0, 8, 8, 128);
|
|
||||||
private static final PxRect RIGHT_EDGE_RECT = new PxRect(88, 8, 8, 128);
|
|
||||||
private static final PxRect TOP_RECT = new PxRect(8, 0, 80, 8);
|
|
||||||
private static final PxRect BOTTOM_RECT = new PxRect(88, 0, 80, 8);
|
|
||||||
|
|
||||||
public CloakFeatureRenderer(FeatureRendererContext<PlayerEntityRenderState, PlayerEntityModel> context,
|
|
||||||
EquipmentModelLoader equipmentModelLoader) {
|
|
||||||
super(context);
|
|
||||||
this.equipmentModelLoader = equipmentModelLoader;
|
|
||||||
Arrays.fill(segmentValues, 0.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasCustomModelForLayer(ItemStack stack, EquipmentModel.LayerType layerType) {
|
|
||||||
EquippableComponent equippableComponent = (EquippableComponent) stack
|
|
||||||
.get(DataComponentTypes.EQUIPPABLE);
|
|
||||||
if (equippableComponent != null && !equippableComponent.assetId().isEmpty()) {
|
|
||||||
EquipmentModel equipmentModel = this.equipmentModelLoader
|
|
||||||
.get((RegistryKey<EquipmentAsset>) equippableComponent.assetId().get());
|
|
||||||
return !equipmentModel.getLayers(layerType).isEmpty();
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void vertex(VertexConsumer vc, Matrix4f posMat, Matrix3f normalMat,
|
|
||||||
Vec3d pos, int color,
|
|
||||||
float u, float v, int overlay, int light,
|
|
||||||
float nx, float ny, float nz) {
|
|
||||||
|
|
||||||
Vector4f p = new Vector4f((float) pos.x, (float) pos.y, (float) pos.z, 1.0f);
|
|
||||||
p.mul(posMat);
|
|
||||||
|
|
||||||
Vector3f n = new Vector3f(nx, ny, nz);
|
|
||||||
n.mul(normalMat);
|
|
||||||
|
|
||||||
vc.vertex(
|
|
||||||
p.x(), p.y(), p.z(),
|
|
||||||
color,
|
|
||||||
u, v,
|
|
||||||
overlay, light,
|
|
||||||
n.x(), n.y(), n.z());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void renderCapeQuad(VertexConsumer vertexConsumer, MatrixStack.Entry entry,
|
|
||||||
Vec3d bottomLeft, Vec3d bottomRight, Vec3d topRight, Vec3d topLeft,
|
|
||||||
float u1, float v1, float u2, float v2, int light, int overlay,
|
|
||||||
float normalX, float normalY, float normalZ, boolean flipWinding) {
|
|
||||||
// Extract matrix (you must transform positions manually now)
|
|
||||||
Matrix4f pos = entry.getPositionMatrix();
|
|
||||||
Matrix3f normalMat = entry.getNormalMatrix();
|
|
||||||
|
|
||||||
int color = 0xFFFFFFFF; // white RGBA
|
|
||||||
|
|
||||||
if (!flipWinding) {
|
|
||||||
// CCW
|
|
||||||
vertex(vertexConsumer, pos, normalMat, bottomLeft, color, u1, v2, overlay, light, normalX, normalY,
|
|
||||||
normalZ);
|
|
||||||
vertex(vertexConsumer, pos, normalMat, bottomRight, color, u2, v2, overlay, light, normalX, normalY,
|
|
||||||
normalZ);
|
|
||||||
vertex(vertexConsumer, pos, normalMat, topRight, color, u2, v1, overlay, light, normalX, normalY, normalZ);
|
|
||||||
vertex(vertexConsumer, pos, normalMat, topLeft, color, u1, v1, overlay, light, normalX, normalY, normalZ);
|
|
||||||
} else {
|
|
||||||
// CW
|
|
||||||
vertex(vertexConsumer, pos, normalMat, topLeft, color, u1, v1, overlay, light, normalX, normalY, normalZ);
|
|
||||||
vertex(vertexConsumer, pos, normalMat, topRight, color, u2, v1, overlay, light, normalX, normalY, normalZ);
|
|
||||||
vertex(vertexConsumer, pos, normalMat, bottomRight, color, u2, v2, overlay, light, normalX, normalY,
|
|
||||||
normalZ);
|
|
||||||
vertex(vertexConsumer, pos, normalMat, bottomLeft, color, u1, v2, overlay, light, normalX, normalY,
|
|
||||||
normalZ);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void renderCape(MatrixStack.Entry entry, VertexConsumer vertexConsumer,
|
|
||||||
PlayerEntityRenderState playerState, int light, int overlay) {
|
|
||||||
|
|
||||||
float capeWidth = 10.0f / 16.0f;
|
|
||||||
float capeHeight = 16.0f / 16.0f;
|
|
||||||
float capeDepth = 1.0f / 16.0f;
|
|
||||||
|
|
||||||
final float frontU1 = FRONT_RECT.u1();
|
|
||||||
final float frontU2 = FRONT_RECT.u2();
|
|
||||||
final float frontV1 = FRONT_RECT.v1();
|
|
||||||
final float frontV2 = FRONT_RECT.v2();
|
|
||||||
final float frontPartV = (frontV2 - frontV1) / PARTS;
|
|
||||||
|
|
||||||
final float backU1 = BACK_RECT.u1();
|
|
||||||
final float backU2 = BACK_RECT.u2();
|
|
||||||
final float backV1 = BACK_RECT.v1();
|
|
||||||
final float backV2 = BACK_RECT.v2();
|
|
||||||
final float backPartV = (backV2 - backV1) / PARTS;
|
|
||||||
|
|
||||||
final float leftU1 = LEFT_EDGE_RECT.u1();
|
|
||||||
final float leftU2 = LEFT_EDGE_RECT.u2();
|
|
||||||
final float leftV1 = LEFT_EDGE_RECT.v1();
|
|
||||||
final float leftV2 = LEFT_EDGE_RECT.v2();
|
|
||||||
final float leftPartV = (leftV2 - leftV1) / PARTS;
|
|
||||||
|
|
||||||
final float rightU1 = RIGHT_EDGE_RECT.u1();
|
|
||||||
final float rightU2 = RIGHT_EDGE_RECT.u2();
|
|
||||||
final float rightV1 = RIGHT_EDGE_RECT.v1();
|
|
||||||
final float rightV2 = RIGHT_EDGE_RECT.v2();
|
|
||||||
final float rightPartV = (rightV2 - rightV1) / PARTS;
|
|
||||||
|
|
||||||
final float topU1 = TOP_RECT.u1();
|
|
||||||
final float topU2 = TOP_RECT.u2();
|
|
||||||
final float topV1 = TOP_RECT.v1();
|
|
||||||
final float topV2 = TOP_RECT.v2();
|
|
||||||
|
|
||||||
final float bottomU1 = BOTTOM_RECT.u1();
|
|
||||||
final float bottomU2 = BOTTOM_RECT.u2();
|
|
||||||
final float bottomV1 = BOTTOM_RECT.v1();
|
|
||||||
final float bottomV2 = BOTTOM_RECT.v2();
|
|
||||||
|
|
||||||
// =============================
|
|
||||||
// 1. Spine
|
|
||||||
// =============================
|
|
||||||
|
|
||||||
float[] spineY = new float[PARTS + 1];
|
|
||||||
float[] spineZ = new float[PARTS + 1];
|
|
||||||
|
|
||||||
float partHeight = capeHeight / PARTS;
|
|
||||||
|
|
||||||
for (int i = 0; i < PARTS; i++) {
|
|
||||||
float angle = (2.0f - segmentValues[i]) * ((float) Math.PI / 2f);
|
|
||||||
float dirY = -(float) Math.cos(angle);
|
|
||||||
float dirZ = (float) Math.sin(angle);
|
|
||||||
|
|
||||||
spineY[i + 1] = spineY[i] + dirY * partHeight;
|
|
||||||
spineZ[i + 1] = spineZ[i] + dirZ * partHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================
|
|
||||||
// 2. Grid
|
|
||||||
// =============================
|
|
||||||
|
|
||||||
Vec3d[][] inner = new Vec3d[H_PARTS + 1][PARTS + 1];
|
|
||||||
Vec3d[][] outer = new Vec3d[H_PARTS + 1][PARTS + 1];
|
|
||||||
|
|
||||||
for (int x = 0; x <= H_PARTS; x++) {
|
|
||||||
|
|
||||||
float t = (float) x / H_PARTS;
|
|
||||||
float xPos = -capeWidth / 2.0f + capeWidth * t;
|
|
||||||
|
|
||||||
float centered = t - 0.5f;
|
|
||||||
float curve = (centered * centered) * 0.3f;
|
|
||||||
float zCurve = (curve * horizontalCurve) / PARTS;
|
|
||||||
|
|
||||||
for (int i = 0; i <= PARTS; i++) {
|
|
||||||
float y = spineY[i];
|
|
||||||
float z = spineZ[i];
|
|
||||||
|
|
||||||
int idx = Math.min(i, PARTS - 1);
|
|
||||||
// angle: 0 is horizontal (y-flat), PI/2 is vertical (z-flat)
|
|
||||||
float angle = (2.0f - segmentValues[idx]) * ((float) Math.PI / 2f);
|
|
||||||
|
|
||||||
float cosA = (float) Math.cos(angle);
|
|
||||||
float sinA = (float) Math.sin(angle);
|
|
||||||
|
|
||||||
// Calculate how much the horizontal curve shifts the vertex
|
|
||||||
float currentCurve = zCurve * i;
|
|
||||||
|
|
||||||
// Rotate the curve offset so it aligns with the cape's tilt
|
|
||||||
float curveY = sinA * currentCurve;
|
|
||||||
float curveZ = cosA * currentCurve;
|
|
||||||
|
|
||||||
float thickY = sinA * capeDepth;
|
|
||||||
float thickZ = cosA * capeDepth;
|
|
||||||
|
|
||||||
inner[x][i] = new Vec3d(xPos, y - curveY, z - curveZ);
|
|
||||||
outer[x][i] = new Vec3d(xPos, (y - curveY) - thickY, (z - curveZ) - thickZ);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================
|
|
||||||
// 3. Front + Back
|
|
||||||
// =============================
|
|
||||||
|
|
||||||
for (int x = 0; x < H_PARTS; x++) {
|
|
||||||
|
|
||||||
float uStart = frontU1 + (frontU2 - frontU1) * (1.0f - ((float) x / H_PARTS));
|
|
||||||
float uEnd = frontU1 + (frontU2 - frontU1) * (1.0f - ((float) (x + 1) / H_PARTS));
|
|
||||||
|
|
||||||
float buStart = backU1 + (backU2 - backU1) * ((float) x / H_PARTS);
|
|
||||||
float buEnd = backU1 + (backU2 - backU1) * ((float) (x + 1) / H_PARTS);
|
|
||||||
|
|
||||||
for (int i = 0; i < PARTS; i++) {
|
|
||||||
|
|
||||||
float vStart = frontV1 + frontPartV * i;
|
|
||||||
float vEnd = frontV1 + frontPartV * (i + 1);
|
|
||||||
|
|
||||||
float bvStart = backV1 + backPartV * i;
|
|
||||||
float bvEnd = backV1 + backPartV * (i + 1);
|
|
||||||
|
|
||||||
Vec3d innerTL = inner[x + 1][i];
|
|
||||||
Vec3d innerTR = inner[x][i];
|
|
||||||
Vec3d innerBL = inner[x + 1][i + 1];
|
|
||||||
Vec3d innerBR = inner[x][i + 1];
|
|
||||||
|
|
||||||
Vec3d outerTL = outer[x + 1][i];
|
|
||||||
Vec3d outerTR = outer[x][i];
|
|
||||||
Vec3d outerBL = outer[x + 1][i + 1];
|
|
||||||
Vec3d outerBR = outer[x][i + 1];
|
|
||||||
|
|
||||||
// FRONT
|
|
||||||
renderCapeQuad(vertexConsumer, entry,
|
|
||||||
outerBR, outerBL, outerTL, outerTR,
|
|
||||||
uStart, vStart, uEnd, vEnd,
|
|
||||||
light, overlay, 0, 0, 1, false);
|
|
||||||
|
|
||||||
// BACK
|
|
||||||
renderCapeQuad(vertexConsumer, entry,
|
|
||||||
innerBL, innerBR, innerTR, innerTL,
|
|
||||||
buEnd, bvStart, buStart, bvEnd,
|
|
||||||
light, overlay, 0, 0, -1, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================
|
|
||||||
// 4. LEFT SIDE (x = H_PARTS)
|
|
||||||
// =============================
|
|
||||||
|
|
||||||
for (int i = 0; i < PARTS; i++) {
|
|
||||||
|
|
||||||
Vec3d innerTop = inner[H_PARTS][i];
|
|
||||||
Vec3d innerBot = inner[H_PARTS][i + 1];
|
|
||||||
Vec3d outerTop = outer[H_PARTS][i];
|
|
||||||
Vec3d outerBot = outer[H_PARTS][i + 1];
|
|
||||||
|
|
||||||
float vStart = leftV1 + leftPartV * i;
|
|
||||||
float vEnd = leftV1 + leftPartV * (i + 1);
|
|
||||||
|
|
||||||
renderCapeQuad(vertexConsumer, entry,
|
|
||||||
innerTop, outerTop, outerBot, innerBot,
|
|
||||||
leftU1, vEnd,
|
|
||||||
leftU2, vStart,
|
|
||||||
light, overlay, -1, 0, 0, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================
|
|
||||||
// 5. RIGHT SIDE (x = 0)
|
|
||||||
// =============================
|
|
||||||
|
|
||||||
for (int i = 0; i < PARTS; i++) {
|
|
||||||
|
|
||||||
Vec3d innerTop = inner[0][i];
|
|
||||||
Vec3d innerBot = inner[0][i + 1];
|
|
||||||
Vec3d outerTop = outer[0][i];
|
|
||||||
Vec3d outerBot = outer[0][i + 1];
|
|
||||||
|
|
||||||
float vStart = rightV1 + rightPartV * i;
|
|
||||||
float vEnd = rightV1 + rightPartV * (i + 1);
|
|
||||||
|
|
||||||
renderCapeQuad(vertexConsumer, entry,
|
|
||||||
outerTop, innerTop, innerBot, outerBot,
|
|
||||||
rightU1, vEnd,
|
|
||||||
rightU2, vStart,
|
|
||||||
light, overlay, 1, 0, 0, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================
|
|
||||||
// 6. TOP (i = 0)
|
|
||||||
// =============================
|
|
||||||
|
|
||||||
for (int x = 0; x < H_PARTS; x++) {
|
|
||||||
|
|
||||||
Vec3d outerL = outer[x][0];
|
|
||||||
Vec3d outerR = outer[x + 1][0];
|
|
||||||
Vec3d innerR = inner[x + 1][0];
|
|
||||||
Vec3d innerL = inner[x][0];
|
|
||||||
|
|
||||||
float uStart = topU1 + (topU2 - topU1) * ((float) x / H_PARTS);
|
|
||||||
float uEnd = topU1 + (topU2 - topU1) * ((float) (x + 1) / H_PARTS);
|
|
||||||
|
|
||||||
renderCapeQuad(vertexConsumer, entry,
|
|
||||||
outerL, outerR, innerR, innerL,
|
|
||||||
uStart, topV1, uEnd, topV2,
|
|
||||||
light, overlay, 0, 1, 0, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================
|
|
||||||
// 7. BOTTOM (i = PARTS)
|
|
||||||
// =============================
|
|
||||||
|
|
||||||
for (int x = 0; x < H_PARTS; x++) {
|
|
||||||
|
|
||||||
Vec3d innerL = inner[x][PARTS];
|
|
||||||
Vec3d innerR = inner[x + 1][PARTS];
|
|
||||||
Vec3d outerR = outer[x + 1][PARTS];
|
|
||||||
Vec3d outerL = outer[x][PARTS];
|
|
||||||
|
|
||||||
float uStart = bottomU1 + (bottomU2 - bottomU1) * ((float) x / H_PARTS);
|
|
||||||
float uEnd = bottomU1 + (bottomU2 - bottomU1) * ((float) (x + 1) / H_PARTS);
|
|
||||||
|
|
||||||
renderCapeQuad(vertexConsumer, entry,
|
|
||||||
innerL, innerR, outerR, outerL,
|
|
||||||
uStart, bottomV1, uEnd, bottomV2,
|
|
||||||
light, overlay, 0, -1, 0, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shift array left and insert new value at the start
|
|
||||||
private void updateSegmentValues(float value) {
|
|
||||||
// Shift all elements one position to the right (from end to start)
|
|
||||||
for (int i = segmentValues.length - 1; i > 0; i--) {
|
|
||||||
segmentValues[i] = segmentValues[i - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert the new value at index 0
|
|
||||||
segmentValues[0] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private long lastUpdate = 0;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void render(MatrixStack matrices, OrderedRenderCommandQueue queue, int light, PlayerEntityRenderState state,
|
|
||||||
float limbAngle, float limbDistance) {
|
|
||||||
if (state.invisible || !state.capeVisible
|
|
||||||
|| state.skinTextures.cape() != null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SaturnPlayer player = state.getData(SaturnRenderState.saturnDataKey);
|
|
||||||
|
|
||||||
if (player == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IdentifierRef customCape = Cloaks.getCurrentCloakTexture(player.cloak);
|
|
||||||
if (customCape == null
|
|
||||||
|| this.hasCustomModelForLayer(state.equippedChestStack, LayerType.WINGS)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int minBrightness = 7;
|
|
||||||
int blockLight = (light >> 4) & 0xF;
|
|
||||||
int skyLight = (light >> 20) & 0xF;
|
|
||||||
blockLight = Math.max(blockLight, minBrightness);
|
|
||||||
skyLight = Math.max(skyLight, minBrightness);
|
|
||||||
light = (skyLight << 20) | (blockLight << 4);
|
|
||||||
|
|
||||||
matrices.push();
|
|
||||||
|
|
||||||
matrices.translate(0.0f, 0.0f, 0.12f);
|
|
||||||
|
|
||||||
if (this.hasCustomModelForLayer(state.equippedChestStack, LayerType.HUMANOID)) {
|
|
||||||
matrices.translate(0.0F, -0.053125F, 0.06875F);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state.isInSneakingPose) {
|
|
||||||
matrices.translate(0, 0.16f, 0.0f);
|
|
||||||
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(29.0f));
|
|
||||||
}
|
|
||||||
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
if (now - lastUpdate >= 20) {
|
|
||||||
float velX = Math.min(0.8f, state.field_53537 / 108.0f);
|
|
||||||
float rawVelY = state.field_53536;
|
|
||||||
float velY = (rawVelY > 3.4f ? rawVelY : rawVelY < -3.4f ? rawVelY : 0.0f) / 16;
|
|
||||||
|
|
||||||
float value = Math.max(0.0f, Math.min(2.0f, state.isSwimming ? 0.0f : velX + velY));
|
|
||||||
|
|
||||||
if (Config.cloakPhysics.value) {
|
|
||||||
updateSegmentValues(segmentValues[0] + (value - segmentValues[0]) * 0.3f);
|
|
||||||
} else {
|
|
||||||
Arrays.fill(segmentValues, segmentValues[0] + (value - segmentValues[0]) * 0.05f);
|
|
||||||
}
|
|
||||||
lastUpdate = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int l = light;
|
|
||||||
|
|
||||||
horizontalCurve = MathHelper.clamp(state.field_53537 / 150.0f, -1.0f, 1.0f);
|
|
||||||
|
|
||||||
queue.submitCustom(matrices, ShaderUtils.getRenderLayer(customCape), (entry, vertexConsumer) -> {
|
|
||||||
renderCape(entry, vertexConsumer, state, l, OverlayTexture.DEFAULT_UV);
|
|
||||||
});
|
|
||||||
|
|
||||||
matrices.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-51
@@ -1,51 +0,0 @@
|
|||||||
package org.saturnclient.impl.cosmetics;
|
|
||||||
|
|
||||||
import org.joml.Quaternionf;
|
|
||||||
import org.saturnclient.client.player.SaturnPlayer;
|
|
||||||
import org.saturnclient.impl.cosmetics.obj.MtlLoader;
|
|
||||||
import org.saturnclient.impl.cosmetics.obj.ObjModel;
|
|
||||||
|
|
||||||
import net.minecraft.client.render.OverlayTexture;
|
|
||||||
import net.minecraft.client.render.VertexConsumerProvider;
|
|
||||||
import net.minecraft.client.render.command.OrderedRenderCommandQueue;
|
|
||||||
import net.minecraft.client.render.entity.feature.FeatureRenderer;
|
|
||||||
import net.minecraft.client.render.entity.feature.FeatureRendererContext;
|
|
||||||
import net.minecraft.client.render.entity.model.PlayerEntityModel;
|
|
||||||
import net.minecraft.client.render.entity.state.PlayerEntityRenderState;
|
|
||||||
import net.minecraft.client.util.math.MatrixStack;
|
|
||||||
import net.minecraft.client.model.ModelPart;
|
|
||||||
|
|
||||||
public class HatFeatureRenderer extends FeatureRenderer<PlayerEntityRenderState, PlayerEntityModel> {
|
|
||||||
public HatFeatureRenderer(FeatureRendererContext<PlayerEntityRenderState, PlayerEntityModel> context) {
|
|
||||||
super(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Override
|
|
||||||
public void render(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light,
|
|
||||||
PlayerEntityRenderState state, float limbAngle, float limbDistance) {
|
|
||||||
if (state.displayName == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
SaturnPlayer player = SaturnPlayer.get(state.displayName.getString());
|
|
||||||
|
|
||||||
if (state.invisible || player == null || player.hat.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
matrices.push();
|
|
||||||
|
|
||||||
ModelPart head = this.getContextModel().head;
|
|
||||||
matrices.multiply(new Quaternionf().rotationZYX(head.roll, head.yaw, head.pitch));
|
|
||||||
|
|
||||||
ObjModel.cosmetic("hat", player.hat).render(MtlLoader.cosmetic(player.hat),
|
|
||||||
matrices, vertexConsumers, light,
|
|
||||||
OverlayTexture.DEFAULT_UV);
|
|
||||||
|
|
||||||
matrices.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void render(MatrixStack matrices, OrderedRenderCommandQueue queue, int light, PlayerEntityRenderState state,
|
|
||||||
float limbAngle, float limbDistance) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
package org.saturnclient.impl.cosmetics.obj;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
|
|
||||||
import de.javagl.obj.Mtl;
|
|
||||||
import de.javagl.obj.Obj;
|
|
||||||
import net.minecraft.client.MinecraftClient;
|
|
||||||
import net.minecraft.client.render.VertexConsumerProvider;
|
|
||||||
import net.minecraft.client.util.math.MatrixStack;
|
|
||||||
import net.minecraft.resource.Resource;
|
|
||||||
import net.minecraft.resource.ResourceManager;
|
|
||||||
import net.minecraft.util.Identifier;
|
|
||||||
|
|
||||||
public class ObjModel {
|
|
||||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
|
||||||
public static final Map<Identifier, ObjModel> loadedObjModels = new HashMap<>();
|
|
||||||
|
|
||||||
public record Config(
|
|
||||||
@JsonProperty("translate") Vec3d transform,
|
|
||||||
@JsonProperty("scale") Vec3d scale,
|
|
||||||
@JsonProperty("rotation") Vec3d rotation) {
|
|
||||||
|
|
||||||
public Config {
|
|
||||||
transform = transform == null ? new Vec3d(0, 0, 0) : transform;
|
|
||||||
scale = scale == null ? new Vec3d(1, 1, 1) : scale;
|
|
||||||
rotation = rotation == null ? new Vec3d(0, 0, 0) : rotation;
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonFormat(shape = JsonFormat.Shape.ARRAY)
|
|
||||||
public record Vec3d(float x, float y, float z) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Obj obj;
|
|
||||||
Config config;
|
|
||||||
|
|
||||||
public static ObjModel cosmetic(String cosmeticKind, String id) {
|
|
||||||
return of(Identifier.of("saturnclient", "models/cosmetic/" + cosmeticKind + "/" + id.split("_")[0] + "/model"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ObjModel of(Identifier obj) {
|
|
||||||
if (loadedObjModels.containsKey(obj))
|
|
||||||
return loadedObjModels.get(obj);
|
|
||||||
|
|
||||||
ObjModel o = new ObjModel(obj);
|
|
||||||
loadedObjModels.put(obj, o);
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjModel(Identifier identifier) {
|
|
||||||
Identifier objId = Identifier.of(identifier.getNamespace(), identifier.getPath() + ".obj");
|
|
||||||
Identifier jsonId = Identifier.of(identifier.getNamespace(), identifier.getPath() + ".json");
|
|
||||||
|
|
||||||
try {
|
|
||||||
this.obj = ObjRenderer.loadObj(objId);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try loading JSON config if it exists
|
|
||||||
ResourceManager resourceManager = MinecraftClient.getInstance().getResourceManager();
|
|
||||||
Optional<Resource> resource = resourceManager.getResource(jsonId);
|
|
||||||
|
|
||||||
if (resource.isPresent()) {
|
|
||||||
try (InputStream stream = resource.get().getInputStream()) {
|
|
||||||
this.config = MAPPER.readValue(stream, Config.class);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void render(Map<String, Mtl> mtlMap, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light,
|
|
||||||
int overlay) {
|
|
||||||
matrices.push();
|
|
||||||
|
|
||||||
matrices.multiply(net.minecraft.util.math.RotationAxis.POSITIVE_X.rotationDegrees(180.0f));
|
|
||||||
matrices.multiply(net.minecraft.util.math.RotationAxis.POSITIVE_Y.rotationDegrees(180.0f));
|
|
||||||
|
|
||||||
if (this.config != null) {
|
|
||||||
matrices.translate(config.transform.x, config.transform.y, config.transform.z);
|
|
||||||
|
|
||||||
matrices.scale(config.scale.x, config.scale.y, config.scale.z);
|
|
||||||
|
|
||||||
matrices.multiply(net.minecraft.util.math.RotationAxis.POSITIVE_X.rotationDegrees(config.rotation.x));
|
|
||||||
matrices.multiply(net.minecraft.util.math.RotationAxis.POSITIVE_Y.rotationDegrees(config.rotation.y));
|
|
||||||
matrices.multiply(net.minecraft.util.math.RotationAxis.POSITIVE_Z.rotationDegrees(config.rotation.z));
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjRenderer.renderObj(this.obj, mtlMap, matrices, vertexConsumers, light, overlay);
|
|
||||||
|
|
||||||
matrices.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
package org.saturnclient.impl.cosmetics.obj;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.saturnclient.common.ref.asset.IdentifierRef;
|
|
||||||
import org.saturnclient.impl.cosmetics.utils.ShaderUtils;
|
|
||||||
|
|
||||||
import de.javagl.obj.*;
|
|
||||||
|
|
||||||
import net.minecraft.client.MinecraftClient;
|
|
||||||
import net.minecraft.client.render.VertexConsumer;
|
|
||||||
import net.minecraft.client.render.VertexConsumerProvider;
|
|
||||||
import net.minecraft.client.util.math.MatrixStack;
|
|
||||||
import net.minecraft.util.Identifier;
|
|
||||||
|
|
||||||
public class ObjRenderer {
|
|
||||||
|
|
||||||
public static Obj loadObj(Identifier objId) throws IOException {
|
|
||||||
try (InputStream is = MinecraftClient.getInstance().getResourceManager()
|
|
||||||
.getResource(objId).get().getInputStream()) {
|
|
||||||
return ObjReader.read(is);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void renderObj(Obj obj, Map<String, Mtl> mtlMap, MatrixStack matrices,
|
|
||||||
VertexConsumerProvider vertexConsumers, int light, int overlay) {
|
|
||||||
MatrixStack.Entry entry = matrices.peek();
|
|
||||||
|
|
||||||
Map<String, Obj> materialGroups = ObjSplitting.splitByMaterialGroups(obj);
|
|
||||||
|
|
||||||
for (Map.Entry<String, Obj> group : materialGroups.entrySet()) {
|
|
||||||
String materialName = group.getKey();
|
|
||||||
Obj groupObj = group.getValue();
|
|
||||||
|
|
||||||
Mtl mtl = mtlMap != null ? mtlMap.get(materialName) : null;
|
|
||||||
|
|
||||||
// Resolve texture identifier using same logic as ObjUnbakedModelModel
|
|
||||||
IdentifierRef texture = IdentifierRef.ofVanilla("textures/misc/white.png");
|
|
||||||
|
|
||||||
if (mtl != null) {
|
|
||||||
String mapKd = mtl.getMapKd();
|
|
||||||
if (mapKd != null) {
|
|
||||||
if (!mapKd.startsWith("#")) {
|
|
||||||
texture = IdentifierRef.of(mapKd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Diffuse color (Kd)
|
|
||||||
float r = 1f, g = 1f, b = 1f;
|
|
||||||
if (mtl != null) {
|
|
||||||
FloatTuple kd = mtl.getKd();
|
|
||||||
if (kd != null) {
|
|
||||||
r = kd.getX();
|
|
||||||
g = kd.getY();
|
|
||||||
b = kd.getZ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VertexConsumer consumer = vertexConsumers.getBuffer(ShaderUtils.getRenderLayer(texture));
|
|
||||||
|
|
||||||
int faces = groupObj.getNumFaces();
|
|
||||||
final float fr = r, fg = g, fb = b;
|
|
||||||
|
|
||||||
for (int f = 0; f < faces; f++) {
|
|
||||||
ObjFace face = groupObj.getFace(f);
|
|
||||||
int verts = face.getNumVertices();
|
|
||||||
|
|
||||||
// Your original winding order logic, untouched
|
|
||||||
for (int i = verts - 1; i >= 0; i--) {
|
|
||||||
writeVertex(groupObj, face, i, consumer, entry, light, overlay, fr, fg, fb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void writeVertex(Obj obj, ObjFace face, int index, VertexConsumer consumer,
|
|
||||||
MatrixStack.Entry matrix, int light, int overlay,
|
|
||||||
float r, float g, float b) {
|
|
||||||
|
|
||||||
FloatTuple pos = obj.getVertex(face.getVertexIndex(index));
|
|
||||||
float x = pos.getX();
|
|
||||||
float y = pos.getY();
|
|
||||||
float z = pos.getZ();
|
|
||||||
|
|
||||||
float nx = 0f, ny = 1f, nz = 0f;
|
|
||||||
int normalIndex = face.getNormalIndex(index);
|
|
||||||
if (normalIndex >= 0) {
|
|
||||||
FloatTuple n = obj.getNormal(normalIndex);
|
|
||||||
nx = n.getX();
|
|
||||||
ny = n.getY();
|
|
||||||
nz = n.getZ();
|
|
||||||
}
|
|
||||||
|
|
||||||
float u = 0f, v = 0f;
|
|
||||||
int texIndex = face.getTexCoordIndex(index);
|
|
||||||
if (texIndex >= 0) {
|
|
||||||
FloatTuple tc = obj.getTexCoord(texIndex);
|
|
||||||
u = tc.getX();
|
|
||||||
v = 1f - tc.getY(); // Flip V: OBJ bottom-left origin -> Minecraft top-left
|
|
||||||
}
|
|
||||||
|
|
||||||
consumer.vertex(matrix, x, y, z)
|
|
||||||
.color(r, g, b, 1f)
|
|
||||||
.texture(u, v)
|
|
||||||
.overlay(overlay)
|
|
||||||
.light(light)
|
|
||||||
.normal(matrix, nx, ny, nz);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-71
@@ -1,71 +0,0 @@
|
|||||||
package org.saturnclient.impl.cosmetics.utils;
|
|
||||||
|
|
||||||
import org.saturnclient.common.ref.asset.IdentifierRef;
|
|
||||||
import org.saturnclient.saturnclient.SaturnClient;
|
|
||||||
|
|
||||||
import net.minecraft.client.texture.NativeImage;
|
|
||||||
import net.minecraft.client.texture.NativeImageBackedTexture;
|
|
||||||
import net.minecraft.util.Identifier;
|
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.awt.image.DataBufferInt;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class IdentifierUtils {
|
|
||||||
|
|
||||||
public static void registerBufferedImageTextureFast(IdentifierRef identifierRef, BufferedImage bufferedImage) {
|
|
||||||
try {
|
|
||||||
Identifier identifier = (Identifier) (Object) identifierRef;
|
|
||||||
|
|
||||||
int width = bufferedImage.getWidth();
|
|
||||||
int height = bufferedImage.getHeight();
|
|
||||||
|
|
||||||
NativeImage nativeImage = new NativeImage(NativeImage.Format.RGBA, width, height, false);
|
|
||||||
|
|
||||||
if (bufferedImage.getType() == BufferedImage.TYPE_INT_ARGB) {
|
|
||||||
int[] pixels = ((DataBufferInt) bufferedImage.getRaster().getDataBuffer()).getData();
|
|
||||||
|
|
||||||
int index = 0;
|
|
||||||
for (int y = 0; y < height; y++) {
|
|
||||||
for (int x = 0; x < width; x++) {
|
|
||||||
nativeImage.setColorArgb(x, y, pixels[index++]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
for (int y = 0; y < height; y++) {
|
|
||||||
for (int x = 0; x < width; x++) {
|
|
||||||
nativeImage.setColorArgb(x, y, bufferedImage.getRGB(x, y));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
SaturnClient.client.execute(() -> {
|
|
||||||
NativeImageBackedTexture texture = new NativeImageBackedTexture(
|
|
||||||
() -> identifier.toString(),
|
|
||||||
nativeImage);
|
|
||||||
|
|
||||||
SaturnClient.client.getTextureManager().registerTexture(identifier, texture);
|
|
||||||
});
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
SaturnClient.LOGGER.error("Failed to register texture: {}", identifierRef, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void registerBufferedImageTexturesBulk(Map<IdentifierRef, BufferedImage> textures) {
|
|
||||||
|
|
||||||
long start = System.currentTimeMillis();
|
|
||||||
|
|
||||||
textures.forEach(IdentifierUtils::registerBufferedImageTextureFast);
|
|
||||||
|
|
||||||
long end = System.currentTimeMillis();
|
|
||||||
|
|
||||||
SaturnClient.LOGGER.info(
|
|
||||||
"Registered {} textures in {}ms",
|
|
||||||
textures.size(),
|
|
||||||
(end - start));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
package org.saturnclient.impl.cosmetics.utils;
|
|
||||||
|
|
||||||
import org.saturnclient.common.ref.asset.IdentifierRef;
|
|
||||||
import org.saturnclient.cosmetics.utils.GifUtils;
|
|
||||||
|
|
||||||
import com.mojang.blaze3d.pipeline.RenderPipeline;
|
|
||||||
|
|
||||||
import net.minecraft.client.gl.RenderPipelines;
|
|
||||||
import net.minecraft.client.render.RenderLayer;
|
|
||||||
import net.minecraft.client.render.RenderPhase.Textures;
|
|
||||||
import net.minecraft.client.render.block.entity.EndPortalBlockEntityRenderer;
|
|
||||||
import net.minecraft.util.Identifier;
|
|
||||||
|
|
||||||
public class ShaderUtils {
|
|
||||||
public static final RenderPipeline END_GATEWAY_PIPELINE = RenderPipelines.register(
|
|
||||||
RenderPipeline.builder(new RenderPipeline.Snippet[] { RenderPipelines.RENDERTYPE_END_PORTAL_SNIPPET })
|
|
||||||
.withLocation("pipeline/end_gateway")
|
|
||||||
.withShaderDefine("PORTAL_LAYERS", 16)
|
|
||||||
.withCull(false)
|
|
||||||
.build());
|
|
||||||
|
|
||||||
public static final RenderLayer END_GATEWAY = RenderLayer.of("end_gateway", 1536, false, false,
|
|
||||||
END_GATEWAY_PIPELINE,
|
|
||||||
RenderLayer.MultiPhaseParameters.builder()
|
|
||||||
.texture(Textures.create().add(EndPortalBlockEntityRenderer.SKY_TEXTURE, false)
|
|
||||||
.add(EndPortalBlockEntityRenderer.PORTAL_TEXTURE, false).build())
|
|
||||||
.build(false));
|
|
||||||
|
|
||||||
public static RenderLayer getRenderLayer(IdentifierRef texture) {
|
|
||||||
String path = texture.toString();
|
|
||||||
if (path.endsWith(".gif")) {
|
|
||||||
return RenderLayer.getEntityAlpha((Identifier) (Object) GifUtils.get(texture));
|
|
||||||
} else if (path.endsWith("end.png")) {
|
|
||||||
return END_GATEWAY;
|
|
||||||
} else {
|
|
||||||
return RenderLayer.getEntityAlpha((Identifier) (Object) texture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-46
@@ -1,46 +0,0 @@
|
|||||||
package org.saturnclient.impl.features.mixins.entity;
|
|
||||||
|
|
||||||
import org.saturnclient.impl.features.entity.CameraOverriddenEntity;
|
|
||||||
import org.saturnclient.mod.mods.FreelookMod;
|
|
||||||
import org.saturnclient.saturnclient.SaturnClient;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
import net.minecraft.client.network.ClientPlayerEntity;
|
|
||||||
import net.minecraft.client.render.Camera;
|
|
||||||
import net.minecraft.entity.Entity;
|
|
||||||
import net.minecraft.world.BlockView;
|
|
||||||
|
|
||||||
@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 (FreelookMod.isFreeLooking() && cameraEntity instanceof ClientPlayerEntity) {
|
|
||||||
CameraOverriddenEntity cameraOverriddenEntity = (CameraOverriddenEntity) cameraEntity;
|
|
||||||
|
|
||||||
if (firstTime && SaturnClient.client.player != null) {
|
|
||||||
cameraOverriddenEntity.freelook$setCameraPitch(SaturnClient.client.player.getPitch());
|
|
||||||
cameraOverriddenEntity.freelook$setCameraYaw(SaturnClient.client.player.getYaw());
|
|
||||||
firstTime = false;
|
|
||||||
}
|
|
||||||
this.setRotation(cameraOverriddenEntity.freelook$getCameraYaw(),
|
|
||||||
cameraOverriddenEntity.freelook$getCameraPitch());
|
|
||||||
|
|
||||||
}
|
|
||||||
if (!FreelookMod.isFreeLooking() && cameraEntity instanceof ClientPlayerEntity) {
|
|
||||||
firstTime = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
-37
@@ -1,37 +0,0 @@
|
|||||||
package org.saturnclient.impl.features.mixins.render;
|
|
||||||
|
|
||||||
import net.minecraft.client.render.GameRenderer;
|
|
||||||
|
|
||||||
import org.saturnclient.mod.mods.ZoomMod;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Overrides the game's field-of-view when {@link ZoomMod} is active.
|
|
||||||
*
|
|
||||||
* The old code checked both {@code Zoom.isZooming} and
|
|
||||||
* {@code Zoom.shouldZoom()} separately. The refactored
|
|
||||||
* {@link ZoomMod#shouldZoom()} already ORs both conditions
|
|
||||||
* ({@code enabled.value && isZooming}), so only one check is needed.
|
|
||||||
*
|
|
||||||
* No {@link org.saturnclient.common.module.ModProvider} is required
|
|
||||||
* here because zooming is a pure render-time override with no per-tick
|
|
||||||
* engine queries.
|
|
||||||
*/
|
|
||||||
@Mixin(GameRenderer.class)
|
|
||||||
public class GameRendererMixin {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* After the vanilla FOV has been computed, divide it by the zoom
|
|
||||||
* level to produce the narrowed field-of-view.
|
|
||||||
*/
|
|
||||||
@Inject(method = "getFov", at = @At("RETURN"), cancellable = true)
|
|
||||||
private void onGetFov(CallbackInfoReturnable<Float> cir) {
|
|
||||||
if (ZoomMod.shouldZoom()) {
|
|
||||||
float zoomedFov = cir.getReturnValue() / ZoomMod.getZoomLevel();
|
|
||||||
cir.setReturnValue(zoomedFov);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-59
@@ -1,59 +0,0 @@
|
|||||||
package org.saturnclient.impl.features.mixins.render;
|
|
||||||
|
|
||||||
import net.minecraft.client.render.entity.state.LivingEntityRenderState;
|
|
||||||
|
|
||||||
import org.saturnclient.common.feature.EntityFeature;
|
|
||||||
import org.saturnclient.impl.features.entity.HealthRenderState;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements {@link HealthRenderState} on
|
|
||||||
* {@link LivingEntityRenderState}, injecting health and entity-type
|
|
||||||
* storage into every living entity's render-state snapshot.
|
|
||||||
*
|
|
||||||
* Previously imported {@code NametagsInterface.EntityType}; the enum
|
|
||||||
* now lives in {@link EntityFeature.EntityType} which is the single
|
|
||||||
* canonical definition shared by the mixin layer and the feature layer.
|
|
||||||
*
|
|
||||||
* The stored values are written by
|
|
||||||
* {@link LivingEntityRendererMixin#saturn$captureHealth} each time a
|
|
||||||
* render state is extracted from a live entity, and read by
|
|
||||||
* {@link NametagsMixin} at render time.
|
|
||||||
*/
|
|
||||||
@Mixin(LivingEntityRenderState.class)
|
|
||||||
public class LivingEntityRenderStateMixin implements HealthRenderState {
|
|
||||||
|
|
||||||
@Unique
|
|
||||||
private float saturn$health = 0f;
|
|
||||||
@Unique
|
|
||||||
private float saturn$maxHealth = 1f;
|
|
||||||
@Unique
|
|
||||||
private EntityFeature.EntityType saturn$entityType = EntityFeature.EntityType.OTHER;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public float saturn$getHealth() {
|
|
||||||
return saturn$health;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public float saturn$getMaxHealth() {
|
|
||||||
return saturn$maxHealth;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void saturn$setHealth(float health, float maxHealth) {
|
|
||||||
this.saturn$health = health;
|
|
||||||
this.saturn$maxHealth = maxHealth;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public EntityFeature.EntityType saturn$getEntityType() {
|
|
||||||
return saturn$entityType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void saturn$setEntityType(EntityFeature.EntityType type) {
|
|
||||||
saturn$entityType = type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-36
@@ -1,36 +0,0 @@
|
|||||||
package org.saturnclient.impl.features.world;
|
|
||||||
|
|
||||||
import org.saturnclient.common.feature.WorldFeature;
|
|
||||||
|
|
||||||
import net.minecraft.client.MinecraftClient;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fabric implementation of {@link WorldFeature}.
|
|
||||||
*
|
|
||||||
* Reads the client world's time directly from {@link MinecraftClient}.
|
|
||||||
* Returns safe defaults when no world is loaded.
|
|
||||||
*/
|
|
||||||
public class WorldFeatureImpl implements WorldFeature {
|
|
||||||
|
|
||||||
private final MinecraftClient mc;
|
|
||||||
|
|
||||||
public WorldFeatureImpl(MinecraftClient mc) {
|
|
||||||
this.mc = mc;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasWorld() {
|
|
||||||
return mc.world != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the total world age in ticks, or {@code 0} when no world
|
|
||||||
* is loaded. Used by {@link TpsFeature#onTimePacket} (which is
|
|
||||||
* called from the mixin and stores its own copy) and by
|
|
||||||
* {@link DayCounterFeature} for the day count.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public long getWorldAge() {
|
|
||||||
return hasWorld() ? mc.world.getTime() : 0L;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-162
@@ -1,162 +0,0 @@
|
|||||||
package org.saturnclient.impl.mixins;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.saturnclient.common.ref.asset.IdentifierRef;
|
|
||||||
import org.saturnclient.common.ref.game.MinecraftClientRef;
|
|
||||||
import org.saturnclient.common.ref.render.WindowRef;
|
|
||||||
import org.saturnclient.impl.ui.SaturnScreenFabric;
|
|
||||||
import org.saturnclient.ui.SaturnScreen;
|
|
||||||
import org.saturnclient.ui.screens.TitleMenu;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
|
|
||||||
import net.minecraft.client.MinecraftClient;
|
|
||||||
import net.minecraft.client.gui.screen.Screen;
|
|
||||||
import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen;
|
|
||||||
import net.minecraft.client.gui.screen.option.OptionsScreen;
|
|
||||||
import net.minecraft.client.gui.screen.world.SelectWorldScreen;
|
|
||||||
import net.minecraft.client.option.GameOptions;
|
|
||||||
import net.minecraft.client.session.Session;
|
|
||||||
import net.minecraft.client.util.Window;
|
|
||||||
import net.minecraft.resource.ReloadableResourceManagerImpl;
|
|
||||||
import net.minecraft.util.Identifier;
|
|
||||||
|
|
||||||
@Mixin(MinecraftClient.class)
|
|
||||||
public abstract class MinecraftClientMixin implements MinecraftClientRef {
|
|
||||||
@Shadow
|
|
||||||
public File runDirectory;
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
private Window window;
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
private ReloadableResourceManagerImpl resourceManager;
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
public GameOptions options;
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
private Session session;
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
public abstract void setScreen(@Nullable Screen screen);
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
@Override
|
|
||||||
public abstract void scheduleStop();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public File getRunDirectory() {
|
|
||||||
return runDirectory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InputStream getResource(IdentifierRef identifier) {
|
|
||||||
try {
|
|
||||||
return resourceManager.getResource((Identifier) (Object) identifier).get().getInputStream();
|
|
||||||
} catch (Exception e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WindowRef getWindow() {
|
|
||||||
return (WindowRef) (Object) this.window;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setScreen(SaturnScreen screen) {
|
|
||||||
this.setScreen(new SaturnScreenFabric(screen));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setScreen(MinecraftScreen screen) {
|
|
||||||
SaturnScreenFabric exitTarget = new SaturnScreenFabric(new TitleMenu());
|
|
||||||
|
|
||||||
switch (screen) {
|
|
||||||
case SelectWorld:
|
|
||||||
this.setScreen(new SelectWorldScreen(exitTarget));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Multiplayer:
|
|
||||||
this.setScreen(new MultiplayerScreen(exitTarget));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Options:
|
|
||||||
this.setScreen(new OptionsScreen(exitTarget, this.options));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAccessToken() {
|
|
||||||
if (session == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.session.getAccessToken();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UUID getUuid() {
|
|
||||||
if (session == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return this.session.getUuidOrNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUsername() {
|
|
||||||
if (session == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return this.session.getUsername();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClientStopping(Runnable handler) {
|
|
||||||
ClientLifecycleEvents.CLIENT_STOPPING.register(_o -> handler.run());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void executeOnThread(Runnable runnable) {
|
|
||||||
((java.util.concurrent.Executor) (Object) this).execute(runnable);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("resource")
|
|
||||||
public String getPlayerListEntry(UUID uuid) {
|
|
||||||
var client = (MinecraftClient) (Object) this;
|
|
||||||
var handler = client.getNetworkHandler();
|
|
||||||
|
|
||||||
if (handler == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
var entry = handler.getPlayerListEntry(uuid);
|
|
||||||
if (entry == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return entry.getProfile().name();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("resource")
|
|
||||||
public UUID getPlayerListEntryUUID(String name) {
|
|
||||||
var client = (MinecraftClient) (Object) this;
|
|
||||||
var handler = client.getNetworkHandler();
|
|
||||||
|
|
||||||
if (handler == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
var entry = handler.getPlayerListEntry(name);
|
|
||||||
if (entry == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return entry.getProfile().id();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
package org.saturnclient.impl.mixins;
|
|
||||||
|
|
||||||
import org.saturnclient.common.ref.asset.IdentifierRef;
|
|
||||||
import org.saturnclient.common.ref.render.TextRef;
|
|
||||||
import org.saturnclient.saturnclient.SaturnClient;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
|
|
||||||
import net.minecraft.text.Style;
|
|
||||||
import net.minecraft.text.Text;
|
|
||||||
import net.minecraft.text.StyleSpriteSource.Font;
|
|
||||||
import net.minecraft.util.Identifier;
|
|
||||||
|
|
||||||
@Mixin(Text.class)
|
|
||||||
public interface TextMixin extends TextRef {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public default TextRef withFont(IdentifierRef font) {
|
|
||||||
return (TextRef) (((Text) this).copy().setStyle(Style.EMPTY.withFont(new Font((Identifier) (Object) font))));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public default int getWidth() {
|
|
||||||
return SaturnClient.client.textRenderer.getWidth((Text) this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
package org.saturnclient.impl.provider;
|
|
||||||
|
|
||||||
import org.saturnclient.common.provider.RefConstructorProvider;
|
|
||||||
import org.saturnclient.common.ref.asset.IdentifierRef;
|
|
||||||
import org.saturnclient.common.ref.render.TextRef;
|
|
||||||
|
|
||||||
import net.minecraft.text.Text;
|
|
||||||
import net.minecraft.util.Identifier;
|
|
||||||
|
|
||||||
public class RefConstructorImpl implements RefConstructorProvider {
|
|
||||||
@Override
|
|
||||||
public IdentifierRef identifier(String fullPath) {
|
|
||||||
return (IdentifierRef) (Object) Identifier.of(fullPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IdentifierRef identifier(String namespace, String path) {
|
|
||||||
return (IdentifierRef) (Object) Identifier.of(namespace, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TextRef text(String text) {
|
|
||||||
return (TextRef) Text.literal(text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
package org.saturnclient.impl.provider;
|
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import net.fabricmc.loader.api.FabricLoader;
|
|
||||||
import net.minecraft.client.MinecraftClient;
|
|
||||||
import net.minecraft.client.toast.SystemToast;
|
|
||||||
import net.minecraft.text.Text;
|
|
||||||
|
|
||||||
import org.saturnclient.common.provider.SaturnProvider;
|
|
||||||
import org.saturnclient.common.ref.asset.IdentifierRef;
|
|
||||||
import org.saturnclient.common.ref.game.MinecraftClientRef;
|
|
||||||
import org.saturnclient.impl.cosmetics.utils.IdentifierUtils;
|
|
||||||
import org.saturnclient.saturnclient.SaturnClient;
|
|
||||||
|
|
||||||
public class SaturnProviderImpl implements SaturnProvider {
|
|
||||||
@Override
|
|
||||||
public MinecraftClientRef getClient() {
|
|
||||||
return (MinecraftClientRef) SaturnClient.client;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void playEmote(UUID fromPlayerUuid, String emoteIdOrNull) {
|
|
||||||
// if (SaturnClient.client == null || SaturnClient.client.world == null) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// for (AbstractClientPlayerEntity player : SaturnClient.client.world.getPlayers()) {
|
|
||||||
// if (!player.getUuid().equals(fromPlayerUuid)) {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// AnimationStack animationStack = PlayerAnimationAccess.getPlayerAnimLayer(player);
|
|
||||||
|
|
||||||
// if (emoteIdOrNull != null && !emoteIdOrNull.isEmpty()) {
|
|
||||||
// if (animationStack.isActive() && animationStack.getPriority() == 1000) {
|
|
||||||
// animationStack.removeLayer(1000);
|
|
||||||
// }
|
|
||||||
// animationStack.addAnimLayer(1000,
|
|
||||||
// PlayerAnimationRegistry
|
|
||||||
// .getAnimation(Identifier.of("saturnclient", emoteIdOrNull))
|
|
||||||
// .playAnimation());
|
|
||||||
// } else {
|
|
||||||
// animationStack.removeLayer(1000);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void logInfo(String message) {
|
|
||||||
SaturnClient.LOGGER.info(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void logError(String message) {
|
|
||||||
SaturnClient.LOGGER.error(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void logError(String message, Throwable throwable) {
|
|
||||||
SaturnClient.LOGGER.error(message, throwable);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Shown longer than the vanilla default, since these ask the player to act. */
|
|
||||||
private static final SystemToast.Type WARNING_TOAST = new SystemToast.Type(15_000L);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getModVersion() {
|
|
||||||
return FabricLoader.getInstance().getModContainer(SaturnClient.MOD_ID)
|
|
||||||
.map(mod -> mod.getMetadata().getVersion().getFriendlyString())
|
|
||||||
.orElse("unknown");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showWarning(String title, String message) {
|
|
||||||
MinecraftClient client = MinecraftClient.getInstance();
|
|
||||||
client.execute(() -> client.getToastManager().add(
|
|
||||||
SystemToast.create(client, WARNING_TOAST, Text.literal(title), Text.literal(message))));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void registerBufferedImageTexture(IdentifierRef i, BufferedImage bi) {
|
|
||||||
IdentifierUtils.registerBufferedImageTextureFast(i, bi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
package org.saturnclient.impl.ui;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.joml.Quaternionf;
|
|
||||||
import org.joml.Vector3f;
|
|
||||||
import org.saturnclient.saturnclient.SaturnClient;
|
|
||||||
import org.saturnclient.ui.ElementContext;
|
|
||||||
import org.saturnclient.ui.RenderScope;
|
|
||||||
import org.saturnclient.ui.components.SkinPreview.EntityDrawer;
|
|
||||||
|
|
||||||
import net.minecraft.client.render.entity.EntityRenderManager;
|
|
||||||
import net.minecraft.client.render.entity.EntityRenderer;
|
|
||||||
import net.minecraft.client.render.entity.state.EntityRenderState;
|
|
||||||
import net.minecraft.entity.LivingEntity;
|
|
||||||
|
|
||||||
public class EntityDrawerImpl implements EntityDrawer {
|
|
||||||
@Override
|
|
||||||
public void render(RenderScope renderScope, boolean negativeAngle, float angle, float scale, ElementContext ctx) {
|
|
||||||
LivingEntity entity = SaturnClient.client.player;
|
|
||||||
|
|
||||||
if (entity != null) {
|
|
||||||
drawEntity(renderScope, 0, 0, 75, 78, 30, 0.0625F, ctx.mouseX / scale, ctx.mouseY / scale,
|
|
||||||
SaturnClient.client.player);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void drawEntity(RenderScope renderScope, int x1, int y1, int x2, int y2, int size, float scale,
|
|
||||||
float mouseX, float mouseY, LivingEntity entity) {
|
|
||||||
float f = (float) (x1 + x2) / 2.0F;
|
|
||||||
float g = (float) (y1 + y2) / 2.0F;
|
|
||||||
renderScope.enableScissor(x1, y1, x2, y2);
|
|
||||||
float h = (float) Math.atan((double) ((f - mouseX) / 40.0F));
|
|
||||||
float i = (float) Math.atan((double) ((g - mouseY) / 40.0F));
|
|
||||||
Quaternionf quaternionf = (new Quaternionf()).rotateZ((float) Math.PI);
|
|
||||||
Quaternionf quaternionf2 = (new Quaternionf()).rotateX(i * 20.0F * ((float) Math.PI / 180F));
|
|
||||||
quaternionf.mul(quaternionf2);
|
|
||||||
float j = entity.bodyYaw;
|
|
||||||
float k = entity.getYaw();
|
|
||||||
float l = entity.getPitch();
|
|
||||||
float m = entity.lastHeadYaw;
|
|
||||||
float n = entity.headYaw;
|
|
||||||
entity.bodyYaw = 180.0F + h * 20.0F;
|
|
||||||
entity.setYaw(180.0F + h * 40.0F);
|
|
||||||
entity.setPitch(-i * 20.0F);
|
|
||||||
entity.headYaw = entity.getYaw();
|
|
||||||
entity.lastHeadYaw = entity.getYaw();
|
|
||||||
float o = entity.getScale();
|
|
||||||
Vector3f vector3f = new Vector3f(0.0F, entity.getHeight() / 2.0F + scale * o, 0.0F);
|
|
||||||
float p = (float) size / o;
|
|
||||||
drawEntity(renderScope, x1, y1, x2, y2, p, vector3f, quaternionf, quaternionf2, entity);
|
|
||||||
entity.bodyYaw = j;
|
|
||||||
entity.setYaw(k);
|
|
||||||
entity.setPitch(l);
|
|
||||||
entity.lastHeadYaw = m;
|
|
||||||
entity.headYaw = n;
|
|
||||||
renderScope.disableScissor();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void drawEntity(RenderScope renderScope, int x1, int y1, int x2, int y2, float scale,
|
|
||||||
Vector3f translation, Quaternionf rotation, @Nullable Quaternionf overrideCameraAngle,
|
|
||||||
LivingEntity entity) {
|
|
||||||
EntityRenderManager entityRenderDispatcher = SaturnClient.client.getEntityRenderDispatcher();
|
|
||||||
EntityRenderer<? super LivingEntity, ?> entityRenderer = entityRenderDispatcher.getRenderer(entity);
|
|
||||||
EntityRenderState entityRenderState = entityRenderer.getAndUpdateRenderState(entity, 1.0F);
|
|
||||||
entityRenderState.hitbox = null;
|
|
||||||
|
|
||||||
if (renderScope instanceof RenderScopeImpl i)
|
|
||||||
i.addEntity(entityRenderState, scale, translation, rotation, overrideCameraAngle, x1, y1, x2, y2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,347 +0,0 @@
|
|||||||
package org.saturnclient.impl.ui;
|
|
||||||
|
|
||||||
import java.util.ArrayDeque;
|
|
||||||
import java.util.Deque;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.joml.Matrix3x2f;
|
|
||||||
import org.joml.Matrix3x2fStack;
|
|
||||||
import org.joml.Quaternionf;
|
|
||||||
import org.joml.Vector3f;
|
|
||||||
|
|
||||||
import com.mojang.blaze3d.textures.GpuTextureView;
|
|
||||||
|
|
||||||
import org.saturnclient.common.ref.asset.IdentifierRef;
|
|
||||||
import org.saturnclient.common.ref.asset.SpriteRef;
|
|
||||||
import org.saturnclient.common.ref.game.ItemStackRef;
|
|
||||||
import org.saturnclient.common.ref.render.MatrixStackRef;
|
|
||||||
import org.saturnclient.impl.ref.Matrix3x2fStackRef;
|
|
||||||
import org.saturnclient.saturnclient.SaturnClient;
|
|
||||||
import org.saturnclient.saturnclient.mixin.DrawContextAccessor;
|
|
||||||
import org.saturnclient.ui.RenderScope;
|
|
||||||
import org.saturnclient.ui.resources.Fonts;
|
|
||||||
import org.saturnclient.ui.resources.SvgTexture;
|
|
||||||
|
|
||||||
import net.minecraft.client.gl.RenderPipelines;
|
|
||||||
import net.minecraft.client.gui.DrawContext;
|
|
||||||
import net.minecraft.client.gui.ScreenRect;
|
|
||||||
import net.minecraft.client.gui.render.state.ColoredQuadGuiElementRenderState;
|
|
||||||
import net.minecraft.client.gui.render.state.GuiRenderState;
|
|
||||||
import net.minecraft.client.gui.render.state.ItemGuiElementRenderState;
|
|
||||||
import net.minecraft.client.gui.render.state.TextGuiElementRenderState;
|
|
||||||
import net.minecraft.client.gui.render.state.TexturedQuadGuiElementRenderState;
|
|
||||||
import net.minecraft.client.gui.render.state.special.EntityGuiElementRenderState;
|
|
||||||
import net.minecraft.client.render.entity.state.EntityRenderState;
|
|
||||||
import net.minecraft.client.render.item.KeyedItemRenderState;
|
|
||||||
import net.minecraft.client.texture.Sprite;
|
|
||||||
import net.minecraft.client.texture.TextureSetup;
|
|
||||||
import net.minecraft.entity.LivingEntity;
|
|
||||||
import net.minecraft.item.ItemDisplayContext;
|
|
||||||
import net.minecraft.item.ItemStack;
|
|
||||||
import net.minecraft.text.Text;
|
|
||||||
import net.minecraft.util.Identifier;
|
|
||||||
import net.minecraft.util.crash.CrashException;
|
|
||||||
import net.minecraft.util.crash.CrashReport;
|
|
||||||
import net.minecraft.util.crash.CrashReportSection;
|
|
||||||
import net.minecraft.world.World;
|
|
||||||
|
|
||||||
public class RenderScopeImpl implements RenderScope {
|
|
||||||
|
|
||||||
public final Matrix3x2fStackRef matrices;
|
|
||||||
public final GuiRenderState state;
|
|
||||||
|
|
||||||
private ScissorStack scissorStack;
|
|
||||||
private int opacity = 0xFF << 24;
|
|
||||||
|
|
||||||
public RenderScopeImpl(DrawContext context) {
|
|
||||||
this(context.getMatrices(), ((DrawContextAccessor) (Object) context).getState());
|
|
||||||
}
|
|
||||||
|
|
||||||
public RenderScopeImpl(Matrix3x2fStack matrices, GuiRenderState state) {
|
|
||||||
this.matrices = new Matrix3x2fStackRef(matrices);
|
|
||||||
this.state = state;
|
|
||||||
this.scissorStack = new ScissorStack();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MatrixStackRef getMatrixStack() {
|
|
||||||
return matrices;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setOpacity(float alpha) {
|
|
||||||
this.opacity = ((int) (alpha * 255)) << 24;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getColor(int color) {
|
|
||||||
int originalAlpha = (color >>> 24) & 0xFF;
|
|
||||||
int newAlpha = (opacity >>> 24) & 0xFF;
|
|
||||||
int mixedAlpha = (originalAlpha * newAlpha) / 255;
|
|
||||||
return (mixedAlpha << 24) | (color & 0x00FFFFFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void fill(int x1, int y1, int x2, int y2, int color) {
|
|
||||||
this.state.addSimpleElement(
|
|
||||||
new ColoredQuadGuiElementRenderState(
|
|
||||||
RenderPipelines.GUI,
|
|
||||||
TextureSetup.empty(),
|
|
||||||
new Matrix3x2f(this.matrices.stack),
|
|
||||||
x1, y1, x2, y2, color, color,
|
|
||||||
this.scissorStack.peekLast()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void drawRectangle(int x, int y, int width, int height, int color) {
|
|
||||||
if (color == 0)
|
|
||||||
return;
|
|
||||||
color = getColor(color);
|
|
||||||
|
|
||||||
int x1 = x;
|
|
||||||
int x2 = x + width;
|
|
||||||
int y1 = y;
|
|
||||||
int y2 = y + height;
|
|
||||||
|
|
||||||
if (x2 < x1) {
|
|
||||||
int tmp = x1;
|
|
||||||
x1 = x2;
|
|
||||||
x2 = tmp;
|
|
||||||
}
|
|
||||||
if (y2 < y1) {
|
|
||||||
int tmp = y1;
|
|
||||||
y1 = y2;
|
|
||||||
y2 = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.fill(x1, y1, x2, y2, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void drawText(String text, int x, int y, int font, int color) {
|
|
||||||
drawText(1.0f, text, x, y, font, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void drawText(float scale, String text, int x, int y, int font, int color) {
|
|
||||||
if (color == 0)
|
|
||||||
return;
|
|
||||||
if (font == 0)
|
|
||||||
scale *= 2;
|
|
||||||
|
|
||||||
int lineIndex = 0;
|
|
||||||
for (String line : text.split("\n")) {
|
|
||||||
int finalColor = getColor(color);
|
|
||||||
|
|
||||||
matrices.push();
|
|
||||||
matrices.translate(x, y + (lineIndex * Fonts.getHeight()));
|
|
||||||
matrices.scale(scale, scale);
|
|
||||||
|
|
||||||
this.state.addText(
|
|
||||||
new TextGuiElementRenderState(
|
|
||||||
SaturnClient.client.textRenderer,
|
|
||||||
((Text) Fonts.setFont(line, font)).asOrderedText(),
|
|
||||||
new Matrix3x2f(this.matrices.stack),
|
|
||||||
0, font == 0 ? 1 : 8,
|
|
||||||
finalColor, 0, false, this.scissorStack.peekLast()));
|
|
||||||
|
|
||||||
matrices.pop();
|
|
||||||
|
|
||||||
lineIndex++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getScaledWindowWidth() {
|
|
||||||
return SaturnClient.client.getWindow().getScaledWidth();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getScaledWindowHeight() {
|
|
||||||
return SaturnClient.client.getWindow().getScaledHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Texture rendering
|
|
||||||
@Override
|
|
||||||
public void drawTexture(IdentifierRef sprite, int x, int y, float u, float v, int width, int height) {
|
|
||||||
drawTexture(sprite, x, y, u, v, width, height, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void drawTexture(IdentifierRef sprite, int x, int y, float u, float v, int width, int height, int color) {
|
|
||||||
drawTexture(sprite, x, y, u, v, width, height, width, height, width, height, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void drawTexture(IdentifierRef sprite, int x, int y, float u, float v, int width, int height,
|
|
||||||
int regionWidth, int regionHeight, int textureWidth, int textureHeight) {
|
|
||||||
drawTexture(sprite, x, y, u, v, width, height, regionWidth, regionHeight, textureWidth, textureHeight, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void drawTexture(IdentifierRef sprite, int x, int y, float u, float v, int width, int height,
|
|
||||||
int regionWidth, int regionHeight, int textureWidth, int textureHeight, int color) {
|
|
||||||
drawTexturedQuad((Identifier) (Object) sprite, x, x + width, y, y + height,
|
|
||||||
(u + 0f) / textureWidth,
|
|
||||||
(u + regionWidth) / textureWidth,
|
|
||||||
(v + 0f) / textureHeight,
|
|
||||||
(v + regionHeight) / textureHeight,
|
|
||||||
color);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawTexturedQuad(Identifier sprite, int x1, int x2, int y1, int y2,
|
|
||||||
float u1, float u2, float v1, float v2, int color) {
|
|
||||||
if (color == 0)
|
|
||||||
return;
|
|
||||||
color = getColor(color);
|
|
||||||
|
|
||||||
if (sprite.getPath().endsWith(".svg")) {
|
|
||||||
sprite = (Identifier) (Object) SvgTexture.getSvg(
|
|
||||||
(IdentifierRef) (Object) sprite,
|
|
||||||
(x2 - x1) * 2, (y2 - y1) * 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
GpuTextureView gpuTextureView = SaturnClient.client.getTextureManager()
|
|
||||||
.getTexture(sprite).getGlTextureView();
|
|
||||||
|
|
||||||
this.state.addSimpleElement(new TexturedQuadGuiElementRenderState(
|
|
||||||
RenderPipelines.GUI_TEXTURED,
|
|
||||||
TextureSetup.withoutGlTexture(gpuTextureView),
|
|
||||||
new Matrix3x2f(this.matrices.stack),
|
|
||||||
x1, y1, x2, y2, u1, u2, v1, v2, color,
|
|
||||||
this.scissorStack.peekLast()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scissor management
|
|
||||||
@Override
|
|
||||||
public void enableScissor(int x1, int y1, int x2, int y2) {
|
|
||||||
ScreenRect rect = new ScreenRect(x1, y1, x2 - x1, y2 - y1).transform(this.matrices.stack);
|
|
||||||
scissorStack.push(rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void disableScissor() {
|
|
||||||
scissorStack.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean scissorContains(int x, int y) {
|
|
||||||
return scissorStack.contains(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ScissorStack {
|
|
||||||
private final Deque<ScreenRect> stack = new ArrayDeque<>();
|
|
||||||
|
|
||||||
public ScreenRect push(ScreenRect rect) {
|
|
||||||
ScreenRect last = stack.peekLast();
|
|
||||||
if (last != null) {
|
|
||||||
ScreenRect intersection = Objects.requireNonNullElse(rect.intersection(last), ScreenRect.empty());
|
|
||||||
stack.addLast(intersection);
|
|
||||||
return intersection;
|
|
||||||
} else {
|
|
||||||
stack.addLast(rect);
|
|
||||||
return rect;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public ScreenRect pop() {
|
|
||||||
if (stack.isEmpty())
|
|
||||||
throw new IllegalStateException("Scissor stack underflow");
|
|
||||||
stack.removeLast();
|
|
||||||
return stack.peekLast();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public ScreenRect peekLast() {
|
|
||||||
return stack.peekLast();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean contains(int x, int y) {
|
|
||||||
return stack.isEmpty() || stack.peekLast().contains(x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Item rendering
|
|
||||||
@Override
|
|
||||||
public void drawItem(ItemStackRef stack, int x, int y) {
|
|
||||||
drawItem(null, SaturnClient.client.world, stack, x, y, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawItem(@Nullable LivingEntity entity, @Nullable World world, ItemStackRef stack, int x, int y,
|
|
||||||
int seed) {
|
|
||||||
drawItem(entity, world, (ItemStack) (Object) stack, x, y, seed, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawItem(@Nullable LivingEntity entity, @Nullable World world, ItemStack stack, int x, int y, int seed,
|
|
||||||
int z) {
|
|
||||||
if (!stack.isEmpty()) {
|
|
||||||
KeyedItemRenderState keyedItemRenderState = new KeyedItemRenderState();
|
|
||||||
SaturnClient.client.getItemModelManager().clearAndUpdate(keyedItemRenderState, stack,
|
|
||||||
ItemDisplayContext.GUI, world,
|
|
||||||
entity, seed);
|
|
||||||
|
|
||||||
try {
|
|
||||||
this.state.addItem(new ItemGuiElementRenderState(stack.getItem().getName().toString(),
|
|
||||||
new Matrix3x2f(this.matrices.stack), keyedItemRenderState, x, y,
|
|
||||||
this.scissorStack.peekLast()));
|
|
||||||
} catch (Throwable throwable) {
|
|
||||||
CrashReport crashReport = CrashReport.create(throwable, "Rendering item");
|
|
||||||
CrashReportSection crashReportSection = crashReport.addElement("Item being rendered");
|
|
||||||
crashReportSection.add("Item Type", () -> String.valueOf(stack.getItem()));
|
|
||||||
crashReportSection.add("Item Components", () -> String.valueOf(stack.getComponents()));
|
|
||||||
crashReportSection.add("Item Foil", () -> String.valueOf(stack.hasGlint()));
|
|
||||||
throw new CrashException(crashReport);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void drawSpriteStretched(SpriteRef sprite, int x, int y, int width, int height) {
|
|
||||||
drawSpriteStretched(sprite, x, y, width, height, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void drawSpriteStretched(SpriteRef sprite, int x, int y, int width, int height, int color) {
|
|
||||||
Sprite mcSprite = (Sprite) sprite;
|
|
||||||
if (color == 0 || width == 0 || height == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
drawTexturedQuad(mcSprite.getAtlasId(), x, x + width, y, y + height,
|
|
||||||
mcSprite.getMinU(), mcSprite.getMaxU(), mcSprite.getMinV(), mcSprite.getMaxV(), color);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void draw() {
|
|
||||||
// No-op for now
|
|
||||||
}
|
|
||||||
|
|
||||||
public void drawBorder(int x, int y, int width, int height, int color) {
|
|
||||||
fill(x, y, x + width, y + 1, color);
|
|
||||||
fill(x, y + height - 1, x + width, y + height, color);
|
|
||||||
fill(x, y + 1, x + 1, y + height - 1, color);
|
|
||||||
fill(x + width - 1, y + 1, x + width, y + height - 1, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addEntity(EntityRenderState entityState, float scale, Vector3f translation, Quaternionf rotation,
|
|
||||||
@Nullable Quaternionf overrideCameraAngle, int x1, int y1, int x2, int y2) {
|
|
||||||
|
|
||||||
Matrix3x2f mat = this.matrices.stack;
|
|
||||||
float offsetX = mat.m20;
|
|
||||||
float offsetY = mat.m21;
|
|
||||||
float scaleX = mat.m00; // current matrix X scale
|
|
||||||
float scaleY = mat.m11; // current matrix Y scale
|
|
||||||
|
|
||||||
int adjustedX1 = (int) (x1 * scaleX + offsetX);
|
|
||||||
int adjustedY1 = (int) (y1 * scaleY + offsetY);
|
|
||||||
int adjustedX2 = (int) (x2 * scaleX + offsetX);
|
|
||||||
int adjustedY2 = (int) (y2 * scaleY + offsetY);
|
|
||||||
|
|
||||||
float adjustedScale = scale * scaleX; // apply matrix scale to entity scale too
|
|
||||||
|
|
||||||
this.state.addSpecialElement(new EntityGuiElementRenderState(entityState, translation, rotation,
|
|
||||||
overrideCameraAngle, adjustedX1, adjustedY1, adjustedX2, adjustedY2, adjustedScale,
|
|
||||||
this.scissorStack.peekLast()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
package org.saturnclient.impl.ui;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.time.Instant;
|
|
||||||
|
|
||||||
import org.saturnclient.ui.RenderScope;
|
|
||||||
import org.saturnclient.ui.SaturnScreen;
|
|
||||||
import org.saturnclient.ui.SaturnScreen.ScreenProvider;
|
|
||||||
|
|
||||||
import net.minecraft.client.MinecraftClient;
|
|
||||||
import net.minecraft.client.gui.Click;
|
|
||||||
import net.minecraft.client.gui.CubeMapRenderer;
|
|
||||||
import net.minecraft.client.gui.DrawContext;
|
|
||||||
import net.minecraft.client.gui.RotatingCubeMapRenderer;
|
|
||||||
import net.minecraft.client.gui.screen.Screen;
|
|
||||||
import net.minecraft.client.input.KeyInput;
|
|
||||||
import net.minecraft.client.texture.ResourceTexture;
|
|
||||||
import net.minecraft.client.texture.TextureManager;
|
|
||||||
import net.minecraft.text.Text;
|
|
||||||
import net.minecraft.util.Identifier;
|
|
||||||
|
|
||||||
public class SaturnScreenFabric extends Screen implements ScreenProvider {
|
|
||||||
protected static final Identifier PANORAMA = Identifier.of("saturnclient",
|
|
||||||
"textures/gui/title/background/panorama");
|
|
||||||
protected static final CubeMapRenderer PANORAMA_RENDERER = new CubeMapRenderer(PANORAMA);
|
|
||||||
|
|
||||||
public static final RotatingCubeMapRenderer ROTATING_PANORAMA_RENDERER;
|
|
||||||
|
|
||||||
static {
|
|
||||||
ROTATING_PANORAMA_RENDERER = new RotatingCubeMapRenderer(PANORAMA_RENDERER);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final SaturnScreen screen;
|
|
||||||
|
|
||||||
public static void preload(MinecraftClient client) {
|
|
||||||
TextureManager textureManager = client.getTextureManager();
|
|
||||||
for (int i = 0; i < 6; i++) {
|
|
||||||
String var10001 = PANORAMA.getPath();
|
|
||||||
Identifier tex = PANORAMA.withPath(var10001 + "_" + i + ".png");
|
|
||||||
ResourceTexture resourceTexture = new ResourceTexture(tex);
|
|
||||||
textureManager.registerTexture(tex, resourceTexture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public SaturnScreenFabric(SaturnScreen screen) {
|
|
||||||
super(Text.literal(screen.title));
|
|
||||||
screen.provider = this;
|
|
||||||
this.screen = screen;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void init() {
|
|
||||||
screen.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
|
||||||
if (screen.start == null) {
|
|
||||||
screen.start = Instant.now();
|
|
||||||
}
|
|
||||||
long elapsed = Duration.between(screen.start, Instant.now()).toMillis();
|
|
||||||
|
|
||||||
mouseX *= 2;
|
|
||||||
mouseY *= 2;
|
|
||||||
|
|
||||||
if (client.world == null && client.getCurrentServerEntry() == null) {
|
|
||||||
// ROTATING_PANORAMA_RENDERER.render(context, this.width, this.height, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
RenderScope renderScope = new RenderScopeImpl(context);
|
|
||||||
|
|
||||||
screen.render(renderScope, mouseX, mouseY, delta, elapsed);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean mouseClicked(Click click, boolean doubled) {
|
|
||||||
if (screen.mouseClicked(click.x(), click.y(), click.button())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.mouseClicked(click, doubled);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean mouseDragged(Click click, double offsetX, double offsetY) {
|
|
||||||
if (screen.mouseDragged(click.x(), click.y(), click.button(), 0.0, 0.0)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.mouseDragged(click, offsetX, offsetY);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean mouseReleased(Click click) {
|
|
||||||
if (screen.mouseReleased(click.x(), click.y(), click.button())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.mouseReleased(click);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) {
|
|
||||||
if (screen.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean keyPressed(KeyInput input) {
|
|
||||||
if (screen.keyPressed(input.getKeycode(), input.scancode(), input.modifiers())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.keyPressed(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void resize(MinecraftClient client, int width, int height) {
|
|
||||||
screen.resize(width, height);
|
|
||||||
super.resize(client, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
this.screen.onClose();
|
|
||||||
super.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getWidth() {
|
|
||||||
return width * 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getHeight() {
|
|
||||||
return height * 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package org.saturnclient.saturnclient;
|
|
||||||
|
|
||||||
import org.saturnclient.client.player.SaturnPlayer;
|
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.client.rendering.v1.RenderStateDataKey;
|
|
||||||
|
|
||||||
public class SaturnRenderState {
|
|
||||||
public static RenderStateDataKey<SaturnPlayer> saturnDataKey = RenderStateDataKey
|
|
||||||
.create(() -> "saturn-client-player");
|
|
||||||
}
|
|
||||||
-58
@@ -1,58 +0,0 @@
|
|||||||
package org.saturnclient.saturnclient.event;
|
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
|
||||||
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
|
|
||||||
import net.minecraft.client.option.KeyBinding;
|
|
||||||
import net.minecraft.client.util.InputUtil;
|
|
||||||
import net.minecraft.util.Identifier;
|
|
||||||
|
|
||||||
import org.saturnclient.config.Config;
|
|
||||||
import org.saturnclient.saturnclient.SaturnClient;
|
|
||||||
import org.saturnclient.common.provider.Providers;
|
|
||||||
import org.saturnclient.ui.screens.EmoteWheel;
|
|
||||||
import org.saturnclient.ui.screens.ShiftMenu;
|
|
||||||
|
|
||||||
// import dev.kosmx.playerAnim.api.layered.AnimationStack;
|
|
||||||
// import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationAccess;
|
|
||||||
|
|
||||||
import org.lwjgl.glfw.GLFW;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles keyboard input events for the Saturn Client.
|
|
||||||
* Manages keybindings and their associated actions.
|
|
||||||
*/
|
|
||||||
public class KeyInputHandler {
|
|
||||||
private static final Identifier KEY_CATEGORY = Identifier.of("saturnclient", "key.category.saturnclient");
|
|
||||||
private static final String MAIN_MENU_KEY_ID = "key.saturnclient.main_menu";
|
|
||||||
private static final int DEFAULT_MENU_KEY = GLFW.GLFW_KEY_RIGHT_SHIFT;
|
|
||||||
private static KeyBinding mainMenuKeyBinding;
|
|
||||||
|
|
||||||
public static void register() {
|
|
||||||
mainMenuKeyBinding = KeyBindingHelper.registerKeyBinding(
|
|
||||||
new KeyBinding(
|
|
||||||
MAIN_MENU_KEY_ID,
|
|
||||||
DEFAULT_MENU_KEY,
|
|
||||||
KeyBinding.Category.create(KEY_CATEGORY)));
|
|
||||||
|
|
||||||
// Register the event handler for the main menu key
|
|
||||||
ClientTickEvents.END_CLIENT_TICK.register(client -> {
|
|
||||||
if (mainMenuKeyBinding.wasPressed()) {
|
|
||||||
Providers.saturn.getClient().setScreen(new ShiftMenu());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Config.openEmoteWheel.wasKeyPressed() && client.currentScreen == null
|
|
||||||
&& !InputUtil.isKeyPressed(client.getWindow(), GLFW.GLFW_KEY_F3)) {
|
|
||||||
Providers.saturn.getClient().setScreen(new EmoteWheel());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SaturnClient.client.player != null && SaturnClient.client.player.isSneaking()) {
|
|
||||||
// AnimationStack animationStack =
|
|
||||||
// PlayerAnimationAccess.getPlayerAnimLayer(SaturnClient.client.player);
|
|
||||||
// if (animationStack.isActive() && animationStack.getPriority() == 1000) {
|
|
||||||
// animationStack.removeLayer(1000);
|
|
||||||
// ServiceClient.emote("");
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-12
@@ -1,12 +0,0 @@
|
|||||||
package org.saturnclient.saturnclient.mixin;
|
|
||||||
|
|
||||||
import net.minecraft.client.gui.DrawContext;
|
|
||||||
import net.minecraft.client.gui.render.state.GuiRenderState;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
|
||||||
|
|
||||||
@Mixin(DrawContext.class)
|
|
||||||
public interface DrawContextAccessor {
|
|
||||||
@Accessor("state")
|
|
||||||
GuiRenderState getState();
|
|
||||||
}
|
|
||||||
-61
@@ -1,61 +0,0 @@
|
|||||||
package org.saturnclient.saturnclient.mixin;
|
|
||||||
|
|
||||||
import net.minecraft.client.network.ClientPlayerLikeEntity;
|
|
||||||
import net.minecraft.client.render.entity.EntityRendererFactory;
|
|
||||||
import net.minecraft.client.render.entity.LivingEntityRenderer;
|
|
||||||
import net.minecraft.client.render.entity.PlayerEntityRenderer;
|
|
||||||
import net.minecraft.client.render.entity.model.PlayerEntityModel;
|
|
||||||
import net.minecraft.client.render.entity.state.PlayerEntityRenderState;
|
|
||||||
import net.minecraft.entity.PlayerLikeEntity;
|
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
|
||||||
import net.minecraft.text.MutableText;
|
|
||||||
import net.minecraft.text.Text;
|
|
||||||
import net.minecraft.util.Formatting;
|
|
||||||
|
|
||||||
import org.saturnclient.client.player.Roles;
|
|
||||||
import org.saturnclient.client.player.SaturnPlayer;
|
|
||||||
import org.saturnclient.impl.cosmetics.CloakFeatureRenderer;
|
|
||||||
import org.saturnclient.impl.cosmetics.HatFeatureRenderer;
|
|
||||||
import org.saturnclient.saturnclient.SaturnRenderState;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
@Mixin(PlayerEntityRenderer.class)
|
|
||||||
public abstract class PlayerEntityRendererMixin
|
|
||||||
extends LivingEntityRenderer<PlayerEntity, PlayerEntityRenderState, PlayerEntityModel> {
|
|
||||||
|
|
||||||
protected PlayerEntityRendererMixin() {
|
|
||||||
super(null, null, 0.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "<init>", at = @At("TAIL"))
|
|
||||||
private void addCustomFeatureRenderer(EntityRendererFactory.Context ctx, boolean slim, CallbackInfo ci) {
|
|
||||||
this.addFeature(new HatFeatureRenderer(this));
|
|
||||||
this.addFeature(new CloakFeatureRenderer(this, ctx.getEquipmentModelLoader()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "updateRenderState", at = @At("TAIL"))
|
|
||||||
public <A extends PlayerLikeEntity & ClientPlayerLikeEntity> void updateRenderState(
|
|
||||||
A entity, PlayerEntityRenderState state,
|
|
||||||
float f, CallbackInfo ci) {
|
|
||||||
if (entity == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SaturnPlayer player = SaturnPlayer.get(entity.getUuid());
|
|
||||||
|
|
||||||
state.setData(SaturnRenderState.saturnDataKey, player);
|
|
||||||
|
|
||||||
if (player != null) {
|
|
||||||
MutableText iconText = Text.literal(Roles.getSaturnIndicator())
|
|
||||||
.styled(style -> style.withColor(Roles.getIconColor(player.uuid)));
|
|
||||||
|
|
||||||
state.displayName = Text.empty()
|
|
||||||
.append(iconText.copy())
|
|
||||||
.append(Text.empty().formatted(Formatting.RESET))
|
|
||||||
.append(state.displayName.copy());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-162
@@ -1,162 +0,0 @@
|
|||||||
package org.saturnclient.saturnclient.mixin;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
import org.saturnclient.config.Theme;
|
|
||||||
import org.saturnclient.impl.ui.RenderScopeImpl;
|
|
||||||
import org.saturnclient.ui.RenderScope;
|
|
||||||
import org.saturnclient.ui.resources.Textures;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Overwrite;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
|
|
||||||
import net.minecraft.client.MinecraftClient;
|
|
||||||
import net.minecraft.client.gui.DrawContext;
|
|
||||||
import net.minecraft.client.gui.screen.SplashOverlay;
|
|
||||||
import net.minecraft.resource.ResourceReload;
|
|
||||||
import net.minecraft.util.Util;
|
|
||||||
import net.minecraft.util.math.MathHelper;
|
|
||||||
|
|
||||||
@Mixin(SplashOverlay.class)
|
|
||||||
public abstract class SplashOverlayMixin {
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
private MinecraftClient client;
|
|
||||||
@Shadow
|
|
||||||
private ResourceReload reload;
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
private long reloadCompleteTime;
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
private long reloadStartTime;
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
@Final
|
|
||||||
private boolean reloading;
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
@Final
|
|
||||||
private Consumer<Optional<Throwable>> exceptionHandler;
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
private float progress;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author SaturnClient
|
|
||||||
* @reason Replace vanilla splash rendering completely but keep exit logic
|
|
||||||
*/
|
|
||||||
@Overwrite
|
|
||||||
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
|
||||||
int screenWidth = context.getScaledWindowWidth();
|
|
||||||
int screenHeight = context.getScaledWindowHeight();
|
|
||||||
long currentTime = Util.getMeasuringTimeMs();
|
|
||||||
|
|
||||||
// Initialize reload start time if not set
|
|
||||||
if (reloadStartTime == -1L) {
|
|
||||||
reloadStartTime = currentTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute fade-out progress after reload completes
|
|
||||||
float fadeOutProgress = reloadCompleteTime > -1L
|
|
||||||
? (float) (currentTime - reloadCompleteTime) / 1000f
|
|
||||||
: -1f;
|
|
||||||
|
|
||||||
int alpha = fadeOutProgress >= 0f
|
|
||||||
? MathHelper.ceil((1.0f - MathHelper.clamp(fadeOutProgress - 1f, 0f, 1f)) * 255f)
|
|
||||||
: 255;
|
|
||||||
|
|
||||||
// Compute fade-in progress while reloading
|
|
||||||
float reloadProgress = reloadStartTime > -1L
|
|
||||||
? (float) (currentTime - reloadStartTime) / 500f
|
|
||||||
: -1f;
|
|
||||||
|
|
||||||
// Get render scope for better UI
|
|
||||||
RenderScope scope = new RenderScopeImpl(context);
|
|
||||||
|
|
||||||
// Draw background overlay
|
|
||||||
if (fadeOutProgress >= 1.0F) {
|
|
||||||
renderCurrentScreen(context, mouseX, mouseY, delta);
|
|
||||||
int overlayAlpha = computeOverlayAlpha(fadeOutProgress - 1f);
|
|
||||||
scope.drawTexture(Textures.SPLASH, 0, 0, 0, 0, screenWidth, screenHeight,
|
|
||||||
Theme.withAlpha(overlayAlpha, 0xFFFFFFFF));
|
|
||||||
} else if (reloading) {
|
|
||||||
if (reloadProgress < 1.0F) {
|
|
||||||
renderCurrentScreen(context, mouseX, mouseY, delta);
|
|
||||||
}
|
|
||||||
scope.drawTexture(Textures.SPLASH, 0, 0, 0, 0, screenWidth, screenHeight,
|
|
||||||
Theme.withAlpha(alpha, 0xFFFFFFFF));
|
|
||||||
} else {
|
|
||||||
scope.drawTexture(Textures.SPLASH, 0, 0, 0, 0, screenWidth, screenHeight,
|
|
||||||
Theme.withAlpha(alpha, 0xFFFFFFFF));
|
|
||||||
}
|
|
||||||
|
|
||||||
float u = this.reload.getProgress();
|
|
||||||
this.progress = MathHelper.clamp(this.progress * 0.95F + u * 0.050000012F, 0.0F, 1.0F);
|
|
||||||
|
|
||||||
// Draw central logo
|
|
||||||
drawLogo(scope, screenWidth, screenHeight, alpha);
|
|
||||||
renderProgressBar(scope, context, screenWidth, screenHeight, alpha);
|
|
||||||
|
|
||||||
// Remove overlay after fade-out completes
|
|
||||||
if (fadeOutProgress >= 2.0F) {
|
|
||||||
client.setOverlay(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle reload completion and exceptions
|
|
||||||
handleReloadCompletion(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void renderCurrentScreen(DrawContext context, int mouseX, int mouseY, float delta) {
|
|
||||||
if (client.currentScreen != null) {
|
|
||||||
client.currentScreen.render(context, mouseX, mouseY, delta);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Draw the main logo centered */
|
|
||||||
private void drawLogo(RenderScope scope, int screenWidth, int screenHeight, int alpha) {
|
|
||||||
scope.drawTexture(Textures.LOGO, (screenWidth - 60) / 2, ((screenHeight - 60) / 2) - 20, 0, 0, 60, 60,
|
|
||||||
Theme.withAlpha(alpha, 0xFFFFFFFF));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void renderProgressBar(RenderScope scope, DrawContext context, int screenWidth, int screenHeight,
|
|
||||||
int alpha) {
|
|
||||||
int progressY = ((screenHeight - 5) / 2) + 25;
|
|
||||||
// context.drawBorder((screenWidth - 120) / 2, progressY, 120, 5,
|
|
||||||
// Theme.withAlpha(alpha, 0xFFFFFFFF));
|
|
||||||
|
|
||||||
int progressWidth = Math.min((int) (progress * 120), 120);
|
|
||||||
int progressX = (screenWidth - 120) / 2;
|
|
||||||
|
|
||||||
context.fill(progressX, progressY, progressX + progressWidth, progressY + 5,
|
|
||||||
Theme.withAlpha(alpha, 0xFFFFFFFF));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Compute overlay alpha from fade progress */
|
|
||||||
private int computeOverlayAlpha(float progress) {
|
|
||||||
return MathHelper.ceil((1.0F - MathHelper.clamp(progress, 0.0F, 1.0F)) * 255.0F);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Handle reload completion logic */
|
|
||||||
private void handleReloadCompletion(DrawContext context) {
|
|
||||||
float reloadProgress = reloadStartTime > -1L ? (float) (Util.getMeasuringTimeMs() - reloadStartTime) / 500f
|
|
||||||
: -1f;
|
|
||||||
|
|
||||||
if (reloadCompleteTime == -1L && reload.isComplete() && (!reloading || reloadProgress >= 2.0F)) {
|
|
||||||
try {
|
|
||||||
reload.throwException();
|
|
||||||
exceptionHandler.accept(Optional.empty());
|
|
||||||
} catch (Throwable ex) {
|
|
||||||
exceptionHandler.accept(Optional.of(ex));
|
|
||||||
}
|
|
||||||
|
|
||||||
reloadCompleteTime = Util.getMeasuringTimeMs();
|
|
||||||
|
|
||||||
if (client.currentScreen != null) {
|
|
||||||
client.currentScreen.init(client, context.getScaledWindowWidth(), context.getScaledWindowHeight());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
package org.saturnclient.saturnclient.mixin;
|
|
||||||
|
|
||||||
import net.minecraft.client.network.PlayerListEntry;
|
|
||||||
import net.minecraft.scoreboard.Team;
|
|
||||||
import net.minecraft.text.Text;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import org.saturnclient.client.player.Roles;
|
|
||||||
import org.saturnclient.client.player.SaturnPlayer;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|
||||||
|
|
||||||
import com.mojang.authlib.GameProfile;
|
|
||||||
|
|
||||||
@Mixin(PlayerListEntry.class)
|
|
||||||
public abstract class TabListMixin {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the Saturn Client icon to the player's name if they are online with
|
|
||||||
* Saturn Client, keeping any name, rank prefix or team formatting the server
|
|
||||||
* set.
|
|
||||||
*/
|
|
||||||
@Inject(method = "getDisplayName", at = @At("RETURN"), cancellable = true)
|
|
||||||
private void saturn$addSaturnIcon(CallbackInfoReturnable<Text> cir) {
|
|
||||||
PlayerListEntry entry = (PlayerListEntry) (Object) this;
|
|
||||||
GameProfile profile = entry.getProfile();
|
|
||||||
String name = profile.name();
|
|
||||||
UUID uuid = profile.id();
|
|
||||||
|
|
||||||
if (SaturnPlayer.get(name, uuid) == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Text displayName = cir.getReturnValue();
|
|
||||||
|
|
||||||
// With no server-set name, vanilla shows the team-decorated profile name.
|
|
||||||
if (displayName == null) {
|
|
||||||
displayName = Team.decorateName(entry.getScoreboardTeam(), Text.literal(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
cir.setReturnValue(Text.empty()
|
|
||||||
.append(Text.literal(Roles.getSaturnIndicator())
|
|
||||||
.styled(style -> style.withColor(Roles.getIconColor(uuid))))
|
|
||||||
.append(displayName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
"required": true,
|
|
||||||
"minVersion": "0.8",
|
|
||||||
"package": "org.saturnclient.impl.features.mixins",
|
|
||||||
"compatibilityLevel": "JAVA_21",
|
|
||||||
"client": [
|
|
||||||
"render.GameRendererMixin",
|
|
||||||
"render.LightmapTextureManagerMixin",
|
|
||||||
"render.LivingEntityRendererMixin",
|
|
||||||
"render.LivingEntityRenderStateMixin",
|
|
||||||
"render.BackgroundRendererMixin",
|
|
||||||
"render.RenderMixin",
|
|
||||||
"world.TpsMixin",
|
|
||||||
"entity.CameraMixin",
|
|
||||||
"entity.EntityMixin"
|
|
||||||
],
|
|
||||||
"injectors": {
|
|
||||||
"defaultRequire": 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
"required": true,
|
|
||||||
"minVersion": "0.8",
|
|
||||||
"package": "org.saturnclient.impl.mixins",
|
|
||||||
"compatibilityLevel": "JAVA_21",
|
|
||||||
"client": [
|
|
||||||
"IdentifierMixin",
|
|
||||||
"ItemStackMixin",
|
|
||||||
"MinecraftClientMixin",
|
|
||||||
"QuaternionfMixin",
|
|
||||||
"WindowMixin",
|
|
||||||
"TextMixin",
|
|
||||||
"SpriteMixin",
|
|
||||||
"StatusEffectMixin"
|
|
||||||
],
|
|
||||||
"injectors": {
|
|
||||||
"defaultRequire": 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user