123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- package hrt.prefab;
- class Reference extends Object3D {
- @:s public var editMode : Bool = false;
- public var refInstance : Prefab;
- public static function copy_overrides(from:Dynamic) : haxe.ds.StringMap<Dynamic> {
- if (Std.isOfType(from, haxe.ds.StringMap)) {
- return from != null ? cast(from, haxe.ds.StringMap<Dynamic>).copy() : new haxe.ds.StringMap<Dynamic>();
- }
- else {
- var m = new haxe.ds.StringMap<Dynamic>();
- for (f in Reflect.fields(from)) {
- m.set(f, Reflect.getProperty(from ,f));
- }
- return m;
- }
- }
- override function save() {
- var obj : Dynamic = super.save();
- #if editor
- if( editMode && refInstance != null ) {
- var sheditor = Std.downcast(shared, hide.prefab.ContextShared);
- if( sheditor.editor != null ) sheditor.editor.watchIgnoreChanges(source);
- var s = refInstance.serialize();
- sys.io.File.saveContent(hide.Ide.inst.getPath(source), hide.Ide.inst.toJSON(s));
- }
- #end
- return obj;
- }
- #if editor
- override function setEditorChildren(sceneEditor:hide.comp.SceneEditor, scene: hide.comp.Scene) {
- super.setEditorChildren(sceneEditor, scene);
- if (refInstance != null) {
- refInstance.setEditor(sceneEditor, scene);
- }
- }
- #end
- function resolveRef() : Prefab {
- if(source == null)
- return null;
- if (refInstance != null)
- return refInstance;
- #if editor
- try {
- #end
- var refInstance = hxd.res.Loader.currentInstance.load(source).to(hrt.prefab.Resource).load().clone();
- refInstance.shared.parentPrefab = this;
- return refInstance;
- #if editor
- } catch (_) {
- return null;
- }
- #end
- }
- override function makeInstance() {
- if( source == null )
- return;
- #if editor
- if (hasCycle()) {
- hide.Ide.inst.quickError('Reference ${getAbsPath()} to $source is creating a cycle. Please fix the reference.');
- refInstance = null;
- return;
- }
- #end
- var p = resolveRef();
- var refLocal3d : h3d.scene.Object = null;
- if (Std.downcast(p, Object3D) != null) {
- refLocal3d = shared.current3d;
- } else {
- super.makeInstance();
- refLocal3d = local3d;
- }
- if (p == null) {
- refInstance = null;
- return;
- }
- var sh = p.shared;
- @:privateAccess sh.root3d = sh.current3d = refLocal3d;
- @:privateAccess sh.root2d = sh.current2d = findFirstLocal2d();
- #if editor
- sh.editor = this.shared.editor;
- sh.scene = this.shared.scene;
- #end
- sh.parentPrefab = this;
- sh.customMake = this.shared.customMake;
- refInstance = p;
- if (refInstance.to(Object3D) != null) {
- var obj3d = refInstance.to(Object3D);
- obj3d.loadTransform(this); // apply this transform to the reference prefab
- obj3d.name = name;
- obj3d.visible = visible;
- refInstance.make();
- local3d = Object3D.getLocal3d(refInstance);
- }
- else {
- refInstance.make();
- }
- }
- override public function find<T:Prefab>(?cl: Class<T>, ?filter : T -> Bool, followRefs : Bool = false ) : Null<T> {
- var res = super.find(cl, filter, followRefs);
- if (res == null && followRefs ) {
- var p = resolveRef();
- if( p != null )
- return p.find(cl, filter, followRefs);
- }
- return res;
- }
- override public function getOpt<T:Prefab>( ?cl : Class<T>, ?name : String, ?followRefs : Bool ) : Null<T> {
- var res = super.getOpt(cl, name, followRefs);
- if (res == null && followRefs && refInstance != null) {
- return refInstance.getOpt(cl, name, followRefs);
- }
- return res;
- }
- override public function flatten<T:Prefab>( ?cl : Class<T>, ?arr: Array<T> ) : Array<T> {
- arr = super.flatten(cl, arr);
- if (editMode && refInstance != null) {
- arr = refInstance.flatten(cl, arr);
- }
- return arr;
- }
- override function dispose() {
- super.dispose();
- if( refInstance != null )
- refInstance.dispose();
- }
- #if editor
- override public function editorRemoveObjects() : Void {
- if (refInstance != null) {
- for (child in refInstance.flatten()) {
- shared.editor.removeInteractive(child);
- }
- refInstance.editorRemoveObjects();
- }
- super.editorRemoveObjects();
- }
- public function hasCycle(?seenPaths: Map<String, Bool>) : Bool {
- if (editorOnly)
- return false;
- var oldEditMode = editMode;
- editMode = false;
- seenPaths = seenPaths?.copy() ?? [];
- var curPath = this.shared.currentPath;
- if (seenPaths.get(curPath) != null) {
- editMode = oldEditMode;
- return true;
- }
- seenPaths.set(curPath, true);
- if (source != null) {
- var ref = resolveRef();
- if (ref != null) {
- var root = ref;
- if (Std.isOfType(root, hrt.prefab.fx.BaseFX)) {
- root = hrt.prefab.fx.BaseFX.BaseFXTools.getFXRoot(root) ?? root;
- }
- var allRefs = root.flatten(Reference);
- for (r in allRefs) {
- if (r.hasCycle(seenPaths)){
- editMode = oldEditMode;
- return true;
- }
- }
- }
- }
- editMode = oldEditMode;
- return false;
- }
- override function makeInteractive() {
- if( editMode )
- return null;
- return super.makeInteractive();
- }
- override function edit( ctx : hide.prefab.EditContext ) {
- var element = new hide.Element('
- <div class="group" name="Reference">
- <dl>
- <dt>Reference</dt><dd><input type="fileselect" extensions="prefab l3d fx" field="source"/></dd>
- <dt>Edit</dt><dd><input type="checkbox" field="editMode"/></dd>
- </dl>
- </div>');
- function updateProps() {
- var input = element.find("input");
- var found = resolveRef() != null;
- input.toggleClass("error", !found);
- }
- updateProps();
- var props = ctx.properties.add(element, this, function(pname) {
- ctx.onChange(this, pname);
- if(pname == "source" || pname == "editMode") {
- if (pname == "source") {
- editorRemoveObjects();
- refInstance = null;
- }
- if (hasCycle()) {
- hide.Ide.inst.quickError('Reference to $source would create a cycle. The reference change was aborted.');
- ctx.properties.undo.undo();
- @:privateAccess ctx.properties.undo.redoElts.pop();
- return;
- }
- updateProps();
- if(!ctx.properties.isTempChange) {
- if (pname == "source") {
- ctx.rebuildPrefab(this);
- }
- else {
- if (refInstance != null) {
- for (child in refInstance.flatten()) {
- shared.editor.removeInteractive(child);
- }
- }
- shared.editor.refreshInteractive(this);
- @:privateAccess shared.editor.refreshTree();
- }
- }
- }
- });
- super.edit(ctx);
- }
- override function getHideProps() : hide.prefab.HideProps {
- return { icon : "share", name : "Reference" };
- }
- #end
- public static var _ = hrt.prefab.Prefab.register("reference", Reference);
- }
|