123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413 |
- package hrt.prefab;
- /**
- Prefab is an data-oriented tree container capable of creating instances of Heaps objects.
- **/
- @:keepSub
- class Prefab {
- /**
- The type of prefab, allows to identify which class it should be loaded with.
- **/
- public var type(default, null) : String;
- /**
- The name of the prefab in the tree view
- **/
- public var name(default, set) : String;
- /**
- The parent of the prefab in the tree view
- **/
- public var parent(default, set) : Prefab;
- /**
- The associated source file (an image, a 3D model, etc.) if the prefab type needs it.
- **/
- public var source(default, set) : String;
- /**
- The list of children prefab in the tree view
- **/
- public var children(default, null) : Array<Prefab>;
- /**
- Tells if the prefab will create an instance when calling make() or be ignored. Also apply to this prefab children.
- **/
- public var enabled : Bool = true;
- /**
- A storage for some extra properties
- **/
- public var props : Any;
- /**
- Creates a new prefab with the given parent.
- **/
- public function new(?parent) {
- this.parent = parent;
- children = [];
- }
- function set_name(n) {
- return name = n;
- }
- function set_source(f) {
- return source = f;
- }
- function set_parent(p) {
- if( parent != null )
- parent.children.remove(this);
- parent = p;
- if( parent != null )
- parent.children.push(this);
- return p;
- }
- #if editor
- /**
- Allows to customize how the prefab object is edited within Hide
- **/
- public function edit( ctx : hide.prefab.EditContext ) {
- }
- /**
- Allows to customize how the prefab object is displayed / handled within Hide
- **/
- public function getHideProps() : hide.prefab.HideProps {
- return { icon : "question-circle", name : "Unknown" };
- }
- /**
- Allows to customize how the prefab instance changes when selected/unselected within Hide
- **/
- public function setSelected( ctx : Context, b : Bool ) {
- var materials = ctx.shared.getMaterials(this);
- if( !b ) {
- for( m in materials ) {
- m.mainPass.stencil = null;
- m.removePass(m.getPass("highlight"));
- }
- return;
- }
- var shader = new h3d.shader.FixedColor(0xffffff);
- for( m in materials ) {
- var p = m.allocPass("highlight");
- p.culling = None;
- p.depthWrite = false;
- p.addShader(shader);
- }
- }
- #end
- /**
- Iterate over children prefab
- **/
- public inline function iterator() : Iterator<Prefab> {
- return children.iterator();
- }
- /**
- Override to implement your custom prefab data loading
- **/
- function load( v : Dynamic ) {
- throw "Not implemented";
- }
- /**
- Override to implement your custom prefab data saving
- **/
- function save() : {} {
- throw "Not implemented";
- return null;
- }
- /**
- Creates an instance for this prefab only (and not its children).
- Use make(ctx) to creates the whole instances tree;
- **/
- public function makeInstance( ctx : Context ) : Context {
- return ctx;
- }
- /**
- Allows to customize how an instance gets updated when a property name changes.
- You can also call updateInstance(ctx) in order to force whole instance synchronization against current prefab data.
- **/
- public function updateInstance( ctx : Context, ?propName : String ) {
- }
- /**
- Removes the created instance for this prefab only (not is children).
- If false is returned, the instance could not be removed and the whole context scene needs to be rebuilt
- **/
- public function removeInstance( ctx : Context ) : Bool {
- return false;
- }
- /**
- Save the whole prefab data and its children.
- **/
- @:final public function saveData() : {} {
- var obj : Dynamic = save();
- obj.type = type;
- if( !enabled )
- obj.enabled = false;
- if( name != null )
- obj.name = name;
- if( source != null )
- obj.source = source;
- if( children.length > 0 )
- obj.children = [for( s in children ) s.saveData()];
- if( props != null && obj.props == null )
- obj.props = props;
- return obj;
- }
- /**
- Load the whole prefab data and creates its children.
- **/
- @:final public function loadData( v : Dynamic ) {
- type = v.type;
- name = v.name;
- enabled = v.enabled == null ? true : v.enabled;
- props = v.props;
- source = v.source;
- load(v);
- if( children.length > 0 )
- children = [];
- var children : Array<Dynamic> = v.children;
- if( children != null )
- for( v in children )
- loadPrefab(v, this);
- }
- /**
- Updates in-place the whole prefab data and its children.
- **/
- public function reload( p : Dynamic ) {
- name = p.name;
- enabled = p.enabled == null ? true : p.enabled;
- props = p.props;
- source = p.source;
- load(p);
- var childData : Array<Dynamic> = p.children;
- if( childData == null ) {
- if( this.children.length > 0 ) this.children = [];
- return;
- }
- var curChild = new Map();
- for( c in children )
- curChild.set(c.name, c);
- var newchild = [];
- for( v in childData ) {
- var name : String = v.name;
- var prev = curChild.get(name);
- if( prev != null && prev.type == v.type ) {
- curChild.remove(name);
- prev.reload(v);
- newchild.push(prev);
- } else {
- newchild.push(loadPrefab(v,this));
- }
- }
- children = newchild;
- }
- /**
- Creates the correct prefab based on v.type and load its data and children.
- If one the prefab in the tree is not registered, a hxd.prefab.Unkown is created instead.
- **/
- public static function loadPrefab( v : Dynamic, ?parent : Prefab ) {
- var pcl = @:privateAccess Library.registeredElements.get(v.type);
- var pcl = pcl == null ? null : pcl.cl;
- if( pcl == null ) pcl = Unknown;
- var p = Type.createInstance(pcl, [parent]);
- p.loadData(v);
- return p;
- }
- /**
- Creates an instance for this prefab and its children.
- **/
- public function make( ctx : Context ) : Context {
- if( !enabled )
- return ctx;
- if( ctx == null ) {
- ctx = new Context();
- ctx.init();
- }
- ctx = makeInstance(ctx);
- for( c in children )
- c.make(ctx);
- return ctx;
- }
- #if castle
- /**
- Returns which CDB model this prefab props represents
- **/
- public function getCdbModel( ?p : Prefab ) : cdb.Sheet {
- if( p == null )
- p = this;
- if( parent != null )
- return parent.getCdbModel(p);
- return null;
- }
- #end
- /**
- Search the prefab tree for the prefab matching the given name, returns null if not found
- **/
- public function getPrefabByName( name : String ) {
- if( this.name == name )
- return this;
- for( c in children ) {
- var p = c.getPrefabByName(name);
- if( p != null )
- return p;
- }
- return null;
- }
- /**
- Simlar to get() but returns null if not found.
- **/
- public function getOpt<T:Prefab>( cl : Class<T>, ?name : String ) : T {
- if( name == null || this.name == name ) {
- var cval = to(cl);
- if( cval != null ) return cval;
- }
- for( c in children ) {
- var p = c.getOpt(cl, name);
- if( p != null )
- return p;
- }
- return null;
- }
- /**
- Search the prefab tree for the prefab matching the given prefab class (and name, if specified).
- Throw an exception if not found. Uses getOpt() to return null instead.
- **/
- public function get<T:Prefab>( cl : Class<T>, ?name : String ) : T {
- var v = getOpt(cl, name);
- if( v == null )
- throw "Missing prefab " + (name == null ? Type.getClassName(cl) : (cl == null ? name : name+"(" + Type.getClassName(cl) + ")"));
- return v;
- }
- /**
- Return all prefabs in the tree matching the given prefab class.
- **/
- public function getAll<T:Prefab>( cl : Class<T>, ?arr: Array<T> ) : Array<T> {
- return findAll(function(p) return p.to(cl));
- }
- /**
- Find a single prefab in the tree by calling `f` on each and returning the first not-null value returned, or null if not found.
- **/
- public function find<T>( f : Prefab -> Null<T> ) : Null<T> {
- var v = f(this);
- if( v != null )
- return v;
- for( p in children ) {
- var v = p.find(f);
- if( v != null ) return v;
- }
- return null;
- }
- /**
- Find several prefabs in the tree by calling `f` on each and returning all the not-null values returned.
- **/
- public function findAll<T>( f : Prefab -> Null<T>, ?arr : Array<T> ) : Array<T> {
- if( arr == null ) arr = [];
- var v = f(this);
- if( v != null )
- arr.push(v);
- for( o in children )
- o.findAll(f,arr);
- return arr;
- }
- /**
- Returns all prefabs in the tree matching the specified class.
- **/
- public function flatten<T:Prefab>( ?cl : Class<T>, ?arr: Array<T> ) : Array<T> {
- if(arr == null)
- arr = [];
- if( cl == null )
- arr.push(cast this);
- else {
- var i = to(cl);
- if(i != null)
- arr.push(i);
- }
- for(c in children)
- c.flatten(cl, arr);
- return arr;
- }
- /**
- Returns the first parent in the tree matching the specified class or null if not found.
- **/
- public function getParent<T:Prefab>( c : Class<T> ) : Null<T> {
- var p = parent;
- while(p != null) {
- var inst = p.to(c);
- if(inst != null) return inst;
- p = p.parent;
- }
- return null;
- }
- /**
- Converts the prefab to another prefab class.
- Returns null if not of this type.
- **/
- public function to<T:Prefab>( c : Class<T> ) : Null<T> {
- return Std.instance(this, c);
- }
- /**
- Returns the absolute name path for this prefab
- **/
- public function getAbsPath() {
- var p = this;
- var path = [];
- while(p.parent != null) {
- var n = p.name;
- if( n == null ) n = getDefaultName();
- path.unshift(n);
- p = p.parent;
- }
- return path.join('.');
- }
- /**
- Returns the default name for this prefab
- **/
- public function getDefaultName() : String {
- if(source != null) {
- var f = new haxe.io.Path(source).file;
- f = f.split(" ")[0].split("-")[0];
- return f;
- }
- return type.split(".").pop();
- }
- /**
- Clone this prefab and all its children
- **/
- public function clone() : Prefab {
- var obj = saveData();
- return loadPrefab(haxe.Json.parse(haxe.Json.stringify(obj)));
- }
- }
|