I create an json asset array in a script and tried to get all this files into a single array with an ID appended to them dynamically…but when try to see the final result the property id my script show the same value…
// swap method called for script hot-reloading
// inherit your script state here
TypeBScript.prototype.swap = function (old) {
this.enabled = true;
old.app.keyboard.off("keydown");
this.app.keyboard.on("keydown", (e) => {
switch (e.key) {
case pc.KEY_1:
let finalJson = [];
this.jsonAssets.forEach((asset, index) => {
let resource = asset.resource;
resource.id = index;
console.log(index);
console.log(resource);
finalJson.push(resource);
});
console.log(finalJson);
}
});
};
Inside your loop try to change or add any property inside this jsonAsset resource (i tried to create a new property called “id” and put the index of the loop interaction as its value)
Add each instance to an array
Print the array
Result Expected: I will have the same json info I created in assets panel but each one of them will have a different id because of the loop interaction
Result i have now: Instead of getting different “id” values I’m getting the last of index of the array in all elements
I think the problem is the getter function from an asset object
//myScript.js
let resource = asset.resource;
//definition in asset.js
get resource() {
return this._resources[0];
}
This getter is not returning a copy from this.resources[0] but the actual object…since i’m using the same asset in attribute array it must be referencing the same “pointer” and I suspect any modifications to this resource object, even in my local variable, will apply this changes to all places where this resource is used
I got this working by adding theses lines before add it to my array…
//attempt to create a copy from the modified resource before adding to array
let tempStringParsed = JSON.parse(JSON.stringify(resource));
let fullJson = [];
this.jsonAssets.forEach((r,i) => {
let resource = r.resource;
resource.id = i;
let tempString = JSON.stringify(resource);
let tempStringParsed = JSON.parse(tempString);
fullJson.push(tempStringParsed);
});
console.log(fullJson)
…but i know i won’t be able to call JSON.stringify() on entities if I decide to include entities in this resource because of the circular references that this object has
Assuming this all reference the same JSON asset, then yes, theses are all references to the same asset.
//myScript.js
let resource = asset.resource;
This does not make a copy, it is just a reference. If you modify resource, you are modifying the asset resource so any other scripts/references to the asset will also be affected because they are all referencing the same object
Yes, here you are making a ‘deep’ copy of the JSON data and have a new object.
Good is not a bug!
The bad part i’m out of ideas on how to create a json attribute with multiple schemas exposed to the inspector panel like I used to do in UnrealEngine 4 with C++
With C++ and C# structs, they are copied by value.
I don’t understand what you mean by ‘json attribute with multiple schemas’. Can you give a concrete example with how it looks in Unreal and usage please?
Thats why i thought creating a “schema asset” like we have the “json” or “text” asset would help in this feature…because in a single jsonAtribute we could just place the schemasAssets as sub-attributes and the parser just needed to draw this models on the inspector
Instead of creating the schema inside the script attributes we do it somewhere else, in another menu, then we just plug it in the attributes…
The usage is be able to config everything from the editor in a single script without needing to create “i don’t know how many sub-entities and sub-scripts” just to be able to concatenate a full json with every data from sub-entity’s script attributes to do something like newUser.address.zipcode with info from the editor
Unfortunately, you are stuck with flat JSON schemas for script attributes. It’s not just the GUI/Editor that needs to be updated but the backend and how that data is stored as well.
So either you have to have some structured entity hierarchy to have ‘nested’ JSON data and build that up on startup or if the data doesn’t reference an PlayCanvas asset/entity, you can have this data in Google Sheets and export as JSON that can be imported into PlayCanvas. (which quite a few people do)
There’s no real good answer here to have nested data structures as script attributes at the moment.