monkeystudio / scripts /core /feature_registry.gd
geter62's picture
Upload folder using huggingface_hub
84e8204 verified
Raw History Blame Contribute Delete
4.91 kB
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())