Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
3e255aa
Release 5.2.0
rdbtCVS Aug 3, 2026
fcd475d
Use client ctjs api for mixins
rdbtCVS Aug 3, 2026
20b3f2d
Move v5 mixins into ctjs
rdbtCVS Aug 3, 2026
9e01cb0
new rendering
rdbtCVS Aug 3, 2026
b694044
typings
rdbtCVS Aug 3, 2026
916ad5d
fix: delete rdbt-slop; use skija&gizmo not the absurdity he pushed
EpsilonPhoenix Aug 4, 2026
2f41d7e
codex: perf(renderer): reduce Skija frame overhead
rdbtCVS Aug 5, 2026
1651119
codex: optimise pathfinder by 2-3x.
rdbtCVS Aug 5, 2026
2bb1813
codex: optimise pathfinder by 2-3x.
rdbtCVS Aug 5, 2026
1553f5f
fix cache invalidation sorta
rdbtCVS Aug 5, 2026
65ffff5
codex: further optimise pathfinder
rdbtCVS Aug 5, 2026
b88f75f
codex: further optimise pathfinder
rdbtCVS Aug 5, 2026
08a71a6
codex: change double to float for performance improvements in pathfin…
rdbtCVS Aug 7, 2026
760cae7
codex: change double to float for performance improvements in pathfin…
rdbtCVS Aug 7, 2026
6d1a3b5
Refactor RenderUtils -> Render3D and Renderer -> Render2D
rdbtCVS Aug 14, 2026
b0a9541
Merge new renderer into 5.2.0
rdbtCVS Aug 16, 2026
296c6ad
Merge new renderer into 5.2.0
rdbtCVS Aug 16, 2026
339825c
Merge branch '26.1.2' into 5.2.0
rdbtCVS Aug 16, 2026
c09d652
Merge remote-tracking branch 'origin/5.2.0' into 5.2.0
rdbtCVS Aug 16, 2026
d626e3a
Merge remote-tracking branch 'origin/5.2.0' into 5.2.0
rdbtCVS Aug 16, 2026
ba0823f
Remove legacy mod loader support
rdbtCVS Aug 17, 2026
2a85254
codex: 26.2 support
rdbtCVS Aug 18, 2026
22933c7
typings grrr
rdbtCVS Aug 18, 2026
68d28b3
ponytail + testing agents.md
rdbtCVS Aug 18, 2026
f9c723f
codex: optimise rendering
rdbtCVS Aug 19, 2026
4b016db
bump deps
rdbtCVS Aug 19, 2026
2ae7269
add bulk 3d render apis
rdbtCVS Aug 19, 2026
c83cc36
typings upadte
rdbtCVS Aug 19, 2026
e6abc33
ConcurrentHashMap image cache
rdbtCVS Aug 19, 2026
ad43578
optimise text rendering (like 10% gui optimisation)
rdbtCVS Aug 19, 2026
55a7918
codex: add vulkan support
rdbtCVS Aug 19, 2026
8372986
fix background process getting left
rdbtCVS Aug 19, 2026
d62bc70
fix
rdbtCVS Aug 19, 2026
c7e8c63
Pathfinder unloaded chunk warning
rdbtCVS Aug 30, 2026
0a999bb
optimise chunk caching
rdbtCVS Aug 30, 2026
52904d4
optimise chunk caching
rdbtCVS Aug 30, 2026
3156db1
optimise profile hider mixin being always active
rdbtCVS Aug 31, 2026
96b6041
fix music overlay memory leak
rdbtCVS Aug 31, 2026
eeaa54a
optimise chatlib precompute regex
rdbtCVS Aug 31, 2026
bb00f88
fix image rendering memory leak
rdbtCVS Aug 31, 2026
b792198
optimise tooltip register when no register
rdbtCVS Aug 31, 2026
2ff3849
optimise pathfinder, only sync dirty chunks
rdbtCVS Aug 31, 2026
2737e45
Remove chunks from native side mem lek
rdbtCVS Aug 31, 2026
f1360cc
prevent overlapping ct reloads
rdbtCVS Aug 31, 2026
c47ed60
ensure sounds and images are destroyed properly
rdbtCVS Aug 31, 2026
2c4be32
Fix discord rpc child not being killed
rdbtCVS Aug 31, 2026
8d55e25
Add fastEtherwarp callback
rdbtCVS Aug 31, 2026
291a3eb
Add fastEtherwarp callback
rdbtCVS Aug 31, 2026
9c8b1d3
Use github releases for auto updater
rdbtCVS Aug 31, 2026
d105631
fix proxy dupe glitch
rdbtCVS Aug 31, 2026
23c61c9
Add text caching to rendering
rdbtCVS Sep 1, 2026
0517582
codex: hopefully stop orphan ctjs processes
rdbtCVS Sep 1, 2026
84be2b2
clean up code
rdbtCVS Sep 2, 2026
282af4e
clean up code
rdbtCVS Sep 2, 2026
9c993e8
fix /ct load regression
rdbtCVS Sep 2, 2026
cb2a840
auth this auth that idk what im doing
rdbtCVS Sep 3, 2026
ea3fd26
fix mod compatabilities in 26.2 ig??
rdbtCVS Sep 5, 2026
92c0400
fix: ProfileHider (fps issues, animation issues, and also general
EpsilonPhoenix Sep 6, 2026
d00513a
Move irc into kotlin side
rdbtCVS Sep 8, 2026
07f5090
Remove welcome screen
rdbtCVS Sep 9, 2026
f1947f1
combine auth shit
rdbtCVS Sep 9, 2026
1a44780
clean up shit
rdbtCVS Sep 9, 2026
6de905e
Allow support for unauthed connections
rdbtCVS Sep 12, 2026
b38f59a
fix background text rendering
rdbtCVS Sep 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 19 additions & 13 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ permissions:

jobs:
build:
name: Build
name: Build Minecraft ${{ matrix.minecraft }}
runs-on: blacksmith-4vcpu-ubuntu-2404
strategy:
matrix:
minecraft: [26.1.2, 26.2]

steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
Expand All @@ -29,7 +32,7 @@ jobs:
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
with:
distribution: temurin
java-version: 21
java-version: 25

- uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
Expand All @@ -41,18 +44,18 @@ jobs:
${{ runner.os }}-gradle-

- name: Build
run: ./gradlew --no-daemon build -PreleaseBuild
run: ./gradlew --no-daemon :${{ matrix.minecraft }}:build -PreleaseBuild

- name: Upload Loader
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: V5-Loader-26.1.2
path: build/libs/V5-Loader-26.1.2.jar
name: V5-Loader-${{ matrix.minecraft }}
path: versions/${{ matrix.minecraft }}/build/libs/V5-Loader-${{ matrix.minecraft }}.jar
if-no-files-found: error

publish:
needs: build
if: ${{ github.ref == 'refs/heads/26.1.2' }}
if: ${{ github.ref == 'refs/heads/26.1.2' || github.ref == 'refs/heads/26.2' }}
runs-on: blacksmith-4vcpu-ubuntu-2404
permissions:
contents: write
Expand All @@ -65,24 +68,24 @@ jobs:
- name: Download Loader
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: V5-Loader-26.1.2
pattern: V5-Loader-*
path: build/libs
merge-multiple: true

- name: Publish GitHub release
env:
GH_TOKEN: ${{ github.token }}
SHA: ${{ inputs.sha || github.sha }}
run: |
version=$(sed -nE 's/^[[:space:]]*const val MOD_VERSION = "([^"]+)".*/\1/p' src/main/kotlin/com/chattriggers/ctjs/CTJS.kt)
test -n "$version"
version=$(./gradlew -q :26.2:printVersion)
prefix="${version//./\\.}-r"
tag=$(gh api --paginate "repos/$GITHUB_REPOSITORY/releases?per_page=100" --jq ".[] | select(.target_commitish == \"$SHA\") | .tag_name" | sed -nE "s/^${prefix}[0-9]+$/&/p" | head -n1)
if [ -z "$tag" ]; then
revision=$(gh release list --limit 1000 --json tagName --jq '.[].tagName' | sed -nE "s/^${prefix}([0-9]+)$/\1/p" | sort -n | tail -n1)
tag="${version}-r$(( ${revision:-0} + 1 ))"
gh release create "$tag" --target "$SHA" --title "$tag" --generate-notes
fi
gh release upload "$tag" build/libs/V5-Loader-26.1.2.jar --clobber
gh release upload "$tag" build/libs/V5-Loader-*.jar --clobber

- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
Expand All @@ -97,6 +100,9 @@ jobs:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
run: |
sha256sum build/libs/V5-Loader-26.1.2.jar | awk '{print $1}' > V5-Loader-26.1.2.jar.sha256
wrangler r2 object put v5-builds/V5-Loader-26.1.2.jar.sha256 --file V5-Loader-26.1.2.jar.sha256 --remote
wrangler r2 object put v5-builds/V5-Loader-26.1.2.jar --file build/libs/V5-Loader-26.1.2.jar --remote
for jar in build/libs/V5-Loader-*.jar; do
name=$(basename "$jar")
sha256sum "$jar" | awk '{print $1}' > "$name.sha256"
wrangler r2 object put "v5-builds/$name.sha256" --file "$name.sha256" --remote
wrangler r2 object put "v5-builds/$name" --file "$jar" --remote
done
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,6 @@ replay_*.log
*.jfr

versions/*/api/
versions/*/logs/

grunt-main.jar
grunt-main.jar
42 changes: 42 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Repository Guidelines

## Coding Style

You are a lazy senior developer. Lazy means efficient, not careless. The best code is the code never written.

Before writing any code, stop at the first rung that holds:

Does this need to be built at all? (YAGNI)
Does it already exist in this codebase? Reuse the helper, util, or pattern that's already here, don't re-write it.
Does the standard library already do this? Use it.
Does a native platform feature cover it? Use it.
Does an already-installed dependency solve it? Use it.
Can this be one line? Make it one line.
Only then: write the minimum code that works.
The ladder runs after you understand the problem, not instead of it: read the task and the code it touches, trace the real flow end to end, then climb.

Bug fix = root cause, not symptom: a report names a symptom. Grep every caller of the function you touch and fix the shared function once — one guard there is a smaller diff than one per caller, and patching only the path the ticket names leaves a sibling caller still broken.

Rules:

No abstractions that weren't explicitly requested.
No new dependency if it can be avoided.
No boilerplate nobody asked for.
Deletion over addition. Boring over clever. Fewest files possible.
Shortest working diff wins, but only once you understand the problem. The smallest change in the wrong place isn't lazy, it's a second bug.
Question complex requests: "Do you actually need X, or does Y cover it?"
Pick the edge-case-correct option when two stdlib approaches are the same size, lazy means less code, not the flimsier algorithm.
Mark deliberate simplifications that cut a real corner with a known ceiling (global lock, O(n²) scan, naive heuristic) with a ponytail: comment naming the ceiling and upgrade path.
Not lazy about: understanding the problem (read it fully and trace the real flow before picking a rung, a small diff you don't understand is just laziness dressed up as efficiency), input validation at trust boundaries, error handling that prevents data loss, security, accessibility, the calibration real hardware needs (the platform is never the spec ideal, a clock drifts, a sensor reads off), anything explicitly requested. Lazy code without its check is unfinished: non-trivial logic leaves ONE runnable check behind, the smallest thing that fails if the logic breaks (an assert-based demo/self-check or one small test file; no frameworks, no fixtures). Trivial one-liners need no test.

## Build, Test, and Development Process

- `./gradlew build` — compile all supported Minecraft versions and produces `versions/<version>/build/libs/V5-Loader-DEV-<version>.jar`.
- `./gradlew generateTypings` — regenerate `typing-generator/src/main/resources/typings.d.ts` after exported API changes.

## Testing Guidelines

Do not implement any testing coverage.
Before finishing, run `./gradlew build` only, do not use any other gradlew commands for confirming build status.
Changes affecting API should run `./gradlew generateTypings`. NEVER manually edit the `typings.d.ts` file EVER.
For native changes, rebuild with CMake for local only; Automated workflows will handle building all natives on push.
2 changes: 1 addition & 1 deletion NativeSrc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,5 @@ set_target_properties(V5PathJNI PROPERTIES
if (MSVC)
target_compile_options(V5PathJNI PRIVATE /O2 /EHsc)
else()
target_compile_options(V5PathJNI PRIVATE -O3 -fvisibility=hidden -fvisibility-inlines-hidden)
target_compile_options(V5PathJNI PRIVATE -O3)
endif()
62 changes: 32 additions & 30 deletions NativeSrc/src/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,40 +50,42 @@ inline uint64_t chunkKey(const int x, const int z) {
return (px << 32) | pz;
}

struct ActionCosts {
static constexpr double INF_COST = 1e6;
static constexpr double FLY_ONE_BLOCK_TIME = 1.0 / 0.7;
static constexpr double SPRINT_ONE_BLOCK_TIME = 1.0 / 0.2806;
static constexpr double SPRINT_DIAGONAL_TIME = SPRINT_ONE_BLOCK_TIME * 1.4142135623730951;
static constexpr double MOMENTUM_LOSS_PENALTY = 6.0;
static constexpr double JUMP_PENALTY = 2.0;
static constexpr double GAP_JUMP_REWARD_OFFSET = 1.5;
static constexpr double SLAB_ASCENT_TIME = SPRINT_ONE_BLOCK_TIME * 1.1;
static constexpr double WALK_OFF_EDGE_TIME = SPRINT_ONE_BLOCK_TIME * 0.5;
static constexpr double LAND_RECOVERY_TIME = 2.0;
static constexpr double JUMP_UP_ONE_BLOCK_TIME = 28.0 + MOMENTUM_LOSS_PENALTY + SPRINT_ONE_BLOCK_TIME;

std::array<double, 257> fallTimes{};
constexpr std::array<float, 257> makeFallTimes() {
std::array<float, 257> fallTimes{};
float currentDistance = 0.0f;
int tick = 0;
float velocity = 0.0f;

ActionCosts() {
double currentDistance = 0.0;
int tick = 0;
double velocity = 0.0;

for (int targetDistance = 1; targetDistance <= 256; targetDistance++) {
while (currentDistance < targetDistance) {
velocity = (velocity - 0.08) * 0.98;
currentDistance -= velocity;
tick++;
}
fallTimes[static_cast<size_t>(targetDistance)] = static_cast<double>(tick);
for (int targetDistance = 1; targetDistance <= 256; targetDistance++) {
while (currentDistance < targetDistance) {
velocity = (velocity - 0.08f) * 0.98f;
currentDistance -= velocity;
tick++;
}
fallTimes[static_cast<size_t>(targetDistance)] = static_cast<float>(tick);
}
return fallTimes;
}

struct ActionCosts {
static constexpr float INF_COST = 1e6f;
static constexpr float FLY_ONE_BLOCK_TIME = 1.0f / 0.7f;
static constexpr float SPRINT_ONE_BLOCK_TIME = 1.0f / 0.2806f;
static constexpr float SPRINT_DIAGONAL_TIME = SPRINT_ONE_BLOCK_TIME * 1.41421356f;
static constexpr float MOMENTUM_LOSS_PENALTY = 6.0f;
static constexpr float JUMP_PENALTY = 2.0f;
static constexpr float GAP_JUMP_REWARD_OFFSET = 1.5f;
static constexpr float SLAB_ASCENT_TIME = SPRINT_ONE_BLOCK_TIME * 1.1f;
static constexpr float WALK_OFF_EDGE_TIME = SPRINT_ONE_BLOCK_TIME * 0.5f;
static constexpr float LAND_RECOVERY_TIME = 2.0f;
static constexpr float JUMP_UP_ONE_BLOCK_TIME = 28.0f + MOMENTUM_LOSS_PENALTY + SPRINT_ONE_BLOCK_TIME;

inline static constexpr auto FALL_TIMES = makeFallTimes();

[[nodiscard]] double getFallTime(const int blocks) const {
if (blocks <= 0) return 0.0;
if (blocks >= static_cast<int>(fallTimes.size())) return INF_COST;
return fallTimes[static_cast<size_t>(blocks)] + LAND_RECOVERY_TIME;
[[nodiscard]] static float getFallTime(const int blocks) {
if (blocks <= 0) return 0.0f;
if (blocks >= static_cast<int>(FALL_TIMES.size())) return INF_COST;
return FALL_TIMES[static_cast<size_t>(blocks)] + LAND_RECOVERY_TIME;
}
};

Expand Down
4 changes: 2 additions & 2 deletions NativeSrc/src/etherwarp_search.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ struct SimplifiedEtherwarpPath {

struct SharedState {
explicit SharedState(const int reserveTarget)
: heap(nodeF, nodeHeapPos) {
: heap(nodeF, nodeH, nodeG, nodeHeapPos) {
nodeX.reserve(static_cast<size_t>(reserveTarget));
nodeY.reserve(static_cast<size_t>(reserveTarget));
nodeZ.reserve(static_cast<size_t>(reserveTarget));
Expand Down Expand Up @@ -135,7 +135,7 @@ struct SharedState {
std::vector<float> nodePitch;
std::vector<int> nodeHeapPos;
std::unordered_map<uint64_t, int> coordToNode;
detail::Heap heap;
detail::Heap<double> heap;

int iterations = 0;
int activeExpanders = 0;
Expand Down
Loading
Loading