Copy link to clipboard
Copied
I'm creating tiles for a game engine.
I have a MASTER layout file into which I place linked external TILE psb files.
Each linked TILE file has inside it linked external TEXTURE psb files (so I can ensure all my base textures tile correctly)
As far as i can tell, if i change the TEXTURE tile, i have to manually open every TILE file and updated the modified content, then open the MASTER file and update all the modified content.
Is thewre any way for the MASTER file when opening to check the modified nested structure and update by itself? And if not could Adobe add such a function?
Copy link to clipboard
Copied
You are correct in that it does work that way.
I wonder though if a script could be written to open each and update? I am no expert in scripting though, so have tagged a couple of folk who are: @jazz-y @Stephen Marsh
Dave
Copy link to clipboard
Copied
If I am understanding the "Russian Doll" issue, then yes, I believe that a script can handle this... Even better, I believe that it is within my capabilities!
Copy link to clipboard
Copied
Yes that is how it works on multiple files. Look into Layer comps, they are a great way to have one master file to create multiple files in a series.
With layer comps use file >> Export >> Layer Comps To files to generate your files.
Another way taht shdou work is to drag a layer to your library. Later after adding the library item to your files or Russian doll, edit the library item by double clicking on the item in the library.
Copy link to clipboard
Copied
Thanks Mike, i did get the script method working, but the library method sounds promising as well. One reason we avoid photoshop libraries (in our company) is that we use an SVN to commit and version projects so have always tried to avoid being tied to a users library.. maybe there's a way to keep the project library as a local foldered version?
Copy link to clipboard
Copied
@Gravois – The following script will update linked files within linked files, so only 2 levels deep. I have tested it and I believe that it meets your criteria. Let me know how it goes for you...
/*
Update linked layers inside linked layers.jsx
https://community.adobe.com/t5/photoshop-ecosystem-discussions/nested-smart-objects-auto-update-2022/m-p/12968009
Stephen Marsh, 28th May 2022, Version 1.0
With special thanks to Christoph Pfaffenbichler for the recursive SO processing framework:
https://feedback.photoshop.com/photoshop_family/topics/rasterize_all_smart_objects_in_a_psd_file_to_shrink_down_its_size
*/
#target photoshop
var myDocument = app.activeDocument;
myDocument.suspendHistory("processAllSmartObjects", "processSOLayers(myDocument)");
processSOLayers(theLayer);
function processSOLayers(docLayers) {
var restoreDialogMode = app.displayDialogs;
app.displayDialogs = DialogModes.NO;
// Loop over all the layers
for (var i = docLayers.layers.length - 1; i >= 0; i--) {
var theLayer = docLayers.layers[i];
// Only run on smart object layers
if (theLayer.typename === "ArtLayer" && theLayer.kind === LayerKind.SMARTOBJECT) {
var theVisibility = theLayer.visible;
myDocument.activeLayer = theLayer;
// Edit the linked smart object layer
app.runMenuItem(stringIDToTypeID('placedLayerEditContents'));
// Update all modified content
app.runMenuItem(stringIDToTypeID('placedLayerUpdateAllModified'));
// Close and save
app.activeDocument.close(SaveOptions.SAVECHANGES);
// Reset visibility;
theLayer.visible = theVisibility;
// Run on the contents of layerSets (implied, not explicitly defined)
} else {
processSOLayers(theLayer);
}
}
app.displayDialogs = restoreDialogMode;
return;
}
https://prepression.blogspot.com/2017/11/downloading-and-installing-adobe-scripts.html#Photoshop
Copy link to clipboard
Copied
@Stephen Marsh Thanks Stephen 🙂
Dave
Copy link to clipboard
Copied
Hi @Stephen Marsh thankyou for helping. The script works as long as I remove all other non-linked smart objects. Is there a way to ammend the script so that it can ignore normal smart embedded smart objects or bg layers? or should every item (such as non-tiling assets) be stored as externally linked objects as well?
thankyou very much for your help.
Copy link to clipboard
Copied
@Gravois wrote:
Hi @Stephen Marsh thankyou for helping. The script works as long as I remove all other non-linked smart objects. Is there a way to ammend the script so that it can ignore normal smart embedded smart objects or bg layers? or should every item (such as non-tiling assets) be stored as externally linked objects as well?
thankyou very much for your help.
Ah, your OP only mentioned linked smart objects, not a mixture of linked and embedded. Of course, I didn't test for that! :]
There is a conditional in there to only process smart object layers, however, I'll have to find out a way to differentiate between linked vs. embedded, off-hand I don't know of a property for that.
@c.pfaffenbichler – I borrowed the smart object code from one of your scripts, do you know of a property or hack to isolate linked from embedded?
Copy link to clipboard
Copied
The easiest way would probably be wrapping the updating-line into a try-clause.
Copy link to clipboard
Copied
@c.pfaffenbichler – I couldn't get that to work, however, I did find some code from @r-bin that appears do what I originally wanted.
Copy link to clipboard
Copied
Depending on the number of Smart Objects addressing them via DOM might take a bit long-ish.
Switching to AM-code could offer some advantages speed-wise, but I am not sure whether it’s worth the trouble.
Copy link to clipboard
Copied
I guess that this is always the case, the more layers the longer the for loops take. The challenge is twofold (for me):
1) Finding suitable examples of AM code
2) Understanding them, extracting the code and making it generic or usable in other scripts
Copy link to clipboard
Copied
Here is an example to collect Smart Objects.
// 2017, use it at your own risk;
if (app.documents.length > 0) {
alert (collectSmartObjects2017().join("\n"));
};
////////////////////////////////////
////// collect smart objects, probably based on code by paul, mike or x //////
function collectSmartObjects2017 () {
// the file;
var myDocument = app.activeDocument;
// get number of layers;
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var applicationDesc = executeActionGet(ref);
var theNumber = applicationDesc.getInteger(stringIDToTypeID("numberOfLayers"));
// process the layers;
var theLayers = new Array;
for (var m = 0; m <= theNumber; m++) {
try {
var ref = new ActionReference();
ref.putIndex( charIDToTypeID( "Lyr " ), m);
var layerDesc = executeActionGet(ref);
var layerSet = typeIDToStringID(layerDesc.getEnumerationValue(stringIDToTypeID("layerSection")));
var isBackground = layerDesc.getBoolean(stringIDToTypeID("background"));
// if not layer group collect values;
if (layerSet != "layerSectionEnd" && layerSet != "layerSectionStart" && isBackground != true) {
var theName = layerDesc.getString(stringIDToTypeID('name'));
var theID = layerDesc.getInteger(stringIDToTypeID('layerID'));
if(layerDesc.hasKey(stringIDToTypeID('smartObject'))) {theLayers.push([theName, theID])}
};
}
catch (e) {};
};
return theLayers
};
This one collects the paths of linked smart objects.
// get list of linked smart objects’ paths;
// 2022, use it at your own risk;
var aaa = collectSmartObjectsLinks ();
alert ("\n"+aaa.join("\n\n"));
////// collect layers //////
function collectSmartObjectsLinks () {
// get number of layers;
var ref = new ActionReference();
ref.putProperty(stringIDToTypeID('property'), stringIDToTypeID('numberOfLayers'));
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var applicationDesc = executeActionGet(ref);
var theNumber = applicationDesc.getInteger(stringIDToTypeID("numberOfLayers"));
// process the layers;
var theLayers = new Array;
for (var m = 0; m <= theNumber; m++) {
try {
var ref = new ActionReference();
ref.putIndex( charIDToTypeID( "Lyr " ), m);
var layerDesc = executeActionGet(ref);
var layerSet = typeIDToStringID(layerDesc.getEnumerationValue(stringIDToTypeID("layerSection")));
var isBackground = layerDesc.getBoolean(stringIDToTypeID("background"));
var isSmartObject = layerDesc.hasKey(stringIDToTypeID("smartObject"));
// collect smart object links;
if (isSmartObject == true /*&& layerSet != "layerSectionEnd" && layerSet != "layerSectionStart" && isBackground != true*/) {
var theSO = layerDesc.getObjectValue(stringIDToTypeID("smartObject"));
if (theSO.getBoolean(stringIDToTypeID("linked")) == true) {
var theLink = theSO.getPath(stringIDToTypeID("link"));
var theCheck = true;
for (var n = 0; n < theLayers.length; n++) {
if (theLayers[n] == String(theLink)) {theCheck = false}
};
if (theCheck == true) {theLayers.push(theLink)};
};
};
}
catch (e) {};
};
return theLayers
};
Copy link to clipboard
Copied
@Gravois – So, how did the revised 1.1 version script work for you?
Copy link to clipboard
Copied
Try this 1.1 version:
/*
Update linked layers inside linked layers v1-1.jsx
https://community.adobe.com/t5/photoshop-ecosystem-discussions/nested-smart-objects-auto-update-2022/m-p/12968009
Stephen Marsh, 31st May 2022, Version 1.1
*/
#target photoshop
var myDocument = app.activeDocument;
myDocument.suspendHistory("processAllSmartObjects", "processSOLayers(myDocument)");
function processSOLayers(docLayers) {
// processSOLayers function courtesy of c.pfaffenbichler
var restoreDialogMode = app.displayDialogs;
app.displayDialogs = DialogModes.NO;
// Loop over all the layers
for (var i = docLayers.layers.length - 1; i >= 0; i--) {
var theLayer = docLayers.layers[i];
if (theLayer.typename === "ArtLayer") {
var theVisibility = theLayer.visible;
myDocument.activeLayer = theLayer;
// Linked SO conditional check courtesy of r-bin
var r = new ActionReference();
r.putProperty(stringIDToTypeID("property"), stringIDToTypeID("smartObject"));
r.putEnumerated(stringIDToTypeID("layer"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
var d = executeActionGet(r);
if (d.hasKey(stringIDToTypeID("smartObject"))) {
d = d.getObjectValue(stringIDToTypeID("smartObject"));
if (d.hasKey(stringIDToTypeID("link"))) {
// Edit the linked smart object layer
app.runMenuItem(stringIDToTypeID('placedLayerEditContents'));
// Update all modified content
app.runMenuItem(stringIDToTypeID('placedLayerUpdateAllModified'));
// Close and save
app.activeDocument.close(SaveOptions.SAVECHANGES);
}
}
// Reset visibility;
theLayer.visible = theVisibility;
// Run on the contents of layerSets (implied, not explicitly defined)
} else {
processSOLayers(theLayer);
}
}
app.displayDialogs = restoreDialogMode;
return;
}