InícioDocs para devsBlueprint kind region: placa de pressão com primeiro/último ocupante
Exemplos por kind 6 min de leitura

Blueprint kind region: placa de pressão com primeiro/último ocupante

Grafos completos de entrada e saída: abrem uma porta na primeira chegada e fecham na última saída.

Objetivo

Mantenha uma porta aberta enquanto pelo menos um token elegível ocupa a região. Entrada e saída ocorrem a cada travessia elegível; compare count do contexto confiável com 1 na chegada e0 na saída. Não use Change state para controlar a ocupação da região.

Estes JSONs descrevem o subdocumento Blueprint v2 armazenado pelo host. São fixtures para desenvolvimento: não são módulo instalável, projeto completo do Builder ou arquivo de campanha. Recrie os nós no editor ou use os arquivos em testes isolados de contribuição ao host. Este guia não presume um botão de importar JSON no editor de Objetos Inteligentes.

Baixe o pacote completo de exemplos ou o validador. Todos os exemplos usam dados sintéticos originais. O avaliador Python interno serve ao desenvolvimento do código-fonte; módulos de navegador devem usar o SDK público.

Monte no editor

  1. Crie uma porta nativa e um retângulo Region no Map Builder. Dê nome aos dois, habilite a região e escolha sua camada de projeto.

  2. Para o equivalente pronto, escolha Controlled door na região e Apply pressure plate. Isso substitui o comportamento: use apenas quando quiser substituir o grafo existente.

  3. Para o exemplo manual, abra Edit behavior. Em On area enter, adicione Event context → Occupancy count, Compare value com number/eq/1 e Check state. Conecte o resultado booleano a Test da condição, substituindo sua comparação de estado padrão.

  4. Conecte On area enter à condição; True segue para Change state: Opened. Adicione Element reference da porta escolhida e conecte sua saída Target à entrada Target da ação.

  5. Em On area exit, monte a mesma cadeia com number/eq/0 e Change state: Closed. Referencie a mesma porta. O UUID 11111111-1111-4111-8111-111111111111 da fixture é sintético: escolha uma porta real da campanha no editor.

  6. Mantenha as aparências Empty e Occupied em inherit. Change sprite e Change state não controlam a imagem nem a ocupação de uma região.

JSON completo

Baixar region-pressure-plate.json

json
{
  "version": 2,
  "kind": "region",
  "states": {
    "empty": {
      "appearance": "inherit"
    },
    "occupied": {
      "appearance": "inherit"
    }
  },
  "graphs": {
    "presence:enter": {
      "nodes": [
        {
          "id": "start",
          "type": "event",
          "x": 40,
          "y": 80,
          "event": "presence:enter"
        },
        {
          "id": "count",
          "type": "eventContext",
          "x": 300,
          "y": 300,
          "property": "count"
        },
        {
          "id": "matches",
          "type": "compareValue",
          "x": 560,
          "y": 300,
          "valueType": "number",
          "expected": 1,
          "operator": "eq"
        },
        {
          "id": "check",
          "type": "condition",
          "x": 560,
          "y": 80,
          "state": "empty"
        },
        {
          "id": "door",
          "type": "reference",
          "x": 820,
          "y": 300,
          "targetId": "11111111-1111-4111-8111-111111111111"
        },
        {
          "id": "change",
          "type": "state",
          "x": 820,
          "y": 80,
          "targetState": "open"
        }
      ],
      "edges": [
        {
          "from": "start",
          "to": "check",
          "output": "next",
          "kind": "execution"
        },
        {
          "from": "check",
          "to": "change",
          "output": "true",
          "kind": "execution"
        },
        {
          "from": "count",
          "to": "matches",
          "output": "value",
          "kind": "data",
          "input": "value"
        },
        {
          "from": "matches",
          "to": "check",
          "output": "result",
          "kind": "data",
          "input": "test"
        },
        {
          "from": "door",
          "to": "change",
          "output": "door",
          "kind": "data",
          "input": "target"
        }
      ]
    },
    "presence:exit": {
      "nodes": [
        {
          "id": "start",
          "type": "event",
          "x": 40,
          "y": 80,
          "event": "presence:exit"
        },
        {
          "id": "count",
          "type": "eventContext",
          "x": 300,
          "y": 300,
          "property": "count"
        },
        {
          "id": "matches",
          "type": "compareValue",
          "x": 560,
          "y": 300,
          "valueType": "number",
          "expected": 0,
          "operator": "eq"
        },
        {
          "id": "check",
          "type": "condition",
          "x": 560,
          "y": 80,
          "state": "empty"
        },
        {
          "id": "door",
          "type": "reference",
          "x": 820,
          "y": 300,
          "targetId": "11111111-1111-4111-8111-111111111111"
        },
        {
          "id": "change",
          "type": "state",
          "x": 820,
          "y": 80,
          "targetState": "closed"
        }
      ],
      "edges": [
        {
          "from": "start",
          "to": "check",
          "output": "next",
          "kind": "execution"
        },
        {
          "from": "check",
          "to": "change",
          "output": "true",
          "kind": "execution"
        },
        {
          "from": "count",
          "to": "matches",
          "output": "value",
          "kind": "data",
          "input": "value"
        },
        {
          "from": "matches",
          "to": "check",
          "output": "result",
          "kind": "data",
          "input": "test"
        },
        {
          "from": "door",
          "to": "change",
          "output": "door",
          "kind": "data",
          "input": "target"
        }
      ]
    }
  }
}

Resultado esperado

EventoContagem após a travessiaAção prevista
presence:enter1abrir porta referenciada
presence:enter2nenhuma
presence:exit1nenhuma
presence:exit0fechar porta referenciada

O estado real da região é occupied nas três primeiras linhas e empty na última. Condições consultam o retrato do evento, não valores alterados por ações anteriores.

Execute a fixture em uma instalação de desenvolvimento

Extraia o pacote de exemplos em data/blueprint-examples, dentro de um checkout descartável da versão documentada. Na raiz do checkout, execute:

sh
uv run --locked python data/blueprint-examples/check-examples.py --host .

O verificador configura banco em memória, bloqueia consultas ao banco e chama as funções reais clean_blueprint e evaluate_graph. Ele valida os quatro tipos de objeto, os dois tipos de conexão e os 44 tipos de nó, incluindo requestRoll e setQuestStatus. Confere as duas visibilidades de rolagem, os seis status de missão e a continuação da execução sem rolar dados nem alterar diários. Isso verifica o formato e as ações previstas. Use também Test behavior para conferir alvos reais, autorização e a cadeia completa no servidor.

Para inspecionar esta receita no shell Django de desenvolvimento, após extrair os arquivos:

sh
uv run --locked python manage.py shell --no-imports
python
import json
from pathlib import Path
from gravewright.maps.blueprints import clean_blueprint, evaluate_graph

raw = json.loads(Path("data/blueprint-examples/region-pressure-plate.json").read_text(encoding="utf-8"))
blueprint = clean_blueprint(raw, asset_ids=set(), light_ids=set(), track_ids=set())
result = evaluate_graph(blueprint, "presence:enter", "occupied", event_context={"count": 1, "presence": "enter"})
print(result["trace"])
print(result["actions"])
assert result["actions"][0]["targetState"] == "open"
assert result["actions"][0]["target"] == "11111111-1111-4111-8111-111111111111"

Teste como GM e jogador

Use Simulate para inspecionar um evento local. Depois use Test behavior para ensaiar pelo servidor; as alterações desse ensaio são revertidas. Gere ou atualize a cena como GM e teste uma cena sintética com GM e jogador autorizado. Confira que streamer não consegue gravar. Ao editar novamente o projeto, use Update scene antes de esperar mudanças no comportamento da mesa.

Como GM, mova o token A para dentro, B para dentro, A para fora e B para fora. Confira as quatro linhas e o disparador real em Automation. Repita com tokens controlados por jogador e porta destrancada. Se a porta estiver trancada, continuam valendo as restrições normais do jogador; a região não concede novos direitos. Habilitar/editar a região recalcula a ocupação silenciosamente e não deve inventar chegadas.

Erros comuns

  • “Tirar um dos dois tokens fechou a porta”: compare count com 0 na saída; um evento de saída não significa região vazia.

  • “A região nunca fica ocupada”: confira enabled, centro do token, elevação e filtros de presença; movimento bloqueado ou só de prévia não confirma uma travessia.

  • “O UUID é válido, mas nada abre”: sintaxe válida não significa alvo real autorizado. Vincule a porta real e confira alvos ausentes/incompatíveis em Automation.

  • “Tentei state: occupied”: o estado da região é derivado. State aceita estados graváveis de porta/alavanca e não altera uma região.

Como usar a IA para adaptar este exemplo

text
Revise region-pressure-plate.json com o Gravewright 0.3.1. Acrescente uma mensagem original só na primeira entrada, preservando o fechamento na última saída. Use eventContext count e compareValue numérico; preserve empty/occupied como estados derivados. Explique IDs do projeto versus IDs nativos gerados e vincule a porta pelo editor. Entregue JSON completo e testes com dois tokens, filtro de elevação, alvo ausente e jogador diante de porta trancada. Não invente porta interact para region.

Todos os kinds de Blueprint · Conexões execution/data · Exemplos dos 44 tipos de nó