• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.badlogic.gdx.graphics.g3d.particles;
2 
3 import com.badlogic.gdx.assets.AssetDescriptor;
4 import com.badlogic.gdx.assets.AssetManager;
5 import com.badlogic.gdx.utils.Array;
6 import com.badlogic.gdx.utils.GdxRuntimeException;
7 import com.badlogic.gdx.utils.IntArray;
8 import com.badlogic.gdx.utils.Json;
9 import com.badlogic.gdx.utils.JsonValue;
10 import com.badlogic.gdx.utils.ObjectMap;
11 import com.badlogic.gdx.utils.ObjectMap.Entry;
12 import com.badlogic.gdx.utils.reflect.ClassReflection;
13 import com.badlogic.gdx.utils.reflect.ReflectionException;
14 
15 /** This class handles the assets and configurations required by a given resource when de/serialized.
16  * It's handy when a given object or one of its members requires some assets to be loaded to work properly after
17  * being deserialized. To save the assets, the object should implement the {@link Configurable} interface and obtain
18  * a {@link SaveData} object to store every required asset or information which will be used during the loading phase.
19  * The passed in {@link AssetManager} is generally used to find the asset file name for a given resource of a given type.
20  * The class can also store global configurations, this is useful when dealing with objects which should be allocated once
21  * (i.e singleton).
22  * The deserialization process must happen in the same order of serialization, because the per object {@link SaveData} blocks are stored
23  * as an {@link Array} within the {@link ResourceData}, while the global {@link SaveData} instances can be accessed in any order because
24  * require a unique {@link String} and are stored in an {@link ObjectMap}.
25  * @author Inferno */
26 public class ResourceData<T> implements Json.Serializable{
27 
28 	/** This interface must be implemented by any class requiring additional assets to be loaded/saved */
29 	public static interface Configurable<T>{
save(AssetManager manager, ResourceData<T> resources)30 		public void save(AssetManager manager, ResourceData<T> resources);
load(AssetManager manager, ResourceData<T> resources)31 		public void load(AssetManager manager, ResourceData<T> resources);
32 	}
33 
34 	/** Contains all the saved data.
35 	 * {@link #data} is a map which link an asset name to its instance.
36 	 * {@link #assets} is an array of indices addressing a given
37 	 * {@link com.badlogic.gdx.graphics.g3d.particles.ResourceData.AssetData} in the {@link ResourceData} */
38 	public static class SaveData implements Json.Serializable{
39 		ObjectMap<String, Object> data;
40 		IntArray assets;
41 		private int loadIndex;
42 		protected ResourceData resources;
43 
SaveData()44 		public SaveData(){
45 			data = new ObjectMap<String, Object>();
46 			assets = new IntArray();
47 			loadIndex = 0;
48 		}
49 
SaveData(ResourceData resources)50 		public SaveData(ResourceData resources){
51 			data = new ObjectMap<String, Object>();
52 			assets = new IntArray();
53 			loadIndex = 0;
54 			this.resources = resources;
55 		}
56 
saveAsset(String filename, Class<K> type)57 		public <K> void saveAsset(String filename, Class<K> type){
58 			int i = resources.getAssetData(filename, type);
59 			if(i == -1){
60 				resources.sharedAssets.add(new AssetData(filename, type));
61 				i = resources.sharedAssets.size -1;
62 			}
63 			assets.add(i);
64 		}
65 
save(String key, Object value)66 		public void save(String key, Object value){
67 			data.put(key, value);
68 		}
69 
loadAsset()70 		public AssetDescriptor loadAsset(){
71 			if(loadIndex == assets.size) return null;
72 			AssetData data = (AssetData)resources.sharedAssets.get(assets.get(loadIndex++));
73 			return new AssetDescriptor(data.filename, data.type);
74 		}
75 
load(String key)76 		public <K> K load(String key){
77 			return (K)data.get(key);
78 		}
79 
80 		@Override
write(Json json)81 		public void write (Json json) {
82 			json.writeValue("data", data, ObjectMap.class);
83 			json.writeValue("indices", assets.toArray(), int[].class);
84 		}
85 
86 		@Override
read(Json json, JsonValue jsonData)87 		public void read (Json json, JsonValue jsonData) {
88 			data = json.readValue("data", ObjectMap.class, jsonData);
89 			assets.addAll(json.readValue("indices", int[].class, jsonData));
90 		}
91 	}
92 
93 	/** This class contains all the information related to a given asset */
94 	public static class AssetData<T> implements Json.Serializable{
95 		public String filename;
96 		public Class<T> type;
AssetData()97 		public AssetData(){}
AssetData(String filename, Class<T> type)98 		public AssetData(String filename, Class<T> type){
99 			this.filename = filename;
100 			this.type = type;
101 		}
102 		@Override
write(Json json)103 		public void write (Json json) {
104 			json.writeValue("filename", filename);
105 			json.writeValue("type", type.getName());
106 		}
107 		@Override
read(Json json, JsonValue jsonData)108 		public void read (Json json, JsonValue jsonData) {
109 			filename = json.readValue("filename", String.class, jsonData);
110 			String className = json.readValue("type", String.class, jsonData);
111 			try {
112 				type = (Class<T>)ClassReflection.forName(className);
113 			} catch (ReflectionException e) {
114 				throw new GdxRuntimeException("Class not found: " + className, e);
115 			}
116 		}
117 	}
118 
119 	/** Unique data, can be used to save/load generic data which is not always loaded back after saving.
120 	 * Must be used to store data which is uniquely addressable by a given string (i.e a system configuration).*/
121 	private ObjectMap<String, SaveData> uniqueData;
122 
123 	/** Objects save data, must be loaded in the same saving order*/
124 	private Array<SaveData> data;
125 
126 	/** Shared assets among all the configurable objects*/
127 	Array<AssetData> sharedAssets;
128 	private int currentLoadIndex;
129 	public T resource;
130 
ResourceData()131 	public ResourceData(){
132 		uniqueData = new ObjectMap<String, SaveData>();
133 		data = new Array<SaveData>(true, 3, SaveData.class);
134 		sharedAssets = new Array<AssetData>();
135 		currentLoadIndex = 0;
136 	}
137 
ResourceData(T resource)138 	public ResourceData(T resource){
139 		this();
140 		this.resource = resource;
141 	}
142 
getAssetData(String filename, Class<K> type)143 	<K> int getAssetData(String filename, Class<K> type){
144 		int i=0;
145 		for(AssetData data : sharedAssets){
146 			if(data.filename.equals(filename) && data.type.equals(type)){
147 				return i;
148 			}
149 			++i;
150 		}
151 		return -1;
152 	}
153 
getAssetDescriptors()154 	public Array<AssetDescriptor> getAssetDescriptors () {
155 		Array<AssetDescriptor> descriptors = new Array<AssetDescriptor>();
156 		for(AssetData data : sharedAssets){
157 			descriptors.add(new AssetDescriptor<T>(data.filename, data.type));
158 		}
159 		return descriptors;
160 	}
161 
getAssets()162 	public Array<AssetData> getAssets(){
163 		return sharedAssets;
164 	}
165 
166 	/** Creates and adds a new SaveData object to the save data list*/
createSaveData()167 	public SaveData createSaveData() {
168 		SaveData saveData = new SaveData(this);
169 		data.add(saveData);
170 		return saveData;
171 	}
172 
173 	/** Creates and adds a new and unique SaveData object to the save data map*/
createSaveData(String key)174 	public SaveData createSaveData(String key) {
175 		SaveData saveData = new SaveData(this);
176 		if(uniqueData.containsKey(key))
177 			throw new RuntimeException("Key already used, data must be unique, use a different key");
178 		uniqueData.put(key, saveData);
179 		return saveData;
180 	}
181 
182 	/** @return the next save data in the list */
getSaveData()183 	public SaveData getSaveData() {
184 		return data.get(currentLoadIndex++);
185 	}
186 
187 	/** @return the unique save data in the map */
getSaveData(String key)188 	public SaveData getSaveData(String key) {
189 		return uniqueData.get(key);
190 	}
191 
192 	@Override
write(Json json)193 	public void write (Json json) {
194 		json.writeValue("unique", uniqueData, ObjectMap.class);
195 		json.writeValue("data", data, Array.class, SaveData.class);
196 		json.writeValue("assets", sharedAssets.toArray(AssetData.class), AssetData[].class);
197 		json.writeValue("resource", resource, null);
198 	}
199 
200 	@Override
read(Json json, JsonValue jsonData)201 	public void read (Json json, JsonValue jsonData) {
202 		uniqueData = json.readValue("unique", ObjectMap.class, jsonData);
203 		for(Entry<String, SaveData> entry : uniqueData.entries()){
204 			entry.value.resources = this;
205 		}
206 
207 		data = json.readValue("data", Array.class, SaveData.class, jsonData);
208 		for(SaveData saveData : data){
209 			saveData.resources = this;
210 		}
211 
212 		sharedAssets.addAll(json.readValue("assets", Array.class, AssetData.class, jsonData));
213 		resource = json.readValue("resource", null, jsonData);
214 	}
215 
216 
217 }
218