Compare commits

..
16 Commits
Author SHA1 Message Date
selimaj-devandclaude eebfe8fa4d Switch the root build scripts to Kotlin and limit parallel remaps
Check / compile (pull_request) Successful in 7m47s
- settings.gradle, stonecutter.gradle and the root build.gradle become
  .kts. Loom's version for the Stonecutter versions moves to the root
  gradle.properties (loom_version), read by pluginManagement, since the
  Kotlin plugins block can't read properties. The old mc-<v> projects keep
  their Groovy scripts until they're folded in.
- buildAll ran all eight remapJar tasks at once. Each loads a Minecraft
  classpath and remaps a ~50 MB jar, which doesn't fit in the 3 GB daemon
  heap: a cold build stalled in garbage collection for 40+ minutes, and
  earlier runs failed. A shared build service now lets two remaps run
  together; a cold buildAll takes about 2 minutes.
- port.sh and VERSION_GUIDE follow the .kts file names.

The 1.21.11 jar is the same as with the Groovy scripts.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 04:51:28 +02:00
selimaj-devandclaude 019e5cfb43 Build 1.21.11 with Stonecutter from a shared src/
Step 1 of #8. 1.21.11's version-specific code moves from versions/1.21.11/src
to the top-level src/, built by Stonecutter as the project :1.21.11. The other
versions still build from their own copies as :mc-<v> until they're folded in.

- settings.gradle: applies Stonecutter (Groovy controller) with
  stonecutterVersions = ["1.21.11"] and skips those folders when including
  the old mc-<v> projects.
- The old root build.gradle becomes stonecutter.gradle (the root project's
  script, with the shared repositories, common wiring and buildAll), and
  1.21.11's build.gradle becomes the root build.gradle that Stonecutter runs
  for each version. versions/1.21.11 keeps its gradle.properties and run/.
- The jar has the same 415 entries, fabric.mod.json and mixin configs as
  before; the only class differences also appear when rebuilding an
  untouched version today.
- scripts/port.sh treats src/ as the active Stonecutter version, so changes
  port between it and the old copies both ways.
- README and VERSION_GUIDE describe the layout, version comments and how to
  add a version.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 04:18:42 +02:00
selimaj-dev 6ed2ac1b60 Merge pull request 'Replace player-animation-lib with the Saturn emote library' (#22) from emote-library into master
Reviewed-on: #22
2026-09-26 20:04:00 +00:00
selimaj-devandclaude 1853b09443 Point common at master after saturnclientmc/common#5 merged
Check / compile (pull_request) Successful in 7m5s
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-26 21:21:48 +02:00
selimaj-devandclaude 9126faa11c Replace player-animation-lib with the Saturn emote library
- Every version depends on org.saturnclient:emotes-fabric
  (${emotes_version}+<mc>, bundled). playEmote plays Saturn's emotes
  through it, and sneaking stops your own emote and tells the server.
  Emotes now work on 1.21.6+ too, where player-animation-lib was
  commented out.
- Removed every player-animation-lib and bendy-lib reference: the KoSmX
  repository, the dependencies, the player_anim properties, and the old
  (partly commented out) code in SaturnProviderImpl and KeyInputHandler.
- Build: Loom 1.15 -> 1.17.21 (the emotes jar is built with 1.17 and
  older Loom refuses it), Gradle 9.3 -> 9.8 (needed by Loom 1.17), and
  sourceSets moved out of the dependencies block in the root build.gradle,
  which Gradle 9.8 rejects.
- common: points at the emote-library branch (saturnclientmc/common#5).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-26 21:16:29 +02:00
selimaj-dev 090e5132b2 Merge pull request 'Refresh the README and use a local logo' (#21) from readme-refresh into master
Reviewed-on: #21
2026-09-26 02:24:33 +00:00
selimaj-devandclaude bbe6d02568 Refresh the README and use a local logo
Check / compile (pull_request) Successful in 2m4s
- Reference logo.png from the repo instead of the dead raw.github URL
  (the logo lives in the common submodule, which Gitea can't serve from
  a relative path, so a copy sits next to screenshot.png)
- Drop the section emojis and horizontal-rule separators
- Add supported versions, the built-in mods, installation (Modrinth,
  releases), network use (Mojang session sign-in; the access token never
  reaches the Saturn server), building from source with submodules, and
  a pointer to the version guide for multi-version changes

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-26 04:22:11 +02:00
selimaj-dev 04e7064790 Merge pull request 'CI: setup-java v5 and Gradle build cache' (#20) from ci-caching into master
Reviewed-on: #20
2026-09-26 02:10:44 +00:00
selimaj-devandclaude ff0bce4d24 Run the compile check on pull requests only, not on merges
Check / compile (pull_request) Successful in 10m49s
A merge to master re-ran the same compile the PR had just done. Keep
the pull_request trigger and drop the push-to-master one.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-26 03:48:54 +02:00
selimaj-devandclaude 2ecb4f80ea Move setup-java to v5 and enable Gradle's build cache
Check / compile (pull_request) Successful in 9m39s
- setup-java v4 is deprecated; use v5 (still with `cache: gradle`,
  which works once job containers can reach the runner's cache server).
- Enable Gradle's build cache (org.gradle.caching) so unchanged
  compilations are restored from cache instead of re-run.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-26 03:19:11 +02:00
selimaj-dev 41f9be8595 Merge pull request 'Version port script and compile check for pull requests' (#19) from port-tooling into master
Check / compile (push) Canceled after 12m52s
Reviewed-on: #19
2026-09-26 00:52:56 +00:00
selimaj-devandclaude f73f7e733c Add a version port script and a compile check for pull requests
Check / compile (pull_request) Successful in 18m7s
- scripts/port.sh ports a change made under versions/<from>/src to the
  other versions with `git apply --3way`: clean where files match,
  normal conflicts only where a version really differs. Supports
  uncommitted changes or --commit, --to, --dry-run, and detects changes
  already applied.
- .gitea/workflows/check.yml compiles every version on pull requests and
  pushes to master (--continue reports all failing versions).
- VERSION_GUIDE.md documents the layout, porting, and adding a version.

Closes #17, closes #18

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-26 02:41:22 +02:00
selimaj-dev 91b53daac9 Merge pull request 'Publish to Modrinth with Node instead of Python' (#16) from modrinth-node into master
Reviewed-on: #16
2026-09-25 17:18:13 +00:00
selimaj-devandclaude 5bcdc72b83 Publish to Modrinth with Node instead of Python
actions/setup-python can only install Python on GitHub's Ubuntu images,
so it fails on this runner's job image ("version 3.12 ... was not found
for this operating system"). Every Gitea runner has Node, since it runs
JavaScript actions, so port the publisher to a dependency-free Node
script (fetch/FormData/Blob) and drop the setup step. Behaviour is
unchanged.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-25 19:16:55 +02:00
selimaj-dev 3f0670ea9d Merge pull request 'Add a manual workflow that publishes a Gitea release to Modrinth' (#15) from modrinth-publish into master
Reviewed-on: #15
2026-09-25 17:13:53 +00:00
selimaj-devandclaude c54b5ae6d7 Add a manual workflow that publishes a Gitea release to Modrinth
"Publish to Modrinth" (workflow_dispatch, tag + dry_run inputs) takes the
jars the Release workflow attached to a Gitea release and creates one
Modrinth version per jar: version_number <version>+<mc>, that Minecraft
version, fabric loader, Fabric API as a required dependency, the release
notes as the changelog, and alpha/beta/release from the tag. It doesn't
rebuild, skips versions already on Modrinth, and downloads jars through
the public URL (Gitea's reported URLs use its internal ROOT_URL).

Needs a MODRINTH_TOKEN secret with the "Create versions" scope.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-25 19:11:41 +02:00
102 changed files with 916 additions and 643 deletions
+164
View File
@@ -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)));
+33
View File
@@ -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
+36
View File
@@ -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
+4 -1
View File
@@ -44,8 +44,11 @@ jobs:
fi
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
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: 21
+36 -20
View File
@@ -1,5 +1,5 @@
<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>
<h1 align="center">Saturn Client</h1>
@@ -13,27 +13,47 @@
<img src="screenshot.png" alt="Saturn Client Screenshot"/>
</p>
---
## ✨ About
## About
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.
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
- 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
- Clean and modern UI with animations
- Ongoing performance improvements
- 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 (versions not on Stonecutter yet: :mc-1.21.10)
./gradlew :1.21.11:runClient # launch a development client
```
Building needs Java 21.
## Contributing
We welcome contributions of all kinds:
@@ -43,11 +63,11 @@ We welcome contributions of all kinds:
- Cosmetic designs
- 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 are laid out, porting a change to all of them with `scripts/port.sh`, and adding a new Minecraft version. Every pull request is compiled for all versions automatically.
## 🙌 Credits
## Credits
- **Cloak Rendering:** `IIpho3nix` & Saturn
- **Who Am I:** `FokshaWasTaken`
@@ -57,13 +77,9 @@ If you're an artist or designer interested in helping with cosmetics or visual a
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.
---
## License
## 📜 License
Saturn Client is free and open-source using **Apache-2.0**
---
Saturn Client is free and open-source under the **Apache-2.0** license.
<p align="center">
Made with ❤️ by the Saturn Client team
+62 -1
View File
@@ -1,3 +1,64 @@
# 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
Saturn is moving from one full copy of the version-specific code per Minecraft version to a single copy built with [Stonecutter](https://stonecutter.kikugie.dev/) (issue #8). During the move there are two kinds of version:
- `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) for the versions built by Stonecutter, currently **1.21.11**. It's one copy: where Minecraft's API differs between them, the code goes behind version comments (see below). Each of these versions is the Gradle project `:<mc>`, and `versions/<mc>/` holds only its `gradle.properties` (Minecraft, Yarn, Fabric Loader and Fabric API versions), `build/` and `run/`.
- `versions/<mc>/src/`: the versions not moved yet (1.21.4 to 1.21.10), each a full copy, as the Gradle project `:mc-<mc>` with its own `build.gradle`.
`settings.gradle.kts` lists the Stonecutter versions in `stonecutterVersions` and includes every other folder under `versions/` as `:mc-<mc>`. The root `build.gradle.kts` builds each Stonecutter version, and `stonecutter.gradle.kts` configures the root project (shared repositories, the `common` wiring and `buildAll`). Loom's version for the Stonecutter versions 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) {*/
```
- `./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.
## Porting a change to the other versions
Make the change in one version, usually the newest, then run:
```sh
scripts/port.sh # port uncommitted changes to every other version
scripts/port.sh --dry-run # see what would apply cleanly first
scripts/port.sh --to 1.21.9,1.21.10 # only some versions
scripts/port.sh --commit <rev> # port what a commit changed instead
```
The script applies the diff under one version's source to each other version with `git apply --3way`. The Stonecutter `src/` counts as one version (1.21.11), so changes port between it and the old copies in both directions:
- **applied**: the files matched, and nothing else is needed.
- **CONFLICTS**: that version's code really differs. The file gets normal conflict markers, with the version's own code in `ours` and the ported change in `theirs`. Adapt the change to that version's API and resolve.
- **already has this change**: nothing to do, which is safe to see when re-running.
Only source is ported. `build.gradle` and `gradle.properties` are version-specific on purpose. Then build everything:
```sh
./gradlew compileJava
```
The **Check** workflow runs the same compile on every pull request, so a version that was missed or mis-ported fails before merging.
## Adding a Minecraft version
Add new versions to Stonecutter rather than copying a folder:
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.
-64
View File
@@ -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"
}
}
+81
View File
@@ -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
+8
View File
@@ -1,7 +1,15 @@
org.gradle.jvmargs=-Xmx3G
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
org.gradle.configuration-cache=false
mod_version=0.1.1-beta
# Saturn's emote library (git.selimaj.dev/saturnclientmc/emotes)
emotes_version=0.1.0
# Loom, for the Stonecutter versions (settings.gradle.kts). Old mc-<v> projects set their own.
loom_version=1.17.21
Binary file not shown.
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
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
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Vendored
+3 -3
View File
@@ -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:
#
@@ -29,7 +29,7 @@
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
# ksh gradlew
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
@@ -57,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (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.
#
# You can find Gradle at https://github.com/gradle/gradle/.
Vendored
+52 -33
View File
@@ -19,12 +19,39 @@
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem gradlew startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Set local scope for the variables, and ensure extensions are enabled
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
if "%DIRNAME%"=="" set DIRNAME=.
@@ -45,13 +72,14 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
1>&2 echo.
1>&2 echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
1>&2 echo.
1>&2 echo Please set the JAVA_HOME variable in your environment to match the
1>&2 echo location of your Java installation.
goto fail
"%COMSPEC%" /c exit 1
goto exitWithErrorLevel
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
@@ -59,35 +87,26 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
1>&2 echo.
1>&2 echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
1>&2 echo.
1>&2 echo Please set the JAVA_HOME variable in your environment to match the
1>&2 echo location of your Java installation.
goto fail
"%COMSPEC%" /c exit 1
goto exitWithErrorLevel
:execute
@rem Setup the command line
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
@rem Execute gradlew
@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 End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
: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
@rem This label must not be changed. We rely on old scripts being able to jump to this point.
:exitWithErrorLevel
@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
"%COMSPEC%" /c exit %ERRORLEVEL%
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

+184
View File
@@ -0,0 +1,184 @@
#!/usr/bin/env bash
# Port a change made in one Minecraft version's code to the other versions.
#
# Takes the diff under one version's source folder and applies it to the others
# with `git apply --3way`: it applies cleanly where the files match, and leaves
# normal merge conflicts only where a version really differs. Only source is
# ported; build.gradle and gradle.properties are version-specific on purpose.
#
# Versions moved to Stonecutter (stonecutterVersions in settings.gradle.kts)
# share the top-level src/, which counts as one version: the active one set in
# stonecutter.gradle.kts. The others keep their own copy in versions/<v>/src.
#
# Usage:
# scripts/port.sh [--from VERSION] [--to V1,V2,...] [--commit REV] [--dry-run]
#
# --from version the change was made in. Default: the only version with
# uncommitted changes (or changed by --commit).
# --to comma-separated versions to port to. Default: all others.
# --commit port the changes a commit made instead of uncommitted changes.
# --dry-run report what would happen without changing anything.
#
# Exit status: 0 if every version applied cleanly (or already had the change),
# 1 if any version has conflicts or failed.
set -euo pipefail
cd "$(git rev-parse --show-toplevel)"
from=""
to=""
commit=""
dry_run=false
while [ $# -gt 0 ]; do
case "$1" in
--from) from="$2"; shift 2 ;;
--to) to="$2"; shift 2 ;;
--commit) commit="$2"; shift 2 ;;
--dry-run) dry_run=true; shift ;;
-h|--help) sed -n '2,23p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
*) echo "Unknown option: $1 (see --help)" >&2; exit 2 ;;
esac
done
# Versions sharing the Stonecutter src/, and the one that stands for them.
stonecutter_versions=$(sed -n 's/^val stonecutterVersions = listOf(\(.*\))/\1/p' settings.gradle.kts | tr -d '" ' | tr ',' ' ')
stonecutter_active=$(sed -n 's/^stonecutter active "\(.*\)"/\1/p' stonecutter.gradle.kts 2>/dev/null || true)
is_stonecutter() {
printf '%s\n' $stonecutter_versions | grep -qx "$1"
}
# Where a version's source lives.
src_of() {
if is_stonecutter "$1"; then echo "src"; else echo "versions/$1/src"; fi
}
old_versions=$(for d in versions/*/; do [ -d "$d/src" ] && basename "$d"; done)
all_versions=$(printf '%s\n' $old_versions $stonecutter_active | grep . | sort -t. -k1,1n -k2,2n -k3,3n)
version_exists() {
[ -d "$(src_of "$1")" ]
}
# Versions with changes, from the working tree or from the given commit.
changed_versions() {
if [ -n "$commit" ]; then
git show --name-only --format= "$commit" -- versions/ src/
else
git diff HEAD --name-only -- versions/ src/
git ls-files --others --exclude-standard -- versions/ src/
fi | sed -n -e 's#^versions/\([^/]*\)/src/.*#\1#p' -e "s#^src/.*#${stonecutter_active}#p" | sort -u
}
if [ -z "$from" ]; then
candidates=$(changed_versions)
count=$(printf '%s\n' "$candidates" | grep -c . || true)
if [ "$count" -ne 1 ]; then
echo "Changes found in ${count} versions (${candidates//$'\n'/, }); pass --from to choose one." >&2
exit 2
fi
from="$candidates"
fi
version_exists "$from" || { echo "No such version: $from" >&2; exit 2; }
if is_stonecutter "$from"; then
from="$stonecutter_active"
fi
from_src=$(src_of "$from")
if [ -z "$to" ]; then
to=$(printf '%s\n' $all_versions | grep -vx "$from" | paste -sd, -)
fi
# New files are only included in `git diff HEAD` once git knows about them.
if [ -z "$commit" ]; then
untracked=$(git ls-files --others --exclude-standard -- "$from_src")
if [ -n "$untracked" ]; then
if $dry_run; then
echo "note: new files in $from_src are untracked and won't be ported in a dry run:" >&2
printf ' %s\n' $untracked >&2
else
printf '%s\n' "$untracked" | xargs git add --intent-to-add --
fi
fi
fi
# --full-index gives --3way the real blob ids to merge against.
if [ -n "$commit" ]; then
patch=$(git show --full-index --binary --format= "$commit" -- "$from_src")
else
patch=$(git diff HEAD --full-index --binary -- "$from_src")
fi
if [ -z "$patch" ]; then
echo "No changes under $from_src to port." >&2
exit 2
fi
files=$(printf '%s\n' "$patch" | grep -c '^diff --git' || true)
echo "Porting $files file(s) from $from${commit:+ (commit $commit)}"
from_re=$(printf '%s' "$from_src" | sed 's/\./\\./g')
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
status=0
IFS=',' read -r -a targets <<< "$to"
for target in "${targets[@]}"; do
if [ "$target" = "$from" ]; then
continue
fi
if is_stonecutter "$target" && [ "$target" != "$stonecutter_active" ]; then
printf ' %-8s skipped: shares src/ with %s\n' "$target" "$stonecutter_active"
[ "$from" = "$stonecutter_active" ] || status=1
continue
fi
if ! version_exists "$target"; then
printf ' %-8s skipped: no such version\n' "$target"
status=1
continue
fi
# Point the patch's file headers at the target version's source folder.
target_src=$(src_of "$target")
printf '%s\n' "$patch" | sed -E "/^(diff --git |--- |\+\+\+ |rename (from|to) |copy (from|to) )/ s#([ab]/|(from|to) )${from_re}/#\1${target_src}/#g" > "$tmp/$target.patch"
if git apply --check --reverse "$tmp/$target.patch" 2>/dev/null; then
printf ' %-8s already has this change\n' "$target"
continue
fi
if $dry_run; then
if git apply --check "$tmp/$target.patch" 2>/dev/null; then
printf ' %-8s would apply cleanly\n' "$target"
else
printf ' %-8s would need a 3-way merge (possible conflicts)\n' "$target"
fi
continue
fi
if output=$(git apply --3way "$tmp/$target.patch" 2>&1); then
printf ' %-8s applied\n' "$target"
else
conflicts=$(git diff --name-only --diff-filter=U -- "$target_src")
if [ -n "$conflicts" ]; then
printf ' %-8s CONFLICTS in:\n' "$target"
printf '%s\n' "$conflicts" | sed 's/^/ /'
else
printf ' %-8s FAILED:\n' "$target"
printf '%s\n' "$output" | sed 's/^/ /'
fi
status=1
fi
done
if ! $dry_run; then
echo
echo "Ported changes are staged in the target versions. Resolve any conflicts, then build"
echo "the affected versions, e.g. ./gradlew compileJava"
fi
exit $status
-21
View File
@@ -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
}
+43
View File
@@ -0,0 +1,43 @@
pluginManagement {
repositories {
maven("https://maven.fabricmc.net/")
maven("https://maven.kikugie.dev/releases")
gradlePluginPortal()
mavenCentral()
}
// Loom's version, for the Stonecutter versions' build.gradle.kts (the old mc-<v> projects set
// their own in versions/<v>/gradle.properties).
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.11")
stonecutter {
create(rootProject) {
versions(stonecutterVersions)
vcsVersion = "1.21.11"
}
}
// Versions not moved to Stonecutter yet still build from their own copy in versions/<v>/src,
// as projects named mc-<v>.
file("versions").listFiles { file -> file.isDirectory && file.name !in stonecutterVersions }!!
.sortedBy { it.name }
.forEach { dir ->
include("mc-${dir.name}")
project(":mc-${dir.name}").projectDir = dir
}
@@ -11,6 +11,7 @@ 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.cosmetics.Emotes;
import org.saturnclient.impl.cosmetics.utils.IdentifierUtils;
import org.saturnclient.saturnclient.SaturnClient;
@@ -22,31 +23,13 @@ public class SaturnProviderImpl implements SaturnProvider {
@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;
// }
if (fromPlayerUuid == null) {
return;
}
// An empty or unknown ID stops whatever the player is playing.
Emotes.get(emoteIdOrNull == null ? "" : emoteIdOrNull).ifPresentOrElse(
emote -> org.saturnclient.emotes.fabric.Emotes.play(fromPlayerUuid, emote.animation()),
() -> org.saturnclient.emotes.fabric.Emotes.stop(fromPlayerUuid));
}
@Override
@@ -9,12 +9,11 @@ import net.minecraft.util.Identifier;
import org.saturnclient.config.Config;
import org.saturnclient.saturnclient.SaturnClient;
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.ShiftMenu;
// import dev.kosmx.playerAnim.api.layered.AnimationStack;
// import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationAccess;
import org.lwjgl.glfw.GLFW;
/**
@@ -45,13 +44,11 @@ public class KeyInputHandler {
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("");
// }
// Sneaking cancels your own emote, for everyone.
if (SaturnClient.client.player != null && SaturnClient.client.player.isSneaking()
&& Emotes.playing(SaturnClient.client.player.getUuid()).isPresent()) {
Emotes.stop(SaturnClient.client.player.getUuid());
ServiceClient.emote("");
}
});
}
+71
View File
@@ -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")
}
}
+2 -10
View File
@@ -11,7 +11,6 @@ base {
}
repositories {
// maven { name = "KoSmX Maven"; url = 'https://maven.kosmx.dev/' }
maven { name = "Selimaj"; url = 'https://git.selimaj.dev/api/packages/selimaj-dev/maven' }
}
@@ -24,10 +23,8 @@ dependencies {
// 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}"
// )
// Saturn's emote library (limb bending, Emotecraft emotes)
include modImplementation("org.saturnclient:emotes-fabric:${project.emotes_version}+${project.minecraft_version}")
implementation project(":common")
@@ -37,11 +34,6 @@ dependencies {
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}"
// )
}
/*
+1 -3
View File
@@ -10,12 +10,10 @@ org.gradle.configuration-cache=false
minecraft_version=1.21.10
yarn_mappings=1.21.10+build.3
loader_version=0.19.0
loom_version=1.15-SNAPSHOT
loom_version=1.17.21
fabric_api_version=0.138.4+1.21.10
# Mod Properties
maven_group=org.saturnclient
archives_base_name=saturn-client
# player_anim = 2.0.2+1.21.5
@@ -11,6 +11,7 @@ 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.cosmetics.Emotes;
import org.saturnclient.impl.cosmetics.utils.IdentifierUtils;
import org.saturnclient.saturnclient.SaturnClient;
@@ -22,31 +23,13 @@ public class SaturnProviderImpl implements SaturnProvider {
@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;
// }
if (fromPlayerUuid == null) {
return;
}
// An empty or unknown ID stops whatever the player is playing.
Emotes.get(emoteIdOrNull == null ? "" : emoteIdOrNull).ifPresentOrElse(
emote -> org.saturnclient.emotes.fabric.Emotes.play(fromPlayerUuid, emote.animation()),
() -> org.saturnclient.emotes.fabric.Emotes.stop(fromPlayerUuid));
}
@Override
@@ -9,12 +9,11 @@ import net.minecraft.util.Identifier;
import org.saturnclient.config.Config;
import org.saturnclient.saturnclient.SaturnClient;
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.ShiftMenu;
// import dev.kosmx.playerAnim.api.layered.AnimationStack;
// import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationAccess;
import org.lwjgl.glfw.GLFW;
/**
@@ -45,13 +44,11 @@ public class KeyInputHandler {
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("");
// }
// Sneaking cancels your own emote, for everyone.
if (SaturnClient.client.player != null && SaturnClient.client.player.isSneaking()
&& Emotes.playing(SaturnClient.client.player.getUuid()).isPresent()) {
Emotes.stop(SaturnClient.client.player.getUuid());
ServiceClient.emote("");
}
});
}
-109
View File
@@ -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.
}
}
-3
View File
@@ -10,12 +10,9 @@ org.gradle.configuration-cache=false
minecraft_version=1.21.11
yarn_mappings=1.21.11+build.4
loader_version=0.19.0
loom_version=1.15-SNAPSHOT
fabric_api_version=0.141.3+1.21.11
# Mod Properties
maven_group=org.saturnclient
archives_base_name=saturn-client
# player_anim = 2.0.2+1.21.5
-10
View File
@@ -1,10 +0,0 @@
pluginManagement {
repositories {
maven {
name = 'Fabric'
url = 'https://maven.fabricmc.net/'
}
mavenCentral()
gradlePluginPortal()
}
}
+2 -10
View File
@@ -11,7 +11,6 @@ base {
}
repositories {
maven { name = "KoSmX Maven"; url = 'https://maven.kosmx.dev/' }
maven { name = "Selimaj"; url = 'https://git.selimaj.dev/api/packages/selimaj-dev/maven' }
}
@@ -24,10 +23,8 @@ dependencies {
// 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}"
)
// Saturn's emote library (limb bending, Emotecraft emotes)
include modImplementation("org.saturnclient:emotes-fabric:${project.emotes_version}+${project.minecraft_version}")
implementation project(":common")
@@ -37,11 +34,6 @@ dependencies {
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}"
// )
}
/*
+1 -3
View File
@@ -10,7 +10,7 @@ org.gradle.configuration-cache=false
minecraft_version=1.21.4
yarn_mappings=1.21.4+build.8
loader_version=0.18.4
loom_version=1.15-SNAPSHOT
loom_version=1.17.21
# Mod Properties
maven_group=org.saturnclient
@@ -18,5 +18,3 @@ archives_base_name=saturn-client
# Dependencies
fabric_api_version=0.119.4+1.21.4
player_anim = 2.0.3+1.21.4
@@ -11,15 +11,10 @@ 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.cosmetics.Emotes;
import org.saturnclient.impl.cosmetics.utils.IdentifierUtils;
import org.saturnclient.saturnclient.SaturnClient;
import dev.kosmx.playerAnim.api.layered.AnimationStack;
import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationAccess;
import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationRegistry;
import net.minecraft.client.network.AbstractClientPlayerEntity;
import net.minecraft.util.Identifier;
public class SaturnProviderImpl implements SaturnProvider {
@Override
public MinecraftClientRef getClient() {
@@ -28,31 +23,13 @@ public class SaturnProviderImpl implements SaturnProvider {
@Override
public void playEmote(UUID fromPlayerUuid, String emoteIdOrNull) {
if (SaturnClient.client == null || SaturnClient.client.world == null) {
if (fromPlayerUuid == 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;
}
// An empty or unknown ID stops whatever the player is playing.
Emotes.get(emoteIdOrNull == null ? "" : emoteIdOrNull).ifPresentOrElse(
emote -> org.saturnclient.emotes.fabric.Emotes.play(fromPlayerUuid, emote.animation()),
() -> org.saturnclient.emotes.fabric.Emotes.stop(fromPlayerUuid));
}
@Override
@@ -9,12 +9,10 @@ import org.saturnclient.config.Config;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.client.ServiceClient;
import org.saturnclient.common.provider.Providers;
import org.saturnclient.emotes.fabric.Emotes;
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;
/**
@@ -45,13 +43,12 @@ public class KeyInputHandler {
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);
// Sneaking cancels your own emote, for everyone.
if (SaturnClient.client.player != null && SaturnClient.client.player.isSneaking()
&& Emotes.playing(SaturnClient.client.player.getUuid()).isPresent()) {
Emotes.stop(SaturnClient.client.player.getUuid());
ServiceClient.emote("");
}
}
});
}
}
+2 -10
View File
@@ -11,7 +11,6 @@ base {
}
repositories {
maven { name = "KoSmX Maven"; url = 'https://maven.kosmx.dev/' }
maven { name = "Selimaj"; url = 'https://git.selimaj.dev/api/packages/selimaj-dev/maven' }
}
@@ -24,10 +23,8 @@ dependencies {
// 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}"
)
// Saturn's emote library (limb bending, Emotecraft emotes)
include modImplementation("org.saturnclient:emotes-fabric:${project.emotes_version}+${project.minecraft_version}")
implementation project(":common")
@@ -37,11 +34,6 @@ dependencies {
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}"
// )
}
/*
+1 -3
View File
@@ -10,12 +10,10 @@ org.gradle.configuration-cache=false
minecraft_version=1.21.5
yarn_mappings=1.21.5+build.1
loader_version=0.18.4
loom_version=1.15-SNAPSHOT
loom_version=1.17.21
fabric_api_version=0.128.2+1.21.5
# Mod Properties
maven_group=org.saturnclient
archives_base_name=saturn-client
player_anim = 2.0.2+1.21.5
@@ -11,15 +11,10 @@ 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.cosmetics.Emotes;
import org.saturnclient.impl.cosmetics.utils.IdentifierUtils;
import org.saturnclient.saturnclient.SaturnClient;
import dev.kosmx.playerAnim.api.layered.AnimationStack;
import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationAccess;
import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationRegistry;
import net.minecraft.client.network.AbstractClientPlayerEntity;
import net.minecraft.util.Identifier;
public class SaturnProviderImpl implements SaturnProvider {
@Override
public MinecraftClientRef getClient() {
@@ -28,31 +23,13 @@ public class SaturnProviderImpl implements SaturnProvider {
@Override
public void playEmote(UUID fromPlayerUuid, String emoteIdOrNull) {
if (SaturnClient.client == null || SaturnClient.client.world == null) {
if (fromPlayerUuid == 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;
}
// An empty or unknown ID stops whatever the player is playing.
Emotes.get(emoteIdOrNull == null ? "" : emoteIdOrNull).ifPresentOrElse(
emote -> org.saturnclient.emotes.fabric.Emotes.play(fromPlayerUuid, emote.animation()),
() -> org.saturnclient.emotes.fabric.Emotes.stop(fromPlayerUuid));
}
@Override
@@ -9,12 +9,10 @@ import org.saturnclient.config.Config;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.client.ServiceClient;
import org.saturnclient.common.provider.Providers;
import org.saturnclient.emotes.fabric.Emotes;
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;
/**
@@ -45,13 +43,12 @@ public class KeyInputHandler {
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);
// Sneaking cancels your own emote, for everyone.
if (SaturnClient.client.player != null && SaturnClient.client.player.isSneaking()
&& Emotes.playing(SaturnClient.client.player.getUuid()).isPresent()) {
Emotes.stop(SaturnClient.client.player.getUuid());
ServiceClient.emote("");
}
}
});
}
}
+2 -10
View File
@@ -11,7 +11,6 @@ base {
}
repositories {
// maven { name = "KoSmX Maven"; url = 'https://maven.kosmx.dev/' }
maven { name = "Selimaj"; url = 'https://git.selimaj.dev/api/packages/selimaj-dev/maven' }
}
@@ -24,10 +23,8 @@ dependencies {
// 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}"
// )
// Saturn's emote library (limb bending, Emotecraft emotes)
include modImplementation("org.saturnclient:emotes-fabric:${project.emotes_version}+${project.minecraft_version}")
implementation project(":common")
@@ -37,11 +34,6 @@ dependencies {
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}"
// )
}
/*
+1 -3
View File
@@ -10,12 +10,10 @@ org.gradle.configuration-cache=false
minecraft_version=1.21.6
yarn_mappings=1.21.6+build.1
loader_version=0.18.5
loom_version=1.15-SNAPSHOT
loom_version=1.17.21
fabric_api_version=0.128.2+1.21.6
# Mod Properties
maven_group=org.saturnclient
archives_base_name=saturn-client
# player_anim = 2.0.2+1.21.5
@@ -11,6 +11,7 @@ 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.cosmetics.Emotes;
import org.saturnclient.impl.cosmetics.utils.IdentifierUtils;
import org.saturnclient.saturnclient.SaturnClient;
@@ -22,31 +23,13 @@ public class SaturnProviderImpl implements SaturnProvider {
@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;
// }
if (fromPlayerUuid == null) {
return;
}
// An empty or unknown ID stops whatever the player is playing.
Emotes.get(emoteIdOrNull == null ? "" : emoteIdOrNull).ifPresentOrElse(
emote -> org.saturnclient.emotes.fabric.Emotes.play(fromPlayerUuid, emote.animation()),
() -> org.saturnclient.emotes.fabric.Emotes.stop(fromPlayerUuid));
}
@Override
@@ -8,12 +8,11 @@ import net.minecraft.client.util.InputUtil;
import org.saturnclient.config.Config;
import org.saturnclient.saturnclient.SaturnClient;
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.ShiftMenu;
// import dev.kosmx.playerAnim.api.layered.AnimationStack;
// import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationAccess;
import org.lwjgl.glfw.GLFW;
/**
@@ -44,12 +43,11 @@ public class KeyInputHandler {
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("");
// }
// Sneaking cancels your own emote, for everyone.
if (SaturnClient.client.player != null && SaturnClient.client.player.isSneaking()
&& Emotes.playing(SaturnClient.client.player.getUuid()).isPresent()) {
Emotes.stop(SaturnClient.client.player.getUuid());
ServiceClient.emote("");
}
});
}
+2 -10
View File
@@ -11,7 +11,6 @@ base {
}
repositories {
// maven { name = "KoSmX Maven"; url = 'https://maven.kosmx.dev/' }
maven { name = "Selimaj"; url = 'https://git.selimaj.dev/api/packages/selimaj-dev/maven' }
}
@@ -24,10 +23,8 @@ dependencies {
// 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}"
// )
// Saturn's emote library (limb bending, Emotecraft emotes)
include modImplementation("org.saturnclient:emotes-fabric:${project.emotes_version}+${project.minecraft_version}")
implementation project(":common")
@@ -37,11 +34,6 @@ dependencies {
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}"
// )
}
/*
+1 -3
View File
@@ -10,12 +10,10 @@ org.gradle.configuration-cache=false
minecraft_version=1.21.7
yarn_mappings=1.21.7+build.8
loader_version=0.19.0
loom_version=1.15-SNAPSHOT
loom_version=1.17.21
fabric_api_version=0.129.0+1.21.7
# Mod Properties
maven_group=org.saturnclient
archives_base_name=saturn-client
# player_anim = 2.0.2+1.21.5
@@ -11,6 +11,7 @@ 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.cosmetics.Emotes;
import org.saturnclient.impl.cosmetics.utils.IdentifierUtils;
import org.saturnclient.saturnclient.SaturnClient;
@@ -22,31 +23,13 @@ public class SaturnProviderImpl implements SaturnProvider {
@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;
// }
if (fromPlayerUuid == null) {
return;
}
// An empty or unknown ID stops whatever the player is playing.
Emotes.get(emoteIdOrNull == null ? "" : emoteIdOrNull).ifPresentOrElse(
emote -> org.saturnclient.emotes.fabric.Emotes.play(fromPlayerUuid, emote.animation()),
() -> org.saturnclient.emotes.fabric.Emotes.stop(fromPlayerUuid));
}
@Override
@@ -8,12 +8,11 @@ import net.minecraft.client.util.InputUtil;
import org.saturnclient.config.Config;
import org.saturnclient.saturnclient.SaturnClient;
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.ShiftMenu;
// import dev.kosmx.playerAnim.api.layered.AnimationStack;
// import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationAccess;
import org.lwjgl.glfw.GLFW;
/**
@@ -44,12 +43,11 @@ public class KeyInputHandler {
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("");
// }
// Sneaking cancels your own emote, for everyone.
if (SaturnClient.client.player != null && SaturnClient.client.player.isSneaking()
&& Emotes.playing(SaturnClient.client.player.getUuid()).isPresent()) {
Emotes.stop(SaturnClient.client.player.getUuid());
ServiceClient.emote("");
}
});
}
+2 -10
View File
@@ -11,7 +11,6 @@ base {
}
repositories {
// maven { name = "KoSmX Maven"; url = 'https://maven.kosmx.dev/' }
maven { name = "Selimaj"; url = 'https://git.selimaj.dev/api/packages/selimaj-dev/maven' }
}
@@ -24,10 +23,8 @@ dependencies {
// 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}"
// )
// Saturn's emote library (limb bending, Emotecraft emotes)
include modImplementation("org.saturnclient:emotes-fabric:${project.emotes_version}+${project.minecraft_version}")
implementation project(":common")
@@ -37,11 +34,6 @@ dependencies {
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}"
// )
}
/*
+1 -3
View File
@@ -10,12 +10,10 @@ org.gradle.configuration-cache=false
minecraft_version=1.21.8
yarn_mappings=1.21.8+build.1
loader_version=0.19.0
loom_version=1.15-SNAPSHOT
loom_version=1.17.21
fabric_api_version=0.136.1+1.21.8
# Mod Properties
maven_group=org.saturnclient
archives_base_name=saturn-client
# player_anim = 2.0.2+1.21.5
@@ -11,6 +11,7 @@ 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.cosmetics.Emotes;
import org.saturnclient.impl.cosmetics.utils.IdentifierUtils;
import org.saturnclient.saturnclient.SaturnClient;
@@ -22,31 +23,13 @@ public class SaturnProviderImpl implements SaturnProvider {
@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;
// }
if (fromPlayerUuid == null) {
return;
}
// An empty or unknown ID stops whatever the player is playing.
Emotes.get(emoteIdOrNull == null ? "" : emoteIdOrNull).ifPresentOrElse(
emote -> org.saturnclient.emotes.fabric.Emotes.play(fromPlayerUuid, emote.animation()),
() -> org.saturnclient.emotes.fabric.Emotes.stop(fromPlayerUuid));
}
@Override
@@ -8,12 +8,11 @@ import net.minecraft.client.util.InputUtil;
import org.saturnclient.config.Config;
import org.saturnclient.saturnclient.SaturnClient;
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.ShiftMenu;
// import dev.kosmx.playerAnim.api.layered.AnimationStack;
// import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationAccess;
import org.lwjgl.glfw.GLFW;
/**
@@ -44,12 +43,11 @@ public class KeyInputHandler {
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("");
// }
// Sneaking cancels your own emote, for everyone.
if (SaturnClient.client.player != null && SaturnClient.client.player.isSneaking()
&& Emotes.playing(SaturnClient.client.player.getUuid()).isPresent()) {
Emotes.stop(SaturnClient.client.player.getUuid());
ServiceClient.emote("");
}
});
}
+2 -10
View File
@@ -11,7 +11,6 @@ base {
}
repositories {
// maven { name = "KoSmX Maven"; url = 'https://maven.kosmx.dev/' }
maven { name = "Selimaj"; url = 'https://git.selimaj.dev/api/packages/selimaj-dev/maven' }
}
@@ -24,10 +23,8 @@ dependencies {
// 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}"
// )
// Saturn's emote library (limb bending, Emotecraft emotes)
include modImplementation("org.saturnclient:emotes-fabric:${project.emotes_version}+${project.minecraft_version}")
implementation project(":common")
@@ -37,11 +34,6 @@ dependencies {
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}"
// )
}
/*
+1 -3
View File
@@ -10,12 +10,10 @@ org.gradle.configuration-cache=false
minecraft_version=1.21.9
yarn_mappings=1.21.9+build.1
loader_version=0.19.0
loom_version=1.15-SNAPSHOT
loom_version=1.17.21
fabric_api_version=0.134.1+1.21.9
# Mod Properties
maven_group=org.saturnclient
archives_base_name=saturn-client
# player_anim = 2.0.2+1.21.5

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