ガイド
CraftScript
Crafting の言語です。英語のキーワード、短い構文、コンパイル不要。ファイルを保存すれば Mod が再読み込みされます。10 行の Mod にも、クラスと型を使う 40 ファイルの Mod にも使えます。
今日できること
| 分野 | 方法 |
|---|---|
| アイテム | item "ruby" { … }:レア度、エンチャントの輝き、食料、ツール、耐久値、テクスチャ、クリエイティブタブ、使用時の動作。 |
| ブロック | block "ruby_ore" { … }:硬さ、爆発耐性、明るさ、サウンド、ツールと最低ティア、ドロップ、摩擦、透過、使用時の動作。形とモデルはブロックの形を参照してください。階段、ドア、フェンス、チェスト、看板、作物、鉱石などゲームの他の種類、座席、高さ 2 ブロックのブロックは、ブロックの種類を参照してください。ブロックは、踏まれたりティックに反応したり、ポータルになったり、ステートを持ったり、レッドストーンを使ったり、アイテムを保持したりもできます。ブロック、アイテム、レシピを参照してください。 |
| ワールド生成 | ore、tree、patch、structure、biome:新しいチャンクに現れるもの。terrain、biome_map、carver、そして plan/build を持つ構造物:コードで作る地形、バイオーム、洞窟、建物。ワールド生成とコードによる生成を参照してください。 |
| モブ | creature "ghost" { … }:ゲーム内のモブの体に、あなたのテクスチャまたは独自の 3D モデル、ステータス、行動、ターゲット、ドロップを組み合わせます、さらに自然スポーン、手なずけ、繁殖、騎乗、遠距離攻撃、キーフレームアニメーション。モブを参照してください。 |
| サウンドとパーティクル | sound "chime" { file: … }、particle "spark" { textures: … }。id で使います。サウンドとパーティクルを参照してください。 |
| レシピ | recipe shaped、shapeless、smelting。モデル、ドロップ、タグ、翻訳は自動で生成されます。 |
| イベント | on join、on break(e)…すべてのイベントに対応し、優先度とキャンセルも使えます。 |
| 防具、武器、クールダウン | 身に着けるには armor: { slot, defense, texture }、攻撃時は on_hit、使用間隔は cooldown。ブロック、アイテム、レシピを参照。 |
| エフェクト、属性、装備 | e.add_effect(…)、e.attribute(…)、e.set_attribute(…)、e.set_equipment(…)。ワールドとプレイヤーを参照。 |
| キー | key "dash" { label: "Dash", default: "R" } と on key(e)。エンティティのイベント on interact_entity、on attack。インターフェースとイベントを参照。 |
| コマンド | command pay(to: player, amount: int) requires "eco.pay"。エイリアス、説明、権限付き。 |
| 時間 | every 5 minutes { }、after 10 seconds { }、on tick。 |
| ワールドとプレイヤー | 状態付きのブロック、エンティティ、爆発、パーティクル、サウンド、時刻、チェスト、看板。インベントリ、体力、タイトル、テレポート。ワールドとプレイヤーを参照してください。 |
| インターフェース | form(…) と player.show_form、server.boss_bar、player.set_sidebar。インターフェースを参照してください。 |
| セーブデータ | p.data.set("rubies.visits", n)、p.data.get_int("rubies.visits"):プレイヤー、エンティティ、ブロック、ワールドに保存され、再起動後も残ります。ワールドとプレイヤーを参照してください。 |
| 設定とネットワーク | config("settings", { … })、listen、send、send_to_server。設定とネットワークを参照してください。 |
| 大規模な Mod | 省略可能な型、継承できるクラス、列挙型、モジュール、定数。 |
Kotlin のみ:バックグラウンド処理、Java ライブラリ、そしてワールド生成では、コードで作るフィーチャーとタグ。
ファイル
Mod は 1 つのファイル(mods/gems.craft)か、大きくなってきたら、main.craft とそれがインポートするファイルを入れたフォルダーにするのがおすすめです。main.craft は、id、名前、バージョンを示す mod ヘッダーで始まります。
mod "rubies" { name: "Rubies", version: "1.0.0", author: "you" }
// What exists
import "content/items"
import "content/ores"
import "content/world"
import "content/dimensions"
import "content/creatures"
import "content/sounds"
import "content/particles"
import "content/recipes"
// What happens
import "events/mining"
import "events/hunting"
import "events/welcome"
import "commands/realm"
import "commands/rubies"
import "commands/shop"残りをどうフォルダーに分けるか、そしてその理由は Mod の整理 を参照してください。
値と変数
let coins = 100
const MAX_HOMES = 3 // const:再代入できない
let greeting = "コインを {coins * 2} 枚持っています"
let names = ["Ana", "Ben"]
let prices = { gold: 5, ruby: 2 }
names.add("Cleo")
prices["diamond"] = 9
log(len(names), prices.gold, prices.keys())数値(常に小数)、文字列、true/false、null、リスト、マップ。ダブルクォートは {expression} を展開し、\{ で波括弧そのものを書けます。シングルクォートは展開しません。チャットの色は & で書きます:"&aGreen"。
制御フロー
fun describe(coins: number, banned: bool): string {
if coins > 100 and not banned {
return "裕福"
} else if coins == 0 {
return "無一文"
}
return "普通"
}
fun countdown() {
for i in 1..5 { broadcast("{6 - i}…") } // 両端を含む範囲
for p in players() { p.send("スタート!") }
}
fun who(target: Player?, fallback: Player): string {
let p = target ?? fallback // ?? :null のときの値
return p?.name ?? "誰もいない" // ?. :null でも安全
}関数
fun give_rubies(p: Player, amount: number = 1) {
p.give(item("rubies:ruby", amount))
}
fun healthy(): list<Player> {
return players().filter(fun(p) { return p.health > 10 })
}デフォルト値付きの引数、return、そして fun(x) { … } による無名関数。map、filter、on_use に関数を渡すときはこれを使います。
イベント
on の中では、イベントのプロパティが変数(player、message、block…)になります。イベントに名前を付けることもできます:on chat(e)。キャンセル可能なイベントは e.cancel() でキャンセルします。
const BLOCKED = ["spam", "scam"]
on chat(e) priority high {
if BLOCKED.any(fun(w) { return e.message.contains(w) }) {
e.cancel()
e.player.send("&c仲良くしましょう")
}
}コマンド
command heal(target: player?, amount: number?) requires "rubies.heal" alias "h" describe "プレイヤーを回復する" {
let p = target ?? player
if p == null { return "プレイヤーを指定してください" }
p.health = min(p.max_health, p.health + (amount ?? 20))
return "{p.name} を回復しました"
}コマンドの中では sender、player(コンソールが実行した場合は null)、args が使えます。return したものが返答になります。引数が足りない、または型が違う場合、プレイヤーには正しい使い方が表示されます。
時間
every 5 minutes { broadcast("&6投票をお忘れなく") }
after 10 seconds { log("サーバーが起動して 10 秒経ちました") }大規模な Mod
省略可能な型
型を書いた場所では型が強制され、書かない場所ではコードは自由なままです。何も書かなくても、チェッカーは API 全体の型を知っています。
on join {
player.helth = 20 // タイプミス
player.name = "Admin" // 読み取り専用のプロパティ
player.give() // 引数が足りない
}welcome.craft:2: error: Player has no property 'helth'. Did you mean 'health'?
welcome.craft:3: error: Player.name is read-only
welcome.craft:4: error: give() expects 1 argument(s), got 0fun heal(p: Player, amount: number = 20): bool {
p.health = min(p.max_health, p.health + amount)
return true
}
// heal(player, "a lot") → error: Argument 'amount' of heal() must be number, got string型:number、string、bool、id、list<T>、map<T>、T?(null の場合あり)、any、void、fun、API の型(Player、World、Block、Entity、ItemStack、Location、Inventory…)、イベント、そして自分のクラスと列挙型。null チェックの後では、チェッカーは値が存在することを知っています。
command home(target: player?) {
if target == null { return "プレイヤーを指定してください" }
target.teleport(world().block_at(0, 80, 0).location) // ここでは target はもう null ではない
}クラス
class Wallet {
coins: number = 100
fun pay(n: number): bool {
if n > this.coins { return false }
this.coins -= n
return true
}
}
class VipWallet extends Wallet {
fun pay(n: number): bool {
return super.pay(n / 2) // VIP は半額
}
}クラスが宣言していないフィールドへの代入はエラーになります(タイプミスを見逃さないため)。クラスが init(…) を定義していれば、それがコンストラクターです。定義していなければ、引数が順番にフィールドを埋めます。is(value, Class) で型を確認できます。
列挙型
enum Rank { PEASANT, KNIGHT, LORD, KING }
fun rank_for(coins: number): Rank {
if coins >= 1000 { return Rank.LORD }
return Rank.PEASANT
}
// Rank.LORD.name → "LORD", Rank.values() → [PEASANT, …], Rank.from("king") → KINGモジュール
import { VipWallet } from "/lib/wallet"
import { rank_for } from "/lib/rank"
let wallets = {}
on join {
wallets[player.name] = VipWallet()
player.send("ランク:{rank_for(wallets[player.name].coins).name}")
}ファイルがどのブロックの外でも宣言したものは、すべてインポートできます:関数、クラス、列挙型、定数。複数のファイルからインポートされても、各ファイルは一度しか実行されません。
チェック、再読み込み、安全性
- Mod の読み込み時にすべてがチェックされます。エラーがあると読み込まれず、場所が示されます。警告はログに出ます。
crafting check main.craftはターミナルから同じことを、インポートをたどりながら行います。 - 開発モード(
-Dcrafting.dev=true、crafting sandboxでは常にオン)では保存すると Mod が再読み込みされます。/crafting reload <id>でも同じです。新しいアイテムやブロックにはゲームの再起動が必要ですが、それ以外はすぐに変わります。 - スクリプトから見えるのは Crafting の API だけです。ファイルを読む、接続を開く、Java のクラスを使うことはできません。
- 各イベント、コマンド、タイマーには 2,000,000 ステップの上限があります。無限ループはサーバーを止めるのではなく、エラーで打ち切られます。
- 実行時エラーはファイルと行とともにログに記録され、サーバーは動き続けます。
すべての関数、演算子、メンバーは CraftScript リファレンス にあります。