Mga gabay
Kotlin at Java
Para sa malalaking mod. Parehong API ng CraftScript, may static type, buong IDE at anumang Java library, at ilang bahagi na dito lang muna meron. Kotlin ang ginagamit ng gabay na ito; pareho ang paraan sa Java at ipinapakita ito sa dulo.
Ang kaya mong gawin
| Bahagi | Sa API | Sa CraftScript |
|---|---|---|
| Mga item, block, recipe | ContentBuilder: item, block, shaped, shapeless, smelting |
Oo |
| Mga nilalang | ContentBuilder.creature: katawan, texture, stats, Behaviour, TargetRule, loot, kusang paglitaw, pagpapaamo, pagpaparami, pagsakay, sariling behaviour |
Oo |
| Mga tunog at partikulo | ContentBuilder.sound, ContentBuilder.particle |
Oo |
| World generation | ContentBuilder: ore, tree, patch, structure (mga pool, plan/build), biome, dimension, feature, terrain, biomes, carver, tag. Tingnan ang World generation at Paglikha gamit ang code |
Lahat maliban sa feature, tag, salt at aboveBottom |
| Interface | Form at player.showForm; server.bossBar; player.setSidebar |
Oo |
| Mga kaganapan | Crafting.events.on<E> { }, may priority at cancellation |
Oo |
| Mga effect, attribute, kagamitan | addEffect, attribute, setAttribute, equipment, setEquipment, EquipmentSlot |
Yes |
| Mga key | ContentBuilder.key, PlayerKeyEvent |
Yes |
| Mga command | Crafting.commands.command(…): subcommand, typed na argument, permission, alias |
Oo |
| Mundo at mga player | World, Block, Entity, Player, Inventory, Server |
Oo |
| Mga task | Crafting.scheduler: runLater, runRepeating, runAsync, runSync |
Walang trabaho sa background |
| Settings sa file | Typed na Config sa TOML, puwedeng i-sync sa mga client |
Oo (config) |
| Networking | Crafting.network.channel(…), may sariling codec |
Oo (listen, send) |
| Saved data | player.data["rubies.visits"] = n, data.getInt(…); pati sa mga entity, block at mundo |
Oo |
| Mga Java library | Kahit ano ang gusto mo | Hindi |
Ang wala pa sa API ay wala sa anumang wika. Huwag itong lusutan sa pagtawag sa mga class ng Minecraft: mawawala sa mod ang garantiya na patuloy itong gagana kapag nagbago ang laro.
Gawin ang proyekto
crafting new rubies --kind kotlin
cd rubies && gradle buildWala pa sa public na Maven repository ang API. I-install ito sa local Maven mo mula sa source ng Crafting at ideklara ito bilang compileOnly: ibinibigay ito ng Crafting sa mod habang tumatakbo.
cd crafting && ./gradlew :crafting-api:publishToMavenLocalplugins { kotlin("jvm") version "2.4.21" }
repositories { mavenCentral(); mavenLocal() }
dependencies {
compileOnly("dev.crafting:crafting-api:0.1.0")
}
kotlin { jvmToolchain(25) } // Tumatakbo ang Minecraft 26.x sa Java 25Ginagawa ng crafting new ang file na ito at isang proyektong nakahati na ayon sa responsibilidad: <Name>Mod.kt, na nagkakabit lang ng mga bahagi, content/ModContent.kt, events/Welcome.kt at commands/GemCommand.kt.
Istruktura
Mga package ayon sa paksa, isang entry class na nagkakabit lang ng mga bahagi, at isang file bawat bahagi. Ipinapaliwanag ng gabay na Pag-aayos ng mod kung bakit; narito ang buong halimbawang mod:
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.pngsrc/main/kotlin/com/example/rubies/
Walang ginagawa nang mag-isa ang entry class: ginagawa nito ang mga shared at tinatawag ang bawat bahagi.
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()
}
}Ang manifest
{
"id": "rubies",
"name": "Rubies",
"version": "1.0.0",
"kind": "mod",
"side": "both",
"entrypoints": ["com.example.rubies.RubiesMod"],
"depends": { "crafting": ">=0.1.0" }
}| Patlang | Ano ito |
|---|---|
id |
2–64 na character: maliliit na titik, digit, _ o -, nagsisimula sa titik. Ito rin ang namespace ng mga item at block mo. |
kind |
mod o plugin (server lang, nare-reload; tingnan sa ibaba). |
side |
both, client o server. Tahimik na hindi pinapansin ang client mod sa dedicated server. |
entrypoints |
Ang mga class na nag-i-implement ng CraftingMod. |
depends, optional, incompatible |
Id → range ng bersyon: >=1.2 <2, ^1.4, ~1.4.2, 1.20.x, [1.0,2.0). Kung may pumalya, sabay-sabay na iniuulat ng Crafting ang bawat problema, may mungkahi. |
loadAfter, loadBefore |
Pagkakasunod ng pag-load nang walang mahigpit na dependency. |
Siklo ng buhay
interface CraftingMod {
fun onLoad(ctx: ModContext)
fun onReady(ctx: ModContext) {}
fun onShutdown(ctx: ModContext) {}
}onLoad: i-register ang content, mga event at mga command.- Ginagawa ng Crafting ang mga block at item sa laro. Mula rito, nagthi-throw ng
RegistryFrozenExceptionang pag-register ng content. onReady: naka-load na ang lahat ng mod; sinasabi ngCrafting.runtime.isModLoaded("other_mod")kung may ibang mod.onShutdown: sa paglabas.
Mga plugin ng server
Ang plugin ay isang CraftingMod na may "kind": "plugin" at "side": "server"; ginagawa ng crafting new chatguard --kind plugin ang entry class, events/ChatFilter.kt at commands/HelloCommand.kt. Hindi ito nagdadagdag ng block o item, kaya makakapasok ang mga player na may Minecraft na walang mod sa server na plugin lang ang meron. Ine-enable, dini-disable at nire-reload mo ito nang hindi nagre-restart: tumatakbo ang onLoad at onReady kapag na-enable ito, at ang onShutdown kapag na-disable o na-reload ito.
crafting new chatguard --kind pluginpackage com.example.chatguard
class ChatGuardPlugin : CraftingMod {
override fun onLoad(ctx: ModContext) {
ChatFilter.register()
Crafting.commands.command("guard") {
permission = "chatguard.admin"
executes { it.reply("Aktibo ang ChatGuard") }
}
}
override fun onShutdown(ctx: ModContext) = ctx.logger.info("Na-disable ang ChatGuard")
}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("&cMaging magalang po tayo")
}
}
}
}Nakatali sa plugin ang lahat ng nire-register nito. Tinatawag ng /crafting reload chatguard ang onShutdown, inaalis ang mga listener, command at task nito, binabasa muli ang jar at tinatawag ang onLoad. Sa development mode, awtomatiko itong nangyayari kapag pinalitan mo ang jar.
| Mod | Plugin | |
|---|---|---|
| Folder | mods/ |
plugins/ |
| Side | Client at/o server | Server lang |
| Bagong block at item | Oo | Hindi |
| Reload nang walang restart | Hindi | Oo |
| Makakapasok ang client na walang mod | Hindi, kung nagdadagdag ito ng content | Oo |
Java
Parehong API, parehong istruktura. Mula sa Java, Crafting.INSTANCE ang entry point, ipinapasa mo ang bawat parameter na may default value, at nagre-return ng Unit.INSTANCE ang listener:
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();
}
}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;
});
}
}Mga lumang paraan
Gumagana pa rin ang mga ito, pero minarkahan silang deprecated at may kapalit:
| Dati | Ngayon |
|---|---|
class X : CraftingPlugin() na may onEnable/onDisable |
CraftingMod na may "kind": "plugin" |
Mga method na may @Subscribe at events.register(obj) |
events.on<E> { } (Java: events.subscribe(E.class, …)) |
@Mod("id") sa class |
Ang class sa entrypoints ng manifest |
EntityDamageEvent.source |
damageType (isang id, gaya ng minecraft:fall) |
world.setBlockState(x, y, z, "…[open=true]") |
world.setBlock(x, y, z, type, mapOf("open" to true)) |
Mga patakaran
- Huwag mag-import ng anuman mula sa
net.minecraft. Iyan ang nagpapanatiling gumagana ng mod kapag nagbago ang laro. - Sa
onLoadlang mag-register ng content. - Hindi ginagalaw ng task na
runAsyncang mundo; bumalik sa thread ng laro gamit angrunSync.