Integration of Jukebox Library (#451) (#457)

* add Jukebox library

todo:
- saving / loading of new format
- inferrence of unknown data like past versions
- move the temporary float casts to proper use of double
- make sound related functions take double for timing
- inform people that the Jukebox sound player was renamed to SoundByte lol

* make sound, input scheduling, and super curve use double precision

* successfully load charts

* editor works again

v1 riqs can be saved and loaded

* first tempo and volume markers are unmovable

fix loading of charts' easing values

* use gsync / freesync

* update Jukebox refs to SoundByte

* game events use double part 1

Air Rally - Glee Club converted

* don't load song if chart load fails

* finish conversion of all minigames

* remove editor waveform toggle

* timeline now respects added song offset length

clear cache files on app close
prepped notes for dsp sync

* update timeline length when offset changed

* update to latest Jukebox

* make error panel object in global game manager

* improve conductor music scheduling

* added error message box

fix first game events sometimes not playing
This commit is contained in:
minenice55
2023-06-10 15:17:06 -04:00
committed by GitHub
parent b7afd697ce
commit b1fab52ad9
176 changed files with 4868 additions and 3013 deletions

View File

@ -25,7 +25,6 @@ namespace HeavenStudio.Editor.Track
private float lastTimelineSize;
private float contentPosX => Mathf.Abs(scrollRect.content.localPosition.x / scrollRect.content.localScale.x);
private float secPerBeat => 60.0f / GameManager.instance.Beatmap.bpm;
private List<GameObject> Lines = new List<GameObject>();

View File

@ -160,9 +160,9 @@ namespace HeavenStudio.Editor
int selected = 0;
for (int i = 0; i < GameManager.instance.Beatmap.entities.Count; i++)
for (int i = 0; i < Timeline.instance.eventObjs.Count; i++)
{
TimelineEventObj e = GameManager.instance.Beatmap.entities[i].eventObj;
TimelineEventObj e = Timeline.instance.eventObjs[i];
if (selectionBox.Overlaps(GetWorldRect(e.GetComponent<RectTransform>())))
{

View File

@ -2,6 +2,8 @@ using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Jukebox;
using Jukebox.Legacy;
using HeavenStudio.Editor.Track;
@ -98,7 +100,7 @@ namespace HeavenStudio.Editor.Commands
{
if (pos[id].eventObj == null)
{
pos[id].eventObj = GameManager.instance.Beatmap.entities.Find(c => c.eventObj.eventObjID == pos[id].eventObj.eventObjID).eventObj;
pos[id].eventObj = Timeline.instance.eventObjs.Find(c => c.eventObjID == pos[id].eventObj.eventObjID);
}
}
}
@ -119,7 +121,7 @@ namespace HeavenStudio.Editor.Commands
public void Redo()
{
deletedObj = Timeline.instance.AddEventObject(deletedObj.entity.datamodel, false, new Vector3(deletedObj.entity.beat, -deletedObj.entity.track * Timeline.instance.LayerHeight()), deletedObj.entity, true, deletedObj.entity.eventObj.eventObjID);
deletedObj = Timeline.instance.AddEventObject(deletedObj.entity.datamodel, false, new Vector3((float) deletedObj.entity.beat, -deletedObj.entity["track"] * Timeline.instance.LayerHeight()), deletedObj.entity, true);
}
public void Undo()
@ -127,7 +129,7 @@ namespace HeavenStudio.Editor.Commands
deletedObj = eventObj;
Selections.instance.Deselect(eventObj);
Timeline.instance.DestroyEventObject(eventObj.entity);
// DynamicBeatmap.DynamicEntity e = deletedObjs[i].entity;
// RiqEntity e = deletedObjs[i].entity;
// Timeline.instance.AddEventObject(e.datamodel, false, new Vector3(e.beat, -e.track * Timeline.instance.LayerHeight()), e, true, e.eventObj.eventObjID);
}
}
@ -166,8 +168,8 @@ namespace HeavenStudio.Editor.Commands
{
for (int i = 0; i < deletedObjs.Count; i++)
{
DynamicBeatmap.DynamicEntity e = deletedObjs[i].entity;
eventObjs[i] = Timeline.instance.AddEventObject(e.datamodel, false, new Vector3(e.beat, -e.track * Timeline.instance.LayerHeight()), e, true, e.eventObj.eventObjID);
RiqEntity e = deletedObjs[i].entity;
eventObjs[i] = Timeline.instance.AddEventObject(e.datamodel, false, new Vector3((float)e.beat, -e["track"] * Timeline.instance.LayerHeight()), e, true);
}
}
}
@ -190,8 +192,8 @@ namespace HeavenStudio.Editor.Commands
{
for (int i = 0; i < copiedObjs.Count; i++)
{
DynamicBeatmap.DynamicEntity e = copiedObjs[i].entity;
eventObjs[i] = Timeline.instance.AddEventObject(e.datamodel, false, new Vector3(e.beat, -e.track * Timeline.instance.LayerHeight()), e, true, e.eventObj.eventObjID);
RiqEntity e = copiedObjs[i].entity;
eventObjs[i] = Timeline.instance.AddEventObject(e.datamodel, false, new Vector3((float)e.beat, -e["track"] * Timeline.instance.LayerHeight()), e, true);
}
}

View File

@ -18,6 +18,8 @@ using HeavenStudio.Editor.Track;
using HeavenStudio.Util;
using HeavenStudio.StudioDance;
using Jukebox;
using System.IO.Compression;
using System.Text;
@ -78,8 +80,6 @@ namespace HeavenStudio.Editor
public bool isShortcutsEnabled { get { return (!inAuthorativeMenu) && (!editingInputField); } }
private byte[] MusicBytes;
public static Editor instance { get; private set; }
private void Start()
@ -256,11 +256,22 @@ namespace HeavenStudio.Editor
{
if (paths.Length > 0)
{
Conductor.instance.musicSource.clip = await LoadClip(Path.Combine(paths));
changedMusic = true;
Timeline.FitToSong();
try
{
if (paths.Length == 0) return;
RiqFileHandler.WriteSong(paths[0]);
StartCoroutine(LoadMusic());
return;
}
catch (System.Exception e)
{
Debug.Log($"Error selecting music file: {e.Message}");
Debug.LogException(e);
GlobalGameManager.ShowErrorMessage("Error", e.Message);
return;
}
}
await Task.Yield();
}
);
#else
@ -268,84 +279,34 @@ namespace HeavenStudio.Editor
{
if (paths.Length > 0)
{
Conductor.instance.musicSource.clip = await LoadClip("file://" + Path.Combine(paths));
changedMusic = true;
Timeline.FitToSong();
Timeline.CreateWaveform();
try
{
if (paths.Length == 0) return;
RiqFileHandler.WriteSong(paths[0]);
StartCoroutine(LoadMusic());
return;
}
catch (System.Exception e)
{
Debug.Log($"Error selecting music file: {e.Message}");
Debug.LogException(e);
GlobalGameManager.ShowErrorMessage("Error", e.Message);
return;
}
}
await Task.Yield();
}
);
#endif
}
private async Task<AudioClip> LoadClip(string path)
IEnumerator LoadMusic()
{
AudioClip clip = null;
AudioType audioType = AudioType.OGGVORBIS;
// this is a bad solution but i'm lazy
if (path.Substring(path.Length - 3) == "ogg")
audioType = AudioType.OGGVORBIS;
else if (path.Substring(path.Length - 3) == "mp3")
audioType = AudioType.MPEG;
else if (path.Substring(path.Length - 3) == "wav")
audioType = AudioType.WAV;
using (UnityWebRequest uwr = UnityWebRequestMultimedia.GetAudioClip(path, audioType))
{
uwr.SendWebRequest();
try
{
while (!uwr.isDone) await Task.Delay(5);
if (uwr.result == UnityWebRequest.Result.ProtocolError) Debug.Log($"{uwr.error}");
else
{
clip = DownloadHandlerAudioClip.GetContent(uwr);
}
}
catch (Exception err)
{
Debug.Log($"{err.Message}, {err.StackTrace}");
}
}
try
{
if (clip != null)
MusicBytes = OggVorbis.VorbisPlugin.GetOggVorbis(clip, 1);
else
{
MusicBytes = null;
Debug.LogWarning("Failed to load music file! The stream is currently empty.");
}
}
catch (System.ArgumentNullException)
{
clip = null;
MusicBytes = null;
Debug.LogWarning("Failed to load music file! The stream is currently empty.");
}
catch (System.ArgumentOutOfRangeException)
{
clip = null;
MusicBytes = null;
Debug.LogWarning("Failed to load music file! The stream is malformed.");
}
catch (System.ArgumentException)
{
clip = null;
MusicBytes = null;
Debug.LogWarning("Failed to load music file! Only 1 or 2 channels are supported!.");
}
return clip;
yield return GameManager.instance.LoadMusic();
Timeline.FitToSong();
// Timeline.CreateWaveform();
}
public void SaveRemix(bool saveAs = true)
{
if (saveAs == true)
@ -383,24 +344,17 @@ namespace HeavenStudio.Editor
private void SaveRemixFile(string path)
{
using (FileStream zipFile = File.Open(path, FileMode.Create))
try
{
using (var archive = new ZipArchive(zipFile, ZipArchiveMode.Update))
{
var levelFile = archive.CreateEntry("remix.json", System.IO.Compression.CompressionLevel.NoCompression);
using (var zipStream = levelFile.Open())
zipStream.Write(Encoding.UTF8.GetBytes(GetJson()), 0, Encoding.UTF8.GetBytes(GetJson()).Length);
if (MusicBytes != null)
{
var musicFile = archive.CreateEntry("song.ogg", System.IO.Compression.CompressionLevel.NoCompression);
using (var zipStream = musicFile.Open())
zipStream.Write(MusicBytes, 0, MusicBytes.Length);
}
}
currentRemixPath = path;
UpdateEditorStatus(false);
RiqFileHandler.WriteRiq(GameManager.instance.Beatmap);
RiqFileHandler.PackRiq(path, true);
Debug.Log("Packed RIQ successfully!");
return;
}
catch (System.Exception e)
{
Debug.Log($"Error packing RIQ: {e.Message}");
return;
}
}
@ -410,17 +364,18 @@ namespace HeavenStudio.Editor
Timeline.instance?.Stop(0);
else
GameManager.instance.Stop(0);
MusicBytes = null;
LoadRemix("");
LoadRemix(true);
}
public void LoadRemix(string json = "", string type = "riq")
public void LoadRemix(bool create = false)
{
GameManager.instance.LoadRemix(json, type);
if (create)
GameManager.instance.NewRemix();
else
{
GameManager.instance.LoadRemix(true);
}
Timeline.instance.LoadRemix();
// Timeline.instance.SpecialInfo.UpdateStartingBPMText();
// Timeline.instance.VolumeInfo.UpdateStartingVolumeText();
// Timeline.instance.SpecialInfo.UpdateOffsetText();
Timeline.FitToSong();
currentRemixPath = string.Empty;
@ -440,49 +395,30 @@ namespace HeavenStudio.Editor
var path = Path.Combine(paths);
if (path == string.Empty) return;
loadedMusic = false;
string extension = path.GetExtension();
using var zipFile = File.Open(path, FileMode.Open);
using var archive = new ZipArchive(zipFile, ZipArchiveMode.Read);
foreach (var entry in archive.Entries)
switch (entry.Name)
{
case "remix.json":
{
using var stream = entry.Open();
using var reader = new StreamReader(stream);
LoadRemix(reader.ReadToEnd(), extension);
break;
}
case "song.ogg":
{
using var stream = entry.Open();
using var memoryStream = new MemoryStream();
stream.CopyTo(memoryStream);
MusicBytes = memoryStream.ToArray();
Conductor.instance.musicSource.clip = OggVorbis.VorbisPlugin.ToAudioClip(MusicBytes, "music");
loadedMusic = true;
Timeline.FitToSong();
break;
}
}
if (!loadedMusic)
GlobalGameManager.ShowLoadingMessage("Loading", $"Loading remix from {path}");
try
{
Conductor.instance.musicSource.clip = null;
MusicBytes = null;
string tmpDir = RiqFileHandler.ExtractRiq(path);
Debug.Log("Imported RIQ successfully!");
LoadRemix();
}
catch (System.Exception e)
{
Debug.Log($"Error importing RIQ: {e.Message}");
Debug.LogException(e);
GlobalGameManager.ShowErrorMessage("Error Loading RIQ", e.Message + "\n\n" + e.StackTrace);
return;
}
StartCoroutine(LoadMusic());
currentRemixPath = path;
remixName = Path.GetFileName(path);
UpdateEditorStatus(false);
CommandManager.instance.Clear();
Timeline.FitToSong();
Timeline.CreateWaveform();
GlobalGameManager.instance.HideDialog();
});
}
@ -521,13 +457,6 @@ namespace HeavenStudio.Editor
GlobalGameManager.UpdateDiscordStatus($"{remixName}", true, updateTime);
}
public string GetJson()
{
string json = string.Empty;
json = JsonConvert.SerializeObject(GameManager.instance.Beatmap);
return json;
}
public void SetGameEventTitle(string txt)
{
GameEventSelectorTitle.text = txt;

View File

@ -3,6 +3,8 @@ using System.Collections.Generic;
using UnityEngine;
using HeavenStudio.Editor.Track;
using Jukebox;
using Jukebox.Legacy;
namespace HeavenStudio.Editor
{
@ -20,7 +22,7 @@ namespace HeavenStudio.Editor
[SerializeField] private GameObject ColorP;
[SerializeField] private GameObject StringP;
public DynamicBeatmap.DynamicEntity entity;
public RiqEntity entity;
public bool active;
@ -61,7 +63,7 @@ namespace HeavenStudio.Editor
Editor.instance.SetGameEventTitle($"Select game event for {gridGameSelector.SelectedMinigame.Replace("\n", "")}");
}
public void StartParams(DynamicBeatmap.DynamicEntity entity)
public void StartParams(RiqEntity entity)
{
active = true;
AddParams(entity);
@ -76,7 +78,7 @@ namespace HeavenStudio.Editor
_ => EditorTheme.theme.properties.Layer1Col
};
private void AddParams(DynamicBeatmap.DynamicEntity entity)
private void AddParams(RiqEntity entity)
{
var minigame = EventCaller.instance.GetMinigame(entity.datamodel.Split(0));
int actionIndex = minigame.actions.IndexOf(minigame.actions.Find(c => c.actionName == entity.datamodel.Split(1)));
@ -87,7 +89,7 @@ namespace HeavenStudio.Editor
eventSelector.SetActive(false);
this.entity = entity;
string col = TrackToThemeColour(entity.track);
string col = TrackToThemeColour(entity["track"]);
Editor.instance.SetGameEventTitle($"Properties for <color=#{col}>{action.displayName}</color> on Beat {entity.beat}");
DestroyParams();

View File

@ -251,10 +251,10 @@ namespace HeavenStudio.Editor
index = 0;
}
eventObj = Timeline.instance.AddEventObject(mg.name + "/" + mg.actions[index].actionName, true, new Vector3(0, 0), null, true, Timeline.RandomID());
eventObj = Timeline.instance.AddEventObject(mg.name + "/" + mg.actions[index].actionName, true, new Vector3(0, 0), null, true);
}
else
eventObj = Timeline.instance.AddEventObject($"gameManager/switchGame/{mg.name}", true, new Vector3(0, 0), null, true, Timeline.RandomID());
eventObj = Timeline.instance.AddEventObject($"gameManager/switchGame/{mg.name}", true, new Vector3(0, 0), null, true);
}
else
{
@ -268,7 +268,7 @@ namespace HeavenStudio.Editor
index = currentEventIndex;
}
eventObj = Timeline.instance.AddEventObject(mg.name + "/" + mg.actions[index].actionName, true, new Vector3(0, 0), null, true, Timeline.RandomID());
eventObj = Timeline.instance.AddEventObject(mg.name + "/" + mg.actions[index].actionName, true, new Vector3(0, 0), null, true);
}
eventObj.isCreating = true;

View File

@ -3,6 +3,8 @@ using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HeavenStudio.Editor.Track;
using Jukebox;
using Jukebox.Legacy;
using TMPro;
@ -32,7 +34,7 @@ namespace HeavenStudio.Editor
[SerializeField] public GameObject HeaderP;
[SerializeField] public GameObject SubHeaderP;
[NonSerialized] public DynamicBeatmap chart;
[NonSerialized] public RiqBeatmap chart;
List<GameObject> tabContents;
private void Start() { }
@ -73,9 +75,9 @@ namespace HeavenStudio.Editor
foreach (PropertyTag property in tags)
{
if (chart.properties.ContainsKey(property.tag))
if (chart.data.properties.ContainsKey(property.tag))
{
container.AddParam(this, property.tag, chart.properties[property.tag], property.label, property.isReadOnly);
container.AddParam(this, property.tag, chart.data.properties[property.tag], property.label, property.isReadOnly);
}
else
{

View File

@ -30,8 +30,8 @@ public class SectionDialog : Dialog
public void SetSectionObj(SectionTimelineObj sectionObj)
{
this.sectionObj = sectionObj;
sectionName.text = sectionObj.chartSection.sectionName;
challengeEnable.isOn = sectionObj.chartSection.startPerfect;
sectionName.text = sectionObj.chartSection["sectionName"];
challengeEnable.isOn = sectionObj.chartSection["startPerfect"];
}
public void DeleteSection()
@ -41,20 +41,20 @@ public class SectionDialog : Dialog
Editor.instance.inAuthorativeMenu = false;
}
if (sectionObj == null) return;
GameManager.instance.Beatmap.beatmapSections.Remove(sectionObj.chartSection);
GameManager.instance.Beatmap.SectionMarkers.Remove(sectionObj.chartSection);
sectionObj.DeleteObj();
}
public void ChangeSectionName(string name)
{
if (sectionObj == null) return;
sectionObj.chartSection.sectionName = name;
sectionObj.chartSection["sectionName"] = name;
sectionObj.UpdateLabel();
}
public void SetSectionChallenge()
{
if (sectionObj == null) return;
sectionObj.chartSection.startPerfect = challengeEnable.isOn;
sectionObj.chartSection["startPerfect"] = challengeEnable.isOn;
}
}

View File

@ -6,6 +6,8 @@ using System;
using TMPro;
using Starpelly;
using Jukebox;
using Jukebox.Legacy;
namespace HeavenStudio.Editor.Track
{
@ -45,14 +47,23 @@ namespace HeavenStudio.Editor.Track
public void Setup()
{
ClearSpecialTimeline();
GameManager.instance.SortEventsList();
bool first = true;
foreach (var tempoChange in GameManager.instance.Beatmap.TempoChanges)
{
AddTempoChange(false, tempoChange, first);
first = false;
}
foreach (var tempoChange in GameManager.instance.Beatmap.tempoChanges)
AddTempoChange(false, tempoChange);
first = true;
foreach (var volumeChange in GameManager.instance.Beatmap.VolumeChanges)
{
AddVolumeChange(false, volumeChange, first);
first = false;
}
foreach (var volumeChange in GameManager.instance.Beatmap.volumeChanges)
AddVolumeChange(false, volumeChange);
foreach (var sectionChange in GameManager.instance.Beatmap.beatmapSections)
foreach (var sectionChange in GameManager.instance.Beatmap.SectionMarkers)
AddChartSection(false, sectionChange);
Timeline.instance.timelineState.SetState(Timeline.CurrentTimelineState.State.Selection);
@ -114,7 +125,7 @@ namespace HeavenStudio.Editor.Track
specialTimelineObjs.Clear();
}
public void AddTempoChange(bool create, DynamicBeatmap.TempoChange tempoChange_ = null)
public void AddTempoChange(bool create, RiqEntity tempoChange_ = null, bool first = false)
{
GameObject tempoChange = Instantiate(RefTempoChange.gameObject, this.transform);
@ -131,29 +142,23 @@ namespace HeavenStudio.Editor.Track
tempoChange.transform.position = new Vector3(Editor.instance.EditorCamera.ScreenToWorldPoint(Input.mousePosition).x + 0.08f, tempoChange.transform.position.y);
tempoChange.transform.localPosition = new Vector3(Starpelly.Mathp.Round2Nearest(tempoChange.transform.localPosition.x, Timeline.SnapInterval()), tempoChange.transform.localPosition.y);
DynamicBeatmap.TempoChange tempoC = new DynamicBeatmap.TempoChange();
tempoC.beat = tempoChange.transform.localPosition.x;
float lastTempo = Conductor.instance.GetBpmAtBeat(tempoChange.transform.localPosition.x);
if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
{
tempoC.tempo = GameManager.instance.Beatmap.bpm * 2f;
lastTempo = lastTempo * 2f;
}
else if (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl))
{
tempoC.tempo = GameManager.instance.Beatmap.bpm / 2f;
lastTempo = lastTempo / 2f;
}
else
{
tempoC.tempo = GameManager.instance.Beatmap.bpm;
}
RiqEntity tempoC = GameManager.instance.Beatmap.AddNewTempoChange(tempoChange.transform.localPosition.x, lastTempo);
tempoTimelineObj.tempoChange = tempoC;
GameManager.instance.Beatmap.tempoChanges.Add(tempoC);
}
else
{
tempoChange.transform.localPosition = new Vector3(tempoChange_.beat, tempoChange.transform.localPosition.y);
tempoTimelineObj.tempoChange = tempoChange_;
tempoChange.transform.localPosition = new Vector3((float) tempoTimelineObj.tempoChange.beat, tempoChange.transform.localPosition.y);
tempoTimelineObj.first = first;
}
tempoTimelineObj.SetVisibility(Timeline.instance.timelineState.currentState);
@ -162,7 +167,7 @@ namespace HeavenStudio.Editor.Track
Timeline.instance.FitToSong();
}
public void AddVolumeChange(bool create, DynamicBeatmap.VolumeChange volumeChange_ = null)
public void AddVolumeChange(bool create, RiqEntity volumeChange_ = null, bool first = false)
{
GameObject volumeChange = Instantiate(RefVolumeChange.gameObject, this.transform);
@ -179,25 +184,22 @@ namespace HeavenStudio.Editor.Track
volumeChange.transform.position = new Vector3(Editor.instance.EditorCamera.ScreenToWorldPoint(Input.mousePosition).x + 0.08f, volumeChange.transform.position.y);
volumeChange.transform.localPosition = new Vector3(Starpelly.Mathp.Round2Nearest(volumeChange.transform.localPosition.x, Timeline.SnapInterval()), volumeChange.transform.localPosition.y);
DynamicBeatmap.VolumeChange volumeC = new DynamicBeatmap.VolumeChange();
volumeC.beat = volumeChange.transform.localPosition.x;
volumeC.volume = GameManager.instance.Beatmap.musicVolume;
RiqEntity volumeC = GameManager.instance.Beatmap.AddNewVolumeChange(volumeChange.transform.localPosition.x, 100f);
volumeTimelineObj.volumeChange = volumeC;
GameManager.instance.Beatmap.volumeChanges.Add(volumeC);
GameManager.instance.Beatmap.VolumeChanges.Add(volumeC);
}
else
{
volumeChange.transform.localPosition = new Vector3(volumeChange_.beat, volumeChange.transform.localPosition.y);
volumeTimelineObj.volumeChange = volumeChange_;
volumeChange.transform.localPosition = new Vector3((float) volumeTimelineObj.volumeChange.beat, volumeChange.transform.localPosition.y);
volumeTimelineObj.first = first;
}
volumeTimelineObj.SetVisibility(Timeline.instance.timelineState.currentState);
specialTimelineObjs.Add(volumeTimelineObj);
}
public void AddChartSection(bool create, DynamicBeatmap.ChartSection chartSection_ = null)
public void AddChartSection(bool create, RiqEntity chartSection_ = null)
{
GameObject chartSection = Instantiate(RefSectionChange.gameObject, this.transform);
@ -215,20 +217,15 @@ namespace HeavenStudio.Editor.Track
chartSection.transform.position = new Vector3(Editor.instance.EditorCamera.ScreenToWorldPoint(Input.mousePosition).x + 0.08f, chartSection.transform.position.y);
chartSection.transform.localPosition = new Vector3(Starpelly.Mathp.Round2Nearest(chartSection.transform.localPosition.x, Timeline.SnapInterval()), chartSection.transform.localPosition.y);
DynamicBeatmap.ChartSection sectionC = new DynamicBeatmap.ChartSection();
sectionC.beat = chartSection.transform.localPosition.x;
sectionC.sectionName = "New Section";
sectionC.startPerfect = false;
sectionC.isCheckpoint = false;
RiqEntity sectionC = GameManager.instance.Beatmap.AddNewSectionMarker(chartSection.transform.localPosition.x, "New Section");
sectionTimelineObj.chartSection = sectionC;
GameManager.instance.Beatmap.beatmapSections.Add(sectionC);
GameManager.instance.Beatmap.SectionMarkers.Add(sectionC);
}
else
{
chartSection.transform.localPosition = new Vector3(chartSection_.beat, chartSection.transform.localPosition.y);
sectionTimelineObj.chartSection = chartSection_;
chartSection.transform.localPosition = new Vector3((float) sectionTimelineObj.chartSection.beat, chartSection.transform.localPosition.y);
}
sectionTimelineObj.SetVisibility(Timeline.instance.timelineState.currentState);

View File

@ -5,6 +5,7 @@ using UnityEngine;
using TMPro;
using DG.Tweening;
using Jukebox;
namespace HeavenStudio.Editor.Track
{
@ -15,7 +16,7 @@ namespace HeavenStudio.Editor.Track
[SerializeField] private GameObject chartLine;
[SerializeField] private SectionDialog sectionDialog;
public DynamicBeatmap.ChartSection chartSection;
public RiqEntity chartSection;
new private void Update()
{
@ -30,7 +31,7 @@ namespace HeavenStudio.Editor.Track
public void UpdateLabel()
{
sectionLabel.text = chartSection.sectionName;
sectionLabel.text = chartSection["sectionName"];
}
public override void Init()
@ -55,7 +56,7 @@ namespace HeavenStudio.Editor.Track
public override bool OnMove(float beat)
{
foreach (var sectionChange in GameManager.instance.Beatmap.beatmapSections)
foreach (RiqEntity sectionChange in GameManager.instance.Beatmap.SectionMarkers)
{
if (this.chartSection == sectionChange)
continue;

View File

@ -19,6 +19,7 @@ namespace HeavenStudio.Editor.Track
public bool moving = false;
public bool hovering;
public bool first = false;
private void Start()
{
@ -78,6 +79,7 @@ namespace HeavenStudio.Editor.Track
public void StartMove()
{
if (first) return;
Vector3 mousePos = Editor.instance.EditorCamera.ScreenToWorldPoint(Input.mousePosition);
startPosX = mousePos.x - transform.position.x;
moving = true;
@ -86,6 +88,7 @@ namespace HeavenStudio.Editor.Track
public void DeleteObj()
{
if (first) return;
transform.parent.GetComponent<SpecialTimeline>().specialTimelineObjs.Remove(this);
Destroy(this.gameObject);
}

View File

@ -5,6 +5,8 @@ using UnityEngine;
using TMPro;
using DG.Tweening;
using Jukebox;
using Jukebox.Legacy;
namespace HeavenStudio.Editor.Track
{
@ -14,7 +16,7 @@ namespace HeavenStudio.Editor.Track
[SerializeField] private TMP_Text tempoTXT;
[SerializeField] private GameObject tempoLine;
public DynamicBeatmap.TempoChange tempoChange;
public RiqEntity tempoChange;
new private void Update()
{
@ -31,11 +33,14 @@ namespace HeavenStudio.Editor.Track
if (Input.GetKey(KeyCode.LeftControl))
newTempo /= 100f;
tempoChange.tempo += newTempo;
tempoChange["tempo"] += newTempo;
//make sure tempo is positive
if (tempoChange.tempo < 1)
tempoChange.tempo = 1;
if (tempoChange["tempo"] < 1)
tempoChange["tempo"] = 1;
if (first && newTempo != 0)
Timeline.instance.UpdateStartingBPMText();
}
}
@ -44,7 +49,7 @@ namespace HeavenStudio.Editor.Track
private void UpdateTempo()
{
tempoTXT.text = $"{tempoChange.tempo} BPM";
tempoTXT.text = $"{tempoChange["tempo"]} BPM";
Timeline.instance.FitToSong();
}
@ -61,16 +66,17 @@ namespace HeavenStudio.Editor.Track
public override void OnRightClick()
{
if (first) return;
if (Timeline.instance.timelineState.currentState == Timeline.CurrentTimelineState.State.TempoChange)
{
GameManager.instance.Beatmap.tempoChanges.Remove(tempoChange);
GameManager.instance.Beatmap.TempoChanges.Remove(tempoChange);
DeleteObj();
}
}
public override bool OnMove(float beat)
{
foreach (var tempoChange in GameManager.instance.Beatmap.tempoChanges)
foreach (var tempoChange in GameManager.instance.Beatmap.TempoChanges)
{
if (this.tempoChange == tempoChange)
continue;

View File

@ -5,6 +5,8 @@ using UnityEngine;
using TMPro;
using DG.Tweening;
using Jukebox;
using Jukebox.Legacy;
namespace HeavenStudio.Editor.Track
{
@ -14,7 +16,7 @@ namespace HeavenStudio.Editor.Track
[SerializeField] private TMP_Text volumeTXT;
[SerializeField] private GameObject volumeLine;
public DynamicBeatmap.VolumeChange volumeChange;
public RiqEntity volumeChange;
new private void Update()
{
@ -31,19 +33,21 @@ namespace HeavenStudio.Editor.Track
if (Input.GetKey(KeyCode.LeftControl))
newVolume /= 100f;
volumeChange.volume += newVolume;
volumeChange["volume"] += newVolume;
//make sure volume is positive
volumeChange.volume = Mathf.Clamp(volumeChange.volume, 0, 100);
volumeChange["volume"] = Mathf.Clamp(volumeChange["volume"], 0, 100);
if (first && newVolume != 0)
Timeline.instance.UpdateStartingVolText();
}
}
UpdateVolume();
}
private void UpdateVolume()
{
volumeTXT.text = $"{volumeChange.volume}%";
volumeTXT.text = $"{volumeChange["volume"]}%";
}
public override void Init()
@ -59,16 +63,17 @@ namespace HeavenStudio.Editor.Track
public override void OnRightClick()
{
if (first) return;
if (Timeline.instance.timelineState.currentState == Timeline.CurrentTimelineState.State.MusicVolume)
{
GameManager.instance.Beatmap.volumeChanges.Remove(volumeChange);
GameManager.instance.Beatmap.VolumeChanges.Remove(volumeChange);
DeleteObj();
}
}
public override bool OnMove(float beat)
{
foreach (var volumeChange in GameManager.instance.Beatmap.volumeChanges)
foreach (var volumeChange in GameManager.instance.Beatmap.VolumeChanges)
{
if (this.volumeChange == volumeChange)
continue;

View File

@ -7,6 +7,8 @@ using UnityEngine.EventSystems;
using TMPro;
using Starpelly;
using Jukebox;
using Jukebox.Legacy;
namespace HeavenStudio.Editor.Track
{
@ -184,11 +186,11 @@ namespace HeavenStudio.Editor.Track
}
eventObjs.Clear();
for (int i = 0; i < GameManager.instance.Beatmap.entities.Count; i++)
for (int i = 0; i < GameManager.instance.Beatmap.Entities.Count; i++)
{
var e = GameManager.instance.Beatmap.entities[i];
var e = GameManager.instance.Beatmap.Entities[i];
AddEventObject(e.datamodel, false, new Vector3(e.beat, -e.track * LayerHeight()), e, false, RandomID());
AddEventObject(e.datamodel, false, new Vector3((float)e.beat, -e["track"] * LayerHeight()), e, false);
}
SpecialInfo.Setup();
@ -319,7 +321,7 @@ namespace HeavenStudio.Editor.Track
{
Debug.Log("what");
// DrawWaveform();
StartCoroutine(DrawWaveformRealtime());
// StartCoroutine(DrawWaveformRealtime());
}
public void AutoBtnUpdate()
@ -366,11 +368,11 @@ namespace HeavenStudio.Editor.Track
private void Update()
{
waveform.rectTransform.anchoredPosition = new Vector2(
-(GameManager.instance.Beatmap.firstBeatOffset / (60.0f / GameManager.instance.Beatmap.bpm)),
waveform.rectTransform.anchoredPosition.y);
// waveform.rectTransform.anchoredPosition = new Vector2(
// -(GameManager.instance.Beatmap.data.offset / (60.0f / GameManager.instance.Beatmap.bpm)),
// waveform.rectTransform.anchoredPosition.y);
WaveformBTN.transform.GetChild(0).GetComponent<Image>().color = (Conductor.instance.musicSource.clip != null && waveform.gameObject.activeInHierarchy) ? Color.white : Color.gray;
// WaveformBTN.transform.GetChild(0).GetComponent<Image>().color = (Conductor.instance.musicSource.clip != null && waveform.gameObject.activeInHierarchy) ? Color.white : Color.gray;
if (!Conductor.instance.isPlaying && !Conductor.instance.isPaused)
{
@ -638,7 +640,8 @@ namespace HeavenStudio.Editor.Track
{
if (Conductor.instance.musicSource.clip == null) return;
waveform.gameObject.SetActive(!waveform.gameObject.activeInHierarchy);
// waveform.gameObject.SetActive(!waveform.gameObject.activeInHierarchy);
waveform.gameObject.SetActive(false);
}
public IEnumerator DrawWaveformRealtime()
@ -731,7 +734,7 @@ namespace HeavenStudio.Editor.Track
return tex2D;
}
public TimelineEventObj AddEventObject(string eventName, bool dragNDrop = false, Vector3 pos = new Vector3(), DynamicBeatmap.DynamicEntity entity = null, bool addEvent = false, string eventId = "")
public TimelineEventObj AddEventObject(string eventName, bool dragNDrop = false, Vector3 pos = new Vector3(), RiqEntity entity = null, bool addEvent = false)
{
var game = EventCaller.instance.GetMinigame(eventName.Split(0));
var action = EventCaller.instance.GetGameAction(game, eventName.Split(1));
@ -742,9 +745,9 @@ namespace HeavenStudio.Editor.Track
TimelineEventObj eventObj = g.GetComponent<TimelineEventObj>();
if (eventName.Split(1) == "switchGame")
eventObj.Icon.sprite = Editor.GameIcon(eventName.Split(2));
else
eventObj.Icon.sprite = Editor.GameIcon(eventName.Split(0));
eventObj.Icon.sprite = Editor.GameIcon(eventName.Split(2));
else
eventObj.Icon.sprite = Editor.GameIcon(eventName.Split(0));
Minigames.GameAction gameAction = EventCaller.instance.GetGameAction(EventCaller.instance.GetMinigame(eventName.Split(0)), eventName.Split(1));
@ -770,8 +773,6 @@ namespace HeavenStudio.Editor.Track
}
}
g.SetActive(true);
if (dragNDrop)
{
var mousePos = Editor.instance.EditorCamera.ScreenToWorldPoint(Input.mousePosition);
@ -782,22 +783,16 @@ namespace HeavenStudio.Editor.Track
}
else
{
entity.eventObj = g.GetComponent<TimelineEventObj>();
entity.track = entity.eventObj.GetTrack();
entity["track"] = eventObj.GetTrack();
}
if (addEvent)
{
DynamicBeatmap.DynamicEntity tempEntity = entity;
RiqEntity tempEntity = entity;
if (entity == null)
{
DynamicBeatmap.DynamicEntity en = new DynamicBeatmap.DynamicEntity();
en.datamodel = eventName;
en.eventObj = eventObj;
GameManager.instance.Beatmap.entities.Add(en);
RiqEntity en = GameManager.instance.Beatmap.AddNewEntity(eventName, g.transform.localPosition.x, gameAction.defaultLength);
GameManager.instance.SortEventsList();
tempEntity = en;
@ -832,14 +827,21 @@ namespace HeavenStudio.Editor.Track
}
else
{
GameManager.instance.Beatmap.entities.Add(entity);
GameManager.instance.Beatmap.Entities.Add(tempEntity);
GameManager.instance.SortEventsList();
}
eventObj.entity = tempEntity;
}
else
{
eventObj.entity = entity;
}
eventObjs.Add(eventObj);
eventObj.eventObjID = eventObj.entity.uid;
eventObj.eventObjID = eventId;
g.SetActive(true);
return eventObj;
}
@ -847,8 +849,8 @@ namespace HeavenStudio.Editor.Track
private List<TimelineEventObj> duplicatedEventObjs = new List<TimelineEventObj>();
public TimelineEventObj CopyEventObject(TimelineEventObj e)
{
DynamicBeatmap.DynamicEntity clone = e.entity.DeepCopy();
TimelineEventObj dup = AddEventObject(clone.datamodel, false, new Vector3(clone.beat, -clone.track * Timeline.instance.LayerHeight()), clone, true, RandomID());
RiqEntity clone = e.entity.DeepCopy();
TimelineEventObj dup = AddEventObject(clone.datamodel, false, new Vector3((float)clone.beat, -clone["track"] * Timeline.instance.LayerHeight()), clone, true);
duplicatedEventObjs.Add(dup);
return dup;
@ -860,16 +862,23 @@ namespace HeavenStudio.Editor.Track
duplicatedEventObjs = new List<TimelineEventObj>();
}
public void DestroyEventObject(DynamicBeatmap.DynamicEntity entity)
public void DestroyEventObject(RiqEntity entity)
{
if (EventParameterManager.instance.entity == entity)
EventParameterManager.instance.Disable();
eventObjs.Remove(entity.eventObj);
GameManager.instance.Beatmap.entities.Remove(entity);
Timeline.instance.eventObjs.Remove(entity.eventObj);
Destroy(entity.eventObj.gameObject);
// eventObjs.Remove(entity.eventObj);
foreach (TimelineEventObj e in eventObjs)
{
if (e.entity == entity)
{
Destroy(e.gameObject);
eventObjs.Remove(e);
break;
}
}
GameManager.instance.Beatmap.Entities.Remove(entity);
GameManager.instance.SortEventsList();
}
@ -915,7 +924,7 @@ namespace HeavenStudio.Editor.Track
public void UpdateOffsetText()
{
FirstBeatOffset.text = (GameManager.instance.Beatmap.firstBeatOffset * 1000f).ToString("G");
FirstBeatOffset.text = (GameManager.instance.Beatmap.data.offset * 1000f).ToString("G");
}
public void UpdateOffsetFromText()
@ -930,14 +939,15 @@ namespace HeavenStudio.Editor.Track
// Limit decimal places to 4.
newOffset = (float)System.Math.Round(newOffset, 4);
GameManager.instance.Beatmap.firstBeatOffset = newOffset;
GameManager.instance.Beatmap.data.offset = newOffset;
UpdateOffsetText();
FitToSong();
}
public void UpdateStartingBPMText()
{
StartingTempoSpecialAll.text = GameManager.instance.Beatmap.bpm.ToString("G");
StartingTempoSpecialAll.text = GameManager.instance.Beatmap.TempoChanges[0]["tempo"].ToString("G");
StartingTempoSpecialTempo.text = StartingTempoSpecialAll.text;
}
@ -960,7 +970,9 @@ namespace HeavenStudio.Editor.Track
// Limit decimal places to 4.
newBPM = System.Math.Round(newBPM, 4);
GameManager.instance.Beatmap.bpm = (float) newBPM;
RiqEntity tempoChange = GameManager.instance.Beatmap.TempoChanges[0];
tempoChange["tempo"] = (float) newBPM;
GameManager.instance.Beatmap.TempoChanges[0] = tempoChange;
// In case the newBPM ended up differing from the inputted string.
UpdateStartingBPMText();
@ -970,7 +982,7 @@ namespace HeavenStudio.Editor.Track
public void UpdateStartingVolText()
{
StartingVolumeSpecialVolume.text = (GameManager.instance.Beatmap.musicVolume).ToString("G");
StartingVolumeSpecialVolume.text = (GameManager.instance.Beatmap.VolumeChanges[0]["volume"]).ToString("G");
}
public void UpdateStartingVolFromText()
@ -982,7 +994,9 @@ namespace HeavenStudio.Editor.Track
var newVol = Convert.ToInt32(StartingVolumeSpecialVolume.text);
newVol = Mathf.Clamp(newVol, 0, 100);
GameManager.instance.Beatmap.musicVolume = newVol;
RiqEntity volChange = GameManager.instance.Beatmap.VolumeChanges[0];
volChange["volume"] = newVol;
GameManager.instance.Beatmap.VolumeChanges[0] = volChange;
UpdateStartingVolText();
}

View File

@ -5,6 +5,8 @@ using UnityEngine.UI;
using Starpelly;
using DG.Tweening;
using Jukebox;
using Jukebox.Legacy;
namespace HeavenStudio.Editor.Track
{
@ -29,7 +31,7 @@ namespace HeavenStudio.Editor.Track
// private GameObject moveTemp;
[Header("Properties")]
public DynamicBeatmap.DynamicEntity entity;
public RiqEntity entity;
public float length;
public bool eligibleToMove = false;
private bool lastVisible;
@ -43,7 +45,7 @@ namespace HeavenStudio.Editor.Track
private bool resizingRight;
private bool inResizeRegion;
public bool isCreating;
public string eventObjID;
public int eventObjID;
[Header("Colors")]
public Color NormalCol;
@ -74,7 +76,11 @@ namespace HeavenStudio.Editor.Track
private void Update()
{
selected = Selections.instance.eventsSelected.Contains(this);
entity = GameManager.instance.Beatmap.entities.Find(a => a.eventObj == this);
if (eventObjID != entity.uid)
{
eventObjID = GameManager.instance.Beatmap.Entities.Find(a => a == entity).uid;
Debug.Log($"assigning uid {eventObjID}");
}
mouseHovering = RectTransformUtility.RectangleContainsScreenPoint(rectTransform, Input.mousePosition, Editor.instance.EditorCamera) && Timeline.instance.timelineState.selected;
@ -100,7 +106,7 @@ namespace HeavenStudio.Editor.Track
#endregion
SetColor(entity.track);
SetColor(entity["track"]);
if (selected)
{
@ -143,7 +149,7 @@ namespace HeavenStudio.Editor.Track
}
rectTransform.sizeDelta = new Vector2(rectTransform.sizeDelta.x, Timeline.instance.LayerHeight());
this.transform.localPosition = new Vector3(this.transform.localPosition.x, -entity.track * Timeline.instance.LayerHeight());
this.transform.localPosition = new Vector3(this.transform.localPosition.x, -entity["track"] * Timeline.instance.LayerHeight());
return;
}
@ -250,7 +256,7 @@ namespace HeavenStudio.Editor.Track
}
rectTransform.sizeDelta = new Vector2(rectTransform.sizeDelta.x, Timeline.instance.LayerHeight());
this.transform.localPosition = new Vector3(this.transform.localPosition.x, -entity.track * Timeline.instance.LayerHeight());
this.transform.localPosition = new Vector3(this.transform.localPosition.x, -entity["track"] * Timeline.instance.LayerHeight());
}
#region ClickEvents
@ -406,7 +412,7 @@ namespace HeavenStudio.Editor.Track
private void OnMove()
{
if (GameManager.instance.Beatmap.entities.FindAll(c => c.beat == this.transform.localPosition.x && c.track == GetTrack() && c != this.entity).Count > 0)
if (GameManager.instance.Beatmap.Entities.FindAll(c => c.beat == this.transform.localPosition.x && c["track"] == GetTrack() && c != this.entity).Count > 0)
{
eligibleToMove = false;
}
@ -423,7 +429,7 @@ namespace HeavenStudio.Editor.Track
entity.length = rectTransform.sizeDelta.x;
entity.beat = this.transform.localPosition.x;
GameManager.instance.SortEventsList();
entity.track = GetTrack();
entity["track"] = GetTrack();
}
#endregion
@ -477,7 +483,7 @@ namespace HeavenStudio.Editor.Track
{
// better safety net than canada's healthcare system
// this is still hilarious
// GameManager.instance.Beatmap.entities.Remove(GameManager.instance.Beatmap.entities.Find(c => c.eventObj = this));
// GameManager.instance.Beatmap.Entities.Remove(GameManager.instance.Beatmap.Entities.Find(c => c.eventObj = this));
}
#endregion