funifier-mcp 0.2.26 → 0.2.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor/rules/funifier.mdc +38 -41
- package/.github/copilot-instructions.md +38 -41
- package/AGENTS.md +56 -49
- package/README.md +40 -22
- package/datasource-funifier-docs/.coverage.json +326 -0
- package/datasource-funifier-docs/.validation.json +593 -0
- package/datasource-funifier-docs/knowledge/guides/aggregates.md +182 -70
- package/datasource-funifier-docs/knowledge/guides/database-access.md +174 -88
- package/datasource-funifier-docs/knowledge/guides/java-entities.md +294 -204
- package/datasource-funifier-docs/knowledge/guides/java-libraries.md +202 -226
- package/datasource-funifier-docs/knowledge/guides/java-managers.md +343 -265
- package/datasource-funifier-docs/knowledge/guides/trigger-examples.md +180 -236
- package/datasource-funifier-docs/knowledge/guides/triggers-guide.md +273 -191
- package/datasource-funifier-docs/knowledge/index.md +4 -1
- package/datasource-funifier-docs/knowledge/modules/achievement.md +1126 -28
- package/datasource-funifier-docs/knowledge/modules/action-log.md +469 -62
- package/datasource-funifier-docs/knowledge/modules/action.md +522 -70
- package/datasource-funifier-docs/knowledge/modules/auth.md +718 -69
- package/datasource-funifier-docs/knowledge/modules/avatar.md +483 -18
- package/datasource-funifier-docs/knowledge/modules/backup.md +603 -25
- package/datasource-funifier-docs/knowledge/modules/challenge.md +1048 -220
- package/datasource-funifier-docs/knowledge/modules/compact.md +469 -26
- package/datasource-funifier-docs/knowledge/modules/competition.md +811 -109
- package/datasource-funifier-docs/knowledge/modules/crossword.md +504 -28
- package/datasource-funifier-docs/knowledge/modules/csv-data.md +645 -20
- package/datasource-funifier-docs/knowledge/modules/custom-object.md +701 -36
- package/datasource-funifier-docs/knowledge/modules/database.md +730 -164
- package/datasource-funifier-docs/knowledge/modules/folder.md +935 -280
- package/datasource-funifier-docs/knowledge/modules/kpi-formulas.md +410 -15
- package/datasource-funifier-docs/knowledge/modules/lastmile.md +568 -29
- package/datasource-funifier-docs/knowledge/modules/leaderboard.md +595 -126
- package/datasource-funifier-docs/knowledge/modules/level.md +536 -54
- package/datasource-funifier-docs/knowledge/modules/lottery.md +809 -76
- package/datasource-funifier-docs/knowledge/modules/marketplace.md +688 -17
- package/datasource-funifier-docs/knowledge/modules/mystery.md +662 -52
- package/datasource-funifier-docs/knowledge/modules/notification.md +564 -26
- package/datasource-funifier-docs/knowledge/modules/patterns.md +519 -814
- package/datasource-funifier-docs/knowledge/modules/player.md +773 -73
- package/datasource-funifier-docs/knowledge/modules/point.md +380 -83
- package/datasource-funifier-docs/knowledge/modules/public.md +508 -178
- package/datasource-funifier-docs/knowledge/modules/question.md +619 -99
- package/datasource-funifier-docs/knowledge/modules/quiz.md +565 -120
- package/datasource-funifier-docs/knowledge/modules/scheduler.md +1092 -39
- package/datasource-funifier-docs/knowledge/modules/security.md +674 -112
- package/datasource-funifier-docs/knowledge/modules/staging.md +742 -19
- package/datasource-funifier-docs/knowledge/modules/story.md +565 -29
- package/datasource-funifier-docs/knowledge/modules/studio-page.md +470 -144
- package/datasource-funifier-docs/knowledge/modules/swap.md +552 -84
- package/datasource-funifier-docs/knowledge/modules/team.md +563 -45
- package/datasource-funifier-docs/knowledge/modules/trigger.md +876 -134
- package/datasource-funifier-docs/knowledge/modules/upload.md +468 -95
- package/datasource-funifier-docs/knowledge/modules/virtual-good.md +510 -63
- package/datasource-funifier-docs/knowledge/modules/webhook.md +375 -28
- package/datasource-funifier-docs/knowledge/modules/websocket.md +459 -26
- package/datasource-funifier-docs/knowledge/modules/widget.md +613 -27
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +42 -1
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/init.test.js +74 -3
- package/dist/cli/init.test.js.map +1 -1
- package/dist/cli/persona.d.ts +3 -0
- package/dist/cli/persona.d.ts.map +1 -0
- package/dist/cli/persona.js +25 -0
- package/dist/cli/persona.js.map +1 -0
- package/dist/mcp/bundle.js +119 -93
- package/dist/mcp/index.js +2 -2
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/resources/documentation.d.ts +1 -1
- package/dist/mcp/resources/documentation.d.ts.map +1 -1
- package/dist/mcp/resources/documentation.js +39 -3
- package/dist/mcp/resources/documentation.js.map +1 -1
- package/dist/mcp/tools/connect.d.ts.map +1 -1
- package/dist/mcp/tools/connect.js +18 -8
- package/dist/mcp/tools/connect.js.map +1 -1
- package/dist/mcp/tools/database.d.ts.map +1 -1
- package/dist/mcp/tools/database.js +59 -47
- package/dist/mcp/tools/database.js.map +1 -1
- package/dist/mcp/tools/database.test.js +2 -2
- package/dist/mcp/tools/database.test.js.map +1 -1
- package/dist/mcp/tools/delete.d.ts.map +1 -1
- package/dist/mcp/tools/delete.js +13 -3
- package/dist/mcp/tools/delete.js.map +1 -1
- package/dist/mcp/tools/execute.d.ts.map +1 -1
- package/dist/mcp/tools/execute.js +20 -9
- package/dist/mcp/tools/execute.js.map +1 -1
- package/dist/mcp/tools/folder.d.ts.map +1 -1
- package/dist/mcp/tools/folder.js +22 -12
- package/dist/mcp/tools/folder.js.map +1 -1
- package/dist/mcp/tools/get.d.ts.map +1 -1
- package/dist/mcp/tools/get.js +16 -6
- package/dist/mcp/tools/get.js.map +1 -1
- package/dist/mcp/tools/index.d.ts +1 -1
- package/dist/mcp/tools/index.d.ts.map +1 -1
- package/dist/mcp/tools/index.js +3 -1
- package/dist/mcp/tools/index.js.map +1 -1
- package/dist/mcp/tools/list.d.ts.map +1 -1
- package/dist/mcp/tools/list.js +38 -14
- package/dist/mcp/tools/list.js.map +1 -1
- package/dist/mcp/tools/logs.d.ts.map +1 -1
- package/dist/mcp/tools/logs.js +15 -5
- package/dist/mcp/tools/logs.js.map +1 -1
- package/dist/mcp/tools/save.d.ts.map +1 -1
- package/dist/mcp/tools/save.js +14 -4
- package/dist/mcp/tools/save.js.map +1 -1
- package/dist/mcp/tools/save.test.js +3 -3
- package/dist/mcp/tools/save.test.js.map +1 -1
- package/dist/mcp/tools/search-docs.d.ts +3 -0
- package/dist/mcp/tools/search-docs.d.ts.map +1 -0
- package/dist/mcp/tools/search-docs.js +102 -0
- package/dist/mcp/tools/search-docs.js.map +1 -0
- package/package.json +6 -2
- package/skills/acquire-funifier-knowledge/SKILL.md +132 -0
- package/skills/acquire-funifier-knowledge/assets/templates/CONCERNS.md +25 -0
- package/skills/acquire-funifier-knowledge/assets/templates/CUSTOM_ENDPOINTS.md +24 -0
- package/skills/acquire-funifier-knowledge/assets/templates/CUSTOM_PAGES.md +24 -0
- package/skills/acquire-funifier-knowledge/assets/templates/GAME_MECHANICS.md +35 -0
- package/skills/acquire-funifier-knowledge/assets/templates/INTEGRATIONS.md +35 -0
- package/skills/acquire-funifier-knowledge/assets/templates/LEADERBOARDS.md +24 -0
- package/skills/acquire-funifier-knowledge/assets/templates/OVERVIEW.md +47 -0
- package/skills/acquire-funifier-knowledge/assets/templates/PLAYER_MODEL.md +31 -0
- package/skills/acquire-funifier-knowledge/assets/templates/SCHEDULERS.md +25 -0
- package/skills/acquire-funifier-knowledge/assets/templates/TECHNIQUES_AND_PATTERNS.md +26 -0
- package/skills/acquire-funifier-knowledge/assets/templates/TRIGGERS.md +27 -0
- package/skills/acquire-funifier-knowledge/references/funifier-inventory-checklist.md +81 -0
- package/skills/acquire-funifier-knowledge/references/game-techniques-taxonomy.md +62 -0
- package/skills/acquire-funifier-knowledge/references/mcp-call-patterns.md +118 -0
- package/skills/funifier/SKILL.md +88 -0
- package/skills/funifier/references/configure-security.md +96 -0
- package/skills/{funifier-create-action/SKILL.md → funifier/references/create-action.md} +0 -33
- package/skills/funifier/references/create-aggregate.md +144 -0
- package/skills/funifier/references/create-challenge.md +116 -0
- package/skills/funifier/references/create-competition.md +98 -0
- package/skills/funifier/references/create-crossword.md +574 -0
- package/skills/funifier/references/create-custom-object.md +91 -0
- package/skills/funifier/references/create-custom-page.md +135 -0
- package/skills/funifier/references/create-folder.md +104 -0
- package/skills/funifier/references/create-lastmile.md +643 -0
- package/skills/{funifier-create-leaderboard/SKILL.md → funifier/references/create-leaderboard.md} +0 -33
- package/skills/funifier/references/create-level.md +94 -0
- package/skills/funifier/references/create-lottery.md +913 -0
- package/skills/funifier/references/create-mystery.md +769 -0
- package/skills/funifier/references/create-notification.md +75 -0
- package/skills/{funifier-create-point/SKILL.md → funifier/references/create-point.md} +0 -33
- package/skills/funifier/references/create-quiz.md +98 -0
- package/skills/funifier/references/create-scheduler.md +141 -0
- package/skills/funifier/references/create-story.md +636 -0
- package/skills/funifier/references/create-swap.md +95 -0
- package/skills/{funifier-create-trigger/SKILL.md → funifier/references/create-trigger.md} +0 -33
- package/skills/funifier/references/create-virtual-good.md +96 -0
- package/skills/funifier/references/create-webhook.md +72 -0
- package/skills/funifier/references/create-websocket.md +71 -0
- package/skills/funifier/references/create-widget.md +76 -0
- package/skills/funifier/references/debug.md +87 -0
- package/skills/funifier/references/help.md +81 -0
- package/skills/funifier/references/implement-frontend.md +106 -0
- package/skills/funifier/references/import-csv.md +75 -0
- package/skills/funifier/references/manage-player.md +82 -0
- package/skills/funifier/references/manage-team.md +76 -0
- package/skills/funifier/references/upload-file.md +91 -0
- package/skills/funifier-create-aggregate/SKILL.md +0 -127
- package/skills/funifier-create-challenge/SKILL.md +0 -88
- package/skills/funifier-create-custom-page/SKILL.md +0 -127
- package/skills/funifier-create-level/SKILL.md +0 -87
- package/skills/funifier-create-quiz/SKILL.md +0 -87
- package/skills/funifier-create-scheduler/SKILL.md +0 -127
- package/skills/funifier-create-virtual-good/SKILL.md +0 -87
- package/skills/funifier-debug/SKILL.md +0 -92
- package/skills/funifier-help/SKILL.md +0 -86
- package/skills/funifier-implement-frontend/SKILL.md +0 -90
- package/skills/funifier-index/SKILL.md +0 -58
|
@@ -1,178 +1,96 @@
|
|
|
1
1
|
# Trigger Examples — Padrões de Produção
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## 1. Visão Geral
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
## Eventos Oficiais (dropdown do Studio)
|
|
8
|
-
|
|
9
|
-
| Evento | Quando é acionado |
|
|
10
|
-
|--------|-------------------|
|
|
11
|
-
| `before_win` | Antes de registrar uma conquista (ponto, desafio, item) |
|
|
12
|
-
| `after_win` | Depois de registrar uma conquista |
|
|
13
|
-
| `before_lose` | Antes de remover uma conquista |
|
|
14
|
-
| `after_lose` | Depois de remover uma conquista |
|
|
15
|
-
| `before_create` | Antes de persistir um novo documento |
|
|
16
|
-
| `after_create` | Depois de persistir um novo documento |
|
|
17
|
-
| `before_update` | Antes de atualizar um documento existente |
|
|
18
|
-
| `after_update` | Depois de atualizar um documento |
|
|
19
|
-
| `before_delete` | Antes de deletar um documento |
|
|
20
|
-
| `after_delete` | Depois de deletar um documento |
|
|
5
|
+
### 1.1 O que é este documento
|
|
21
6
|
|
|
22
|
-
|
|
7
|
+
Este documento reúne exemplos de produção de triggers Funifier — código Groovy pronto, anotado, para padrões reais (atualizar coleção relacionada, enriquecer conquista, criar achievement, inicializar jogador, normalizar/rejeitar `__c`, processar lote, disparar ação). Os **conceitos** (eventos, entidades, variáveis, regra de persistência) não são repetidos aqui — vivem no guia de triggers.
|
|
23
8
|
|
|
24
|
-
|
|
9
|
+
### 1.2 Quando consultar
|
|
25
10
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
| `after_bulk` | Depois de um insert/update em lote via API |
|
|
30
|
-
| `csv_before_bulk` | Antes de processar um import CSV |
|
|
31
|
-
| `csv_after_bulk` | Depois de processar um import CSV |
|
|
11
|
+
- Consulte ao precisar de um **exemplo concreto** para um par evento+entidade.
|
|
12
|
+
- Consulte ao implementar **rejeição de criação** (`after_create` + delete) ou **processamento em lote**.
|
|
13
|
+
- Consulte ao precisar **registrar uma ação** a partir de um trigger (`track`/`trackSynchonous`).
|
|
32
14
|
|
|
33
|
-
|
|
15
|
+
### 1.3 Quando NÃO consultar
|
|
34
16
|
|
|
35
|
-
|
|
17
|
+
- **NÃO** consulte para entender **eventos, entidades, `context.extra` ou a regra de persistência** — use `datasource-funifier-docs/knowledge/guides/triggers-guide.md`.
|
|
18
|
+
- **NÃO** consulte para **métodos de manager / campos de entidade / bibliotecas** — use `java-managers.md`, `java-entities.md`, `java-libraries.md`.
|
|
36
19
|
|
|
37
|
-
|
|
20
|
+
### 1.4 Índice de decisão
|
|
38
21
|
|
|
39
|
-
|
|
40
|
-
|
|
22
|
+
| Quero… | Exemplo | Seção |
|
|
23
|
+
|---|---|---|
|
|
24
|
+
| Atualizar um documento `__c` quando uma ação ocorre | `action \| before_win` | §3 |
|
|
25
|
+
| Marcar a origem (ação/desafio) de uma conquista | `achievement \| before_create` | §4 |
|
|
26
|
+
| Creditar pontos a outro jogador como efeito de uma ação | `action \| after_win` | §5 |
|
|
27
|
+
| Preencher dados do jogador no cadastro | `player \| after_create` | §6 |
|
|
28
|
+
| Normalizar campos antes de salvar um `__c` | `custom__c \| before_create` | §7 |
|
|
29
|
+
| Validar e rejeitar a criação de um `__c` | `custom__c \| after_create` | §8 |
|
|
30
|
+
| Processar um import/insert em lote | `custom__c \| after_bulk` | §9 |
|
|
31
|
+
| Disparar uma ação de dentro de um trigger | `track` / `trackSynchonous` | §10 |
|
|
41
32
|
|
|
42
|
-
|
|
43
|
-
`achievement` e todas as coleções customizadas (`__c`) do projeto aparecem aqui.
|
|
44
|
-
Excluídas: `action_log`, `challenge_progress`, `player_status`, `security`, `technique_field`, `join_log`.
|
|
33
|
+
### 1.5 Restrições globais críticas
|
|
45
34
|
|
|
46
|
-
|
|
35
|
+
Todas herdadas de `triggers-guide.md` §1.5 — releia antes de copiar qualquer exemplo. As mais relevantes aqui:
|
|
47
36
|
|
|
48
|
-
|
|
37
|
+
> ⚠️ **`throw` não cancela persistência** → rejeição é em `after_create` + `database.delete` (§8, e `triggers-guide.md` §8).
|
|
38
|
+
> ⚠️ **Em Groovy use `.id`, não `._id`** → todos os exemplos abaixo seguem essa regra.
|
|
39
|
+
> ⚠️ **Nunca `track` a mesma ação que disparou o trigger** → loop infinito; filtre por `entity.actionId` no início (§10).
|
|
49
40
|
|
|
50
|
-
|
|
41
|
+
### 1.6 Documentos relacionados
|
|
51
42
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
| `Achievement.TYPE_CHALLENGE` | `1` | Desafio completado |
|
|
56
|
-
| `Achievement.TYPE_VIRTUAL_GOOD` | `2` | Item de catálogo comprado |
|
|
57
|
-
| `Achievement.TYPE_LEVEL` | `3` | Nível alcançado |
|
|
58
|
-
| `Achievement.TYPE_LOTTERY` | `5` | Loteria |
|
|
59
|
-
| `Achievement.TYPE_COMPETITION` | `9` | Competição |
|
|
43
|
+
> 📄 `datasource-funifier-docs/knowledge/guides/triggers-guide.md` — conceitos (eventos, entidades, `context.extra`, persistência)
|
|
44
|
+
> 📄 `datasource-funifier-docs/knowledge/guides/java-managers.md` — `track`, `addAchievement`, `getJongoConnection`
|
|
45
|
+
> 📄 `datasource-funifier-docs/knowledge/guides/database-access.md` — `findOne`/`save`/`count`/`delete`
|
|
60
46
|
|
|
61
47
|
---
|
|
62
48
|
|
|
63
|
-
##
|
|
64
|
-
|
|
65
|
-
### ActionLog (`entity` em triggers de `action`)
|
|
66
|
-
```java
|
|
67
|
-
entity.actionId // String — ID da ação (ex: "complete_task")
|
|
68
|
-
entity.userId // String — ID do jogador que executou
|
|
69
|
-
entity.attributes // Map<String, Object> — atributos da ação
|
|
70
|
-
entity.time // Date — momento da execução
|
|
71
|
-
entity.id // String — alias para entity._id
|
|
72
|
-
entity._id // String — ID do registro de log
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
### Player (`entity` em triggers de `player`)
|
|
76
|
-
```java
|
|
77
|
-
entity._id / entity.id // String — ID do jogador
|
|
78
|
-
entity.name // String
|
|
79
|
-
entity.email // String
|
|
80
|
-
entity.extra // Map<String, Object> — campos customizados
|
|
81
|
-
entity.teams // List<String> — IDs das equipes
|
|
82
|
-
entity.image // ImageSet — getOriginal().getUrl(), getMedium(), getSmall()
|
|
83
|
-
```
|
|
49
|
+
## 2. Formato do Documento de Trigger
|
|
84
50
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
entity.total // double — quantidade
|
|
90
|
-
entity.type // int — ver tabela de constantes acima
|
|
91
|
-
entity.item // String — ID do ponto/desafio/item
|
|
92
|
-
entity.time // Date
|
|
93
|
-
entity.extra // Map<String, Object>
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
---
|
|
51
|
+
Quando usar: ao deployar qualquer exemplo abaixo via API.
|
|
52
|
+
Não usar quando: criando a trigger pelo Studio (cole só o script no campo).
|
|
53
|
+
Depende de: `Trigger` (`java-entities.md` §10).
|
|
54
|
+
Disponível em: Trigger.
|
|
97
55
|
|
|
98
|
-
|
|
56
|
+
### Descrição
|
|
99
57
|
|
|
100
|
-
|
|
58
|
+
Os exemplos abaixo mostram o **script Groovy** legível. Para deployar via `POST /v3/trigger`, envolva o script (como string JSON-escapada) neste envelope:
|
|
101
59
|
|
|
102
|
-
|
|
103
|
-
context.extra.parentAchievement // Achievement que gerou este evento
|
|
104
|
-
context.extra.parentAchievement.id // String
|
|
105
|
-
context.extra.parentAchievement.type // int (usar constantes acima)
|
|
106
|
-
context.extra.parentAchievement.item // String
|
|
107
|
-
context.extra.parentAchievement.player // String
|
|
108
|
-
context.extra.parentAchievement.total // double
|
|
60
|
+
### Uso
|
|
109
61
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"name": "Nome descritivo",
|
|
65
|
+
"entity": "<entidade>",
|
|
66
|
+
"event": "<evento>",
|
|
67
|
+
"active": true,
|
|
68
|
+
"script": "void trigger(event, entity, player, database) { /* … código … */ }"
|
|
69
|
+
}
|
|
117
70
|
```
|
|
118
71
|
|
|
119
|
-
|
|
72
|
+
### Armadilhas conhecidas
|
|
120
73
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
O Funifier **sempre salva o documento** antes de executar o trigger. Não é possível usar `throw` para cancelar a persistência.
|
|
124
|
-
|
|
125
|
-
**Padrão correto para rejeitar uma criação:**
|
|
126
|
-
1. Use `after_create` (não `before_create`)
|
|
127
|
-
2. Valide no trigger; se inválido:
|
|
128
|
-
```java
|
|
129
|
-
database.delete(entity._id, "collection__c");
|
|
130
|
-
entity.clear();
|
|
131
|
-
entity.put("message", "Motivo da rejeição");
|
|
132
|
-
return;
|
|
133
|
-
```
|
|
134
|
-
3. Para lógica complexa, use uma `BusinessException` interna para centralizar o cleanup:
|
|
135
|
-
```java
|
|
136
|
-
// A exceção é capturada dentro do próprio trigger — não propaga para a plataforma
|
|
137
|
-
try {
|
|
138
|
-
if (condicaoInvalida) throw new BusinessException("Motivo");
|
|
139
|
-
// ... mais validações ...
|
|
140
|
-
} catch (BusinessException e) {
|
|
141
|
-
database.delete(entity._id, "collection__c");
|
|
142
|
-
entity.clear();
|
|
143
|
-
entity.put("message", e.getMessage());
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
public class BusinessException extends Exception {
|
|
147
|
-
private String message;
|
|
148
|
-
public BusinessException(String message) { super(message); this.message = message; }
|
|
149
|
-
public String getMessage() { return this.message; }
|
|
150
|
-
}
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
**`before_create` é para enriquecimento apenas:** normalizar strings, preencher defaults, adicionar metadados.
|
|
74
|
+
- **Atualizar a trigger com `POST` parcial** → o `script` é apagado (full replace; `patterns.md` §1.5). Correção: reenviar o documento completo.
|
|
154
75
|
|
|
155
76
|
---
|
|
156
77
|
|
|
157
|
-
##
|
|
78
|
+
## 3. `action | before_win` — Atualizar Coleção Relacionada
|
|
158
79
|
|
|
159
|
-
|
|
80
|
+
Quando usar: ler atributos de uma ActionLog e atualizar um documento em coleção `__c`.
|
|
81
|
+
Não usar quando: o efeito é conceder pontos/conquista → §5.
|
|
82
|
+
Depende de: `database`/`getJongoConnection` (`database-access.md`), `JsonUtil` (`java-libraries.md`).
|
|
83
|
+
Disponível em: Trigger.
|
|
160
84
|
|
|
161
|
-
|
|
85
|
+
### Descrição
|
|
162
86
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
"entity": "action",
|
|
167
|
-
"event": "before_win",
|
|
168
|
-
"active": true,
|
|
169
|
-
"script": "void trigger(event, entity, player, database) {\n if (!entity.actionId.equals(\"complete_task\")) return;\n\n String taskId = String.valueOf(entity.attributes.get(\"taskId\"));\n if (taskId == null || taskId.equals(\"null\")) return;\n\n HashMap<String, Object> task = manager.getJongoConnection()\n .getCollection(\"task__c\")\n .findOne(\"{_id:#}\", taskId).as(HashMap.class);\n\n if (task != null) {\n task.put(\"status\", \"done\");\n task.put(\"completedAt\", new Date());\n manager.getJongoConnection().getCollection(\"task__c\").save(task);\n entity.attributes.put(\"status\", \"processed\");\n println(\"task updated: \" + JsonUtil.toJson(task));\n }\n}\n"
|
|
170
|
-
}
|
|
171
|
-
```
|
|
87
|
+
Ação `complete_task` marca a task correspondente como concluída em `task__c`.
|
|
88
|
+
|
|
89
|
+
### Uso
|
|
172
90
|
|
|
173
91
|
```groovy
|
|
174
92
|
void trigger(event, entity, player, database) {
|
|
175
|
-
if (!entity.actionId.equals("complete_task")) return;
|
|
93
|
+
if (!entity.actionId.equals("complete_task")) return; // filtra a ação alvo
|
|
176
94
|
|
|
177
95
|
String taskId = String.valueOf(entity.attributes.get("taskId"));
|
|
178
96
|
if (taskId == null || taskId.equals("null")) return;
|
|
@@ -191,28 +109,32 @@ void trigger(event, entity, player, database) {
|
|
|
191
109
|
}
|
|
192
110
|
```
|
|
193
111
|
|
|
112
|
+
### Armadilhas conhecidas
|
|
113
|
+
|
|
114
|
+
- **Não filtrar `entity.actionId`** → roda para toda ação. Correção: `return` cedo se não for a ação alvo.
|
|
115
|
+
- **`get("taskId")` ausente** → `"null"` (String). Correção: comparar com `"null"` após `String.valueOf`.
|
|
116
|
+
|
|
194
117
|
---
|
|
195
118
|
|
|
196
|
-
|
|
119
|
+
## 4. `achievement | before_create` — Enriquecer com Origem
|
|
197
120
|
|
|
198
|
-
|
|
121
|
+
Quando usar: marcar de qual ação/desafio uma conquista de ponto se originou.
|
|
122
|
+
Não usar quando: não precisa da origem → não leia `context.extra`.
|
|
123
|
+
Depende de: `context.extra` (`triggers-guide.md` §7), constantes `TYPE_*` (`java-entities.md` §3).
|
|
124
|
+
Disponível em: Trigger.
|
|
199
125
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
"active": true,
|
|
206
|
-
"script": "void trigger(event, entity, player, database) {\n if (entity.type != Achievement.TYPE_POINT) return;\n\n if (entity.extra == null) entity.extra = new HashMap<>();\n if (context.extra == null) return;\n\n if (context.extra.parentAchievement != null &&\n context.extra.parentAchievement.type == Achievement.TYPE_CHALLENGE) {\n entity.extra.put(\"originChallenge\", context.extra.parentAchievement.id);\n }\n\n if (context.extra.parentActionLog != null) {\n entity.extra.put(\"originAction\", context.extra.parentActionLog.id);\n entity.extra.put(\"originActionId\", context.extra.parentActionLog.actionId);\n }\n\n println(\"entity: \" + JsonUtil.toJson(entity));\n}\n"
|
|
207
|
-
}
|
|
208
|
-
```
|
|
126
|
+
### Descrição
|
|
127
|
+
|
|
128
|
+
Ao criar um Achievement de ponto, grava no `extra` o desafio/ação que o gerou, lendo `context.extra`.
|
|
129
|
+
|
|
130
|
+
### Uso
|
|
209
131
|
|
|
210
132
|
```groovy
|
|
211
133
|
void trigger(event, entity, player, database) {
|
|
212
134
|
if (entity.type != Achievement.TYPE_POINT) return;
|
|
213
135
|
|
|
214
136
|
if (entity.extra == null) entity.extra = new HashMap<>();
|
|
215
|
-
if (context.extra == null) return;
|
|
137
|
+
if (context.extra == null) return; // sem cadeia → nada a marcar
|
|
216
138
|
|
|
217
139
|
if (context.extra.parentAchievement != null &&
|
|
218
140
|
context.extra.parentAchievement.type == Achievement.TYPE_CHALLENGE) {
|
|
@@ -228,21 +150,24 @@ void trigger(event, entity, player, database) {
|
|
|
228
150
|
}
|
|
229
151
|
```
|
|
230
152
|
|
|
153
|
+
### Armadilhas conhecidas
|
|
154
|
+
|
|
155
|
+
- **Acessar `context.extra.*` sem checar null** → NPE. Correção: `if (context.extra == null) return;` e checar cada campo.
|
|
156
|
+
|
|
231
157
|
---
|
|
232
158
|
|
|
233
|
-
|
|
159
|
+
## 5. `action | after_win` — Criar Achievement Programaticamente
|
|
234
160
|
|
|
235
|
-
|
|
161
|
+
Quando usar: creditar pontos a outro jogador como efeito colateral de uma ação.
|
|
162
|
+
Não usar quando: o crédito é para o próprio jogador da ação → as regras da ação já o fazem.
|
|
163
|
+
Depende de: `AchievementManager.addAchievement` (`java-managers.md` §4), `Guid` (`java-libraries.md` §3).
|
|
164
|
+
Disponível em: Trigger.
|
|
236
165
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
"active": true,
|
|
243
|
-
"script": "void trigger(event, entity, player, database) {\n if (!entity.actionId.equals(\"accept_invite\")) return;\n\n String referrerId = String.valueOf(entity.attributes.get(\"referrer\"));\n if (referrerId == null || referrerId.equals(\"null\")) return;\n\n Achievement credit = new Achievement();\n credit.id = Guid.newShortGuid();\n credit.type = Achievement.TYPE_POINT;\n credit.player = referrerId;\n credit.item = \"xp\";\n credit.total = 50;\n credit.time = new Date();\n credit.extra = new HashMap();\n credit.extra.put(\"origin\", entity.id);\n credit.extra.put(\"originAction\", entity.actionId);\n\n manager.getAchievementManager().addAchievement(credit);\n println(\"credited: \" + JsonUtil.toJson(credit));\n}\n"
|
|
244
|
-
}
|
|
245
|
-
```
|
|
166
|
+
### Descrição
|
|
167
|
+
|
|
168
|
+
Ao aceitar um convite (`accept_invite`), credita 50 XP ao indicador (`referrer`).
|
|
169
|
+
|
|
170
|
+
### Uso
|
|
246
171
|
|
|
247
172
|
```groovy
|
|
248
173
|
void trigger(event, entity, player, database) {
|
|
@@ -252,7 +177,7 @@ void trigger(event, entity, player, database) {
|
|
|
252
177
|
if (referrerId == null || referrerId.equals("null")) return;
|
|
253
178
|
|
|
254
179
|
Achievement credit = new Achievement();
|
|
255
|
-
credit.id = Guid.newShortGuid();
|
|
180
|
+
credit.id = Guid.newShortGuid(); // .id, não ._id
|
|
256
181
|
credit.type = Achievement.TYPE_POINT;
|
|
257
182
|
credit.player = referrerId;
|
|
258
183
|
credit.item = "xp";
|
|
@@ -267,21 +192,25 @@ void trigger(event, entity, player, database) {
|
|
|
267
192
|
}
|
|
268
193
|
```
|
|
269
194
|
|
|
195
|
+
### Armadilhas conhecidas
|
|
196
|
+
|
|
197
|
+
- **`credit._id`** → não atribui em Groovy. Correção: `credit.id` (`triggers-guide.md` §1.5).
|
|
198
|
+
- **Creditar sem filtrar a ação** → crédito indevido em qualquer ação. Correção: `return` cedo.
|
|
199
|
+
|
|
270
200
|
---
|
|
271
201
|
|
|
272
|
-
|
|
202
|
+
## 6. `player | after_create` — Inicializar Dados do Jogador
|
|
273
203
|
|
|
274
|
-
|
|
204
|
+
Quando usar: ao criar um jogador, buscar dados relacionados em `__c` e preencher `extra`.
|
|
205
|
+
Não usar quando: os dados já vêm no payload de cadastro.
|
|
206
|
+
Depende de: `PlayerManager` (`java-managers.md` §2), `getJongoConnection` (`database-access.md`).
|
|
207
|
+
Disponível em: Trigger.
|
|
275
208
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
"active": true,
|
|
282
|
-
"script": "void trigger(event, entity, player, database) {\n println(\"new player: \" + JsonUtil.toJson(entity));\n\n HashMap<String, Object> employee = manager.getJongoConnection()\n .getCollection(\"employee__c\")\n .findOne(\"{email:#}\", entity.email).as(HashMap.class);\n\n if (employee == null) return;\n\n Player p = manager.getPlayerManager().findById(entity._id);\n if (p == null) return;\n\n if (p.extra == null) p.extra = new HashMap();\n p.extra.put(\"department\", employee.get(\"department\"));\n p.extra.put(\"role\", employee.get(\"role\"));\n p.extra.put(\"employeeId\", employee.get(\"_id\"));\n\n manager.getPlayerManager().insert(p);\n println(\"player initialized: \" + p._id);\n}\n"
|
|
283
|
-
}
|
|
284
|
-
```
|
|
209
|
+
### Descrição
|
|
210
|
+
|
|
211
|
+
Ao cadastrar o jogador, busca o funcionário correspondente em `employee__c` (por email) e copia `department`/`role` para `player.extra`.
|
|
212
|
+
|
|
213
|
+
### Uso
|
|
285
214
|
|
|
286
215
|
```groovy
|
|
287
216
|
void trigger(event, entity, player, database) {
|
|
@@ -293,34 +222,40 @@ void trigger(event, entity, player, database) {
|
|
|
293
222
|
|
|
294
223
|
if (employee == null) return;
|
|
295
224
|
|
|
296
|
-
Player p = manager.getPlayerManager().findById(entity.
|
|
225
|
+
Player p = manager.getPlayerManager().findById(entity.id); // .id, não ._id
|
|
297
226
|
if (p == null) return;
|
|
298
227
|
|
|
299
228
|
if (p.extra == null) p.extra = new HashMap();
|
|
300
229
|
p.extra.put("department", employee.get("department"));
|
|
301
230
|
p.extra.put("role", employee.get("role"));
|
|
302
|
-
p.extra.put("employeeId", employee.get("_id"));
|
|
231
|
+
p.extra.put("employeeId", employee.get("_id")); // _id é chave do HashMap (__c), não propriedade
|
|
303
232
|
|
|
304
|
-
manager.getPlayerManager().insert(p);
|
|
305
|
-
println("player initialized: " + p.
|
|
233
|
+
manager.getPlayerManager().insert(p); // insert = upsert (java-managers.md §2)
|
|
234
|
+
println("player initialized: " + p.id);
|
|
306
235
|
}
|
|
307
236
|
```
|
|
308
237
|
|
|
238
|
+
> Nota: em `__c` (HashMap) a chave é literalmente `"_id"` (`employee.get("_id")`); a regra `.id` vale só para POJOs em Groovy (`triggers-guide.md` §1.5).
|
|
239
|
+
|
|
240
|
+
### Armadilhas conhecidas
|
|
241
|
+
|
|
242
|
+
- **`pm.save(p)`** → inexistente. Correção: `insert` (`java-managers.md` §2).
|
|
243
|
+
- **`entity._id`** → `null`. Correção: `entity.id`.
|
|
244
|
+
|
|
309
245
|
---
|
|
310
246
|
|
|
311
|
-
|
|
247
|
+
## 7. `custom__c | before_create` — Normalizar Campos
|
|
312
248
|
|
|
313
|
-
|
|
249
|
+
Quando usar: enriquecer/normalizar um documento `__c` antes de salvar.
|
|
250
|
+
Não usar quando: precisa **rejeitar** o documento → §8 (`before_create` não rejeita).
|
|
251
|
+
Depende de: —
|
|
252
|
+
Disponível em: Trigger.
|
|
314
253
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
"active": true,
|
|
321
|
-
"script": "void trigger(event, entity, player, database) {\n entity.put(\"email\", normalizeEmail(entity.get(\"email\")));\n entity.put(\"name\", normalizeName(entity.get(\"name\")));\n entity.put(\"employeeId\", extractNumeric(entity.get(\"employeeId\")));\n}\n\nString normalizeEmail(Object value) {\n if (value == null) return \"\";\n String s = String.valueOf(value).replaceAll(\"\\\\s\", \"\");\n return s.equals(\"null\") ? \"\" : s.toLowerCase();\n}\n\nString normalizeName(Object value) {\n if (value == null) return \"\";\n String s = String.valueOf(value).trim();\n return s.equals(\"null\") ? \"\" : s;\n}\n\nString extractNumeric(Object value) {\n if (value == null) return \"\";\n try {\n return String.valueOf(Long.parseLong(String.valueOf(value).replaceAll(\"\\\\s\", \"\")));\n } catch (NumberFormatException e) {\n return \"\";\n }\n}\n"
|
|
322
|
-
}
|
|
323
|
-
```
|
|
254
|
+
### Descrição
|
|
255
|
+
|
|
256
|
+
`before_create` **não rejeita** (`triggers-guide.md` §8) — apenas normaliza email/nome/ID antes de persistir. Métodos auxiliares extraídos para clareza.
|
|
257
|
+
|
|
258
|
+
### Uso
|
|
324
259
|
|
|
325
260
|
```groovy
|
|
326
261
|
void trigger(event, entity, player, database) {
|
|
@@ -351,21 +286,24 @@ String extractNumeric(Object value) {
|
|
|
351
286
|
}
|
|
352
287
|
```
|
|
353
288
|
|
|
289
|
+
### Armadilhas conhecidas
|
|
290
|
+
|
|
291
|
+
- **Esperar que `before_create` rejeite valores inválidos** → não rejeita; o documento salva. Correção: validar/rejeitar em `after_create` (§8).
|
|
292
|
+
|
|
354
293
|
---
|
|
355
294
|
|
|
356
|
-
|
|
295
|
+
## 8. `custom__c | after_create` — Validar e Rejeitar
|
|
357
296
|
|
|
358
|
-
|
|
297
|
+
Quando usar: validar um documento `__c` recém-criado e rejeitá-lo se inválido.
|
|
298
|
+
Não usar quando: só precisa normalizar → §7.
|
|
299
|
+
Depende de: regra de persistência + `BusinessException` (`triggers-guide.md` §8), `getJongoConnection` (`database-access.md`).
|
|
300
|
+
Disponível em: Trigger.
|
|
359
301
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
"active": true,
|
|
366
|
-
"script": "void trigger(event, entity, player, database) {\n try {\n if (player == null || player.isEmpty()) {\n throw new BusinessException(\"Player obrigatório.\");\n }\n\n HashMap<String, Object> schedule = manager.getJongoConnection()\n .getCollection(\"schedule__c\")\n .findOne(\"{status:#}\", \"open\").as(HashMap.class);\n\n if (schedule == null) {\n throw new BusinessException(\"Nenhuma janela de cadastro aberta.\");\n }\n\n long existing = manager.getJongoConnection().getCollection(\"order__c\")\n .count('{\"_id\":{\"$ne\":#},\"owner\":#,\"status\":{\"$ne\":\"cancelled\"}}',\n entity._id, player);\n\n if (existing >= 3) {\n throw new BusinessException(\"Limite de cadastros atingido nesta janela.\");\n }\n\n } catch (BusinessException e) {\n database.delete(entity._id, \"order__c\");\n entity.clear();\n entity.put(\"message\", e.getMessage());\n println(\"rejected: \" + e.getMessage());\n return;\n }\n}\n\npublic class BusinessException extends Exception {\n private String message;\n public BusinessException(String msg) { super(msg); this.message = msg; }\n public String getMessage() { return this.message; }\n}\n"
|
|
367
|
-
}
|
|
368
|
-
```
|
|
302
|
+
### Descrição
|
|
303
|
+
|
|
304
|
+
O documento já foi salvo (`triggers-guide.md` §1.5). Se inválido, deleta e devolve a mensagem no `entity`. `BusinessException` centraliza o cleanup das múltiplas validações.
|
|
305
|
+
|
|
306
|
+
### Uso
|
|
369
307
|
|
|
370
308
|
```groovy
|
|
371
309
|
void trigger(event, entity, player, database) {
|
|
@@ -384,14 +322,14 @@ void trigger(event, entity, player, database) {
|
|
|
384
322
|
|
|
385
323
|
long existing = manager.getJongoConnection().getCollection("order__c")
|
|
386
324
|
.count('{"_id":{"$ne":#},"owner":#,"status":{"$ne":"cancelled"}}',
|
|
387
|
-
entity.
|
|
325
|
+
entity.id, player);
|
|
388
326
|
|
|
389
327
|
if (existing >= 3) {
|
|
390
328
|
throw new BusinessException("Limite de cadastros atingido nesta janela.");
|
|
391
329
|
}
|
|
392
330
|
|
|
393
331
|
} catch (BusinessException e) {
|
|
394
|
-
database.delete(entity.
|
|
332
|
+
database.delete(entity.id, "order__c"); // documento já salvo → deletar
|
|
395
333
|
entity.clear();
|
|
396
334
|
entity.put("message", e.getMessage());
|
|
397
335
|
println("rejected: " + e.getMessage());
|
|
@@ -406,26 +344,29 @@ public class BusinessException extends Exception {
|
|
|
406
344
|
}
|
|
407
345
|
```
|
|
408
346
|
|
|
347
|
+
### Armadilhas conhecidas
|
|
348
|
+
|
|
349
|
+
- **Usar `before_create` aqui** → `throw` não impede o save (`triggers-guide.md` §8). Correção: `after_create` + delete.
|
|
350
|
+
- **Esquecer `entity.clear()`** → o documento rejeitado mantém os dados. Correção: limpar e devolver só `message`.
|
|
351
|
+
|
|
409
352
|
---
|
|
410
353
|
|
|
411
|
-
|
|
354
|
+
## 9. `custom__c | after_bulk` — Processar Lote
|
|
412
355
|
|
|
413
|
-
|
|
356
|
+
Quando usar: processar cada item de um import/insert em lote.
|
|
357
|
+
Não usar quando: o evento é de documento único → `entity` não é List (`triggers-guide.md` §9).
|
|
358
|
+
Depende de: evento estendido `after_bulk` (`triggers-guide.md` §4, §9).
|
|
359
|
+
Disponível em: Trigger.
|
|
414
360
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
"active": true,
|
|
421
|
-
"script": "void trigger(event, entity, player, database) {\n if (entity == null || entity.isEmpty()) return;\n\n println(\"bulk size: \" + entity.size());\n\n for (Object raw : entity) {\n HashMap<String, Object> item = (HashMap<String, Object>) raw;\n if (item == null) continue;\n\n String employeeId = String.valueOf(item.get(\"employeeId\"));\n if (employeeId == null || employeeId.equals(\"null\")) continue;\n\n HashMap<String, Object> employee = manager.getJongoConnection()\n .getCollection(\"employee__c\")\n .findOne(\"{_id:#}\", employeeId).as(HashMap.class);\n\n if (employee != null) {\n item.put(\"department\", employee.get(\"department\"));\n item.put(\"processed\", true);\n manager.getJongoConnection().getCollection(\"import__c\").save(item);\n }\n }\n\n println(\"bulk processed: \" + entity.size() + \" records\");\n}\n"
|
|
422
|
-
}
|
|
423
|
-
```
|
|
361
|
+
### Descrição
|
|
362
|
+
|
|
363
|
+
Em `after_bulk`, `entity` é uma **List**. Para cada item, busca o funcionário em `employee__c` e enriquece.
|
|
364
|
+
|
|
365
|
+
### Uso
|
|
424
366
|
|
|
425
367
|
```groovy
|
|
426
368
|
void trigger(event, entity, player, database) {
|
|
427
369
|
if (entity == null || entity.isEmpty()) return;
|
|
428
|
-
|
|
429
370
|
println("bulk size: " + entity.size());
|
|
430
371
|
|
|
431
372
|
for (Object raw : entity) {
|
|
@@ -445,36 +386,38 @@ void trigger(event, entity, player, database) {
|
|
|
445
386
|
manager.getJongoConnection().getCollection("import__c").save(item);
|
|
446
387
|
}
|
|
447
388
|
}
|
|
448
|
-
|
|
449
389
|
println("bulk processed: " + entity.size() + " records");
|
|
450
390
|
}
|
|
451
391
|
```
|
|
452
392
|
|
|
393
|
+
### Armadilhas conhecidas
|
|
394
|
+
|
|
395
|
+
- **Tratar `entity` como documento único** → `ClassCastException`. Correção: iterar a List (`triggers-guide.md` §9).
|
|
396
|
+
|
|
453
397
|
---
|
|
454
398
|
|
|
455
|
-
|
|
399
|
+
## 10. Registrar Ação Programaticamente (`track` / `trackSynchonous`)
|
|
456
400
|
|
|
457
|
-
|
|
401
|
+
Quando usar: disparar uma ActionLog de dentro de um trigger, acionando as regras normalmente.
|
|
402
|
+
Não usar quando: a ação a registrar é a **mesma** que disparou o trigger → loop infinito.
|
|
403
|
+
Depende de: `ActionManager.track`/`trackSynchonous` (`java-managers.md` §3).
|
|
404
|
+
Disponível em: Trigger.
|
|
458
405
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
"active": true,
|
|
465
|
-
"script": "void trigger(event, entity, player, database) {\n if (!entity.actionId.equals(\"complete_task\")) return;\n\n ActionLog log = new ActionLog();\n log.id = Guid.newShortGuid();\n log.userId = entity.userId;\n log.actionId = \"task_completed_by_team\";\n log.time = new Date();\n log.attributes = new HashMap();\n log.attributes.put(\"taskId\", entity.attributes.get(\"taskId\"));\n log.attributes.put(\"origin\", entity.id);\n manager.getActionManager().track(log);\n println(\"tracked async: \" + JsonUtil.toJson(log));\n}\n"
|
|
466
|
-
}
|
|
467
|
-
```
|
|
406
|
+
### Descrição
|
|
407
|
+
|
|
408
|
+
`track` é assíncrono (não bloqueia); `trackSynchonous` bloqueia e retorna as conquistas geradas. Escolha pela necessidade de saber o resultado.
|
|
409
|
+
|
|
410
|
+
### Uso
|
|
468
411
|
|
|
412
|
+
**Assíncrono** (dispara e segue):
|
|
469
413
|
```groovy
|
|
470
414
|
void trigger(event, entity, player, database) {
|
|
471
|
-
if (!entity.actionId.equals("complete_task")) return;
|
|
415
|
+
if (!entity.actionId.equals("complete_task")) return; // evita loop (§1.5)
|
|
472
416
|
|
|
473
|
-
// Async: dispara e não bloqueia — conquistas processadas em background
|
|
474
417
|
ActionLog log = new ActionLog();
|
|
475
|
-
log.id = Guid.newShortGuid();
|
|
418
|
+
log.id = Guid.newShortGuid(); // .id, não ._id
|
|
476
419
|
log.userId = entity.userId;
|
|
477
|
-
log.actionId = "task_completed_by_team";
|
|
420
|
+
log.actionId = "task_completed_by_team"; // ação DIFERENTE da que disparou
|
|
478
421
|
log.time = new Date();
|
|
479
422
|
log.attributes = new HashMap();
|
|
480
423
|
log.attributes.put("taskId", entity.attributes.get("taskId"));
|
|
@@ -484,11 +427,10 @@ void trigger(event, entity, player, database) {
|
|
|
484
427
|
}
|
|
485
428
|
```
|
|
486
429
|
|
|
487
|
-
|
|
488
|
-
|
|
430
|
+
**Síncrono** (precisa saber quais conquistas foram geradas):
|
|
489
431
|
```groovy
|
|
490
432
|
void trigger(event, entity, player, database) {
|
|
491
|
-
//
|
|
433
|
+
// if (!entity.actionId.equals("your_action")) return; // filtre para evitar loop
|
|
492
434
|
|
|
493
435
|
ActionLog log = new ActionLog();
|
|
494
436
|
log.id = Guid.newShortGuid();
|
|
@@ -497,7 +439,6 @@ void trigger(event, entity, player, database) {
|
|
|
497
439
|
log.time = new Date();
|
|
498
440
|
log.attributes = new HashMap();
|
|
499
441
|
|
|
500
|
-
// trackSynchonous bloqueia e retorna as conquistas geradas
|
|
501
442
|
List<Achievement> earned = manager.getActionManager().trackSynchonous(log);
|
|
502
443
|
if (earned != null) {
|
|
503
444
|
println("earned: " + earned.size() + " achievements");
|
|
@@ -508,4 +449,7 @@ void trigger(event, entity, player, database) {
|
|
|
508
449
|
}
|
|
509
450
|
```
|
|
510
451
|
|
|
511
|
-
|
|
452
|
+
### Armadilhas conhecidas
|
|
453
|
+
|
|
454
|
+
- **`track`/`trackSynchonous` da mesma ação que disparou** → loop infinito (§1.5). Correção: ação diferente ou filtro por `entity.actionId`.
|
|
455
|
+
- **Esperar conquistas do `track`** → retorna `void`. Correção: `trackSynchonous` (`java-managers.md` §3).
|