i18n: per-player EN/PT via Adventure GlobalTranslator #1
@@ -26,7 +26,7 @@ All player-facing text is Portuguese (pt-BR).
|
|||||||
| `marcos` | Announces round milestones — 100 km walked, 24 hours played — the first time someone crosses one. |
|
| `marcos` | Announces round milestones — 100 km walked, 24 hours played — the first time someone crosses one. |
|
||||||
| `mortes` | Replaces each death message with a comic pt-BR line (cause-based flavor + a death counter) and sends the death coordinates **privately** to the dead player on respawn (the death screen swallows chat sent during the event), so they can run back to their dropped items. Respects `keepInventory`. No storage, no command. |
|
| `mortes` | Replaces each death message with a comic pt-BR line (cause-based flavor + a death counter) and sends the death coordinates **privately** to the dead player on respawn (the death screen swallows chat sent during the event), so they can run back to their dropped items. Respects `keepInventory`. No storage, no command. |
|
||||||
| `zoacao` | A chat message matching the trigger (a pattern + a match mode) is swapped for a random line from `zoacao.mensagens` — a chat gag. The player's name still prefixes it. Default: a bare `f`/`F` (trimmed) → a random gag line. Match modes: `igual` (equals), `contem` (contains), `comeca` (starts with), `termina` (ends with), `regex`. The mode, the pattern, and the message list are all editable in-game with `/canalhandia zoacao ...`. Pure chat swap; the `luto` tribute is unaffected (paying respects still needs the `[F]` button or `/f`). Affects Bedrock chat too (it's a chat event, not a click). |
|
| `zoacao` | A chat message matching the trigger (a pattern + a match mode) is swapped for a random line from `zoacao.mensagens` — a chat gag. The player's name still prefixes it. Default: a bare `f`/`F` (trimmed) → a random gag line. Match modes: `igual` (equals), `contem` (contains), `comeca` (starts with), `termina` (ends with), `regex`. The mode, the pattern, and the message list are all editable in-game with `/canalhandia zoacao ...`. Pure chat swap; the `luto` tribute is unaffected (paying respects still needs the `[F]` button or `/f`). Affects Bedrock chat too (it's a chat event, not a click). |
|
||||||
| `ia` | `/ia <pergunta>` asks an OpenAI-compatible model in chat. Optional wiki grounding, per-player memory, operator corrections. |
|
| `ia` | `/ia <pergunta>` asks an OpenAI-compatible model in chat. Has a personality (`zoeiro` by default — it will tease you), sees the last few chat lines and the live server state, and grounds answers in the asker's real stats. Optional wiki lookup, per-player memory, operator corrections. |
|
||||||
|
|
||||||
Toggle any of them: `/canalhandia modulo <nome> <on|off>`
|
Toggle any of them: `/canalhandia modulo <nome> <on|off>`
|
||||||
|
|
||||||
@@ -170,6 +170,8 @@ Admin (`canalhandia.admin`):
|
|||||||
/canalhandia zoacao adicionar <frase> adiciona uma frase de zoação
|
/canalhandia zoacao adicionar <frase> adiciona uma frase de zoação
|
||||||
/canalhandia zoacao remover <n|texto> remove uma frase de zoação
|
/canalhandia zoacao remover <n|texto> remove uma frase de zoação
|
||||||
/canalhandia zoacao limpar volta para as frases padrão
|
/canalhandia zoacao limpar volta para as frases padrão
|
||||||
|
/ia personalidade lista as personalidades da IA
|
||||||
|
/ia personalidade <nome> zoeiro | amigao | seco | aldeao | neutro
|
||||||
/canalhandia reload
|
/canalhandia reload
|
||||||
/curiosidade modo <entrada|intervalo|ambos|manual>
|
/curiosidade modo <entrada|intervalo|ambos|manual>
|
||||||
/curiosidade intervalo <min> intervalo do modo temporizado
|
/curiosidade intervalo <min> intervalo do modo temporizado
|
||||||
@@ -227,6 +229,8 @@ executed command.
|
|||||||
|---|---|
|
|---|---|
|
||||||
| `/ia <pergunta>` | Asks the model. Public by default — the question and answer broadcast. Needs `canalhandia.ia`. |
|
| `/ia <pergunta>` | Asks the model. Public by default — the question and answer broadcast. Needs `canalhandia.ia`. |
|
||||||
| `/iap <pergunta>` | Asks privately — the answer goes only to the asker. Needs `canalhandia.ia.privado`. |
|
| `/iap <pergunta>` | Asks privately — the answer goes only to the asker. Needs `canalhandia.ia.privado`. |
|
||||||
|
| `/ia personalidade` | Lists the tones and marks the active one. Needs `canalhandia.ia.perfil`. |
|
||||||
|
| `/ia personalidade <nome>` | Switches tone live: `zoeiro` (default), `amigao`, `seco`, `aldeao`, `neutro`. |
|
||||||
| `/ia perfil <economico\|preciso>` | Switches profile live. `ECONOMICO` skips the wiki (fast); `PRECISO` consults the Minecraft Wiki (slower, grounded). Needs `canalhandia.ia.perfil`. |
|
| `/ia perfil <economico\|preciso>` | Switches profile live. `ECONOMICO` skips the wiki (fast); `PRECISO` consults the Minecraft Wiki (slower, grounded). Needs `canalhandia.ia.perfil`. |
|
||||||
| `/ia corrigir <resposta correta>` | Records a correction for the last answered question. Future similar questions get it as context — the cheap alternative to fine-tuning. Needs `canalhandia.ia.corrigir`. |
|
| `/ia corrigir <resposta correta>` | Records a correction for the last answered question. Future similar questions get it as context — the cheap alternative to fine-tuning. Needs `canalhandia.ia.corrigir`. |
|
||||||
| `/ia feedback ruim` | Flags the last answer wrong (in-memory counter shown in `/canalhandia status`). |
|
| `/ia feedback ruim` | Flags the last answer wrong (in-memory counter shown in `/canalhandia status`). |
|
||||||
@@ -236,6 +240,57 @@ Subcommands only hijack when their second token is one they act on (a known
|
|||||||
profile key, or `ruim`), so `/ia perfil do servidor` falls through and is asked.
|
profile key, or `ruim`), so `/ia perfil do servidor` falls through and is asked.
|
||||||
`corrigir` stays greedy — a correction always reads the rest of the line.
|
`corrigir` stays greedy — a correction always reads the rest of the line.
|
||||||
|
|
||||||
|
### Personality
|
||||||
|
|
||||||
|
`ia.personalidade` picks the tone. It is expressed purely as extra system
|
||||||
|
instructions appended after the base ones, so it changes **how** the model
|
||||||
|
talks and never **what it may do**.
|
||||||
|
|
||||||
|
| Persona | Tone |
|
||||||
|
|---|---|
|
||||||
|
| `zoeiro` | Default. A grumpy server veteran: teases the asker, turns their own stats against them ("você já morreu 47 vezes e vem me perguntar sobre lava?"), but answers the question for real. |
|
||||||
|
| `amigao` | Warm and patient, jokes rarely. For servers with new players. |
|
||||||
|
| `seco` | Deadpan, one or two sentences, no exclamation marks. |
|
||||||
|
| `aldeao` | In character as an ancient villager. Flavour only; still answers. |
|
||||||
|
| `neutro` | No personality — the pre-persona behaviour. |
|
||||||
|
|
||||||
|
Every persona, `neutro` included, carries `Persona.GUARD`, which restates the
|
||||||
|
limits inside the persona's own frame: still no server/terminal/file access,
|
||||||
|
still no commands, no inventing stats, no leaking the prompt. That is the
|
||||||
|
layer that stops "you are a grumpy veteran" from reading as licence to claim
|
||||||
|
powers the plugin never grants. Each teasing persona also states where the
|
||||||
|
line is (no real insults, nothing about family, appearance, race, religion,
|
||||||
|
sexuality or money; drop the ribbing if the player asks). Tests assert both
|
||||||
|
properties hold for every persona, so adding a new one cannot quietly skip them.
|
||||||
|
|
||||||
|
Switch live with `/ia personalidade <nome>` — read per-question, no restart.
|
||||||
|
|
||||||
|
### Chat and world awareness
|
||||||
|
|
||||||
|
- **Recent chat** (`contexto-chat`, default 5, 0 disables): the last N public
|
||||||
|
chat lines are sent as context, so the AI can follow what the room is talking
|
||||||
|
about. Held in a bounded in-memory ring (50 lines max, 200 chars per line);
|
||||||
|
nothing is written to disk and a restart starts it empty. Recorded at
|
||||||
|
`MONITOR` priority with `ignoreCancelled`, so what it stores is what players
|
||||||
|
actually saw — a `zoacao` swap included — and a cancelled message is never
|
||||||
|
stored.
|
||||||
|
- **Live server state** (`estado-servidor`, default on): who is online and on
|
||||||
|
which platform, the asker's dimension, in-game time of day, weather, and
|
||||||
|
their coordinates, health, hunger and XP level. This is what lets the AI
|
||||||
|
answer "quem tá online?" or "tá chovendo?" instead of insisting it has no
|
||||||
|
access. Captured on the main thread before the async call — every field
|
||||||
|
reads the Bukkit world API, which is not safe off it — so only the formatted
|
||||||
|
string crosses the thread boundary.
|
||||||
|
|
||||||
|
### Answer styling
|
||||||
|
|
||||||
|
With `estilo-rico` on (default), Java players get the answer with a hover card
|
||||||
|
showing the original question and the active persona, plus a click that
|
||||||
|
pre-fills `/ia ` for a follow-up. The click uses `suggestCommand`, never
|
||||||
|
`runCommand`: nothing executes without the player pressing enter. Bedrock
|
||||||
|
renders neither hover nor click, so it always gets the plain line — built via
|
||||||
|
`broadcastPerPlatform`, like every other interactive message here.
|
||||||
|
|
||||||
### Profile
|
### Profile
|
||||||
|
|
||||||
`ECONOMICO` skips the wiki round trip — fast, ungrounded. `PRECISO` runs a
|
`ECONOMICO` skips the wiki round trip — fast, ungrounded. `PRECISO` runs a
|
||||||
@@ -311,9 +366,42 @@ path for a new jar — `/canalhandia reload` only re-reads `config.yml`.
|
|||||||
```bash
|
```bash
|
||||||
POD=$(microk8s kubectl get pod -n minecraft -l app=crafty-controller -o name | head -1)
|
POD=$(microk8s kubectl get pod -n minecraft -l app=crafty-controller -o name | head -1)
|
||||||
SRV=/crafty/servers/6e39a8b2-300b-42d6-8139-f397c23e461b
|
SRV=/crafty/servers/6e39a8b2-300b-42d6-8139-f397c23e461b
|
||||||
|
microk8s kubectl exec ${POD#pod/} -n minecraft -- \
|
||||||
|
cp $SRV/plugins/Canalhandia-1.0.0.jar $SRV/plugins/Canalhandia-1.0.0.jar.bak-$(date +%F)
|
||||||
microk8s kubectl cp target/Canalhandia-1.0.0.jar minecraft/${POD#pod/}:$SRV/plugins/Canalhandia-1.0.0.jar
|
microk8s kubectl cp target/Canalhandia-1.0.0.jar minecraft/${POD#pod/}:$SRV/plugins/Canalhandia-1.0.0.jar
|
||||||
|
# The JVM runs as uid 1000 / gid 0; a root-owned jar is one it cannot read,
|
||||||
|
# and the failure looks exactly like "the plugin just did not load".
|
||||||
|
microk8s kubectl exec ${POD#pod/} -n minecraft -- chown 1000:0 $SRV/plugins/Canalhandia-1.0.0.jar
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Pre-flight
|
||||||
|
|
||||||
|
`./preflight.sh [jar]` checks a staged deploy **before** anyone restarts
|
||||||
|
anything. Every check is read-only; it never restarts the server, never writes
|
||||||
|
to `plugins/`, and never touches the world.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ ./preflight.sh
|
||||||
|
1. Local build jar opens, plugin.yml present, all 16 commands declared,
|
||||||
|
config.yml bundled
|
||||||
|
2. Tests surefire totals, 0 failures
|
||||||
|
3. Cluster crafty pod found, plugins directory reachable
|
||||||
|
4. Staged jar hash matches the local build, owned 1000:0, a rollback
|
||||||
|
.bak jar exists
|
||||||
|
5. Live config parses as YAML, carries the keys this deploy needs, has a
|
||||||
|
.bak to roll back to
|
||||||
|
6. Health the log is readable and free of recent ERROR lines
|
||||||
|
|
||||||
|
PRE-FLIGHT CLEAN — safe to restart.
|
||||||
|
```
|
||||||
|
|
||||||
|
It exits non-zero on any failure. A missing YAML parser reports as *not
|
||||||
|
checked* rather than *invalid*: a harness that cries wolf is one people learn
|
||||||
|
to ignore.
|
||||||
|
|
||||||
|
Because the plugin is staged dormant (copied in, not restarted), a red line
|
||||||
|
here is a crash-on-boot you get to fix while the server is still up.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Source layout
|
## Source layout
|
||||||
@@ -334,6 +422,9 @@ microk8s kubectl cp target/Canalhandia-1.0.0.jar minecraft/${POD#pod/}:$SRV/plug
|
|||||||
| `OfflineStats.java` | Reads stats JSON for offline players (rankings + the asker's stat summary for the IA) |
|
| `OfflineStats.java` | Reads stats JSON for offline players (rankings + the asker's stat summary for the IA) |
|
||||||
| `RankingMetric.java` | Leaderboard columns and their formatting |
|
| `RankingMetric.java` | Leaderboard columns and their formatting |
|
||||||
| `DeathFlavor.java` | Comic pt-BR verb phrases for each death cause (used by the `mortes` module) |
|
| `DeathFlavor.java` | Comic pt-BR verb phrases for each death cause (used by the `mortes` module) |
|
||||||
|
| `Persona.java` | The AI's five tones, each carrying the safety guard |
|
||||||
|
| `ChatLog.java` | Bounded, thread-safe ring of recent public chat for the AI |
|
||||||
|
| `ServerState.java` | Main-thread snapshot of the live world for the AI |
|
||||||
| `Msg.java` | Shared chat formatting and pt-BR number/duration formatting |
|
| `Msg.java` | Shared chat formatting and pt-BR number/duration formatting |
|
||||||
|
|
||||||
### Adding a curiosity
|
### Adding a curiosity
|
||||||
|
|||||||
Reference in New Issue
Block a user