Skip to content

refactor: Migrate from Static ASM Patcher to Runtime ByteBuddy Agent#9

Merged
sanasol merged 77 commits intosanasol:masterfrom
soyelmismo:master
Feb 8, 2026
Merged

refactor: Migrate from Static ASM Patcher to Runtime ByteBuddy Agent#9
sanasol merged 77 commits intosanasol:masterfrom
soyelmismo:master

Conversation

@soyelmismo
Copy link
Copy Markdown
Contributor

@soyelmismo soyelmismo commented Feb 5, 2026

This PR represents a major architectural shift from the static DualAuthPatcher (raw ASM) to a dynamic Java Agent using ByteBuddy.

This migration solves several critical limitations of the static patcher approach while significantly improving maintainability, performance, and stability.

Key Changes & Benefits:

  • 📉 40% Codebase Reduction: By moving from raw bytecode manipulation to ByteBuddy's declarative API, we drastically reduced code volume and cognitive load. The logic is now readable Java, making it easier for future maintainers (and LLMs) to understand.
  • 🛡️ Non-Destructive / Runtime Patching:
    • Old Way: Modified the physical HytaleServer.jar on disk. Required re-patching after every game update.
    • New Way: Intercepts classes in memory as they load. The original JAR remains pristine. This is ideal for containerized environments (Docker/Kubernetes).
  • 🧵 Robust Context Propagation: The Agent approach allows for much tighter integration with the JVM's lifecycle. We implemented specialized transformers for Async/Netty handlers that properly maintain the authentication context (Omni-Auth/F2P) across thread boundaries, solving previous leakage issues.
  • ⚡ Type-Safe Implementation: No more fragile frame calculation or guessing stack sizes. ByteBuddy handles the heavy lifting of valid bytecode generation.
  • 🔄 Omni-Auth 2.0: Integrated EmbeddedJwkVerifier directly into the validation pipeline using Advice hooks, bypassing strict nimbus-jose checks without needing to rewrite entire methods.

Architecture Overview:

  1. Transformers: Each patching target (JWTValidator, SessionServiceClient, etc.) now has its own isolated Transformer class in com.hytale.dualauth.agent.transformers.
  2. Context: DualAuthContext uses ThreadLocal variables but now utilizes "Reset Hooks" on Netty channel reads to ensure a clean slate for every incoming connection.
  3. Discovery: New DualJwksFetcher logic now includes smart caching and automatic issuer detection for Federated setups.

Verification:
Tested against the latest Hytale server build. Verified successful connections from:

  • (Official Hytale Client)
  • F2P/Custom Clients (sanasol.ws).
  • Self-Hosted/Decentralized Clients (Omni-Auth w/ Embedded JWKs).

🚀 How to Execute (The Migration Guide)

Since this changes the deployment method, here are the new instructions for building and running the DualAuth Agent.

1. Build the Agent

Prerequisites: JDK 21+ and an internet connection (for Gradle dependencies).

# Linux / MacOS
cd dualauth-agent
./gradlew shadowJar

# Windows
cd dualauth-agent
gradlew.bat shadowJar

This produces a jar file at: build/libs/dualauth-agent.jar

(Updated the github actions workflow to make a release of the dualauth-agent.jar, so launchers can fetch it from the repo)

2. Run the Server (Non-Destructive)

Do not use the old patched JAR. Use the original, unmodified HytaleServer.jar. The agent applies the magic at runtime.

# General Syntax
java -javaagent:./dualauth-agent/build/libs/dualauth-agent-1.0.0.jar -jar HytaleServerOriginal.jar

# With arguments (Docker/Production example)
java -Xmx2G \
  -javaagent:dualauth-agent.jar \
  -jar HytaleServer.jar \
  -- --bind 0.0.0.0:25565 --auth-mode authenticated

3. Configuration (Environment Variables)

The agent accepts the same configuration as the old patcher

Variable Description
HYTALE_AUTH_DOMAIN Target F2P Auth domain (e.g., auth.sanasol.ws)
HYTALE_TRUST_ALL_ISSUERS true to enable Omni-Auth (embedded keys), false to restrict.
dualauth.debug Set to true (system property) to see verbose transformer logs.

4. Comparison Check (Verification)

To verify the agent is working, watch the console logs during startup:

image
[DualAuth] ByteBuddy Agent Installed Successfully.
[DualAuth] Waiting for Hytale Server classes to load...
[DualAuth] ✓ TRANSFORMED: com.hypixel.hytale.server.core.auth.JWTValidator
[DualAuth] ✓ TRANSFORMED: com.hypixel.hytale.server.core.auth.SessionServiceClient
...
[DualAuth] F2P tokens stored in manager

If you see these checks, the logic was migrated successfully.

soyelmismo added 30 commits February 3, 2026 08:57
- Removes all hardcoded F2P domains (sanasol.ws, etc.) from the internal logic.
- Implements a two-tier priority system for server identity:
    1. Primary (Pre-fetched): Official hytale.com and the user-defined HYTALE_AUTH_DOMAIN.
    2. Dynamic (On-demand): Any other incoming issuer is resolved via a secondary cache layer.
- Refined routing logic:
    - Standard flows use pre-fetched tokens.
    - Omni-Auth tokens (embedded private keys) use self-signing bypass.
    - Unknown Public issuers now trigger a dynamic /server/auto-auth fetch instead of
      failing with an empty-key self-sign error. These issuers need to follow the
      sanasol/hytale-auth-server /auto-auth API endpoint standard.
@sanasol
Copy link
Copy Markdown
Owner

sanasol commented Feb 5, 2026

😮

@soyelmismo
Copy link
Copy Markdown
Contributor Author

soyelmismo commented Feb 6, 2026

added a logs beautifier so its easier to not get lost in all that printed messages... or so

image

@sanasol sanasol merged commit 4bc7dae into sanasol:master Feb 8, 2026
4 checks passed
@sanasol
Copy link
Copy Markdown
Owner

sanasol commented Feb 8, 2026

Tested, seems to be working for all cases.

Updated Hytale F2P to work with it: amiayweb/Hytale-F2P#277
Updated pterodactyl eggs, docker scripts and fresh image published: https://github.com/sanasol/hytale-server-docker

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants