Skip to content

Commit

Permalink
Asset Manage Reconstruction
Browse files Browse the repository at this point in the history
  • Loading branch information
isHarryh committed Dec 17, 2023
1 parent 3b8f5fc commit f6139c3
Show file tree
Hide file tree
Showing 9 changed files with 646 additions and 470 deletions.
2 changes: 1 addition & 1 deletion assets/UI/Homepage.fxml
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@
</styleClass>
</JFXButton>
</Pane>
<JFXListView id="Search-models-list" fx:id="searchModelList" layoutX="165.0" layoutY="85.0"
<JFXListView id="Search-models-list" fx:id="searchModelView" layoutX="165.0" layoutY="85.0"
prefHeight="265.0" prefWidth="280.0"/>
<VBox id="Loading-failure-tip" fx:id="loadFailureTip" alignment="CENTER" layoutX="1.0" layoutY="85.0"
prefHeight="285.0" prefWidth="458.0" spacing="5.0" visible="false">
Expand Down
3 changes: 2 additions & 1 deletion core/src/cn/harryh/arkpets/ArkChar.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import cn.harryh.arkpets.animations.AnimClip;
import cn.harryh.arkpets.animations.AnimClipGroup;
import cn.harryh.arkpets.animations.AnimData;
import cn.harryh.arkpets.assets.AssetItem;
import cn.harryh.arkpets.utils.*;
import cn.harryh.arkpets.transitions.*;
import com.badlogic.gdx.Gdx;
Expand Down Expand Up @@ -48,7 +49,7 @@ public class ArkChar {
* @param assetAccessor The Asset Accessor of the model.
* @param scale The scale of the character.
*/
public ArkChar(String assetLocation, AssetCtrl.AssetAccessor assetAccessor, float scale) {
public ArkChar(String assetLocation, AssetItem.AssetAccessor assetAccessor, float scale) {
// 1.Graphics setup
camera = new OrthographicCamera();
batch = new TwoColorPolygonBatch();
Expand Down
3 changes: 2 additions & 1 deletion core/src/cn/harryh/arkpets/ArkPets.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package cn.harryh.arkpets;

import cn.harryh.arkpets.animations.*;
import cn.harryh.arkpets.assets.AssetItem;
import cn.harryh.arkpets.utils.*;
import cn.harryh.arkpets.transitions.*;
import com.badlogic.gdx.ApplicationAdapter;
Expand Down Expand Up @@ -56,7 +57,7 @@ public void create() {
getHWndLoopCtrl = new LoopCtrl(1.0f / APP_FPS * 4);
// 2.Character setup
Logger.info("App", "Using model asset \"" + config.character_asset + "\"");
cha = new ArkChar(config.character_asset, new AssetCtrl.AssetAccessor(config.character_files), skelBaseScale);
cha = new ArkChar(config.character_asset, new AssetItem.AssetAccessor(config.character_files), skelBaseScale);
cha.setCanvas();
behavior = new GeneralBehavior(config, cha.animList);
cha.setAnimation(behavior.defaultAnim());
Expand Down
215 changes: 215 additions & 0 deletions core/src/cn/harryh/arkpets/assets/AssetItem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
/** Copyright (c) 2022-2023, Harry Huang
* At GPL-3.0 License
*/
package cn.harryh.arkpets.assets;

import cn.harryh.arkpets.utils.Logger;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;

import java.io.File;
import java.io.Serializable;
import java.util.*;
import java.util.function.Function;


/** One Asset Item is corresponding to one certain local Spine asset.
*/
public class AssetItem implements Serializable {
@JSONField(serialize = false)
public File assetDir;
@JSONField
public String assetId;
@JSONField
public String type;
@JSONField
public String style;
@JSONField
public String name;
@JSONField
public String appellation;
@JSONField
public String skinGroupId;
@JSONField
public String skinGroupName;
@JSONField
public JSONArray sortTags;
@JSONField
public JSONObject assetList;
/** @deprecated Legacy field in old version dataset */ @JSONField @Deprecated
public JSONObject checksum;

private AssetAccessor accessor;

protected static final String[] extensions = {".atlas", ".png", ".skel"};

private AssetItem() {
}

/** Gets the directory where the asset files located in.
* @return A relative path string.
*/
@JSONField(serialize = false)
public String getLocation() {
return assetDir.toString();
}

/** Gets the Asset Accessor of this asset.
* @return An Asset Accessor instance.
*/
@JSONField(serialize = false)
public AssetAccessor getAccessor() {
if (accessor == null)
accessor = new AssetAccessor(assetList);
return accessor;
}

/** Verifies the integrity of the necessary fields of this {@code AssetItem}.
* @return {@code true} if all the following conditions are satisfied, otherwise {@code false}:
* 1. Both {@code assetDir} and {@code type} are not {@code null}.
* 2. The {@code AssetAccessor} is available.
*/
@JSONField(serialize = false)
public boolean isValid() {
return assetDir != null && type != null && getAccessor().isAvailable();
}

/** Verifies the existence of the target local directory.
* @return {@code true} if all the following conditions are satisfied, otherwise {@code false}:
* 1. The method {@code isValid()} returns {@code true}.
* 2. The local {@code assetDir} exists.
*/
@JSONField(serialize = false)
public boolean isExisted() {
return isValid() && assetDir.isDirectory();
}

/** Verifies the integrity of the related local files.
* @return {@code true} if all the following conditions are satisfied, otherwise {@code false}:
* 1. The method {@code isExisted()} returns {@code true}.
* 2. All the local files exist.
*/
@JSONField(serialize = false)
public boolean isChecked() {
if (isExisted()) {
try {
ArrayList<String> existed = new ArrayList<>(List.of(Objects.requireNonNull(assetDir.list())));
existed.replaceAll(String::toLowerCase);
for (String fileName : getAccessor().getAllFiles()) {
fileName = fileName.toLowerCase();
if (!existed.contains(fileName)) {
Logger.warn("Asset", "The asset file " + fileName + " (" + assetDir.getName() + ") is missing.");
return false;
}
}
return true;
} catch (Exception e) {
Logger.warn("Asset", "Failed to check the asset " + assetDir.getName());
return false;
}
} else {
return false;
}
}

@Override
public String toString() {
return name;
}

@Override
public int hashCode() {
return assetDir.hashCode();
}

@Override
public boolean equals(Object obj) {
if (obj instanceof AssetItem) {
return ((AssetItem)obj).assetDir.equals(assetDir);
}
return false;
}


/** The Asset Accessor providing methods to get the resource files of the asset.
* @since ArkPets 2.2
*/
public static class AssetAccessor {
private final ArrayList<String> list;
private final HashMap<String, ArrayList<String>> map;

public AssetAccessor(JSONObject fileMap) {
ArrayList<String> list = new ArrayList<>();
HashMap<String, ArrayList<String>> map = new HashMap<>();
try {
if (fileMap != null && !fileMap.isEmpty()) {
for (String fileType : fileMap.keySet()) {
try {
JSONArray someFiles; // Try to get as array
if ((someFiles = fileMap.getJSONArray(fileType)) != null) {
var temp = someFiles.toJavaList(String.class);
list.addAll(temp);
map.put(fileType, new ArrayList<>(temp));
}
} catch (com.alibaba.fastjson.JSONException | com.alibaba.fastjson2.JSONException ex) {
String oneFile; // Try to get as string
if ((oneFile = fileMap.getString(fileType)) != null) {
list.add(oneFile);
map.put(fileType, new ArrayList<>(List.of(oneFile)));
}
}
}
}
} catch (Exception e) {
Logger.error("Asset", "Failed to establish an asset accessor, details see below.", e);
list = new ArrayList<>();
map = new HashMap<>();
}
this.list = list;
this.map = map;
}

public String[] getAllFiles() {
return list.toArray(new String[0]);
}

public String[] getAllFilesOf(String fileType) {
if (map.containsKey(fileType))
return map.get(fileType).toArray(new String[0]);
Logger.warn("Asset", "getAllFilesOf() Method has returned an empty list.");
return new String[0];
}

public String getFirstFileOf(String fileType) {
String[] all = getAllFilesOf(fileType);
if (all != null && all.length > 0)
return all[0];
Logger.warn("Asset", "getFirstFileOf() Method has returned null.");
return null;
}

public boolean isAvailable() {
return !map.isEmpty() && !list.isEmpty();
}
}


/** The Asset Property Extractor specializing in extracting a specified property.
* @param <T> The type of the specified property, typically {@code String}.
* @since ArkPets 2.2
*/
public interface PropertyExtractor<T> extends Function<AssetItem, Set<T>> {
/** Extracts the specified property of the given Asset Item.
* @param assetItem The given Asset Item.
* @return A value {@link Set} of the extracted property.
*/
@Override
Set<T> apply(AssetItem assetItem);

PropertyExtractor<String> ASSET_ITEM_TYPE = item -> Set.of(item.type);
PropertyExtractor<String> ASSET_ITEM_STYLE = item -> Set.of(item.style);
PropertyExtractor<String> ASSET_ITEM_SKIN_GROUP_NAME = item -> Set.of(item.skinGroupName);
PropertyExtractor<String> ASSET_ITEM_SORT_TAGS = item -> new HashSet<>(item.sortTags.toJavaList(String.class));
}
}
Loading

0 comments on commit f6139c3

Please sign in to comment.