public bool Save() { try { /* * LISTS */ //Just in case, I'm moving this up here System.Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; System.Threading.Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture; _events = _events.OrderBy(x => x._time).ToList(); _notes = _notes.OrderBy(x => x._time).ToList(); _obstacles = _obstacles.OrderBy(x => x._time).ToList(); _BPMChanges = _BPMChanges.OrderBy(x => x._time).ToList(); _bookmarks = _bookmarks.OrderBy(x => x._time).ToList(); _customEvents = _customEvents.OrderBy(x => x._time).ThenBy(x => x._type).ToList(); if (mainNode is null) { mainNode = new JSONObject(); } mainNode["_version"] = _version; JSONArray events = new JSONArray(); foreach (MapEvent e in _events) { events.Add(e.ConvertToJSON()); } JSONArray notes = new JSONArray(); foreach (BeatmapNote n in _notes) { notes.Add(n.ConvertToJSON()); } JSONArray obstacles = new JSONArray(); foreach (BeatmapObstacle o in _obstacles) { obstacles.Add(o.ConvertToJSON()); } JSONArray bpm = new JSONArray(); foreach (BeatmapBPMChange b in _BPMChanges) { bpm.Add(b.ConvertToJSON()); } JSONArray bookmarks = new JSONArray(); foreach (BeatmapBookmark b in _bookmarks) { bookmarks.Add(b.ConvertToJSON()); } JSONArray customEvents = new JSONArray(); foreach (BeatmapCustomEvent c in _customEvents) { customEvents.Add(c.ConvertToJSON()); } mainNode["_notes"] = notes; mainNode["_obstacles"] = obstacles; mainNode["_events"] = events; /* * According to new the new BeatSaver schema, which will be enforced sometime soon™, * Bookmarks, Custom Events, and BPM Changes are now pushed to _customData instead of being on top level. * * Private MM should already has this updated, however public MM will need a PR by someone, or maybe squeaksies if he * wants to go against his own words and go back to that. * * Since these are editor only things, it's fine if I implement them now. Besides, CM reads both versions anyways. */ mainNode["_customData"] = new JSONObject(); if (_BPMChanges.Any()) { mainNode["_customData"]["_BPMChanges"] = bpm; } if (_bookmarks.Any()) { mainNode["_customData"]["_bookmarks"] = bookmarks; } if (_customEvents.Any()) { mainNode["_customEvents"] = customEvents; } if (_time > 0) { mainNode["_customData"]["_time"] = Math.Round(_time, 3); } BeatSaberSong.CleanObject(mainNode["_customData"]); if (!mainNode["_customData"].Children.Any()) { mainNode.Remove("_customData"); } using (StreamWriter writer = new StreamWriter(directoryAndFile, false)) { //Advanced users might want human readable JSON to perform easy modifications and reload them on the fly. //Thus, ChroMapper "beautifies" the JSON if you are in advanced mode. if (Settings.Instance.AdvancedShit) { writer.Write(mainNode.ToString(2)); } else { writer.Write(mainNode.ToString()); } } return(true); } catch (Exception e) { Debug.LogException(e); return(false); } }
public bool Save() { try { /* * LISTS */ //Just in case, I'm moving this up here System.Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; System.Threading.Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture; if (mainNode is null) { mainNode = new JSONObject(); } mainNode["_version"] = _version; JSONArray events = new JSONArray(); foreach (MapEvent e in _events) { events.Add(e.ConvertToJSON()); } JSONArray notes = new JSONArray(); foreach (BeatmapNote n in _notes) { notes.Add(n.ConvertToJSON()); } JSONArray obstacles = new JSONArray(); foreach (BeatmapObstacle o in _obstacles) { obstacles.Add(o.ConvertToJSON()); } JSONArray bpm = new JSONArray(); foreach (BeatmapBPMChange b in _BPMChanges) { bpm.Add(b.ConvertToJSON()); } JSONArray bookmarks = new JSONArray(); foreach (BeatmapBookmark b in _bookmarks) { bookmarks.Add(b.ConvertToJSON()); } JSONArray customEvents = new JSONArray(); foreach (BeatmapCustomEvent c in _customEvents) { customEvents.Add(c.ConvertToJSON()); } JSONArray waypoints = new JSONArray(); // TODO: Add formal support foreach (JSONNode w in _waypoints) { waypoints.Add(w); } mainNode["_notes"] = CleanupArray(notes); mainNode["_obstacles"] = CleanupArray(obstacles); mainNode["_events"] = CleanupArray(events); mainNode["_waypoints"] = waypoints; // TODO: Add formal support /* * According to new the new BeatSaver schema, which will be enforced sometime soon™, * Bookmarks, Custom Events, and BPM Changes are now pushed to _customData instead of being on top level. * * Private MM should already has this updated, however public MM will need a PR by someone, or maybe squeaksies if he * wants to go against his own words and go back to that. * * Since these are editor only things, it's fine if I implement them now. Besides, CM reads both versions anyways. */ if (!mainNode.HasKey("_customData") || mainNode["_customData"] is null || !mainNode["_customData"].Children.Any()) { mainNode["_customData"] = new JSONObject(); } if (_BPMChanges.Any()) { mainNode["_customData"]["_BPMChanges"] = CleanupArray(bpm); } else { mainNode["_customData"].Remove("_BPMChanges"); } if (_bookmarks.Any()) { mainNode["_customData"]["_bookmarks"] = CleanupArray(bookmarks); } else { mainNode["_customData"].Remove("_bookmarks"); } if (_customEvents.Any()) { mainNode["_customData"]["_customEvents"] = CleanupArray(customEvents); } else { mainNode["_customData"].Remove("_customEvents"); } if (_time > 0) { mainNode["_customData"]["_time"] = Math.Round(_time, 3); } BeatSaberSong.CleanObject(mainNode["_customData"]); if (!mainNode["_customData"].Children.Any()) { mainNode.Remove("_customData"); } // I *believe* this automatically creates the file if it doesn't exist. Needs more experiementation if (Settings.Instance.AdvancedShit) { File.WriteAllText(directoryAndFile, mainNode.ToString(2)); } else { File.WriteAllText(directoryAndFile, mainNode.ToString()); } /*using (StreamWriter writer = new StreamWriter(directoryAndFile, false)) * { * //Advanced users might want human readable JSON to perform easy modifications and reload them on the fly. * //Thus, ChroMapper "beautifies" the JSON if you are in advanced mode. * if (Settings.Instance.AdvancedShit) * writer.Write(mainNode.ToString(2)); * else writer.Write(mainNode.ToString()); * }*/ return(true); } catch (Exception e) { Debug.LogException(e); Debug.LogError("This is bad. You are recommendend to restart ChroMapper; progress made after this point is not garaunteed to be saved."); return(false); } }