Legacy Lands Library

repository·main·Indexed 21 days ago

https://github.com/legacylands/legacy-lands-library

A modular toolkit for Minecraft plugin development built on the Fairy Framework, providing high-performance utilities for Spigot, Paper, and Folia environments. It includes an annotation module for automatic processing via AnnotationProcessingService and an AOP module featuring a hybrid proxy pipeline (JDK Dynamic Proxies and ByteBuddy) with built-in aspects for retries, circuit breaking, rate limiting, and security.

Tokens
89.3K
Snippets
219
Records
272
Agent score
71%

What's inside legacy-lands-library

  1. Overview of Task Scheduler (Rust)

    main
    Task Scheduler is a high-performance task execution backend written in Rust. It provides a gRPC service that allows clients to submit tasks (potentially with dependencies) defined via Protocol Buffers. The system leverages Rust's asynchronous capabilities (tokio), concurrency features, and efficient data structures to ensure fast, robust, and scalable task execution. It supports both synchronous and asynchronous task functions, with parameters passed as Protobuf Any messages and decoded into typed Rust values internally.
  2. Use the mongodb module for data storage

    main

    The mongodb module is a wrapper around Morphia designed specifically for Minecraft plugin development. It provides a MongoConfig implementation to simplify setup.

    Note: This module is strictly tied to MongoDB. There is no support for other database types (like MySQL or PostgreSQL) because the design prioritizes MongoDB's schema-less nature, horizontal scalability (sharding), and document model which aligns with the dynamic and complex data structures found in Minecraft.

  3. How AOP proxying works

    main

    The AOP module uses a hybrid proxy pipeline that automatically selects the optimal strategy based on the target type:

    • JDK Dynamic Proxies: Automatically used for interface types.
    • ByteBuddy Class Proxies: Automatically used for concrete classes, which preserves field state through synchronized copy-on-invoke semantics.

    Each plugin maintains its own aspect metadata via ClassLoader Isolation, preventing cross-plugin interference.

    The proxy creation flow follows these steps:

    1. AOPService receives a target object or class.
    2. AspectProxyFactory determines the proxy type (JDK or ByteBuddy).
    3. Applicable interceptors are gathered based on method annotations.
    4. Interceptors are ordered by priority and wrapped into an execution chain.
    5. The proxy is returned for transparent method interception.
  4. Explore the core modules of legacy-lands-library

    main

    The library is composed of several specialized modules. Depending on your needs, you can integrate specific functionalities:

    • foundation: Core testing infrastructure, utilities, and base abstractions.
    • annotation: Annotation processing with flexible scanning and lifecycle management.
    • aop: Aspect-Oriented Programming with ClassLoader isolation (logging, thread safety, performance monitoring).
    • commons: Utilities for VarHandle injection, task/virtual thread scheduling, JSON, and random generation.
    • configuration: Configuration framework built on SimplixStorage with serialization.
    • mongodb: MongoDB integration via Morphia.
    • cache: Multi-tier caching (Caffeine and Redis) with lock management.
    • player: Distributed data management for high-performance entity-relationship networks.
    • script: JavaScript execution engine wrapper supporting Rhino, Nashorn, and V8.
    • experimental/third-party-schedulers: Distributed task processing via gRPC external schedulers (implemented in Rust). Ideal for offloading heavy computations like machine learning or anti-cheat logic to backends that cannot access the Bukkit API.
  5. Use PromptX for AI-assisted development

    main

    PromptX is an AI capability enhancement framework used in this project to manage AI roles and long-term memory. It allows AI agents (primarily Claude Code) to switch into specific professional modes and persist project-specific knowledge, such as module architectures and API designs, to overcome context window limitations.

    Key features include:

    • Role System: Quickly switches the AI to a specific professional mode (e.g., java-backend-developer).
    • Memory Management: Enables the AI to internalize and remember professional knowledge, best practices, and project structures for long-term use.
  6. How the multi-tier cache design works

    main

    The Player module uses a three-tier architecture to balance performance and persistence:

    1. L1 Cache (Caffeine): Local memory cache on each server instance. Provides nanosecond-level performance for online players. Supports automatic expiration and size-based eviction.
    2. L2 Cache (Redis): Distributed cache for hot and shared data. Provides millisecond-level performance and enables cross-server synchronization via distributed locks and Redis Stream message queues.
    3. Persistence Layer (MongoDB): Reliable persistent storage for large datasets and historical data, supporting complex queries and indexing.

    Data Flow:

    • Read Path: L1 (Caffeine) $\rightarrow$ L2 (Redis) $\rightarrow$ Database (MongoDB). Data found in lower tiers automatically populates higher tiers.
    • Write Path: L1 (Caffeine) $\rightarrow$ L2 (Redis) via Redis Stream $\rightarrow$ Database (MongoDB) via scheduled tasks or explicit calls.
  7. Manage variable environments with ScriptScope

    main

    Use ScriptScope to isolate variable environments. This allows you to set, get, and remove variables that are only accessible within a specific execution context, preventing global namespace pollution.

    Note: V8ScriptEngine does not support ScriptScope.

    RhinoScriptEngine scriptEngine = new RhinoScriptEngine();
    RhinoScriptScope scriptScope = RhinoScriptScope.of(scriptEngine);
    
    // Set variables
    scriptScope.setVariable("x", 10);
    scriptScope.setVariable("name", "Legacy");
    
    // Execute in scope
    Object result = scriptEngine.execute("'Hello, ' + name + '! x = ' + x", scriptScope);
    
    // Get/Remove variables
    Object value = scriptScope.getVariable("name");
    scriptScope.removeVariable("name");
  8. Implement Rate Limiting with @RateLimiter

    main

    The @RateLimiter annotation provides multiple strategies to control the rate of requests. It supports different algorithms to handle traffic spikes or maintain constant throughput. You can also implement per-key rate limiting (e.g., per user) using keyExpression and provide fallback methods for when limits are exceeded.

    public interface RateLimitService {
    
        @RateLimiter(limit = 5, period = 1000)
        String fixedWindowOperation(String input);
    
        @RateLimiter(
                limit = 2,
                period = 1000,
                keyExpression = "{#arg0}"
        )
        String perUserOperation(String userId, String data);
    }