creative Java Library

repository·main·Indexed 42 days ago

https://github.com/unnamed/creative

A Java library for Minecraft: Java Edition developers to programmatically create, validate, and optimize resource packs. It enables the customization of textures, models, sounds, translations, and fonts while ensuring packs are compact and bug-free. The library is server-agnostic and supports Kyori's adventure for text components.

Tokens
10.3K
Snippets
44
Records
50
Agent score
52%

What's inside creative

  1. Overview of the creative library

    main
    The creative library is a resource-pack library for Minecraft: Java Edition. It provides a programmatic way to customize Minecraft resource packs, including textures, models, sounds, translations, splashes, credits, and fonts, without modifying the default Minecraft client. It is designed to help developers safely create resource packs, identify bugs within them, and generate the most compact version possible.
  2. Overview of Creative Server

    main

    The creative-server is a fast, lightweight, and specialized HTTP(s) server designed specifically for serving Minecraft: Java Edition resource-packs. It functions by parsing the metadata sent by vanilla Minecraft clients during the resource-pack request process.

    Key capabilities include:

    • Dynamic Resource-Pack Delivery: Return different resource-packs based on client metadata such as player language, Minecraft version, or client name.
    • Client Filtering: Automatically ignore or block non-Minecraft clients (e.g., web browsers) to ensure only game clients access the assets.
  3. Key features of the creative library

    main

    The creative library provides the following capabilities:

    • Programmatic Management: Create, verify, and serve resource packs via code.
    • Optimization: Generates highly compact resource packs by reducing file sizes where possible.
    • Adventure Support: Uses and supports Kyori's adventure for text components.
    • Server Agnostic: It is a library for vanilla Minecraft: Java Edition and does not depend on specific server implementations (works with Spigot, Paper, Waterfall, BungeeCord, Velocity, etc.).
  4. Use Unitary Serialization for individual elements

    main

    Experimental Feature

    Minecraft serializers allow for element-specific serialization/deserialization of individual resource pack components (e.g., fonts, languages) rather than the whole pack.

    Note: This feature is experimental and may change significantly in future major releases.

    Deserializing a font

    Use FontSerializer.INSTANCE.deserialize with a Readable.resource to load a font from the classpath.

    Serializing a language

    Use LanguageSerializer.INSTANCE.serialize to write a Language object to an OutputStream.

    // Deserializing a font
    Font font = FontSerializer.INSTANCE.deserialize(
        Readable.resource(getClass().getClassLoader(), "font.json"),
        Key.key("custom:fontkey")
    );
    
    // Serializing a language
    Language language = ...;
    try (OutputStream output = new FileOutputStream("es.json")) {
        LanguageSerializer.INSTANCE.serialize(language, output);
    }
  5. How Font Providers and Fonts work together

    main

    A Font is a composite object made by merging multiple FontProvider instances. While a single provider might handle specific characters (like a BitMap provider for emojis or a TrueType provider for standard text), the Font object acts as the unified interface for those characters. You create a Font by providing a unique Key and a list of FontProvider objects.

    Font font = Font.font(
        Key.key("namespace", "my_font"),
        fontProvider1,
        fontProvider2,
        ...
    );
  6. How `SoundEvent` and `SoundEntry` work together

    main

    A SoundEvent is a named collection of SoundEntry objects. This is the abstraction used in-game. When a SoundEvent is triggered, the system randomly selects one of its associated SoundEntry objects based on their weight property.

    To use a SoundEvent, you must register it with your ResourcePack using resourcePack.soundEvent(soundEvent).

    SoundEvent soundEvent = SoundEvent.soundEvent()
            .key(Key.key("creative:creative.cat.meow"))
            .sounds(
                    soundEntry1,
                    soundEntry2,
                    soundEntry3
            )
            .replace(false)
            .build();
    
    ResourcePack resourcePack = ...;
    resourcePack.soundEvent(soundEvent);
  7. Build a ResourcePackServer

    main

    Use the ResourcePackServer.server() builder to configure and instantiate a server. You must provide an address/port and a resource pack to serve.

    Important Configuration Notes:

    • Executor: If you do not provide an .executor(...), requests will be processed synchronously (blocking). It is highly recommended to provide a multithreaded executor, such as Executors.newFixedThreadPool(n), to allow concurrent request processing.
    • Handler Path: You can customize the endpoint using .path(String). The default is /.
    • Request Handling: The .pack(ResourcePack) method can be replaced with .handler(...) if you wish to implement custom request handling logic.
    ResourcePackServer server = ResourcePackServer.server()
            .address("127.0.0.1", 7270) // (required) address and port
            .pack(ResourcePack) // (required) pack to serve
            .executor(Executor) // (optional) request executor (IMPORTANT!)
            .secure(...) // (optional) SSL/TLS configuration
            .path("/get/") // (optional) handler path, default = "/"
            .build();
  8. Install creative using Gradle

    main

    Add the following dependencies to your build.gradle or build.gradle.kts file. It is recommended to use the creative-api as the core dependency. Depending on your use case, you may also need the Minecraft serializer or the resource pack server module. All modules are available on Maven Central.

    dependencies {
        implementation("team.unnamed:creative-api:%%REPLACE_latestRelease{team.unnamed:creative-api}%%")
    
        // Serializer for Minecraft format (ZIP / Folder)
        implementation("team.unnamed:creative-serializer-minecraft:%%REPLACE_latestRelease{team.unnamed:creative-serializer-minecraft}%%")
    
        // Resource Pack server
        implementation("team.unnamed:creative-server:%%REPLACE_latestRelease{team.unnamed:creative-server}%%")
    }
  9. Enable multithreaded request processing with Executor

    main

    By default, ResourcePackServer executes handlers in a single thread (the thread that receives the request). This means long-running handlers will block subsequent requests.

    To allow concurrent request processing, configure a custom Executor using the .executor(Executor) method during server construction. This allows the server to process multiple requests simultaneously across different threads.

    ResourcePackServer server = ResourcePackServer.server()
            .address("127.0.0.1", 7270)
            .handler(handler)
            .executor(Executors.newFixedThreadPool(8)) // uses 8 threads for concurrent processing
            .build();
  10. Merge two ResourcePacks using ResourcePack#merge

    main

    You can combine the contents of two ResourcePack instances into one using the ResourcePack#merge(ResourcePack, MergeStrategy) method. This operation modifies the base ResourcePack to include the resources from the second pack according to the specified MergeStrategy.

    // get our resource packs
    ResourcePack base = ...;
    ResourcePack other = ...;
    
    // merge
    base.merge(other, MergeStrategy.override());
    
    // now base contains all the resources from other