Using the Resource service¶
The Resource service creates resources in a running application from the console, keeps them alive, and destroys them. Use it to give a scene content its kzb does not contain: brushes, fonts with fallbacks for CJK and emoji, and in later releases animation timelines, meshes, materials and textures. Together with the NodeTree service, it builds content at runtime.
Like the NodeTree service, it adds to the application rather than reporting on it, so it has its own configuration key, ServiceResourceEnabled, and its own command prefix, resource.*. The service is on by default. Set ServiceResourceEnabled = 0 in kanzimonitor.cfg to switch it off; its commands are then not registered. See Configuring Kanzi Monitor.
Everything the service creates exists only in the running application. Nothing is written back to the project.
resource.create Kanzi.ColorBrush monitor://brushes/Red ColorBrush.Color=1,0,0,1
→ {"success":true,"handle":"@48213977","metaclass":"Kanzi.ColorBrush","createdClass":"Kanzi.ColorBrush",
"builder":"generic","name":"Red","url":"monitor://brushes/Red","keepAlive":false,
"properties":[{"name":"ColorBrush.Color","type":"ColorRGBA","value":"1,0,0,1"}]}
overwatch.setprop "/Screen/RootNode/Button 2D" Node2D.BackgroundBrush @48213977
resource.held # what the service keeps alive
resource.destroy @48213977
→ {"success":true,"handle":"@48213977","metaclass":"Kanzi.ColorBrush","url":"monitor://brushes/Red",
"destroyed":false,"note":"Monitor no longer holds it, but something else does, …"}
resource.destroycreated # drop everything this session created
Creating a resource¶
resource.create <metaclass|alias> <url|-> [name=value ...] [Property=value ...]
The class. Any concrete class derived from
Kanzi.Resourceis created through theObjectFactory, asnodetree.createcreates a node, and set up with property values. That covers, for example,Kanzi.ColorBrushand the other brushes, the 2D effects and the render passes.createdClassin the reply shows the class actually created. An abstract class, such asKanzi.Texture,Kanzi.MeshorKanzi.ShaderProgram, cannot come from the factory and needs a builder of its own; until it has one, it is refused.Kanzi.FontFamilyhas a builder,fontfamily(see Fonts).resource.kindslists which classes can be created, and the builders.The URL. The resource is registered under the URL with the
ResourceManager, so the URL then works wherever a kzb URL does: as a property value, inoverwatch.acquireresourceand in the listings. A URL that already names a resource is refused, so a created resource cannot shadow a kzb one, including one in a loaded kzb file that is not loaded itself; that check reads the kzb file’s index and loads nothing. URLs undermonitor://are a good choice for that reason. A URL is refused as reserved when it isnull, a handle such as@12, a string with a leading/(a node path), or a string with=before any://, which is aname=valuepair from a command that left the URL out. A query after the scheme is accepted:monitor://brushes/Red?v=2.-creates the resource without a URL, reachable by its handle only.Properties are given by their qualified name,
ColorBrush.Color=1,0,0,1, and written asoverwatch.setpropwrites them: the type from the property type registry, the value in that type’s format. They are written before the resource is registered. If any property fails, nothing is created, and nothing is registered.Arguments are the names without a dot. Every class takes
name, the resource’s name, by default the last segment of the URL or the class name without its namespace, andkeepAlive(trueorfalse), which setsResource::setKeepAlive. A builder adds arguments of its own;resource.kindslists them with their type, default and allowed values. An unknown argument, a missing required one and a value that does not parse as its type are refused, each naming the argument.A value that contains spaces is quoted:
name="Red brush". A quote that is never closed is refused.
A class created with no property set may be of little use. A Kanzi.Material from the factory has no shader, and a Kanzi.Animation.TimelineResource holds no timeline and cannot be given one afterwards. Builders for these follow in later releases.
Using a created resource¶
Every created resource gets a handle, such as @48213977, which the reply returns. It is the same handle the resource listings show for it, overwatch.allresources among them, and it lasts one run of the application, like every handle (see Addressing a resource).
As a property value. A Resource-typed property takes the handle as well as the URL, in
overwatch.setprop,overwatch.setresourceprop,nodetree.setcomponentpropandnodetree.addcomponent. A handle sets that resource itself, so a resource created with-can be used too. A handle whose resource has since been destroyed is refused. One that no resource ever had is also looked up as a URL and a ResourceID, as every value was before handles, and refused if nothing answers to it.To read or change it later, use
overwatch.resourcepropsandoverwatch.setresourcepropwith its handle or URL.
Keeping and destroying resources¶
The service keeps every resource it created alive, whatever the ResourceManager’s memory strategy, and overwatch.purge does not reclaim it while the service holds it. The service never takes over a resource the application loaded.
resource.destroy <@handle|url>drops the service’s reference and removes the URL, and reports whether that destroyed the resource."destroyed": falsemeans something else still holds it, typically a property that uses it: the resource is destroyed when that reference goes, for example when the property is set to another value. Only resources the service created can be destroyed this way;overwatch.unregisterresourceremoves an application resource’s URL.resource.destroycreateddoes the same for every resource created in this session, and counts how many were destroyed and how many live on. If a URL cannot be unregistered, Monitor keeps holding that resource, lists it underfailures, and reports"success": false.resource.heldlists the resources the service holds: handle, class, name, URL, whether the URL is still registered (overwatch.unregisterresourcemay have removed it),keepAlive, the arguments it was created with,otherReferences, and for a font familykeptFallbacks, the fallbacks it keeps alive.otherReferencescounts the references besides the service’s own: properties that use the resource, and theResourceManager’s own while the URL is registered underKeepInMemory, which holds a registered resource; underOptimizeMemoryit does not.
After a destroy, the listings still report the URL a resource was registered under for as long as the resource exists: Kanzi keeps it on the resource. The URL itself no longer resolves, and a new resource can be created under it.
What can be created¶
resource.kinds [filter] lists:
builders: each builder with its alias, the class it creates, its arguments and its operations.genericserves every concrete resource class without a builder of its own, so it is not a kind to create: give the class, such asKanzi.ColorBrush.fontfamilycreates font families.sharedArguments: the arguments every class takes,nameandkeepAlive.metaclasses: every registered resource class, withcreatableand the builder that would create it. The filter is a substring of the class name, in any case, as in the other listings:resource.kinds brushlists the brushes.
Fonts¶
A text node draws with the font family in its Node.FontFamily property. Each character the family’s font has no glyph for is drawn from the family’s fallback families, tried in order, and as a missing-glyph box when none has it. The default Fira Sans has no CJK or emoji glyphs, so that is how they render without fallbacks. The fontfamily builder creates a family from a font file, and two operations extend any family, the application’s own included.
resource.create fontfamily monitor://fonts/CJK file=C:/Windows/Fonts/msyh.ttc
resource.create fontfamily monitor://fonts/Emoji file=C:/Windows/Fonts/seguiemj.ttf
resource.addfallback "kzb://runtimeassets/Font Families/DefaultFontFamily" monitor://fonts/CJK
resource.addfallback "kzb://runtimeassets/Font Families/DefaultFontFamily" monitor://fonts/Emoji
# now "Latin 漢字 😀" renders in one Text Block: Latin in Fira Sans, 漢字 and the emoji from the fallbacks
resource.create fontfamily <url|-> file=<path> [weight=Normal] [style=Normal] [fallback=<family>,...]creates a family with one face.fileis a font file on the target; a relative path resolves against the resource directory when one is set (overwatch.resourcedirectory), otherwise against the process working directory. On Android, a relative path with no resource directory set is read from the APK’s assets, not the working directory; with a resource directory set, it is read from that directory only. A font in the assets, and a.fnt’s glyph pages beside it, load only when the APK stores them uncompressed: Kanzi refuses a compressed asset as if it were missing. List their extensions undernoCompressin the app’sbuild.gradle, as the example app does:noCompress "kzb", "cfg", "json", "ttf", "otf", "ttc", "ltt", "fnt", "png"..ttf,.otfand.ttcload through the font engine, and of a.ttccollection only the first face;.lttneeds the iType engine;.fntis a bitmap font, loaded with its glyph pages from the same directory, and needs no font engine. A relative.fntpath that starts withkzb, such askzbfonts/x.fnt, fails to load its glyph pages: Kanzi takes a page directory that starts withkzbfor a kzb location. Use an absolute path, or a directory with another name.weightis one ofThin,ExtraLight,Light,Normal,Medium,SemiBold,Bold,ExtraBoldandBlack, andstyleNormalorItalic.fallbacklists fallback families as handles or URLs, separated by commas; a family given twice is refused. A path can hold any character: a file in a directory with a non-ASCII name loads on Windows too, where the font engine cannot open such a path itself, so the file is read through Kanzi’s file layer and loaded from memory. An empty file is refused as empty, and a file that is not a font of its type, a truncated one say, with the font engine’s reason; nothing is created.resource.addface <family> file=<path> [weight=Normal] [style=Normal]adds a face to any family. A text node picks the face whose style matches and whose weight is closest to itsFontStyleConcept.Weight;selectedForWeightAndStylein the reply says whether the new face is the one the family now picks for that weight and style. Kanzi has no call to remove a face, so a face added to one of the application’s own families is permanent: it stays until the application exits, also afterresource.destroycreated. The reply says"permanent": truewith a note, andresource.heldlists such faces underpermanentFaces. A face added to a family the service created goes with that family.resource.addfallback <family> <fallbackFamily>appends a fallback to any family. Set it on the family the text uses, whichoverwatch.propsreports underNode.FontFamily. Text laid out after the change uses it. A fallback the family already has is refused, because it would be searched twice for every missing glyph. Kanzi lists no family’s fallbacks, so the check compares the font files each fallback supplies for every weight and style: it finds the project’s own fallbacks too, and refuses another family that supplies the very same font file objects, which would add nothing. A family that shares only some of them, its normal face say, is added.
A family is named by its handle or by the URL of a loaded resource. A URL that names nothing loaded is refused rather than loaded: Kanzi cannot tell a kzb resource’s type without loading it, so naming a texture by mistake would decode and upload it. overwatch.acquireresource loads a kzb family that no node has used yet.
Fallbacks are one level deep. A fallback contributes its own font for the weight and style, not its own fallbacks, so a cycle does nothing and is not refused; only a family as its own fallback is.
Under OptimizeMemory, though, a family that nothing uses is released as soon as overwatch.acquireresource loads it. Switch to KeepInMemory with overwatch.setmemorystrategy while you use it; once the service has added it as a fallback, or changed it with resource.addface or resource.addfallback, the service’s own reference keeps it alive under OptimizeMemory too, through overwatch.purge, until resource.destroycreated drops it (KZMON-961).
Removing a fallback. Kanzi holds a fallback weakly and has no call to remove one, so the service keeps every fallback it attached alive: with the family’s own entry when the service created the family, and otherwise until resource.destroycreated. When a created fallback family is destroyed, it is gone from every family it was added to, and text laid out after that no longer uses it. resource.destroy and resource.destroycreated drop the service’s references; the family is destroyed when nothing else holds it, which resource.destroy reports as "destroyed": true. With "destroyed": false, something else still holds it, for example a node that uses it as its own Node.FontFamily, and the families it was added to keep using it until that reference goes too.
An application family the service changed is kept alive until resource.destroycreated, so that a face or fallback added to it is not lost when nothing else holds the family, which can happen under the OptimizeMemory strategy. resource.held counts these as retainedApplicationFamilies.
Color emoji render in color where the font engine can draw the font’s color glyphs: measured with FreeType on Kanzi 4.1.1 and Segoe UI Emoji. Glyphs a font stores as SVG are drawn in monochrome.
A font engine is required for .ttf, .otf, .ttc and .ltt. Without a font engine plugin, Kanzi would load such a file as an empty font that renders nothing, without an error, so the service refuses it and says so. With the iType engine, creating families and faces works through its loader, but fallback families are not measured: the fallback lookup described here is in the FreeType engine’s shaper, and iType links fonts in its own .ltt files instead.
Commands¶
Command |
Description |
|---|---|
|
Creates a resource of any concrete class, sets its properties and registers it under a URL, or none. Usage: |
|
Drops a created resource and its URL, and reports whether that destroyed it. Usage: |
|
Drops every resource created in this session. |
|
Lists the resources the service created and keeps alive, with their handles. |
|
Adds a face of another weight or style to any font family. Usage: |
|
Appends a fallback family to any font family, for the glyphs its fonts lack. Usage: |
|
Lists the builders with their arguments, and which resource classes can be created. Usage: |
The MCP server has the same commands as the create_resource, destroy_resource, destroy_created_resources, list_created_resources, get_resource_kinds, add_font_face and add_font_fallback tools; see Using the Kanzi Monitor MCP server.