File size: 4,906 Bytes
84e8204 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | extends Node
##
## FeatureRegistry - catalog of every tool/feature and its RAM budget.
##
## This is what makes "100+ features that never OOM" possible: features are
## *descriptions*, not live objects. A feature is only instantiated when the
## user actually opens it, and torn down when they close it. The registry maps
## each feature id -> {name, module, cost_mb, loaded}.
##
## Modules are GDScript files under res://scripts/modules/. Each module is a
## Node that implements `_activate(host)` and `_deactivate()`.
##
signal feature_activated(id: String)
signal feature_deactivated(id: String)
signal feature_failed(id: String, reason: String)
## id -> { name, module_path, cost_mb, node, active }
var _features: Dictionary = {}
## Currently instantiated feature nodes, keyed by id.
var _live: Dictionary = {}
## Parent node that hosts active feature modules.
var host: Node = null
func _ready() -> void:
register_all()
## --- Public API -------------------------------------------------------------
## Instantiate and activate a feature. Safe to call twice (no-op if active).
func activate(id: String) -> bool:
if not _features.has(id):
feature_failed.emit(id, "unknown feature")
return false
if _live.has(id):
feature_activated.emit(id)
return true
var f: Dictionary = _features[id]
# Reserve memory *before* instantiating so eviction can happen first.
MemoryManager.register(id, f["module_path"], float(f["cost_mb"]))
var script: Resource = MemoryManager.acquire(id)
if script == null or host == null:
feature_failed.emit(id, "load failed or no host")
MemoryManager.release(id)
return false
var node: Node = (script as GDScript).new()
node.name = "Feature_" + id
host.add_child(node)
if node.has_method("_activate"):
node.call("_activate", host)
_live[id] = node
feature_activated.emit(id)
return true
## Deactivate and destroy a feature, returning its RAM to the pool.
func deactivate(id: String) -> void:
if not _live.has(id):
return
var node: Node = _live[id]
if node.has_method("_deactivate"):
node.call("_deactivate")
node.queue_free()
_live.erase(id)
MemoryManager.release(id)
# If nothing else references the module, drop the loaded script now.
MemoryManager.purge(id)
feature_deactivated.emit(id)
func is_active(id: String) -> bool:
return _live.has(id)
func list_features() -> Array:
var ids := _features.keys()
ids.sort()
return ids
func feature_count() -> int:
return _features.size()
func get_info(id: String) -> Dictionary:
return _features.get(id, {})
## --- Registration -----------------------------------------------------------
func _reg(id: String, name: String, module_path: String, cost_mb: float) -> void:
_features[id] = {
"name": name,
"module_path": module_path,
"cost_mb": cost_mb,
"active": false,
}
## The full feature catalog. Costs are conservative RAM estimates in MB and are
## the numbers MemoryManager uses for eviction decisions.
func register_all() -> void:
# --- Mesh generation (Features 1-20) ---
_reg("mesh.cube", "Cube Primitive", "res://scripts/modules/mesh_gen.gd", 0.5)
_reg("mesh.sphere", "UV Sphere", "res://scripts/modules/mesh_gen.gd", 1.0)
_reg("mesh.cylinder","Cylinder", "res://scripts/modules/mesh_gen.gd", 0.5)
_reg("mesh.plane", "Plane", "res://scripts/modules/mesh_gen.gd", 0.2)
_reg("mesh.suzanne", "Monkey Head", "res://scripts/modules/mesh_gen.gd", 2.0)
_reg("mesh.torus", "Torus", "res://scripts/modules/mesh_gen.gd", 1.5)
_reg("mesh.ico", "Icosphere", "res://scripts/modules/mesh_gen.gd", 1.0)
_reg("mesh.text", "Text Mesh", "res://scripts/modules/mesh_gen.gd", 1.0)
# --- Sculpting (Features 21-40) ---
_reg("sculpt.draw", "Draw Brush", "res://scripts/modules/sculpt.gd", 4.0)
_reg("sculpt.grab", "Grab Brush", "res://scripts/modules/sculpt.gd", 4.0)
_reg("sculpt.pinch", "Pinch Brush", "res://scripts/modules/sculpt.gd", 4.0)
_reg("sculpt.smooth", "Smooth Brush", "res://scripts/modules/sculpt.gd", 4.0)
_reg("sculpt.flatten", "Flatten Brush", "res://scripts/modules/sculpt.gd", 4.0)
# --- Rigging (Features 41-60) ---
_reg("rig.skeleton", "Armature Editor", "res://scripts/modules/rigging.gd", 8.0)
_reg("rig.weight", "Weight Paint", "res://scripts/modules/rigging.gd", 6.0)
# --- Simulation (Features 61-80) ---
_reg("sim.cloth", "Cloth Sim", "res://scripts/modules/simulation.gd", 12.0)
_reg("sim.hair", "Hair Sim", "res://scripts/modules/simulation.gd", 10.0)
_reg("sim.wind", "Wind Field", "res://scripts/modules/simulation.gd", 2.0)
# --- Animation (Features 81-100) ---
_reg("anim.timeline", "Timeline", "res://scripts/modules/timeline.gd", 3.0)
_reg("anim.keyframe", "Keyframe Tool","res://scripts/modules/timeline.gd", 3.0)
print("[FeatureRegistry] %d features registered" % _features.size())
|