Guide

Kotlin e Java

Per le mod grandi. La stessa API di CraftScript, con tipi statici, l’IDE completo e qualsiasi libreria Java, più alcune parti che per ora esistono solo qui. Questa guida usa Kotlin; Java funziona allo stesso modo ed è mostrato alla fine.

Cosa puoi fare

Ambito Nell’API In CraftScript
Oggetti, blocchi, ricette ContentBuilder: item, block, shaped, shapeless, smelting Sì
Creature ContentBuilder.creature: corpo, texture, statistiche, Behaviour, TargetRule, bottino, comparsa naturale, addomesticamento, allevamento, cavalcata, comportamenti propri Sì
Suoni e particelle ContentBuilder.sound, ContentBuilder.particle Sì
Generazione del mondo ContentBuilder: ore, tree, patch, structure (pool, plan/build), biome, dimension, feature, terrain, biomes, carver, tag. Vedi Generazione del mondo e Generazione tramite codice Tutto tranne feature, tag, salt e aboveBottom
Interfaccia Form e player.showForm; server.bossBar; player.setSidebar Sì
Eventi Crafting.events.on<E> { }, con priorità e annullamento Sì
Effetti, attributi, equipaggiamento addEffect, attribute, setAttribute, equipment, setEquipment, EquipmentSlot Yes
Tasti ContentBuilder.key, PlayerKeyEvent Yes
Comandi Crafting.commands.command(…): sottocomandi, argomenti tipizzati, permessi, alias Sì
Mondo e giocatori World, Block, Entity, Player, Inventory, Server Sì
Attività Crafting.scheduler: runLater, runRepeating, runAsync, runSync Senza lavoro in background
Impostazioni su file Config tipizzata in TOML, sincronizzabile con i client Sì (config)
Rete Crafting.network.channel(…), con codec personalizzati Sì (listen, send)
Dati salvati player.data["rubies.visits"] = n, data.getInt(…); anche su entità, blocchi e mondi Sì
Librerie Java Qualsiasi No

Ciò che l’API non ha ancora non esiste in nessun linguaggio. Non aggirarlo chiamando classi di Minecraft: la mod perderebbe la garanzia di continuare a funzionare quando il gioco cambia.

Crea il progetto

Terminale
crafting new rubies --kind kotlin
cd rubies && gradle build

L’API non è ancora in un repository Maven pubblico. Installala nel tuo Maven locale dal codice sorgente di Crafting e dichiarala come compileOnly: è Crafting a fornirla alla mod in esecuzione.

Terminale
cd crafting && ./gradlew :crafting-api:publishToMavenLocal
build.gradle.ktsKotlin
plugins { kotlin("jvm") version "2.4.21" }

repositories { mavenCentral(); mavenLocal() }

dependencies {
    compileOnly("dev.crafting:crafting-api:0.1.0")
}

kotlin { jvmToolchain(25) } // Minecraft 26.x funziona con Java 25

crafting new genera questo file e un progetto già diviso per responsabilità: <Name>Mod.kt, che si limita a collegare le parti, content/ModContent.kt, events/Welcome.kt e commands/GemCommand.kt.

Struttura

Package per tema, una classe di ingresso che si limita a collegare le parti e un file per parte. La guida Organizzare una mod spiega perché; ecco la mod di esempio completa:

StrutturaTesto
rubies/
├── build.gradle.kts
├── settings.gradle.kts
└── src/main/
    ├── kotlin/com/example/rubies/
    │   ├── RubiesMod.kt         entry point: only wires the parts
    │   ├── RubiesConfig.kt      player settings
    │   ├── content/
    │   │   ├── Items.kt
    │   │   ├── Blocks.kt
    │   │   ├── Creatures.kt
    │   │   ├── Sounds.kt
    │   │   ├── Particles.kt
    │   │   └── Recipes.kt
    │   ├── storage/
    │   │   └── Visits.kt        saved data: the keys, in one place
    │   ├── events/
    │   │   ├── MiningEvents.kt
    │   │   ├── CombatEvents.kt
    │   │   └── WelcomeEvents.kt
    │   ├── ui/
    │   │   └── ShopForm.kt       forms: what the player sees
    │   └── commands/
    │       ├── RubyCommand.kt
    │       └── ShopCommand.kt
    └── resources/
        ├── crafting.mod.json
        └── assets/rubies/
            ├── sounds/ruby/chime.ogg
            └── textures/
                ├── item/ruby.png
                ├── entity/ruby_golem.png
                └── particle/ruby_spark_0.png, ruby_spark_1.png

src/main/kotlin/com/example/rubies/

La classe di ingresso non fa nulla da sola: crea ciò che è condiviso e chiama ogni parte.

src/main/kotlin/com/example/rubies/RubiesMod.ktKotlin
package com.example.rubies

class RubiesMod : CraftingMod {
    override fun onLoad(ctx: ModContext) {
        val config = Crafting.configs.load(RubiesConfig())
        val content = ContentBuilder(ctx.metadata.id, Crafting.registries)

        Items.register(content)
        Blocks.register(content)
        Creatures.register(content)
        Sounds.register(content)
        Particles.register(content)
        Recipes.register(content)

        MiningEvents.register(config)
        CombatEvents.register(config)
        WelcomeEvents.register()
        RubyCommand.register()
        ShopCommand.register()
    }
}

Il manifest

src/main/resources/crafting.mod.jsonJSON
{
  "id": "rubies",
  "name": "Rubies",
  "version": "1.0.0",
  "kind": "mod",
  "side": "both",
  "entrypoints": ["com.example.rubies.RubiesMod"],
  "depends": { "crafting": ">=0.1.0" }
}
Campo Cos’è
id 2–64 caratteri: lettere minuscole, cifre, _ o -, che inizia con una lettera. È anche il namespace dei tuoi oggetti e blocchi.
kind mod o plugin (solo server, ricaricabile; vedi sotto).
side both, client o server. Una mod client viene ignorata senza avvisi su un server dedicato.
entrypoints Le classi che implementano CraftingMod.
depends, optional, incompatible Id → intervallo di versioni: >=1.2 <2, ^1.4, ~1.4.2, 1.20.x, [1.0,2.0). Se qualcosa non va, Crafting segnala tutti i problemi insieme, con un suggerimento.
loadAfter, loadBefore Ordine di caricamento senza una dipendenza obbligatoria.

Ciclo di vita

dev.crafting.api.mod.CraftingModKotlin
interface CraftingMod {
    fun onLoad(ctx: ModContext)
    fun onReady(ctx: ModContext) {}
    fun onShutdown(ctx: ModContext) {}
}
  1. onLoad: registra contenuti, eventi e comandi.
  2. Crafting crea i blocchi e gli oggetti nel gioco. Da questo momento, registrare contenuti lancia RegistryFrozenException.
  3. onReady: tutte le mod sono caricate; Crafting.runtime.isModLoaded("other_mod") ti dice se un’altra mod è presente.
  4. onShutdown: all’uscita.

Plugin per server

Un plugin è una CraftingMod con "kind": "plugin" e "side": "server"; crafting new chatguard --kind plugin crea la classe di ingresso, events/ChatFilter.kt e commands/HelloCommand.kt. Non aggiunge blocchi né oggetti, quindi i giocatori con Minecraft senza mod possono entrare in un server che ha solo plugin. Lo attivi, lo disattivi e lo ricarichi senza riavviare: onLoad e onReady vengono eseguiti quando viene attivato, onShutdown quando viene disattivato o ricaricato.

Terminale
crafting new chatguard --kind plugin
src/main/kotlin/com/example/chatguard/ChatGuardPlugin.ktKotlin
package com.example.chatguard

class ChatGuardPlugin : CraftingMod {
    override fun onLoad(ctx: ModContext) {
        ChatFilter.register()
        Crafting.commands.command("guard") {
            permission = "chatguard.admin"
            executes { it.reply("ChatGuard è attivo") }
        }
    }

    override fun onShutdown(ctx: ModContext) = ctx.logger.info("ChatGuard disabled")
}
src/main/kotlin/com/example/chatguard/events/ChatFilter.ktKotlin
package com.example.chatguard.events

object ChatFilter {
    private val blocked = listOf("spam", "scam")

    fun register() {
        Crafting.events.on<PlayerChatEvent> { e ->
            if (blocked.any { it in e.message.lowercase() }) {
                e.cancel()
                e.player.send("&cResta gentile, per favore")
            }
        }
    }
}

Tutto ciò che un plugin registra è legato a esso. /crafting reload chatguard chiama onShutdown, rimuove i suoi listener, comandi e attività, rilegge il jar e chiama onLoad. In modalità sviluppo succede automaticamente quando sostituisci il jar.

Mod Plugin
Cartella mods/ plugins/
Lato Client e/o server Solo server
Nuovi blocchi e oggetti Sì No
Ricarica senza riavvio No Sì
Possono entrare client senza mod No, se aggiunge contenuti Sì

Java

Stessa API, stessa struttura. Da Java, il punto di ingresso è Crafting.INSTANCE, passi ogni parametro che ha un valore predefinito e un listener restituisce Unit.INSTANCE:

src/main/java/com/example/rubies/RubiesMod.javaJava
package com.example.rubies;

public final class RubiesMod implements CraftingMod {
    @Override
    public void onLoad(ModContext ctx) {
        ContentBuilder content = new ContentBuilder(ctx.getMetadata().getId(), Crafting.INSTANCE.getRegistries());
        Items.register(content);
        WelcomeEvents.register();
    }
}
src/main/java/com/example/rubies/events/WelcomeEvents.javaJava
package com.example.rubies.events;

public final class WelcomeEvents {
    public static void register() {
        Crafting.INSTANCE.getEvents().subscribe(PlayerJoinEvent.class, EventPriority.NORMAL, false, null, e -> {
            e.getPlayer().send("&aWelcome, " + e.getPlayer().getName() + "!");
            return Unit.INSTANCE;
        });
    }
}

Modi vecchi

Funzionano ancora, ma sono segnati come deprecati e hanno un sostituto:

Prima Ora
class X : CraftingPlugin() con onEnable/onDisable CraftingMod con "kind": "plugin"
Metodi con @Subscribe e events.register(obj) events.on<E> { } (Java: events.subscribe(E.class, …))
@Mod("id") sulla classe La classe negli entrypoints del manifest
EntityDamageEvent.source damageType (un id, come minecraft:fall)
world.setBlockState(x, y, z, "…[open=true]") world.setBlock(x, y, z, type, mapOf("open" to true))

Regole

  • Non importare nulla da net.minecraft. È questo che permette alla mod di continuare a funzionare quando il gioco cambia.
  • Registra i contenuti solo in onLoad.
  • Un’attività runAsync non tocca il mondo; torna al thread del gioco con runSync.