perf: load dependent characters/frames in the separate thread

Seen in #2689
This commit is contained in:
Jindra Petřík
2026-04-06 19:59:08 +02:00
parent 30b0ec4e26
commit f4d54b924c
3 changed files with 65 additions and 26 deletions

View File

@@ -617,6 +617,12 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
*/
@Internal
public String debuggerPackage = null;
/**
* Lock for getting dependent
*/
@Internal
private final Object dependentLock = new Object();
/**
* Imported characterId to SWF map.
@@ -1156,14 +1162,11 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
* @return Map of characterId to set of dependent characterIds
*/
public Map<Integer, Set<Integer>> getDependentCharacters() {
if (dependentCharacters == null) {
synchronized (this) {
if (dependentCharacters == null) {
computeDependentCharacters();
}
}
synchronized (dependentLock) {
if (dependentCharacters == null) {
computeDependentCharacters();
}
}
return dependentCharacters;
}
@@ -1244,6 +1247,22 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
dependentClassFrames = depCls;
}
/**
* Check if dependent characters are loaded
* @return True if loaded
*/
public boolean isDependentCharactersLoaded() {
return dependentCharacters != null;
}
/**
* Check if dependent frames are loaded
* @return True if loaded
*/
public boolean isDependentFramesLoaded() {
return dependentFrames != null && dependentClassFrames != null;
}
/**
* Gets dependent frames for specified character.
*
@@ -1251,11 +1270,9 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
* @return Set of dependent characterids
*/
public Set<Integer> getDependentFrames(int characterId) {
if (dependentFrames == null) {
synchronized (this) {
if (dependentFrames == null) {
computeDependentFrames();
}
synchronized (dependentLock) {
if (dependentFrames == null) {
computeDependentFrames();
}
}
@@ -1270,7 +1287,7 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
*/
public Set<Integer> getDependentFramesByClass(String characterClass) {
if (dependentClassFrames == null) {
synchronized (this) {
synchronized (dependentLock) {
if (dependentClassFrames == null) {
computeDependentFrames();
}

View File

@@ -263,6 +263,8 @@ import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
@@ -448,6 +450,8 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
private static final DataFlavor TREE_FILE_FLAVOR = new DataFlavor(TreeFileFlavor.class, "TreeFile");
private boolean editingStatusSet = false;
private ExecutorService loadTagInfoExecutor = Executors.newSingleThreadExecutor();
public synchronized void setLoadingScrollPosEnabled(boolean loadingScrollPosEnabled) {
this.loadingScrollPosEnabled = loadingScrollPosEnabled;
@@ -6579,18 +6583,33 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
tagInfo.addInfo("general", "neededCharacters", Helper.joinStrings(needed, ", "));
}
if (tag instanceof CharacterTag) {
if (tag instanceof CharacterTag) {
int characterId = ((CharacterTag) tag).getCharacterId();
Set<Integer> dependent = tag.getSwf().getDependentCharacters(characterId);
if (dependent != null) {
if (dependent.size() > 0) {
tagInfo.addInfo("general", "dependentCharacters", Helper.joinStrings(dependent, ", "));
}
}
Set<Integer> dependent2 = tag.getSwf().getDependentFrames(characterId);
if (dependent2 != null && dependent2.size() > 0) {
tagInfo.addInfo("general", "dependentFrames", Helper.joinStrings(dependent2, ", "));
//getting dependent characters/frames for the first time may be long task
Runnable addDependentFramesRunnable = new Runnable() {
@Override
public void run() {
Set<Integer> dependent = tag.getSwf().getDependentCharacters(characterId);
if (dependent != null) {
if (!dependent.isEmpty()) {
tagInfo.addInfo("general", "dependentCharacters", Helper.joinStrings(dependent, ", "));
}
}
Set<Integer> dependent2 = tag.getSwf().getDependentFrames(characterId);
if (dependent2 != null && !dependent2.isEmpty()) {
tagInfo.addInfo("general", "dependentFrames", Helper.joinStrings(dependent2, ", "));
}
tagInfoPanel.updateTagInfo();
}
};
if (tag.getSwf().isDependentFramesLoaded() && tag.getSwf().isDependentCharactersLoaded()) {
addDependentFramesRunnable.run();
} else {
loadTagInfoExecutor.execute(addDependentFramesRunnable);
}
}

View File

@@ -108,13 +108,17 @@ public class TagInfoPanel extends JPanel {
this.tagInfo = tagInfo;
buildHtmlContent();
}
public void updateTagInfo() {
buildHtmlContent();
}
public void clear() {
this.tagInfo = new TagInfo(null);
buildHtmlContent();
}
private void updateHtmlContent(boolean expand, boolean showDetails) {
private synchronized void updateHtmlContent(boolean expand, boolean showDetails) {
String categoryName = "general";
StringBuilder result = new StringBuilder();
result.append("<html><body><table cellspacing='0' cellpadding='0'>");
@@ -232,7 +236,6 @@ public class TagInfoPanel extends JPanel {
}
result.append("</table></body></html>");
editorPane.setText(result.toString());
}