Skip to content

Entity Visibility System

Journey 3.0 expands the visibility system from NPC-only to all entity types. Any entity in the game — NPCs, mobs, projectiles, item drops, armor stands — can be made visible or invisible on a per-player basis. This powers quest phasing, private dungeons, party-exclusive encounters, and more.


Every managed entity has a visibility type that determines its default behavior:

TypeDescription
OWNER_ONLYOnly the owner player can see the entity
GLOBAL_WHEN_OWNER_ONLINEEveryone sees it while the owner is online; hidden when they log off
CONDITIONALVisible when a MoLang condition evaluates to true per-player
AREA_RESTRICTEDOnly visible to players inside a specific zone/region
ALWAYS_VISIBLEEveryone always sees it (default for normal entities)

The entity is only visible to its owner. Other players cannot see or interact with it.

Use cases: Personal quest NPCs, private spawned Pokemon, player-specific interactables.

{
"entity_uuid": "npc-uuid-here",
"visibility_type": "OWNER_ONLY",
"owner": "player-uuid"
}

Everyone can see the entity while the owner is online. When the owner disconnects, the entity hides from all players.

Use cases: Player shops, personal mounts in public areas, summoned companions.

{
"entity_uuid": "shop-npc-uuid",
"visibility_type": "GLOBAL_WHEN_OWNER_ONLINE",
"owner": "player-uuid"
}

Visibility is determined by a MoLang expression evaluated per-player. This is the most flexible type — it replaces the old NPC visibility condition system.

Use cases: Quest-phased NPCs, progressive story content, badge-gated gym leaders.

{
"entity_uuid": "misty-npc-uuid",
"visibility_type": "CONDITIONAL",
"condition": "q.player.has_flag('gym_badge_boulder')"
}

The entity is only visible to players within a specific zone or Ceremony region.

Use cases: Dungeon bosses, zone-specific NPCs, area-exclusive encounters.

{
"entity_uuid": "dungeon-boss-uuid",
"visibility_type": "AREA_RESTRICTED",
"zones": ["dungeon-zone-uuid"]
}

The entity is visible to everyone at all times. This is the default for all entities not registered with the visibility system.


Groups let multiple players share visibility of entities. When any group member can see an entity, all group members can.

Use cases: Party dungeons, co-op quests, team-based world events.

Groups are defined by tagging entities with a group ID:

{
"entity_uuid": "party-boss-uuid",
"visibility_type": "OWNER_ONLY",
"owner": "player-uuid",
"group": "party:party-uuid"
}

When the owner is in a party, all party members inherit visibility of entities in that party’s group.


Entities spawned by other entities (projectiles, drops, etc.) inherit their parent’s visibility rules automatically. If a mob is OWNER_ONLY, any items it drops or projectiles it fires are also only visible to the owner.

This prevents information leaks where a player could see projectiles from an invisible entity or pick up drops from a fight they shouldn’t see.


For CONDITIONAL visibility, the condition is a MoLang expression with access to:

QueryDescription
q.entity_idThe entity’s UUID
q.entity_x, q.entity_y, q.entity_zEntity position
q.is_owner1.0 if the current player is the entity’s owner
q.player.*All standard player functions (flags, tasks, levelables, zones, etc.)
// Visible after completing a quest
q.player.has_completed_task('journey:rescue_professor')
// Visible to players with a specific flag
q.player.has_flag('spirit_vision')
// Visible at high trainer level
q.player.levelable_level('trainer_rank') >= 25.0
// Visible during a quest phase
q.player.has_flag('quest_phase_2') && !q.player.has_flag('quest_phase_3')
// Visible to the owner always
q.is_owner

Control entity visibility from MoLang scripts:

FunctionDescription
q.player.start_watching_entity('entity-uuid')Make player see an entity
q.player.stop_watching_entity('entity-uuid')Make player stop seeing an entity

The original NPC visibility system still works and runs as a subsystem within the entity visibility framework (priority 100). All existing NPC visibility functions continue to work:

FunctionDescription
npc.set_visibility_condition("molang")Set condition for all players
npc.set_player_visibility('player-uuid', "molang")Set condition for one player
npc.force_show_to_player('player-uuid')Force visible
npc.force_hide_from_player('player-uuid')Force hidden
npc.is_visible_to_player('player-uuid')Check visibility
npc.update_visibility()Refresh for all players

These NPC functions are shortcuts that register the NPC with the entity visibility system using CONDITIONAL type internally.


Journey provides managed spawn commands that automatically register entities with the visibility system:

/mspawnnpc <npc_id> <pos> [for <owner>] [visibility <type>]

Section titled “/mspawnnpc <npc_id> <pos> [for <owner>] [visibility <type>]”

Spawn an NPC with visibility controls.

/mspawnnpc professor_oak ~ ~ ~ for Notch visibility OWNER_ONLY
/mspawnnpc gym_leader ~ ~ ~ visibility CONDITIONAL condition "q.player.has_flag('badge_1')"

/msummon <entity_type> <pos> [for <owner>] [visibility <type>]

Section titled “/msummon <entity_type> <pos> [for <owner>] [visibility <type>]”

Summon any entity with visibility controls.

/msummon minecraft:armor_stand ~ ~ ~ for Notch visibility OWNER_ONLY
/msummon cobblemon:npc ~ ~ ~ visibility AREA_RESTRICTED zones dungeon-zone-uuid

Both commands accept the for <owner> modifier to set entity ownership.


Admins can toggle a “see all” mode that reveals all managed entities regardless of visibility rules, without being able to interact with them. This is useful for debugging and oversight.

/journey visibility seeall

While active, hidden entities appear with a translucent or wireframe effect so admins can distinguish them from normally visible entities.


CommandDescription
/journey visibility test <player> <entity>Check if a player can see an entity
/journey visibility seeallToggle admin see-all mode
/journey visibility status <entity>Show an entity’s visibility config
/journey visibility info <entity>Show detailed visibility info
/journey visibility cleanupRemove visibility data for despawned entities
/mspawnnpc <npc_id> <pos> [for <owner>] [visibility <type>]Spawn NPC with visibility
/msummon <entity> <pos> [for <owner>] [visibility <type>]Summon entity with visibility

Permission: journey.command.visibility (level 2)


Entity visibility configs are stored in config/journey/npc_visibility/ (the directory name is retained for backwards compatibility).

{
"entity_uuid": "unique-entity-uuid",
"visibility_type": "CONDITIONAL",
"condition": "q.player.has_flag('quest_started')",
"owner": "",
"group": "",
"zones": [],
"check_interval": 20
}
FieldTypeDefaultDescription
entity_uuidStringRequiredThe entity’s UUID
visibility_typeString"ALWAYS_VISIBLE"One of the 5 visibility types
conditionString"1.0"MoLang condition (for CONDITIONAL type)
ownerString""Owner player UUID (for OWNER_ONLY and GLOBAL_WHEN_OWNER_ONLINE)
groupString""Visibility group ID
zonesArray[]Zone UUIDs (for AREA_RESTRICTED)
check_intervalNumber20Ticks between condition re-evaluations

The entity visibility system uses a packet-level interception on the network thread with O(1) lookup per entity per packet. This means:

  • No tick overhead — visibility checks don’t run on the main server thread
  • No entity manipulation — entities aren’t teleported or removed, just filtered from packets
  • Scales linearly with network traffic, not entity count
  • Condition re-evaluation happens on a configurable interval (default: every 20 ticks / 1 second)

NPC appears only during a specific quest phase:

{
"entity_uuid": "guide-npc-uuid",
"visibility_type": "CONDITIONAL",
"condition": "q.player.has_flag('quest_phase_2') && !q.player.has_flag('quest_phase_3')"
}

Each gym leader appears after earning the previous badge:

{
"entity_uuid": "misty-uuid",
"visibility_type": "CONDITIONAL",
"condition": "q.player.has_flag('gym_badge_boulder')"
}
{
"entity_uuid": "surge-uuid",
"visibility_type": "CONDITIONAL",
"condition": "q.player.has_flag('gym_badge_cascade')"
}

A boss only visible to the party that spawned it:

{
"entity_uuid": "dungeon-boss-uuid",
"visibility_type": "OWNER_ONLY",
"owner": "party-leader-uuid",
"group": "party:party-uuid"
}

Entities that only appear inside a specific zone:

{
"entity_uuid": "safari-warden-uuid",
"visibility_type": "AREA_RESTRICTED",
"zones": ["safari-zone-uuid"]
}

Entity not appearing:

  • Check visibility type and condition with /journey visibility status <entity>
  • For CONDITIONAL, verify the MoLang condition evaluates correctly
  • For OWNER_ONLY, confirm the owner UUID is correct
  • Use /journey visibility test <player> <entity> to debug

Entity not disappearing:

  • Conditions are re-evaluated every check_interval ticks — wait a moment
  • Check for force-show overrides on the NPC subsystem
  • Run /journey visibility cleanup to clear stale data

Performance concerns:

  • Increase check_interval for entities that don’t need frequent updates
  • Use ALWAYS_VISIBLE or OWNER_ONLY when possible (no condition evaluation needed)
  • CONDITIONAL with complex MoLang expressions costs more than simple flag checks

  • NPCs & Paths — NPC scripting and patrol routes
  • Zones — Zone definitions for AREA_RESTRICTED
  • Flags — Track player progress for conditions
  • MoLang — Write complex visibility conditions
  • Commands — Full command reference