package info.deskchan.talking_system; import info.deskchan.core.Path; import info.deskchan.core_utils.TextOperations; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.json.XML; import org.w3c.dom.Document; import org.xml.sax.InputSource; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import java.io.*; import java.text.SimpleDateFormat; import java.util.*; public class CharacterPreset { /** Character name. **/ public String name; /** Character state controller. **/ protected CharacterController character; protected static Class defaultCharacterController = StandardCharacterController.class; protected static CharacterController getDefaultCharacterController(){ try { return (CharacterController) defaultCharacterController.newInstance(); } catch (Exception e){ e.printStackTrace(); return null; } } /** Current emotion state. **/ protected EmotionsController emotionState; protected static Class defaultEmotionsController = StandardEmotionsController.class; protected EmotionsController getDefaultEmotionsController(){ try { EmotionsController controller = (EmotionsController) defaultEmotionsController.newInstance(); controller.setUpdater(new EmotionsController.UpdateHandler() { @Override public void onUpdate() { inform(); } }); return controller; } catch (Exception e){ e.printStackTrace(); return null; } } /** Additional character and user features like gender, species, interests. **/ public TagsMap tags; /** Phrases list. **/ public PhrasesPackList phrases; /** New preset with standard info. **/ public CharacterPreset() { setDefault(); inform(); } /** New preset from JSON. **/ public CharacterPreset(JSONObject json) { try { setFromJSON(json); } catch (JSONException e) { Main.log(e); setDefault(); } inform(); } /** Set preset tags from its string representation. **/ public void setTags(String text) { tags = new TagsMap(text); } public void setTags(Map newTags) { tags = new TagsMap(newTags); } /** Set preset from JSON. **/ public void setFromJSON(JSONObject json) { if (json.has("preset")) json = json.getJSONObject("preset"); if (json.has("name")) name = json.getString("name"); else name = Main.getString("default_name"); character = getDefaultCharacterController(); if (json.has("character")) character.setFromJSON(json.getJSONObject("character")); phrases = new PhrasesPackList(); if (json.has("phrases")){ List<String> quotesFiles = listFromJSON(json, "phrases"); if (quotesFiles.size() > 0){ phrases.set(quotesFiles); } } phrases.reload(); emotionState = getDefaultEmotionsController(); try { emotionState.setFromJSON(json.getJSONObject("emotions")); } catch (Exception e){ } tags = new TagsMap(); if (json.has("tags")) { json = json.getJSONObject("tags"); for (HashMap.Entry<String, Object> obj : json.toMap().entrySet()) { tags.put(obj.getKey(), (String) obj.getValue()); } } } /** Set default preset. **/ public void setDefault() { character = getDefaultCharacterController(); emotionState = getDefaultEmotionsController(); name = "DeskChan"; phrases = new PhrasesPackList(); tags = new TagsMap(); } public JSONObject toJSON() { JSONObject json = new JSONObject(); json.put("name", name); json.put("character", character.toJSON()); json.put("emotions", emotionState.toJSON()); JSONObject preset_tags = new JSONObject(); for(String key : tags.keySet()) preset_tags.put(key, tags.getAsString(key)); json.put("tags", preset_tags); json.put("phrases", phrases.toPacksList(PhrasesPack.PackType.USER, PhrasesPack.PackType.INTENT_DATABASE)); JSONObject preset = new JSONObject(); preset.put("preset", json); return preset; } public Map<String, Object> toInformationMap() { Map<String, Object> map = new HashMap<>(); map.put("name", name); for(int i = 0; i < CharacterFeatures.getFeatureCount(); i++) map.put(CharacterFeatures.getFeatureName(i), character.getValue(i)); map.put("phrases", phrases.toPacksList(PhrasesPack.PackType.USER, PhrasesPack.PackType.INTENT_DATABASE)); map.put("tags", tags); map.put("emotion", emotionState.getCurrentEmotionName()); return map; } public Runnable onChange = null; protected void inform(){ if (onChange != null) onChange.run(); } public static CharacterPreset getFromFile(Path path) { try { String str = new String(path.readAllBytes()); return new CharacterPreset(XML.toJSONObject(str).getJSONObject("preset")); } catch (Exception e) { Main.log(e); return new CharacterPreset(); } } public void saveInFile(Path path) throws IOException { try { Document doc = DocumentBuilderFactory.newInstance() .newDocumentBuilder() .parse(new InputSource(new StringReader(XML.toString(toJSON())))); Transformer t = TransformerFactory.newInstance().newTransformer(); t.setOutputProperty(javax.xml.transform.OutputKeys.INDENT, "yes"); t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); t.setOutputProperty(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes"); OutputStreamWriter stream = new OutputStreamWriter(new FileOutputStream(path.resolve(name + ".preset")), "UTF-8"); t.transform(new DOMSource(doc), new StreamResult(stream)); } catch(Exception ex){ Main.log(ex); Main.log("Error while writing preset file"); } } public static CharacterPreset getFromFileUnsafe(File path) { try { if (!path.isAbsolute()) path = Main.getPluginProxy().getAssetsDirPath().resolve("presets").resolve(path.getName()); BufferedReader in = new BufferedReader( new InputStreamReader(new FileInputStream(path), "UTF-8") ); final StringBuilder str = new StringBuilder(); String str2; while ((str2 = in.readLine()) != null) { str.append(str2); str.append("\n"); } JSONObject obj = XML.toJSONObject(str.toString()); return new CharacterPreset(obj.getJSONObject("preset")); } catch (Exception e) { Main.log(e); return new CharacterPreset(); } } protected ArrayList<String> listFromJSON(JSONObject obj, String arrayname) { ArrayList<String> list = new ArrayList<>(); if (obj == null || !obj.has(arrayname)) { return list; } JSONArray ar = null; if (obj.get(arrayname) instanceof String) { String sa = obj.getString(arrayname); try { ar = new JSONArray(sa); } catch (Exception e){ list.add(sa); } } if (obj.get(arrayname) instanceof JSONArray) { ar = obj.getJSONArray(arrayname); } if (ar == null) { return list; } for (int i = 0; i < ar.length(); i++) { list.add(ar.getString(i)); } return list; } public String getDefaultSpriteType(){ String characterImage = character.getDefaultSpriteType(); if (characterImage == null) characterImage = emotionState.getDefaultSpriteType(); return characterImage; } @Override public int hashCode() { int hash = name.hashCode(); CharacterController cc = emotionState.construct(character); for (int i = 0; i < CharacterFeatures.getFeatureCount(); i++) hash += cc.getValue(i) * (5 + i); hash += emotionState.getCurrentEmotionName() != null ? emotionState.getCurrentEmotionName().hashCode() : 0; hash += tags.dataHashCode(); hash += phrases.hashCode(); for (PhrasesPack pack : phrases) { hash += pack.hashCode(); } return hash; } }