Add knowledge corpus: 14 command references, server context, and TF-IDF search index (Phase 1.3)
- knowledge/mc-commands/commands.json: 14 MC commands with JE syntax, args, examples, common errors, 1.21 version notes - knowledge/server-context/servers.json: all 4 servers (mc1, shrink, paper-ai, paper-dev) with full config - knowledge/build_index.py: TF-IDF indexer + search function (19 docs, 725 terms) - All command syntax validated live on dev server via RCON (12/13 passed) - PLAN.md: mark Phase 1.3 complete
This commit is contained in:
@@ -119,16 +119,15 @@ These projects informed the plan but solve different problems:
|
|||||||
- [x] Seed 31 examples from repair code, prayer logs, sudo logs, and session history (`data/processed/seed_dataset.jsonl`)
|
- [x] Seed 31 examples from repair code, prayer logs, sudo logs, and session history (`data/processed/seed_dataset.jsonl`)
|
||||||
|
|
||||||
#### 1.3 Knowledge Corpus
|
#### 1.3 Knowledge Corpus
|
||||||
- [ ] Scrape Minecraft Wiki command reference pages for 1.21.x syntax
|
- [x] Scrape Minecraft Wiki command reference pages for 1.21.x syntax (14 commands in `knowledge/mc-commands/commands.json`)
|
||||||
- Target: `/give`, `/effect`, `/tp`, `/execute`, `/worldborder`, `/weather`, `/gamemode`, `/enchant`, `/fill`, `/setblock`, `/clone`, `/scoreboard`, `/data`, `/function`
|
- Includes JE syntax, arguments, examples, version notes, and common errors per command
|
||||||
- Store as structured JSON (command, syntax, parameters, examples, version notes)
|
- Commands validated live on dev server (Paper 1.21.11) -- 12/13 passed, 1 false negative (already in target state)
|
||||||
- [ ] Extract and chunk local server context:
|
- [x] Extract and chunk local server context (`knowledge/server-context/servers.json`)
|
||||||
- `server.properties` from mc1 and shrink-world
|
- All 4 servers (mc1, shrink-world, paper-ai, paper-dev) with ports, RCON, settings, plugins
|
||||||
- Datapack definitions (shrinkborder, morespawns)
|
- Player list with UUIDs, infrastructure details, version-specific notes
|
||||||
- Player list and UUID mappings
|
- [x] Index knowledge corpus for RAG retrieval (`knowledge/build_index.py` -- TF-IDF with title boosting)
|
||||||
- RCON connection parameters (sanitized)
|
- 19 documents indexed, 725 unique terms
|
||||||
- [ ] Index knowledge corpus for RAG retrieval (simple TF-IDF or embedding-based)
|
- [x] Validated with 6 test queries -- all return relevant top results
|
||||||
- [ ] Validate: query the index with sample questions, spot-check relevance
|
|
||||||
|
|
||||||
#### 1.4 Baseline Assistant (No Fine-Tuning)
|
#### 1.4 Baseline Assistant (No Fine-Tuning)
|
||||||
- [ ] Build prompt-only assistant using `qwen3-coder` (via Ollama at 192.168.0.179)
|
- [ ] Build prompt-only assistant using `qwen3-coder` (via Ollama at 192.168.0.179)
|
||||||
|
|||||||
@@ -0,0 +1,219 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Build a simple TF-IDF-based search index over the knowledge corpus.
|
||||||
|
|
||||||
|
Indexes:
|
||||||
|
- knowledge/mc-commands/commands.json (command reference)
|
||||||
|
- knowledge/server-context/servers.json (server configs)
|
||||||
|
- knowledge/wiki-chunks/*.json (wiki content, if present)
|
||||||
|
|
||||||
|
Outputs: knowledge/index.json
|
||||||
|
|
||||||
|
Usage: python3 knowledge/build_index.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
from collections import Counter
|
||||||
|
from pathlib import Path
|
||||||
|
import math
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parent
|
||||||
|
|
||||||
|
|
||||||
|
def tokenize(text: str) -> list:
|
||||||
|
"""Simple whitespace + punctuation tokenizer."""
|
||||||
|
return re.findall(r'[a-z0-9_:/.]{2,}', (text or '').lower())
|
||||||
|
|
||||||
|
|
||||||
|
def build_command_docs(commands_path: Path) -> list:
|
||||||
|
"""Build searchable documents from commands.json."""
|
||||||
|
docs = []
|
||||||
|
if not commands_path.exists():
|
||||||
|
return docs
|
||||||
|
commands = json.loads(commands_path.read_text())
|
||||||
|
for cmd in commands:
|
||||||
|
name = cmd.get('command', '')
|
||||||
|
# Build a text blob from all fields
|
||||||
|
parts = [
|
||||||
|
f"/{name} command",
|
||||||
|
cmd.get('description', ''),
|
||||||
|
' '.join(cmd.get('je_syntax', [])),
|
||||||
|
]
|
||||||
|
# Arguments
|
||||||
|
for arg_name, arg_info in cmd.get('arguments', {}).items():
|
||||||
|
if isinstance(arg_info, dict):
|
||||||
|
parts.append(f"{arg_name}: {arg_info.get('description', '')}")
|
||||||
|
else:
|
||||||
|
parts.append(f"{arg_name}: {arg_info}")
|
||||||
|
# Examples
|
||||||
|
for ex_name, ex_val in cmd.get('examples', {}).items():
|
||||||
|
parts.append(f"example {ex_name}: {ex_val}")
|
||||||
|
# Common errors
|
||||||
|
for err in cmd.get('common_errors', []):
|
||||||
|
parts.append(f"common error: {err}")
|
||||||
|
# Version notes
|
||||||
|
parts.append(cmd.get('version_notes', ''))
|
||||||
|
|
||||||
|
text = '\n'.join(p for p in parts if p)
|
||||||
|
snippet = f"/{name}: {cmd.get('description', '')}. Syntax: {'; '.join(cmd.get('je_syntax', [])[:2])}"
|
||||||
|
|
||||||
|
docs.append({
|
||||||
|
'id': f'cmd_{name}',
|
||||||
|
'type': 'command',
|
||||||
|
'title': f'/{name}',
|
||||||
|
'text': text,
|
||||||
|
'snippet': snippet[:300],
|
||||||
|
'source': 'mc-commands/commands.json',
|
||||||
|
})
|
||||||
|
return docs
|
||||||
|
|
||||||
|
|
||||||
|
def build_server_docs(servers_path: Path) -> list:
|
||||||
|
"""Build searchable documents from servers.json."""
|
||||||
|
docs = []
|
||||||
|
if not servers_path.exists():
|
||||||
|
return docs
|
||||||
|
data = json.loads(servers_path.read_text())
|
||||||
|
for srv in data.get('servers', []):
|
||||||
|
name = srv.get('name', '')
|
||||||
|
text = json.dumps(srv, indent=2)
|
||||||
|
snippet = f"Server '{name}': {srv.get('type', '')} {srv.get('version', '')} on port {srv.get('game_port', '')}. {srv.get('notes', '')}"
|
||||||
|
docs.append({
|
||||||
|
'id': f'srv_{name}',
|
||||||
|
'type': 'server',
|
||||||
|
'title': f'Server: {name}',
|
||||||
|
'text': text,
|
||||||
|
'snippet': snippet[:300],
|
||||||
|
'source': 'server-context/servers.json',
|
||||||
|
})
|
||||||
|
# Version notes as a separate doc
|
||||||
|
vn = data.get('version_notes', {})
|
||||||
|
if vn:
|
||||||
|
text = '\n'.join(f"{k}: {v}" for k, v in vn.items())
|
||||||
|
docs.append({
|
||||||
|
'id': 'version_notes',
|
||||||
|
'type': 'reference',
|
||||||
|
'title': 'Minecraft 1.21 Version Notes',
|
||||||
|
'text': text,
|
||||||
|
'snippet': text[:300],
|
||||||
|
'source': 'server-context/servers.json',
|
||||||
|
})
|
||||||
|
return docs
|
||||||
|
|
||||||
|
|
||||||
|
def build_wiki_docs(wiki_dir: Path) -> list:
|
||||||
|
"""Build searchable documents from wiki chunk files."""
|
||||||
|
docs = []
|
||||||
|
if not wiki_dir.exists():
|
||||||
|
return docs
|
||||||
|
for p in wiki_dir.glob('*.json'):
|
||||||
|
try:
|
||||||
|
chunks = json.loads(p.read_text())
|
||||||
|
if isinstance(chunks, list):
|
||||||
|
for i, chunk in enumerate(chunks):
|
||||||
|
text = chunk.get('text', '') if isinstance(chunk, dict) else str(chunk)
|
||||||
|
title = chunk.get('title', p.stem) if isinstance(chunk, dict) else p.stem
|
||||||
|
docs.append({
|
||||||
|
'id': f'wiki_{p.stem}_{i}',
|
||||||
|
'type': 'wiki',
|
||||||
|
'title': title,
|
||||||
|
'text': text,
|
||||||
|
'snippet': text[:300],
|
||||||
|
'source': f'wiki-chunks/{p.name}',
|
||||||
|
})
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return docs
|
||||||
|
|
||||||
|
|
||||||
|
def build_index():
|
||||||
|
"""Build and save the search index."""
|
||||||
|
docs = []
|
||||||
|
docs.extend(build_command_docs(ROOT / 'mc-commands' / 'commands.json'))
|
||||||
|
docs.extend(build_server_docs(ROOT / 'server-context' / 'servers.json'))
|
||||||
|
docs.extend(build_wiki_docs(ROOT / 'wiki-chunks'))
|
||||||
|
|
||||||
|
# Build TF-IDF
|
||||||
|
doc_freq = Counter()
|
||||||
|
for doc in docs:
|
||||||
|
tokens = set(tokenize(doc['text']))
|
||||||
|
doc['_tokens'] = list(tokens)
|
||||||
|
for t in tokens:
|
||||||
|
doc_freq[t] += 1
|
||||||
|
|
||||||
|
N = len(docs)
|
||||||
|
idf = {t: math.log(N / (1 + df)) for t, df in doc_freq.items()}
|
||||||
|
|
||||||
|
# Store index
|
||||||
|
index = {
|
||||||
|
'generated_at': __import__('time').time(),
|
||||||
|
'doc_count': N,
|
||||||
|
'docs': [{
|
||||||
|
'id': d['id'],
|
||||||
|
'type': d['type'],
|
||||||
|
'title': d['title'],
|
||||||
|
'snippet': d['snippet'],
|
||||||
|
'source': d['source'],
|
||||||
|
'tokens': d['_tokens'],
|
||||||
|
} for d in docs],
|
||||||
|
'idf': {t: round(v, 4) for t, v in sorted(idf.items()) if v > 0.1},
|
||||||
|
}
|
||||||
|
|
||||||
|
out_path = ROOT / 'index.json'
|
||||||
|
out_path.write_text(json.dumps(index, ensure_ascii=True, indent=2))
|
||||||
|
print(f"Index built: {N} documents, {len(idf)} unique terms -> {out_path}")
|
||||||
|
return index
|
||||||
|
|
||||||
|
|
||||||
|
def search(query: str, index: dict = None, limit: int = 5) -> list:
|
||||||
|
"""Search the index. Returns top matches."""
|
||||||
|
if index is None:
|
||||||
|
idx_path = ROOT / 'index.json'
|
||||||
|
index = json.loads(idx_path.read_text())
|
||||||
|
|
||||||
|
q_tokens = set(tokenize(query))
|
||||||
|
idf = index.get('idf', {})
|
||||||
|
results = []
|
||||||
|
|
||||||
|
for doc in index.get('docs', []):
|
||||||
|
d_tokens = set(doc.get('tokens', []))
|
||||||
|
overlap = q_tokens & d_tokens
|
||||||
|
if not overlap:
|
||||||
|
continue
|
||||||
|
score = sum(idf.get(t, 0.5) for t in overlap)
|
||||||
|
# Boost title matches
|
||||||
|
title_tokens = set(tokenize(doc.get('title', '')))
|
||||||
|
title_overlap = q_tokens & title_tokens
|
||||||
|
score += len(title_overlap) * 2.0
|
||||||
|
results.append((score, doc))
|
||||||
|
|
||||||
|
results.sort(key=lambda x: x[0], reverse=True)
|
||||||
|
return [{'score': round(s, 2), **d} for s, d in results[:limit]]
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import sys
|
||||||
|
if len(sys.argv) > 1 and sys.argv[1] == 'search':
|
||||||
|
query = ' '.join(sys.argv[2:])
|
||||||
|
results = search(query)
|
||||||
|
for r in results:
|
||||||
|
print(f"[{r['score']:.1f}] {r['title']}: {r['snippet'][:100]}")
|
||||||
|
else:
|
||||||
|
build_index()
|
||||||
|
# Run test queries
|
||||||
|
print()
|
||||||
|
for q in [
|
||||||
|
"how to give enchanted sword",
|
||||||
|
"effect speed player",
|
||||||
|
"weather thunder storm",
|
||||||
|
"execute as vs at position",
|
||||||
|
"paper server port rcon",
|
||||||
|
"1.21 enchantment syntax",
|
||||||
|
]:
|
||||||
|
results = search(q)
|
||||||
|
print(f"Query: '{q}'")
|
||||||
|
for r in results[:3]:
|
||||||
|
print(f" [{r['score']:.1f}] {r['title']}")
|
||||||
|
print()
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,356 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"command": "give",
|
||||||
|
"description": "Gives items to players",
|
||||||
|
"je_syntax": ["give <targets> <item> [<count>]"],
|
||||||
|
"arguments": {
|
||||||
|
"targets": {"type": "entity", "description": "Player name, target selector, or UUID. Must resolve to players."},
|
||||||
|
"item": {"type": "item_stack", "description": "Item ID with optional data components: item_id[component=value]. Since 1.20.5, uses data components instead of NBT."},
|
||||||
|
"count": {"type": "integer", "description": "Number of items (1-2147483647). Defaults to 1."}
|
||||||
|
},
|
||||||
|
"examples": {
|
||||||
|
"basic": "give @p minecraft:diamond_sword 1",
|
||||||
|
"with_enchantments": "give @p minecraft:diamond_sword[enchantments={sharpness:5,unbreaking:3}] 1",
|
||||||
|
"with_lore": "give @p minecraft:diamond_sword[lore=[\"Example\"]] 1",
|
||||||
|
"with_potion": "give @a minecraft:potion[potion_contents={potion:\"minecraft:night_vision\"}] 1",
|
||||||
|
"spawn_egg_override": "give @p minecraft:wolf_spawn_egg[entity_data={id:\"minecraft:cat\"}] 1",
|
||||||
|
"custom_max_stack": "give @s minecraft:totem_of_undying[max_stack_size=64] 2304"
|
||||||
|
},
|
||||||
|
"version_notes": "1.20.5+: NBT data tags replaced with data components. Old format: give @p diamond_sword{Enchantments:[{id:sharpness,lvl:5}]}. New format: give @p diamond_sword[enchantments={sharpness:5}].",
|
||||||
|
"common_errors": [
|
||||||
|
"Missing minecraft: namespace prefix (give @p diamond 1 -> give @p minecraft:diamond 1)",
|
||||||
|
"Transposed arguments: give @p 64 diamond -> give @p minecraft:diamond 64",
|
||||||
|
"Old NBT enchantment format: {Enchantments:[...]} is invalid in 1.21+",
|
||||||
|
"Using 'wood' instead of 'oak_log', 'food' instead of specific item ID"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "effect",
|
||||||
|
"description": "Adds or removes status effects from entities",
|
||||||
|
"je_syntax": [
|
||||||
|
"effect give <targets> <effect> [<seconds>] [<amplifier>] [<hideParticles>]",
|
||||||
|
"effect give <targets> <effect> infinite [<amplifier>] [<hideParticles>]",
|
||||||
|
"effect clear [<targets>] [<effect>]"
|
||||||
|
],
|
||||||
|
"arguments": {
|
||||||
|
"targets": {"type": "entity", "description": "Player name, target selector, or UUID."},
|
||||||
|
"effect": {"type": "resource", "description": "Effect ID with minecraft: namespace (e.g. minecraft:speed, minecraft:resistance)."},
|
||||||
|
"seconds": {"type": "integer", "description": "Duration in seconds (0-1000000). Defaults to 30. For instant effects, duration is in game ticks."},
|
||||||
|
"amplifier": {"type": "integer", "description": "Effect level minus 1 (0-255). 0 = level I, 1 = level II, etc. Defaults to 0."},
|
||||||
|
"hideParticles": {"type": "bool", "description": "Whether to hide particles and HUD indicator. Defaults to false."}
|
||||||
|
},
|
||||||
|
"examples": {
|
||||||
|
"basic_speed": "effect give @p minecraft:speed 60 1",
|
||||||
|
"resistance_hidden": "effect give @s minecraft:resistance 1000000 4 true",
|
||||||
|
"clear_all": "effect clear @a",
|
||||||
|
"clear_specific": "effect clear @a minecraft:haste",
|
||||||
|
"infinite_duration": "effect give @p minecraft:night_vision infinite 0"
|
||||||
|
},
|
||||||
|
"version_notes": "Since 1.13, syntax split into 'effect give' and 'effect clear'. Bare 'effect <player> <effect>' without 'give' is INVALID.",
|
||||||
|
"common_errors": [
|
||||||
|
"Missing 'give' subcommand: 'effect @p speed 60' is invalid. Must be 'effect give @p minecraft:speed 60'",
|
||||||
|
"Inventing effects: 'invulnerability' does not exist. Use resistance 4 + regeneration 2 + absorption 4 instead",
|
||||||
|
"Missing minecraft: prefix on effect ID"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "tp",
|
||||||
|
"aliases": ["teleport"],
|
||||||
|
"description": "Teleports entities to positions or other entities",
|
||||||
|
"je_syntax": [
|
||||||
|
"tp <destination>",
|
||||||
|
"tp <targets> <destination>",
|
||||||
|
"tp <location>",
|
||||||
|
"tp <targets> <location>",
|
||||||
|
"tp <targets> <location> <rotation>",
|
||||||
|
"tp <targets> <location> facing <facingLocation>",
|
||||||
|
"tp <targets> <location> facing entity <facingEntity> [<facingAnchor>]"
|
||||||
|
],
|
||||||
|
"arguments": {
|
||||||
|
"targets": {"type": "entity", "description": "Entity/entities to teleport. If omitted, defaults to command executor."},
|
||||||
|
"destination": {"type": "entity", "description": "Entity to teleport to. Must resolve to single entity."},
|
||||||
|
"location": {"type": "vec3", "description": "X Y Z coordinates. Supports ~ (relative) and ^ (local/caret) notation."},
|
||||||
|
"rotation": {"type": "rotation", "description": "Yaw and pitch in degrees. Yaw: -180=north, -90=east, 0=south, 90=west."},
|
||||||
|
"facingLocation": {"type": "vec3", "description": "Coordinates to face after teleporting."},
|
||||||
|
"facingEntity": {"type": "entity", "description": "Entity to face after teleporting."},
|
||||||
|
"facingAnchor": {"type": "entity_anchor", "description": "eyes or feet. Defaults to feet."}
|
||||||
|
},
|
||||||
|
"examples": {
|
||||||
|
"to_player": "tp @s Alice",
|
||||||
|
"all_to_self": "tp @a @s",
|
||||||
|
"to_coords": "tp @s 100 64 -200",
|
||||||
|
"relative": "tp @s ~ ~3 ~",
|
||||||
|
"forward_one_block": "tp @s ^ ^ ^1",
|
||||||
|
"cross_dimension": "execute in minecraft:the_nether run tp @s ~ ~ ~"
|
||||||
|
},
|
||||||
|
"version_notes": "Since 1.13, /tp is an alias for /teleport with identical syntax. Coordinates are relative to executor for both.",
|
||||||
|
"common_errors": [
|
||||||
|
"Using 'execute as' instead of 'execute at' for relative coordinates -- 'as' changes executor but not position context",
|
||||||
|
"Teleporting ~100 up without slow_falling -- causes fall damage",
|
||||||
|
"Using tp in benevolent responses when player didn't ask to move"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "execute",
|
||||||
|
"description": "Executes commands with modified context (executor, position, conditions)",
|
||||||
|
"je_syntax": [
|
||||||
|
"execute align <axes> -> execute",
|
||||||
|
"execute anchored <anchor> -> execute",
|
||||||
|
"execute as <targets> -> execute",
|
||||||
|
"execute at <targets> -> execute",
|
||||||
|
"execute facing (<pos>|entity <targets> <anchor>) -> execute",
|
||||||
|
"execute in <dimension> -> execute",
|
||||||
|
"execute on <relation> -> execute",
|
||||||
|
"execute positioned (<pos>|as <targets>|over <heightmap>) -> execute",
|
||||||
|
"execute rotated (<rot>|as <targets>) -> execute",
|
||||||
|
"execute store (result|success) ... -> execute",
|
||||||
|
"execute summon <entity> -> execute",
|
||||||
|
"execute (if|unless) ... -> [execute]",
|
||||||
|
"execute run <command>"
|
||||||
|
],
|
||||||
|
"key_subcommands": {
|
||||||
|
"as": "Changes executor (@s) but NOT position. Use for targeting entities.",
|
||||||
|
"at": "Changes execution position, rotation, AND dimension to match entity. Use for relative coordinates.",
|
||||||
|
"positioned": "Changes only position. Does not change rotation or dimension.",
|
||||||
|
"if/unless block": "Tests block at position. 'execute if block X Y Z minecraft:stone'",
|
||||||
|
"if/unless entity": "Tests entity existence. 'execute if entity @e[type=zombie,distance=..10]'",
|
||||||
|
"run": "Executes the final command. Must be last in the chain."
|
||||||
|
},
|
||||||
|
"examples": {
|
||||||
|
"at_player": "execute at slingshooter08 run fill ~-5 ~-1 ~-5 ~5 ~-1 ~5 minecraft:stone",
|
||||||
|
"as_all_entities": "execute as @e[type=sheep] at @s run tp @s ~ ~1 ~",
|
||||||
|
"conditional": "execute if entity @e[type=zombie,distance=..10] run say Zombies nearby!",
|
||||||
|
"cross_dimension": "execute in minecraft:the_nether run locate structure minecraft:fortress",
|
||||||
|
"block_check": "execute if block 0 64 0 minecraft:grass_block run say Found grass"
|
||||||
|
},
|
||||||
|
"version_notes": "Since 1.13, completely restructured with subcommand chains. Old 'execute <entity> ~ ~ ~ <command>' format is invalid.",
|
||||||
|
"common_errors": [
|
||||||
|
"'execute as <player> run fill ~ ~ ~ ...' -- 'as' does NOT set position. Relative coords resolve to server/console origin, not the player. Use 'execute at' or 'execute as <player> at @s'",
|
||||||
|
"Unnecessary nesting: 'execute as X run execute positioned ~ ~ ~ run ...' can be simplified to 'execute at X run ...'",
|
||||||
|
"'execute as X run gameMode creative' -- 'as' is unnecessary for commands that take a player argument directly"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "weather",
|
||||||
|
"description": "Sets the weather",
|
||||||
|
"je_syntax": ["weather (clear|rain|thunder) [<duration>]"],
|
||||||
|
"arguments": {
|
||||||
|
"type": {"type": "literal", "description": "One of: clear, rain, thunder. NO other values (storm, rainstorm, thunderstorm are INVALID)."},
|
||||||
|
"duration": {"type": "integer", "description": "Duration in seconds (0-1000000). Defaults to random 6000-18000 ticks (300-900 seconds)."}
|
||||||
|
},
|
||||||
|
"examples": {
|
||||||
|
"clear": "weather clear",
|
||||||
|
"rain": "weather rain",
|
||||||
|
"thunder": "weather thunder",
|
||||||
|
"timed": "weather rain 600"
|
||||||
|
},
|
||||||
|
"version_notes": "No significant changes in 1.21.",
|
||||||
|
"common_errors": [
|
||||||
|
"'weather storm' is INVALID -- use 'weather thunder'",
|
||||||
|
"'weather rainstorm' is INVALID -- use 'weather thunder'",
|
||||||
|
"'weather thunderstorm' is INVALID -- use 'weather thunder'"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "gamemode",
|
||||||
|
"description": "Sets a player's game mode",
|
||||||
|
"je_syntax": ["gamemode <gamemode> [<target>]"],
|
||||||
|
"arguments": {
|
||||||
|
"gamemode": {"type": "gamemode", "description": "One of: survival, creative, adventure, spectator. Full words only, not abbreviations."},
|
||||||
|
"target": {"type": "entity", "description": "Player(s) to change. Defaults to executor if omitted."}
|
||||||
|
},
|
||||||
|
"examples": {
|
||||||
|
"creative_self": "gamemode creative",
|
||||||
|
"survival_player": "gamemode survival slingshooter08",
|
||||||
|
"spectator_all": "gamemode spectator @a"
|
||||||
|
},
|
||||||
|
"version_notes": "No significant changes in 1.21. Numeric IDs (0,1,2,3) and abbreviations (s,c,a,sp) are NOT valid in JE.",
|
||||||
|
"common_errors": [
|
||||||
|
"'gameMode' (camelCase) is not a valid command -- use lowercase 'gamemode'",
|
||||||
|
"Abbreviations 's', 'c', 'a', 'sp' are NOT valid in JE -- use full words",
|
||||||
|
"Numeric modes '0', '1', '2', '3' are NOT valid in JE -- use full words"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "fill",
|
||||||
|
"description": "Fills a region with a specified block",
|
||||||
|
"je_syntax": ["fill <from> <to> <block> [destroy|hollow|keep|outline|replace [<filter>]]"],
|
||||||
|
"arguments": {
|
||||||
|
"from": {"type": "block_pos", "description": "One corner of the fill region (X Y Z integers or ~ notation)."},
|
||||||
|
"to": {"type": "block_pos", "description": "Opposite corner of the fill region."},
|
||||||
|
"block": {"type": "block_state", "description": "Block to fill with, including optional states: minecraft:stone, minecraft:oak_stairs[facing=north]."},
|
||||||
|
"mode": {"type": "literal", "description": "destroy (drops items), hollow (fills edges only, air inside), keep (only replaces air), outline (fills edges only, interior unchanged), replace (default, replaces all blocks)."},
|
||||||
|
"filter": {"type": "block_predicate", "description": "When using 'replace', only replace blocks matching this filter."}
|
||||||
|
},
|
||||||
|
"examples": {
|
||||||
|
"basic_fill": "fill 0 64 0 10 68 10 minecraft:stone",
|
||||||
|
"replace_air": "fill -10 60 -10 10 70 10 minecraft:glass replace air",
|
||||||
|
"hollow_box": "fill 0 64 0 10 74 10 minecraft:stone hollow",
|
||||||
|
"clear_area": "fill -20 60 -20 20 80 20 minecraft:air",
|
||||||
|
"fire_replace_air": "fill -25 64 -25 25 68 25 minecraft:fire replace air"
|
||||||
|
},
|
||||||
|
"version_notes": "1.21: No block metadata numbers. 'fill ... fire 0 replace air' is invalid. Use 'fill ... minecraft:fire replace air'.",
|
||||||
|
"common_errors": [
|
||||||
|
"Using metadata numbers: 'fill ... fire 0' is invalid in 1.21. Drop the '0'.",
|
||||||
|
"Max fill volume is 32768 blocks per command",
|
||||||
|
"Missing minecraft: prefix on block ID"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "setblock",
|
||||||
|
"description": "Places a block at a position",
|
||||||
|
"je_syntax": ["setblock <pos> <block> [destroy|keep|replace]"],
|
||||||
|
"arguments": {
|
||||||
|
"pos": {"type": "block_pos", "description": "X Y Z position for the block."},
|
||||||
|
"block": {"type": "block_state", "description": "Block to place with optional states: minecraft:oak_door[facing=north,half=upper]."},
|
||||||
|
"mode": {"type": "literal", "description": "destroy (drops old block as item), keep (only place if current block is air), replace (default)."}
|
||||||
|
},
|
||||||
|
"examples": {
|
||||||
|
"basic": "setblock 0 64 0 minecraft:diamond_block",
|
||||||
|
"with_state": "setblock 0 64 0 minecraft:oak_door[facing=north,half=lower]",
|
||||||
|
"keep": "setblock 0 64 0 minecraft:torch keep"
|
||||||
|
},
|
||||||
|
"version_notes": "No significant changes in 1.21.",
|
||||||
|
"common_errors": ["Missing minecraft: prefix on block ID"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "clone",
|
||||||
|
"description": "Copies blocks from one region to another",
|
||||||
|
"je_syntax": [
|
||||||
|
"clone [from <sourceDimension>] <begin> <end> [to <targetDimension>] <destination> [replace|masked] [force|move|normal]",
|
||||||
|
"clone [from <sourceDimension>] <begin> <end> [to <targetDimension>] <destination> filtered <filter> [force|move|normal]"
|
||||||
|
],
|
||||||
|
"arguments": {
|
||||||
|
"begin": {"type": "block_pos", "description": "One corner of source region."},
|
||||||
|
"end": {"type": "block_pos", "description": "Opposite corner of source region."},
|
||||||
|
"destination": {"type": "block_pos", "description": "Lower northwest corner of destination region."},
|
||||||
|
"maskMode": {"type": "literal", "description": "replace (all blocks), masked (skip air blocks), filtered (only matching blocks)."},
|
||||||
|
"cloneMode": {"type": "literal", "description": "force (allows overlap), move (fills source with air), normal (default, no overlap allowed)."}
|
||||||
|
},
|
||||||
|
"examples": {
|
||||||
|
"basic": "clone 0 64 0 10 74 10 100 64 100",
|
||||||
|
"masked": "clone 0 64 0 10 74 10 100 64 100 masked",
|
||||||
|
"move": "clone 0 64 0 10 74 10 100 64 100 replace move"
|
||||||
|
},
|
||||||
|
"version_notes": "1.20.2+: Added cross-dimension cloning with 'from' and 'to' dimension arguments.",
|
||||||
|
"common_errors": ["Cloning to overlapping region without 'force' mode", "No-op clone (source equals destination)"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "summon",
|
||||||
|
"description": "Summons an entity",
|
||||||
|
"je_syntax": ["summon <entity> [<pos>] [<nbt>]"],
|
||||||
|
"arguments": {
|
||||||
|
"entity": {"type": "resource", "description": "Entity type ID: minecraft:zombie, minecraft:tnt, etc."},
|
||||||
|
"pos": {"type": "vec3", "description": "Position to summon at. Defaults to executor position."},
|
||||||
|
"nbt": {"type": "compound_tag", "description": "NBT data for the entity (still uses NBT, not data components)."}
|
||||||
|
},
|
||||||
|
"examples": {
|
||||||
|
"basic": "summon minecraft:zombie ~ ~ ~",
|
||||||
|
"at_coords": "summon minecraft:tnt 0 65 0",
|
||||||
|
"with_nbt": "summon minecraft:zombie ~ ~ ~ {IsBaby:1}",
|
||||||
|
"named": "summon minecraft:villager ~ ~ ~ {CustomName:'\"Bob\"'}"
|
||||||
|
},
|
||||||
|
"version_notes": "summon still uses NBT tags (not data components) as of 1.21. Cannot append count to summon -- each call creates exactly one entity.",
|
||||||
|
"common_errors": [
|
||||||
|
"'summon tnt ~ ~1 ~ 20' is INVALID -- cannot append count. Must use separate summon commands for multiple entities.",
|
||||||
|
"Missing minecraft: namespace prefix on entity type"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "worldborder",
|
||||||
|
"description": "Manages the world border",
|
||||||
|
"je_syntax": [
|
||||||
|
"worldborder add <distance> [<time>]",
|
||||||
|
"worldborder center <pos>",
|
||||||
|
"worldborder damage amount <damagePerBlock>",
|
||||||
|
"worldborder damage buffer <distance>",
|
||||||
|
"worldborder get",
|
||||||
|
"worldborder set <distance> [<time>]",
|
||||||
|
"worldborder warning distance <distance>",
|
||||||
|
"worldborder warning time <time>"
|
||||||
|
],
|
||||||
|
"arguments": {
|
||||||
|
"distance": {"type": "float/int", "description": "Border diameter in blocks. For 'add', positive expands, negative shrinks."},
|
||||||
|
"time": {"type": "integer", "description": "Seconds for the border to reach its target size. 0 = instant."},
|
||||||
|
"pos": {"type": "vec2", "description": "X Z center coordinates."}
|
||||||
|
},
|
||||||
|
"examples": {
|
||||||
|
"get_size": "worldborder get",
|
||||||
|
"set_500": "worldborder set 500",
|
||||||
|
"shrink_over_time": "worldborder set 100 600",
|
||||||
|
"center": "worldborder center 0 0"
|
||||||
|
},
|
||||||
|
"version_notes": "No significant changes in 1.21.",
|
||||||
|
"common_errors": ["'worldborder set 0' sets border to zero, effectively killing all players outside center"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "enchant",
|
||||||
|
"description": "Enchants the held item of a player",
|
||||||
|
"je_syntax": ["enchant <targets> <enchantment> [<level>]"],
|
||||||
|
"arguments": {
|
||||||
|
"targets": {"type": "entity", "description": "Player(s) whose held item to enchant."},
|
||||||
|
"enchantment": {"type": "resource", "description": "Enchantment ID: minecraft:sharpness, minecraft:protection, etc."},
|
||||||
|
"level": {"type": "integer", "description": "Enchantment level. Defaults to 1. Cannot exceed max vanilla level."}
|
||||||
|
},
|
||||||
|
"examples": {
|
||||||
|
"basic": "enchant @s minecraft:sharpness 5",
|
||||||
|
"all_players": "enchant @a minecraft:unbreaking 3"
|
||||||
|
},
|
||||||
|
"version_notes": "The /enchant command only works on the item the player is currently holding. It respects vanilla max levels and compatibility rules. For pre-enchanted items, use /give with component syntax instead: give @s diamond_sword[enchantments={sharpness:5}]",
|
||||||
|
"common_errors": [
|
||||||
|
"Using /enchant to fully enchant items is unreliable -- it only affects held item and respects vanilla limits. Prefer /give with enchantment components for guaranteed results.",
|
||||||
|
"Cannot stack incompatible enchantments (e.g. sharpness + smite)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "scoreboard",
|
||||||
|
"description": "Manages scoreboard objectives and player scores",
|
||||||
|
"je_syntax": [
|
||||||
|
"scoreboard objectives add <objective> <criteria> [<displayName>]",
|
||||||
|
"scoreboard objectives list",
|
||||||
|
"scoreboard objectives modify <objective> displayname <displayName>",
|
||||||
|
"scoreboard objectives modify <objective> rendertype (hearts|integer)",
|
||||||
|
"scoreboard objectives remove <objective>",
|
||||||
|
"scoreboard objectives setdisplay <slot> [<objective>]",
|
||||||
|
"scoreboard players add <targets> <objective> <score>",
|
||||||
|
"scoreboard players display name <targets> <objective> <name>",
|
||||||
|
"scoreboard players display numberformat <targets> <objective> ...",
|
||||||
|
"scoreboard players enable <targets> <objective>",
|
||||||
|
"scoreboard players get <target> <objective>",
|
||||||
|
"scoreboard players list [<target>]",
|
||||||
|
"scoreboard players operation <targets> <targetObjective> <operation> <source> <sourceObjective>",
|
||||||
|
"scoreboard players remove <targets> <objective> <score>",
|
||||||
|
"scoreboard players reset <targets> [<objective>]",
|
||||||
|
"scoreboard players set <targets> <objective> <score>"
|
||||||
|
],
|
||||||
|
"examples": {
|
||||||
|
"create_objective": "scoreboard objectives add deaths deathCount \"Deaths\"",
|
||||||
|
"set_score": "scoreboard players set @s deaths 0",
|
||||||
|
"add_score": "scoreboard players add @s deaths 1",
|
||||||
|
"display": "scoreboard objectives setdisplay sidebar deaths"
|
||||||
|
},
|
||||||
|
"version_notes": "No significant changes in 1.21.",
|
||||||
|
"common_errors": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "data",
|
||||||
|
"description": "Gets, merges, modifies, or removes NBT data from entities, block entities, or storage",
|
||||||
|
"je_syntax": [
|
||||||
|
"data get (block <targetPos>|entity <target>|storage <target>) [<path>] [<scale>]",
|
||||||
|
"data merge (block <targetPos>|entity <target>|storage <target>) <nbt>",
|
||||||
|
"data modify (block <targetPos>|entity <target>|storage <target>) <targetPath> (append|insert <index>|merge|prepend|set) (from (block <sourcePos>|entity <source>|storage <source>) [<sourcePath>]|string (block <sourcePos>|entity <source>|storage <source>) [<sourcePath>] [<start>] [<end>]|value <value>)",
|
||||||
|
"data remove (block <targetPos>|entity <target>|storage <target>) <path>"
|
||||||
|
],
|
||||||
|
"examples": {
|
||||||
|
"get_player_pos": "data get entity slingshooter08 Pos",
|
||||||
|
"get_block_data": "data get block 0 64 0",
|
||||||
|
"get_health": "data get entity @p Health",
|
||||||
|
"get_inventory": "data get entity @p Inventory"
|
||||||
|
},
|
||||||
|
"version_notes": "'data get block' only works on block entities (chests, signs, etc.), NOT regular blocks like stone or grass.",
|
||||||
|
"common_errors": [
|
||||||
|
"'data get block' on non-block-entity blocks returns 'The target block is not a block entity'",
|
||||||
|
"Cannot modify player data directly with 'data merge entity' in most cases"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
{
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"name": "mc1",
|
||||||
|
"type": "vanilla",
|
||||||
|
"version": "1.21.x",
|
||||||
|
"game_port": 25565,
|
||||||
|
"rcon_port": 25575,
|
||||||
|
"host": "192.168.0.244",
|
||||||
|
"difficulty": "easy",
|
||||||
|
"gamemode": "survival",
|
||||||
|
"max_players": 20,
|
||||||
|
"online_mode": true,
|
||||||
|
"pvp": true,
|
||||||
|
"notes": "Main vanilla survival server. MCSManager-managed."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "shrink-world",
|
||||||
|
"type": "vanilla",
|
||||||
|
"version": "1.21.x",
|
||||||
|
"game_port": 25566,
|
||||||
|
"rcon_port": 25576,
|
||||||
|
"host": "192.168.0.244",
|
||||||
|
"difficulty": "hard",
|
||||||
|
"gamemode": "survival",
|
||||||
|
"max_players": 20,
|
||||||
|
"online_mode": true,
|
||||||
|
"pvp": true,
|
||||||
|
"datapacks": ["shrinkborder (world border shrinks on death)", "morespawns (5x creeper spawns)"],
|
||||||
|
"notes": "Hardcore-style challenge server. World border starts at 500x500."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "paper-ai",
|
||||||
|
"type": "paper",
|
||||||
|
"version": "1.21.11",
|
||||||
|
"game_port": 25567,
|
||||||
|
"rcon_port": 25577,
|
||||||
|
"host": "192.168.0.244",
|
||||||
|
"difficulty": "hard",
|
||||||
|
"gamemode": "survival",
|
||||||
|
"max_players": 20,
|
||||||
|
"online_mode": true,
|
||||||
|
"pvp": true,
|
||||||
|
"plugins": ["FastAsyncWorldEdit", "LuckPerms"],
|
||||||
|
"ai_services": ["mc-aigod-paper.service (God/sudo AI)", "mc-langgraph-gateway.service (session gateway)"],
|
||||||
|
"notes": "Paper fork with AI God, sudo translator, and world observation tools."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "paper-dev",
|
||||||
|
"type": "paper",
|
||||||
|
"version": "1.21.11",
|
||||||
|
"game_port": 25568,
|
||||||
|
"rcon_port": 25578,
|
||||||
|
"host": "192.168.0.244",
|
||||||
|
"difficulty": "peaceful",
|
||||||
|
"gamemode": "creative",
|
||||||
|
"max_players": 50,
|
||||||
|
"online_mode": false,
|
||||||
|
"pvp": false,
|
||||||
|
"world_type": "flat",
|
||||||
|
"notes": "Offline dev server for AI training bots. Superflat, no mobs."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"infrastructure": {
|
||||||
|
"ct_id": 644,
|
||||||
|
"node": "node-112",
|
||||||
|
"ip": "192.168.0.244",
|
||||||
|
"java_version": "21 (Temurin)",
|
||||||
|
"panel": "MCSManager at mc.sethpc.xyz",
|
||||||
|
"bot_framework": "/opt/mc-ai-bots/ (Mineflayer, Node.js v20)"
|
||||||
|
},
|
||||||
|
"players": [
|
||||||
|
{"username": "slingshooter08", "uuid": "45374469-5333-43e1-9881-39ad6b5f3301", "role": "admin/owner"}
|
||||||
|
],
|
||||||
|
"version_notes": {
|
||||||
|
"enchantment_syntax": "1.21+: give player item[enchantments={name:level}]. Old NBT format {Enchantments:[...]} is INVALID.",
|
||||||
|
"effect_syntax": "1.13+: Must use 'effect give <target> <effect>'. Bare 'effect <target> <effect>' is INVALID.",
|
||||||
|
"weather_values": "Only valid values: clear, rain, thunder. 'storm', 'rainstorm' are INVALID.",
|
||||||
|
"execute_as_vs_at": "'execute as' changes executor (@s) but NOT position. 'execute at' changes position. Use 'at' for relative coordinates.",
|
||||||
|
"data_get_blocks": "'data get block' only works on block entities (chests, signs). For regular blocks, use 'execute if block' to test type."
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user