HammeriteNavigationRuntime
Navigation. Inherits RefCounted
Process-wide navigation state, and the one route by which a bake happens.
The HammeriteNavigation autoload is the friendly front door, but it cannot be the place this lives. An autoload is only an identifier inside a running scene tree: a script that mentions one by name will not compile in a headless tool run, which would put this addon's own test suite out of reach of everything built here. So the state is static, and the autoload delegates. Navigation is derived from the map, and saved beside it only as a cache. It was once derived on every load and never stored - about 205 ms for a 256-room level, and no stored bake that could describe a level edited since. A real one is another matter: the reference level took 105 s. So the editor saves what it built (HammeriteNavigationCache) with the map, and a load takes it only while its fingerprint() still matches every input - the brushes, the entities and the profiles. A cache that does not match is a miss, and costs the build and nothing else. Which is also why build() is what the editor tool calls too. A preview that took a different path to the answer than the shipped game does would be a preview of something else.
Properties
| Type | Name | Default |
|---|---|---|
HammeriteNavigationAgentProfiles | profiles | null |
Methods
| Returns | Method |
|---|---|
void | register_entity_types() static |
HammeriteNavigationBakeReport | build(map: HammeriteMap, host: Node) static |
HammeriteNavigationRuntime.Prepared | prepare(map: HammeriteMap, progress: HammeriteCompileProgress = null) static |
HammeriteNavigationBakeReport | attach(prepared: HammeriteNavigationRuntime.Prepared, host: Node) static |
HammeriteNavigationRuntime.Prepared | prepared_for(map: HammeriteMap) static |
void | forget(host: Node) static |
int | set_link_enabled(link_name: String, enabled: bool) static |
int | layer_bit(profile_name: StringName) static |
void | clear() static |
Node[] | hosts() static |
String | fingerprint(map: HammeriteMap) static |
String | cache_path(map: HammeriteMap) static |
HammeriteNavigationRuntime.Prepared | load_cache(map: HammeriteMap) static |
int | save_cache(map: HammeriteMap, host: Node) static |
Constants
CACHE_VERSION
const CACHE_VERSION = 5
Raised when what is saved, or how it is built, changes: a cache from before describes nothing now.
Experimental: The pipeline the autoload and the editor run; a game calls build().
STAGES
const STAGES = PackedStringArray("navigation ground", "navigation links")
The stage names prepare() reports under.
Experimental: The pipeline the autoload and the editor run; a game calls build().
DERIVED_KEY
const DERIVED_KEY = &"navigation"
Where HammeriteMap.derived keeps what prepare() made on a compile's worker.
Experimental: The pipeline the autoload and the editor run; a game calls build().
Property descriptions
profiles
var profiles: HammeriteNavigationAgentProfiles = null
The game's agent profiles (HammeriteNavigationAgentProfiles). Without one, everything is baked for a single stand-in agent (HammeriteNavigationAgentProfiles.placeholder()). Assign it before any map is compiled: what a compile prepares is for the table set then, and a different table found afterwards bakes again on the main thread. Assigning it checks it (HammeriteNavigationAgentProfiles.validate()) and warns of every problem found. Navigation already built is not rebuilt here; the HammeriteNavigation autoload rebuilds the maps it integrated.
Method descriptions
register_entity_types()
static func register_entity_types() -> void
Declare the link entity, unless something already has, and give core's prop the field the build reads (#105). From the autoload, so a game knows them before it builds a map, with or without the editor. The prop's field is put there from navigation rather than declared by core: nav_role is navigation's word, and core installed alone must not know an addon exists (CONTRIBUTING). It defaults to ignore, what the build already answers for a prop that says nothing, so adding it changes what an author can see and never what an existing map does.
build()
static func build(map: HammeriteMap, host: Node) -> HammeriteNavigationBakeReport
Derive the navigation for map and attach it under host, replacing whatever was there before. The whole bake: measure the ground, find the links, stamp both with the layers of the profiles that can use them, and attach the regions and links as children of host. Everything that could not be done comes back in the report rather than being pushed to a log here, so the caller decides where it belongs - a status panel in the editor, the console in a build.
prepare()
static func prepare(map: HammeriteMap, progress: HammeriteCompileProgress = null) -> HammeriteNavigationRuntime.Prepared
The thread-safe half of build(), reporting to progress when one is given. Null when that progress was cancelled part way.
Experimental: The pipeline the autoload and the editor run; a game calls build().
attach()
static func attach(prepared: HammeriteNavigationRuntime.Prepared, host: Node) -> HammeriteNavigationBakeReport
The main-thread half of build(): put what prepared holds under host, replacing whatever was there.
Experimental: The pipeline the autoload and the editor run; a game calls build().
prepared_for()
static func prepared_for(map: HammeriteMap) -> HammeriteNavigationRuntime.Prepared
What a compile's worker prepared for map, if it is still the answer: the world has not gone stale since (which drops it), and the game's profiles are the ones it was prepared for.
Experimental: The pipeline the autoload and the editor run; a game calls build().
forget()
static func forget(host: Node) -> void
Stop tracking host - it is going away, or its navigation has been torn down.
Experimental: The pipeline the autoload and the editor run; a game calls build().
set_link_enabled()
static func set_link_enabled(link_name: String, enabled: bool) -> int
Switch every link named link_name on or off, wherever navigation has been built, and report how many links carry that name, whether or not they were already in that state. Remembered until it is switched back or clear() is called: a link of that name made by any later build, of any map, is made switched off. This is what naming an opening is for at runtime: the boards come off a window and the route through it opens, a drawbridge lowers, a grate is unlocked. The name is the aperture's own (HammeritePortal.get_portal_name()), which is the same string the acoustics use, so one shutter entity naming one window closes it to sound and to navigation together.
layer_bit()
static func layer_bit(profile_name: StringName) -> int
The navigation-layer bit an agent of profile_name should carry, or 0 - which matches nothing - when the game has no such profile.
clear()
static func clear() -> void
Forget every host, what was attached under each, every link switched off, and the profile table.
Experimental: Test support.
hosts()
static func hosts() -> Node[]
Every node navigation is attached under, that is still there.
Experimental: The pipeline the autoload and the editor run; a game calls build().
fingerprint()
static func fingerprint(map: HammeriteMap) -> String
Digest of everything prepare() reads from map, and of the profiles it prepares for: every brush present - its shape, tier, order, fill and properties - and the props and links present, as far as the build reads them. Two maps with the same one have the same navigation.
Experimental: The pipeline the autoload and the editor run; a game calls build().
cache_path()
static func cache_path(map: HammeriteMap) -> String
Where map's navigation cache lives for the variant in effect, beside its saved worldrep: level.nav.res, or level.12.nav.res for another variant. Empty for a map with nowhere to keep one - never saved, or saved as data, which cannot carry a navigation mesh.
Experimental: The pipeline the autoload and the editor run; a game calls build().
load_cache()
static func load_cache(map: HammeriteMap) -> HammeriteNavigationRuntime.Prepared
map's saved navigation, if it still describes the map and the profiles; null otherwise.
Experimental: The pipeline the autoload and the editor run; a game calls build().
save_cache()
static func save_cache(map: HammeriteMap, host: Node) -> int
Save the navigation attached under host as map's cache. ERR_INVALID_DATA when it no longer describes the map - edited since it was built - and so would only be refused.
class Prepared
The part of a bake that touches no scene and no server, so it can run on a worker thread: the ground, the links and the region meshes, for the profiles as they are now.
Properties
Property descriptions
fingerprint
var fingerprint: String = ""
Of the map and profiles it was prepared from, as they were then.
surfaces
var surfaces: HammeriteNavigationSurface[] = []
The measured ground. Emptied by HammeriteNavigationRuntime.attach(), and never filled for one read from a cache.
links
var links: HammeriteNavigationLinkData[] = []
The links some profile can take, their ends settled onto meshes.
meshes
var meshes: Dictionary[Vector4i, NavigationMesh] = {}
Region meshes, keyed as HammeriteNavigationMeshWriter.build_region_meshes() keys them.
profiles
var profiles: HammeriteNavigationAgentProfiles = null
The table it was prepared for, or null for the stand-in agent.
report
var report: HammeriteNavigationBakeReport = <unknown>
Counts and warnings, completed by HammeriteNavigationRuntime.attach().