Auto-Swing (#827)

* BurstLinq

make BGM resync when changing pitch (to test)

* autoswing

some game implementations, most games already work fine

* more game tweaks

* 16th note swing

more game fixes
make pitch change resync optional in the API

* suppress some common warnings

* Update Credits.txt
This commit is contained in:
minenice55 2024-04-07 00:54:06 -04:00 committed by minenice55
parent b602ba1e77
commit 72d555fc1d
49 changed files with 2372 additions and 242 deletions

View file

@ -60,6 +60,7 @@
-<indent=5%>vincells</indent>
-<indent=5%>Yumiko90</indent>
-<indent=5%>fu_majime</indent>
-<indent=5%>bluriskayo</indent>
<align="center"><b>Music</b></align>
-<indent=5%>Jellirby <alpha=#88>(Opening)<alpha=#FF></indent>
@ -80,6 +81,12 @@
-<indent=5%>JoyShockLibrary <alpha=#88>Jibb Smart, fork by RHeavenStudio<alpha=#FF></indent>
-<indent=5%>Jukebox <alpha=#88>RHeavenStudio<alpha=#FF></indent>
-<indent=5%>BurstLinq</indent>
-<indent=5%>Dependencies Hunter</indent>
-<indent=5%>DOTween</indent>
-<indent=5%>Graphy</indent>
-<indent=5%>NaughtyBezierCurves</indent>
-<indent=5%>Newtonsoft.Json</indent>
-<indent=5%>SoftMaskForUGUI</indent>
-<indent=5%>UniTask</indent>
-<indent=5%>Unity-UI-Rounded-Corners</indent>

File diff suppressed because it is too large Load diff

View file

@ -5,7 +5,6 @@ using UnityEngine;
using Jukebox;
using HeavenStudio.Util;
using System.Data.Common;
namespace HeavenStudio
{
@ -20,13 +19,15 @@ namespace HeavenStudio
public List<AddedPitchChange> addedPitchChanges = new List<AddedPitchChange>();
public GameManager gameManager;
// Song beats per minute
// This is determined by the song you're trying to sync up to
public float songBpm;
public float songBpm { get; private set; }
// The number of seconds for each song beat
public float secPerBeat => (float)secPerBeatAsDouble;
public double secPerBeatAsDouble;
public double secPerBeatAsDouble { get; private set; }
// The number of seconds for each song beat, inversely scaled to song pitch (higer pitch = shorter time)
public float pitchedSecPerBeat => (float)pitchedSecPerBeatAsDouble;
@ -38,9 +39,11 @@ namespace HeavenStudio
public double songPositionAsDouble => songPos;
// Current song position, in beats
public double songPosBeat; // for Conductor use only
public float songPositionInBeats => (float)songPosBeat;
public double songPositionInBeatsAsDouble => songPosBeat;
public double songPosBeat { get; private set; }
public float songPositionInBeats => (float)songPositionInBeatsAsDouble;
public double songPositionInBeatsAsDouble { get; private set; }
public float unswungSongPositionInBeats => (float)songPosBeat;
public double unswungSongPositionInBeatsAsDouble => songPosBeat;
// Current time of the song
private double time;
@ -79,7 +82,7 @@ namespace HeavenStudio
// Metronome tick sound enabled
public bool metronome = false;
Util.Sound metronomeSound;
Util.MultiSound metronomeSound;
private int _metronomeTally = 0;
// pitch values
@ -93,12 +96,14 @@ namespace HeavenStudio
private float timelineVolume = 1f;
private float minigameVolume = 1f;
public void SetTimelinePitch(float pitch)
const bool doPitchResync = true;
public void SetTimelinePitch(float pitch, bool resync = false)
{
if (isPaused) return;
if (isPaused || deferTimeKeeping) return;
if (pitch != 0 && pitch != timelinePitch)
{
Debug.Log("added pitch change " + pitch * minigamePitch + " at" + absTime);
// Debug.Log("added pitch change " + pitch * minigamePitch + " at " + absTime);
addedPitchChanges.Add(new AddedPitchChange { time = absTime, pitch = pitch * minigamePitch });
}
@ -106,15 +111,22 @@ namespace HeavenStudio
if (musicSource != null && musicSource.clip != null)
{
musicSource.pitch = SongPitch;
if (doPitchResync && isPlaying && resync && !deferTimeKeeping)
{
time = MapTimeToPitchChanges(absTime + absTimeAdjust);
songPos = startPos + time;
songPosBeat = GetBeatFromSongPos(songPos);
SeekMusicToTime(songPos, firstBeatOffset);
}
}
}
public void SetMinigamePitch(float pitch)
public void SetMinigamePitch(float pitch, bool resync = false)
{
if (isPaused || !isPlaying) return;
if (isPaused || deferTimeKeeping || !isPlaying) return;
if (pitch != 0 && pitch != minigamePitch)
{
Debug.Log("added pitch change " + pitch * timelinePitch + " at" + absTime);
// Debug.Log("added pitch change " + pitch * timelinePitch + " at " + absTime);
addedPitchChanges.Add(new AddedPitchChange { time = absTime, pitch = pitch * timelinePitch });
}
@ -122,6 +134,13 @@ namespace HeavenStudio
if (musicSource != null && musicSource.clip != null)
{
musicSource.pitch = SongPitch;
if (doPitchResync && isPlaying && resync && !deferTimeKeeping)
{
time = MapTimeToPitchChanges(absTime + absTimeAdjust);
songPos = startPos + time;
songPosBeat = GetBeatFromSongPos(songPos);
SeekMusicToTime(songPos, firstBeatOffset);
}
}
}
@ -141,12 +160,10 @@ namespace HeavenStudio
public void SetBeat(double beat)
{
var chart = GameManager.instance.Beatmap;
var chart = gameManager.Beatmap;
double offset = chart.data.offset;
startPos = GetSongPosFromBeat(beat);
double dspTime = AudioSettings.dspTime;
time = startPos;
firstBeatOffset = offset;
@ -154,13 +171,15 @@ namespace HeavenStudio
songPosBeat = GetBeatFromSongPos(time);
GameManager.instance.SetCurrentEventToClosest(beat);
gameManager.SetCurrentEventToClosest(beat);
}
public void PlaySetup(double beat)
{
deferTimeKeeping = true;
songPosBeat = beat;
absTime = 0;
startTime = DateTime.Now;
}
public void Play(double beat)
@ -183,7 +202,7 @@ namespace HeavenStudio
SetMinigameVolume(1f);
}
RiqBeatmap chart = GameManager.instance.Beatmap;
RiqBeatmap chart = gameManager.Beatmap;
double offset = chart.data.offset;
double dspTime = AudioSettings.dspTime;
dspStart = dspTime;
@ -215,6 +234,7 @@ namespace HeavenStudio
_metronomeTally = 0;
startTime = DateTime.Now;
absTime = 0;
absTimeAdjust = 0;
deferTimeKeeping = musicSource.clip != null;
@ -232,7 +252,8 @@ namespace HeavenStudio
{
deferTimeKeeping = false;
// Debug.Log($"dsptime: {dsp}, deferred timekeeping for {DateTime.Now - startTime} seconds (delta dsp {dsp - dspStart})");
startTime += TimeSpan.FromSeconds(dsp - dspStart);
startTime = DateTime.Now;
absTime = 0;
absTimeAdjust = 0;
dspStart = dsp;
}
@ -243,8 +264,8 @@ namespace HeavenStudio
if (!isPlaying) return;
isPlaying = false;
isPaused = true;
deferTimeKeeping = false;
SetMinigamePitch(1f);
deferTimeKeeping = false;
musicSource.Stop();
Util.SoundByte.PauseOneShots();
@ -265,8 +286,8 @@ namespace HeavenStudio
isPlaying = false;
isPaused = false;
deferTimeKeeping = false;
SetMinigamePitch(1f);
deferTimeKeeping = false;
musicSource.Stop();
}
@ -391,6 +412,7 @@ namespace HeavenStudio
songPos = startPos + time;
songPosBeat = GetBeatFromSongPos(songPos);
songPositionInBeatsAsDouble = GetSwungBeat(songPosBeat);
}
}
@ -422,7 +444,14 @@ namespace HeavenStudio
{
if (songPositionInBeatsAsDouble >= Math.Ceiling(startBeat) + _metronomeTally)
{
if (metronome) metronomeSound = Util.SoundByte.PlayOneShot("metronome", Math.Ceiling(startBeat) + _metronomeTally);
// if (metronome) metronomeSound = Util.SoundByte.PlayOneShot("metronome", Math.Ceiling(startBeat) + _metronomeTally);
if (metronome)
{
metronomeSound = Util.MultiSound.Play(new List<Util.MultiSound.Sound> {
new Util.MultiSound.Sound("metronome", Math.Ceiling(startBeat) + _metronomeTally),
new Util.MultiSound.Sound("metronome", Math.Ceiling(startBeat) + _metronomeTally + 0.5, 1.5f, 0.5f)
}, false, true);
}
_metronomeTally++;
}
}
@ -430,7 +459,7 @@ namespace HeavenStudio
{
if (metronomeSound != null)
{
metronomeSound.Stop();
// metronomeSound.StopAll();
metronomeSound = null;
}
}
@ -451,9 +480,9 @@ namespace HeavenStudio
return result;
}
public float GetLoopPositionFromBeat(float beatOffset, float length, bool beatClamp = true)
public float GetLoopPositionFromBeat(float beatOffset, float length, bool beatClamp = true, bool ignoreSwing = true)
{
float beat = songPositionInBeats;
float beat = ignoreSwing ? unswungSongPositionInBeats : songPositionInBeats;
if (beatClamp)
{
beat = Mathf.Max(beat, 0);
@ -461,9 +490,9 @@ namespace HeavenStudio
return Mathf.Repeat((beat / length) + beatOffset, 1);
}
public float GetPositionFromBeat(double startBeat, double length, bool beatClamp = true)
public float GetPositionFromBeat(double startBeat, double length, bool beatClamp = true, bool ignoreSwing = true)
{
float beat = songPositionInBeats;
float beat = ignoreSwing ? unswungSongPositionInBeats : songPositionInBeats;
if (beatClamp)
{
beat = Mathf.Max(beat, 0);
@ -474,71 +503,113 @@ namespace HeavenStudio
private List<RiqEntity> GetSortedTempoChanges()
{
GameManager.instance.SortEventsList();
return GameManager.instance.Beatmap.TempoChanges;
gameManager.SortEventsList();
return gameManager.Beatmap.TempoChanges;
}
public float GetBpmAtBeat(double beat, out float swingRatio)
public float GetBpmAtBeat(double beat, out float swingRatio, out float swingDivision)
{
swingRatio = 0.5f;
var chart = GameManager.instance.Beatmap;
swingDivision = 1f;
var chart = gameManager.Beatmap;
if (chart.TempoChanges.Count == 0)
return 120f;
float bpm = chart.TempoChanges[0]["tempo"];
swingRatio = chart.TempoChanges[0]["swing"] + 0.5f;
RiqEntity tempo = null;
foreach (RiqEntity t in chart.TempoChanges)
{
if (t.beat > beat)
{
break;
}
bpm = t["tempo"];
swingRatio = t["swing"] + 0.5f;
tempo = t;
}
return bpm;
tempo ??= chart.TempoChanges[0];
swingRatio = tempo["swing"] + 0.5f;
swingDivision = tempo["swingDivision"] ?? 1f;
return tempo["tempo"];
}
public float GetBpmAtBeat(double beat)
{
return GetBpmAtBeat(beat, out _);
return GetBpmAtBeat(beat, out _, out _);
}
public float GetSwingRatioAtBeat(double beat)
public float GetSwingRatioAtBeat(double beat, out float swingDivision)
{
float swingRatio;
GetBpmAtBeat(beat, out swingRatio);
GetBpmAtBeat(beat, out swingRatio, out swingDivision);
return swingRatio;
}
public double GetSwungBeat(double beat, float ratio)
public double GetSwungBeat(double beat)
{
return beat + GetSwingOffset(beat, ratio);
float ratio = GetSwingRatioAtBeat(beat, out float division);
int floor = (int)Math.Floor(beat / division);
return (floor * division) + GetSwingOffset(beat, ratio, division);
}
public double GetSwingOffset(double beatFrac, float ratio)
public double GetSwungBeat(double beat, float ratio, float division)
{
beatFrac %= 1;
if (beatFrac <= 0.5)
int floor = (int)Math.Floor(beat / division);
return (floor * division) + GetSwingOffset(beat, ratio, division);
}
public double GetSwingOffset(double beatFrac, float ratio, float division)
{
beatFrac %= division;
if (beatFrac <= ratio)
{
return 0.5 / ratio * beatFrac;
}
else
{
return 0.5 + (0.5 / (1f - ratio) * (beatFrac - ratio));
return 0.5 + 0.5 / (1 - ratio) * (beatFrac - ratio);
}
}
public double GetSongPosFromBeat(double beat)
public double GetUnSwungBeat(double beat)
{
var chart = GameManager.instance.Beatmap;
float ratio = GetSwingRatioAtBeat(beat, out float division);
int floor = (int)Math.Floor(beat / division);
return (floor * division) + GetUnSwingOffset(beat, ratio, division);
}
public double GetUnSwungBeat(double beat, float ratio, float division)
{
int floor = (int)Math.Floor(beat / division);
return (floor * division) + GetUnSwingOffset(beat, ratio, division);
}
public double GetUnSwingOffset(double beatFrac, float ratio, float division)
{
beatFrac %= division;
if (beatFrac <= ratio)
{
return 2 * ratio * beatFrac;
}
else
{
return 2 * (beatFrac - 0.5f) * (1f - ratio) + ratio;
}
}
public double GetSongPosFromBeat(double beat, bool ignoreSwing = false)
{
var chart = gameManager.Beatmap;
float bpm = 120f;
double counter = 0f;
double lastTempoChangeBeat = 0f;
if (!ignoreSwing)
{
beat = GetUnSwungBeat(beat);
}
foreach (RiqEntity t in chart.TempoChanges)
{
if (t.beat > beat)
@ -572,7 +643,7 @@ namespace HeavenStudio
double counterSeconds = 0;
float lastBpm = 120f;
foreach (RiqEntity t in GameManager.instance.Beatmap.TempoChanges)
foreach (RiqEntity t in gameManager.Beatmap.TempoChanges)
{
double beatToNext = t.beat - lastTempoChangeBeat;
double secToNext = BeatsToSecs(beatToNext, lastBpm);

View file

@ -1,5 +1,6 @@
using System;
using System.Linq;
using BurstLinq;
using System.Collections.Generic;
using UnityEngine;
using Jukebox;

View file

@ -4,6 +4,7 @@ using UnityEngine;
using HeavenStudio.Util;
using System.Linq;
using BurstLinq;
using Jukebox;
using Jukebox.Legacy;

View file

@ -86,11 +86,13 @@ namespace HeavenStudio
GameObject Conductor = new GameObject();
Conductor.name = "Conductor";
AudioSource source = Conductor.AddComponent<AudioSource>();
Conductor.AddComponent<Conductor>();
Conductor.GetComponent<Conductor>().musicSource = source;
Conductor cond = Conductor.AddComponent<Conductor>();
cond.musicSource = source;
source.priority = 255;
source.outputAudioMixerGroup = Settings.GetMusicMixer();
// Conductor.AddComponent<AudioDspTimeKeeper>();
cond.gameManager = gameManager;
gameManager.conductor = cond;
GlobalGameManager.GameRenderTexture = gameRenderTexture;
GlobalGameManager.OverlayRenderTexture = overlayRenderTexture;

View file

@ -2,6 +2,8 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using BurstLinq;
using UnityEngine;
using UnityEngine.Pool;
@ -87,6 +89,7 @@ namespace HeavenStudio
public static GameManager instance { get; private set; }
private EventCaller eventCaller;
public Conductor conductor;
// average input accuracy (msec)
List<int> inputOffsetSamples = new List<int>();
@ -173,9 +176,9 @@ namespace HeavenStudio
}
SortEventsList();
Conductor.instance.SetBpm(Beatmap.TempoChanges[0]["tempo"]);
Conductor.instance.SetVolume(Beatmap.VolumeChanges[0]["volume"]);
Conductor.instance.firstBeatOffset = Beatmap.data.offset;
conductor.SetBpm(Beatmap.TempoChanges[0]["tempo"]);
conductor.SetVolume(Beatmap.VolumeChanges[0]["volume"]);
conductor.firstBeatOffset = Beatmap.data.offset;
if (!preLoaded)
{
@ -233,14 +236,17 @@ namespace HeavenStudio
public void NewRemix()
{
Debug.Log("Creating new remix");
AudioLoadDone = false;
Beatmap = new("1", "HeavenStudio");
Beatmap.data.properties = new(Minigames.propertiesModel);
Beatmap.AddNewTempoChange(0, 120f);
RiqEntity t = Beatmap.AddNewTempoChange(0, 120f);
t.CreateProperty("swingDivision", 1f);
Beatmap.AddNewVolumeChange(0, 100f);
Beatmap.data.offset = 0f;
Conductor.instance.musicSource.clip = null;
conductor.musicSource.clip = null;
RiqFileHandler.WriteRiq(Beatmap);
AudioLoadDone = true;
}
@ -263,7 +269,7 @@ namespace HeavenStudio
catch (System.IO.FileNotFoundException f)
{
Debug.LogWarning("chart has no music: " + f.Message);
Conductor.instance.musicSource.clip = null;
conductor.musicSource.clip = null;
AudioLoadDone = true;
yield break;
}
@ -277,7 +283,7 @@ namespace HeavenStudio
}
yield return current;
}
Conductor.instance.musicSource.clip = RiqFileHandler.StreamedAudioClip;
conductor.musicSource.clip = RiqFileHandler.StreamedAudioClip;
AudioLoadDone = true;
}
@ -299,9 +305,9 @@ namespace HeavenStudio
if (!editor)
StartCoroutine(LoadMusic());
SortEventsList();
Conductor.instance.SetBpm(Beatmap.TempoChanges[0]["tempo"]);
Conductor.instance.SetVolume(Beatmap.VolumeChanges[0]["volume"]);
Conductor.instance.firstBeatOffset = Beatmap.data.offset;
conductor.SetBpm(Beatmap.TempoChanges[0]["tempo"]);
conductor.SetVolume(Beatmap.VolumeChanges[0]["volume"]);
conductor.firstBeatOffset = Beatmap.data.offset;
if (!playMode)
{
Stop(0);
@ -444,7 +450,7 @@ namespace HeavenStudio
var inf = GetGameInfo(gameName);
if (inf != null && inf.usesAssetBundle && inf.AssetsLoaded && !inf.SequencesPreloaded)
{
Debug.Log($"Preparing game {gameName}");
// Debug.Log($"Preparing game {gameName}");
PreloadGameSequences(gameName);
}
eventCaller.CallPreEvent(entity);
@ -459,32 +465,31 @@ namespace HeavenStudio
{
if (BeatmapEntities() < 1)
return;
if (!Conductor.instance.isPlaying)
if (conductor.WaitingForDsp || !conductor.isPlaying)
return;
Conductor cond = Conductor.instance;
double clampedBeat = Math.Max(cond.songPositionInBeatsAsDouble, 0);
double clampedBeat = Math.Max(conductor.songPositionInBeatsAsDouble, 0);
if (currentTempoEvent < Beatmap.TempoChanges.Count && currentTempoEvent >= 0)
{
if (cond.songPositionInBeatsAsDouble >= tempoBeats[currentTempoEvent])
if (conductor.songPositionInBeatsAsDouble >= tempoBeats[currentTempoEvent])
{
cond.SetBpm(Beatmap.TempoChanges[currentTempoEvent]["tempo"]);
conductor.SetBpm(Beatmap.TempoChanges[currentTempoEvent]["tempo"]);
currentTempoEvent++;
}
}
if (currentVolumeEvent < Beatmap.VolumeChanges.Count && currentVolumeEvent >= 0)
{
if (cond.songPositionInBeatsAsDouble >= volumeBeats[currentVolumeEvent])
if (conductor.songPositionInBeatsAsDouble >= volumeBeats[currentVolumeEvent])
{
cond.SetVolume(Beatmap.VolumeChanges[currentVolumeEvent]["volume"]);
conductor.SetVolume(Beatmap.VolumeChanges[currentVolumeEvent]["volume"]);
currentVolumeEvent++;
}
}
if (currentSectionEvent < Beatmap.SectionMarkers.Count && currentSectionEvent >= 0)
{
if (cond.songPositionInBeatsAsDouble >= sectionBeats[currentSectionEvent])
if (conductor.songPositionInBeatsAsDouble >= sectionBeats[currentSectionEvent])
{
RiqEntity marker = Beatmap.SectionMarkers[currentSectionEvent];
if (!string.IsNullOrEmpty(marker["sectionName"]))
@ -526,7 +531,7 @@ namespace HeavenStudio
}
}
if (cond.songPositionInBeatsAsDouble >= Math.Ceiling(_playStartBeat) + _pulseTally)
if (conductor.songPositionInBeatsAsDouble >= Math.Ceiling(_playStartBeat) + _pulseTally)
{
if (minigame != null) minigame.OnBeatPulse(Math.Ceiling(_playStartBeat) + _pulseTally);
onBeatPulse?.Invoke(Math.Ceiling(_playStartBeat) + _pulseTally);
@ -543,7 +548,7 @@ namespace HeavenStudio
List<RiqEntity> entitiesInRange = ListPool<RiqEntity>.Get();
List<RiqEntity> fxEntities = ListPool<RiqEntity>.Get();
// allows for multiple events on the same beat to be executed on the same frame, so no more 1-frame delay
while (currentEvent < eventBeats.Count && clampedBeat >= eventBeats[currentEvent] && Conductor.instance.isPlaying)
while (currentEvent < eventBeats.Count && clampedBeat >= eventBeats[currentEvent] && this.conductor.isPlaying)
{
fxEntities.Clear();
entitiesInRange.Clear();
@ -599,9 +604,9 @@ namespace HeavenStudio
}
else
{
double currectSectionStart = cond.GetSongPosFromBeat(currentSection.beat);
double currectSectionStart = conductor.GetSongPosFromBeat(currentSection.beat);
SectionProgress = (cond.songPosition - currectSectionStart) / (cond.GetSongPosFromBeat(nextSectionBeat) - currectSectionStart);
SectionProgress = (conductor.songPosition - currectSectionStart) / (conductor.GetSongPosFromBeat(nextSectionBeat) - currectSectionStart);
}
}
@ -609,10 +614,10 @@ namespace HeavenStudio
{
OverlaysManager.instance.TogleOverlaysVisibility(Editor.Editor.instance == null || Editor.Editor.instance.fullscreen || ((PersistentDataManager.gameSettings.overlaysInEditor) && (!Editor.Editor.instance.fullscreen)) || HeavenStudio.Editor.GameSettings.InPreview);
if (!Conductor.instance.isPlaying)
if (!conductor.isPlaying)
return;
if (Conductor.instance.songPositionInBeatsAsDouble >= Math.Ceiling(_playStartBeat) + _latePulseTally)
if (conductor.songPositionInBeatsAsDouble >= Math.Ceiling(_playStartBeat) + _latePulseTally)
{
if (minigame != null) minigame.OnLateBeatPulse(Math.Ceiling(_playStartBeat) + _latePulseTally);
onBeatPulse?.Invoke(Math.Ceiling(_playStartBeat) + _latePulseTally);
@ -668,8 +673,7 @@ namespace HeavenStudio
public void Play(double beat, float delay = 0f)
{
bool paused = Conductor.instance.isPaused;
Debug.Log("Playing at " + beat);
bool paused = conductor.isPaused;
_playStartBeat = beat;
_pulseTally = 0;
_latePulseTally = 0;
@ -711,14 +715,16 @@ namespace HeavenStudio
private IEnumerator PlayCo(double beat, float delay = 0f)
{
bool paused = Conductor.instance.isPaused;
bool paused = conductor.isPaused;
if (!paused)
{
Conductor.instance.SetBpm(Beatmap.TempoChanges[0]["tempo"]);
Conductor.instance.SetVolume(Beatmap.VolumeChanges[0]["volume"]);
Conductor.instance.firstBeatOffset = Beatmap.data.offset;
conductor.SetBpm(Beatmap.TempoChanges[0]["tempo"]);
conductor.SetVolume(Beatmap.VolumeChanges[0]["volume"]);
conductor.firstBeatOffset = Beatmap.data.offset;
conductor.PlaySetup(beat);
SetCurrentEventToClosest(beat);
Debug.Log("Playing at " + beat);
KillAllSounds();
if (delay > 0)
@ -726,7 +732,6 @@ namespace HeavenStudio
yield return new WaitForSeconds(delay);
}
Conductor.instance.PlaySetup(beat);
Minigame miniGame = null;
if (minigameObj != null && minigameObj.TryGetComponent<Minigame>(out miniGame))
{
@ -765,21 +770,21 @@ namespace HeavenStudio
CircleCursor.LockCursor(true);
}
Application.backgroundLoadingPriority = ThreadPriority.Low;
Conductor.instance.Play(beat);
conductor.Play(beat);
}
public void Pause()
{
Conductor.instance.Pause();
conductor.Pause();
Util.SoundByte.PauseOneShots();
onPause?.Invoke(Conductor.instance.songPositionInBeatsAsDouble);
onPause?.Invoke(conductor.songPositionInBeatsAsDouble);
canInput = false;
}
public void Stop(double beat, bool restart = false, float restartDelay = 0f)
{
// I feel like I should standardize the names
if (Conductor.instance.isPlaying)
if (conductor.isPlaying)
{
SkillStarManager.instance.KillStar();
TimingAccuracyDisplay.instance.StopStarFlash();
@ -796,8 +801,8 @@ namespace HeavenStudio
}
}
Conductor.instance.Stop(beat);
SetCurrentEventToClosest(beat);
conductor.Stop(beat);
conductor.SetBeat(beat);
KillAllSounds();
if (restart)
@ -816,6 +821,10 @@ namespace HeavenStudio
GlobalGameManager.LoadScene("Judgement", 0.35f, 0f, DestroyGame);
CircleCursor.LockCursor(false);
}
else
{
conductor.SetBeat(beat);
}
Application.backgroundLoadingPriority = ThreadPriority.Normal;
}
@ -830,6 +839,8 @@ namespace HeavenStudio
SoundByte.PreloadAudioClipAsync("skillStar");
SoundByte.PreloadAudioClipAsync("perfectMiss");
conductor.SetBeat(beat);
WaitUntil yieldOverlays = new WaitUntil(() => OverlaysManager.OverlaysReady);
WaitUntil yieldBeatmap = new WaitUntil(() => Beatmap != null && BeatmapEntities() > 0);
WaitUntil yieldAudio = new WaitUntil(() => AudioLoadDone || (ChartLoadError && !GlobalGameManager.IsShowingDialog));
@ -842,16 +853,16 @@ namespace HeavenStudio
}
// wait for overlays to be ready
Debug.Log("waiting for overlays");
// Debug.Log("waiting for overlays");
yield return yieldOverlays;
// wait for beatmap to be loaded
Debug.Log("waiting for beatmap");
// Debug.Log("waiting for beatmap");
yield return yieldBeatmap;
//wait for audio clip to be loaded
Debug.Log("waiting for audio");
// Debug.Log("waiting for audio");
yield return yieldAudio;
//wait for games to be loaded
Debug.Log("waiting for minigames");
// Debug.Log("waiting for minigames");
if (yieldGame != null)
yield return yieldGame;
@ -871,7 +882,7 @@ namespace HeavenStudio
public void KillAllSounds()
{
Debug.Log("Killing all sounds");
// Debug.Log("Killing all sounds");
SoundObjects.Clear();
SoundByte.KillOneShots();
}
@ -895,9 +906,10 @@ namespace HeavenStudio
allGameSwitches = EventCaller.GetAllInGameManagerList("gameManager", new string[] { "switchGame" });
preSequenceBeats = new List<double>();
string[] seekEntityDatamodel;
foreach (RiqEntity entity in Beatmap.Entities)
{
string[] seekEntityDatamodel = entity.datamodel.Split('/');
seekEntityDatamodel = entity.datamodel.Split('/');
double seekTime = eventCaller.GetGameAction(seekEntityDatamodel[0], seekEntityDatamodel[1]).preFunctionLength;
preSequenceBeats.Add(entity.beat - seekTime);
}
@ -1023,12 +1035,12 @@ namespace HeavenStudio
if (allEnds.Count > 0)
endBeat = allEnds.Select(c => c.beat).Min();
else
endBeat = Conductor.instance.SongLengthInBeatsAsDouble();
endBeat = conductor.SongLengthInBeatsAsDouble();
}
else
{
SetGame("noGame");
endBeat = Conductor.instance.SongLengthInBeatsAsDouble();
endBeat = conductor.SongLengthInBeatsAsDouble();
}
if (Beatmap.TempoChanges.Count > 0)
@ -1112,9 +1124,9 @@ namespace HeavenStudio
}
}
while (beat + 0.25 > Math.Max(Conductor.instance.songPositionInBeatsAsDouble, 0))
while (beat + 0.25 > Math.Max(conductor.songPositionInBeatsAsDouble, 0))
{
if (!Conductor.instance.isPlaying)
if (!conductor.isPlaying)
{
HeavenStudio.StaticCamera.instance.ToggleCanvasVisibility(true);
SetAmbientGlowToCurrentMinigameColor();
@ -1141,7 +1153,7 @@ namespace HeavenStudio
this.minigame = minigame;
minigame.minigameName = game;
minigame.gameManager = this;
minigame.conductor = Conductor.instance;
minigame.conductor = conductor;
}
Vector3 originalScale = minigameObj.transform.localScale;
minigameObj.transform.parent = eventCaller.GamesHolder.transform;
@ -1165,7 +1177,7 @@ namespace HeavenStudio
{
if (!(inf.AssetsLoaded || inf.AlreadyLoading))
{
Debug.Log($"ASYNC loading assetbundles for game {game}");
// Debug.Log($"ASYNC loading assetbundles for game {game}");
inf.LoadAssetsAsync().Forget();
}
yield return new WaitUntil(() => inf.AssetsLoaded);
@ -1300,8 +1312,8 @@ namespace HeavenStudio
private bool SongPosLessThanClipLength(float t)
{
if (Conductor.instance.musicSource.clip != null)
return Conductor.instance.GetSongPosFromBeat(t) < Conductor.instance.musicSource.clip.length;
if (conductor.musicSource.clip != null)
return conductor.GetSongPosFromBeat(t) < conductor.musicSource.clip.length;
else
return true;
}

View file

@ -41,6 +41,7 @@ namespace HeavenStudio.Games.Scripts_BlueBear
path.positions[0].height = pathToCopy.positions[0].height;
path.positions[1].pos = pathToCopy.positions[1].pos;
game.ScheduleInput(startBeat, flyBeats, isCake ? BlueBear.InputAction_Left : BlueBear.InputAction_Right, Just, Out, Out);
startBeat = Conductor.instance.GetUnSwungBeat(startBeat);
Update();
}
@ -52,7 +53,7 @@ namespace HeavenStudio.Games.Scripts_BlueBear
private void Update()
{
var cond = Conductor.instance;
transform.localPosition = GetPathPositionFromBeat(path, cond.songPositionInBeatsAsDouble, startBeat);
transform.localPosition = GetPathPositionFromBeat(path, cond.unswungSongPositionInBeatsAsDouble, startBeat);
float flyPos = cond.GetPositionFromBeat(startBeat, flyBeats);
if (flyPos > 2f)
@ -75,7 +76,7 @@ namespace HeavenStudio.Games.Scripts_BlueBear
SoundByte.PlayOneShotGame("blueBear/chompDonut");
}
game.Bite(Conductor.instance.songPositionInBeatsAsDouble, isCake, hold);
game.Bite(Conductor.instance.unswungSongPositionInBeatsAsDouble, isCake, hold);
game.EatTreat();
SpawnCrumbs();
@ -100,7 +101,7 @@ namespace HeavenStudio.Games.Scripts_BlueBear
path.positions[0].height = barelyHeight;
path.positions[0].duration = 1;
path.positions[1].pos = new Vector3(path.positions[0].pos.x + (isCake ? -barelyDistX : barelyDistX), path.positions[0].pos.y + barelyDistY);
startBeat = Conductor.instance.songPositionInBeatsAsDouble;
startBeat = Conductor.instance.unswungSongPositionInBeatsAsDouble;
Update();
return;
}

View file

@ -74,11 +74,11 @@ namespace HeavenStudio.Games.Scripts_CatchyTune
{
if (barelyStart > 0f)
{
anim.DoScaledAnimation("barely", barelyStart, isPineapple ? 2f : 1f, clamp: true);
anim.DoScaledAnimation("barely", Conductor.instance.GetUnSwungBeat(barelyStart), isPineapple ? 2f : 1f, clamp: true);
}
else
{
anim.DoScaledAnimation("fruit bounce", startBeat, beatLength + (isPineapple ? 4f : 2f), clamp: true);
anim.DoScaledAnimation("fruit bounce", Conductor.instance.GetUnSwungBeat(startBeat), beatLength + (isPineapple ? 4f : 2f), clamp: true);
}
}
@ -136,7 +136,7 @@ namespace HeavenStudio.Games.Scripts_CatchyTune
if (state <= -1f || state >= 1f)
{
//near miss (barely)
barelyStart = Conductor.instance.songPositionInBeatsAsDouble;
barelyStart = Conductor.instance.unswungSongPositionInBeatsAsDouble;
game.catchBarely(side);

View file

@ -131,7 +131,7 @@ namespace HeavenStudio.Games.Scripts_CropStomp
// var key2Pos = key2.Position;
// key2.Position = new Vector3(key2Pos.x, veggieTrans.position.y + 2f, key2Pos.z);
pickedBeat = Conductor.instance.songPositionInBeatsAsDouble;
pickedBeat = Conductor.instance.unswungSongPositionInBeatsAsDouble;
SoundByte.PlayOneShot("miss");
@ -222,11 +222,11 @@ namespace HeavenStudio.Games.Scripts_CropStomp
veggieState = 1;
game.ScheduleInput(targetBeat, isMole ? 0.5f : 1f, CropStomp.InputAction_FlickRelease, PickJust, PickMiss, Out);
targetBeat = targetBeat + (isMole ? 0.5f : 1f);
targetBeat = cond.GetUnSwungBeat(targetBeat + (isMole ? 0.5f : 1f));
stompedBeat = cond.songPositionInBeatsAsDouble;
stompedBeat = cond.unswungSongPositionInBeatsAsDouble;
landBeat = targetBeat + (float)cond.SecsToBeats(Minigame.NgLateTime() - 1, cond.GetBpmAtBeat(targetBeat));
landBeat = targetBeat + cond.SecsToBeats(Minigame.NgLateTime() - 1, cond.GetBpmAtBeat(targetBeat));
if (autoTriggered)
{
@ -261,12 +261,12 @@ namespace HeavenStudio.Games.Scripts_CropStomp
game.bodyAnim.DoScaledAnimationAsync("Pick", 0.5f);
game.isFlicking = true;
}
var key1 = game.pickCurve.KeyPoints[0];
var keyPos = key1.Position;
key1.Position = new Vector3(keyPos.x, veggieTrans.position.y, keyPos.z);
pickedBeat = Conductor.instance.songPositionInBeatsAsDouble;
pickedBeat = Conductor.instance.unswungSongPositionInBeatsAsDouble;
if (!isMole)
{

View file

@ -25,7 +25,7 @@ namespace HeavenStudio.Games.Scripts_DoubleDate
void Update()
{
double beat = conductor.songPositionInBeatsAsDouble;
double beat = conductor.unswungSongPositionInBeatsAsDouble;
double height = 0f;
if (pathStartBeat > double.MinValue)
{
@ -44,7 +44,7 @@ namespace HeavenStudio.Games.Scripts_DoubleDate
game.ScheduleInput(beat, 1f, DoubleDate.InputAction_FlickPress, Just, Miss, Empty);
path = game.GetPath("BasketBallIn");
UpdateLastRealPos();
pathStartBeat = beat - 1f;
pathStartBeat = Conductor.instance.GetUnSwungBeat(beat - 1f);
Vector3 pos = GetPathPositionFromBeat(path, pathStartBeat, pathStartBeat);
transform.position = pos;
@ -65,7 +65,7 @@ namespace HeavenStudio.Games.Scripts_DoubleDate
}),
});
UpdateLastRealPos();
pathStartBeat = conductor.songPositionInBeatsAsDouble;
pathStartBeat = conductor.unswungSongPositionInBeatsAsDouble;
if (state >= 1f || state <= -1f)
{
path = game.GetPath("BasketBallNg" + (state > 0 ? "Late" : "Early"));
@ -80,7 +80,7 @@ namespace HeavenStudio.Games.Scripts_DoubleDate
void Hit()
{
UpdateLastRealPos();
pathStartBeat = conductor.songPositionInBeatsAsDouble;
pathStartBeat = conductor.unswungSongPositionInBeatsAsDouble;
path = game.GetPath("BasketBallJust");
game.Kick(true, false, true, _jump);
SoundByte.PlayOneShotGame("doubleDate/kick");

View file

@ -261,8 +261,7 @@ namespace HeavenStudio.Games
void Update()
{
var cond = Conductor.instance;
if (cond.isPlaying && !cond.isPaused)
if (conductor.isPlaying && !conductor.isPaused)
{
if (queuedBalls.Count != 0)
{
@ -286,7 +285,7 @@ namespace HeavenStudio.Games
}
else
{
if ((!cond.isPaused) && queuedBalls.Count != 0)
if ((!conductor.isPaused) && queuedBalls.Count != 0)
{
queuedBalls.Clear();
}
@ -352,7 +351,7 @@ namespace HeavenStudio.Games
{
boyAnim.DoScaledAnimationAsync(_isStaring ? "IdleBop2" : "IdleBop", _animSpeed);
}
if (Conductor.instance.songPositionInBeatsAsDouble > lastGirlGacha)
if (conductor.songPositionInBeatsAsDouble > lastGirlGacha)
girlAnim.DoScaledAnimationAsync("GirlBop", _animSpeed);
weasels.Bop();
}
@ -365,7 +364,7 @@ namespace HeavenStudio.Games
if (jump)
{
weasels.Jump();
lastGirlGacha = Conductor.instance.songPositionInBeatsAsDouble + 0.5f;
lastGirlGacha = conductor.songPositionInBeatsAsDouble + 0.5f;
girlAnim.DoScaledAnimationAsync("GirlLookUp", _animSpeed);
}
else if (weaselsHappy) weasels.Happy();
@ -373,7 +372,7 @@ namespace HeavenStudio.Games
{
BeatAction.New(instance, new List<BeatAction.Action>()
{
new BeatAction.Action(Conductor.instance.songPositionInBeatsAsDouble + 1f, delegate
new BeatAction.Action(conductor.songPositionInBeatsAsDouble + 1f, delegate
{
leaves.Play();
treeAnim.DoScaledAnimationAsync("TreeRustle", _animSpeed);
@ -470,11 +469,11 @@ namespace HeavenStudio.Games
public void MissKick(double beat, bool hit = false)
{
lastGirlGacha = Conductor.instance.songPositionInBeatsAsDouble + 1.5f;
lastGirlGacha = conductor.songPositionInBeatsAsDouble + 1.5f;
girlAnim.DoScaledAnimationAsync("GirlSad", _animSpeed);
if (hit)
{
lastHitWeasel = Conductor.instance.songPositionInBeatsAsDouble;
lastHitWeasel = conductor.songPositionInBeatsAsDouble;
BeatAction.New(this, new List<BeatAction.Action>()
{
new BeatAction.Action(beat - (0.25f/3f), delegate { weasels.Hit(beat); }),
@ -482,7 +481,7 @@ namespace HeavenStudio.Games
}
else
{
lastHitWeasel = Conductor.instance.songPositionInBeatsAsDouble;
lastHitWeasel = conductor.songPositionInBeatsAsDouble;
BeatAction.New(this, new List<BeatAction.Action>()
{
new BeatAction.Action(beat + 0.25, delegate { weasels.Hide(beat + 0.25f); }),

View file

@ -25,7 +25,7 @@ namespace HeavenStudio.Games.Scripts_DoubleDate
void Update()
{
double beat = conductor.songPositionInBeatsAsDouble;
double beat = conductor.unswungSongPositionInBeatsAsDouble;
double height = 0f;
if (pathStartBeat > double.MinValue)
{
@ -44,7 +44,7 @@ namespace HeavenStudio.Games.Scripts_DoubleDate
game.ScheduleInput(beat, 1.5f, DoubleDate.InputAction_FlickPress, Just, Miss, Empty);
path = game.GetPath("FootBallInNoHit"); // there's a second path for footballs that hit the weasels, use that if the weasels haven't been hit recently
UpdateLastRealPos();
pathStartBeat = beat - 1f;
pathStartBeat = Conductor.instance.GetUnSwungBeat(beat - 1f);
Vector3 pos = GetPathPositionFromBeat(path, pathStartBeat, pathStartBeat);
transform.position = pos;
@ -60,7 +60,7 @@ namespace HeavenStudio.Games.Scripts_DoubleDate
if (state >= 1f || state <= -1f)
{
UpdateLastRealPos();
pathStartBeat = conductor.songPositionInBeatsAsDouble;
pathStartBeat = conductor.unswungSongPositionInBeatsAsDouble;
path = game.GetPath("FootBallNg" + (state > 0 ? "Late" : "Early"));
SoundByte.PlayOneShot("miss");
game.Kick(false);
@ -84,7 +84,7 @@ namespace HeavenStudio.Games.Scripts_DoubleDate
transform.localScale *= 0.25f;
path = game.GetPath("FootBallFall");
UpdateLastRealPos();
pathStartBeat = conductor.songPositionInBeatsAsDouble + 1f;
pathStartBeat = conductor.unswungSongPositionInBeatsAsDouble + 1f;
}),
new BeatAction.Action(conductor.songPositionInBeatsAsDouble + 12f, delegate
{
@ -96,7 +96,7 @@ namespace HeavenStudio.Games.Scripts_DoubleDate
void Hit()
{
UpdateLastRealPos();
pathStartBeat = conductor.songPositionInBeatsAsDouble;
pathStartBeat = conductor.unswungSongPositionInBeatsAsDouble;
path = game.GetPath("FootBallJust");
game.Kick(true, true, jump: _jump);
SoundByte.PlayOneShotGame("doubleDate/footballKick");

View file

@ -25,7 +25,7 @@ namespace HeavenStudio.Games.Scripts_DoubleDate
void Update()
{
double beat = conductor.songPositionInBeatsAsDouble;
double beat = conductor.unswungSongPositionInBeatsAsDouble;
double height = 0f;
if (pathStartBeat > double.MinValue)
{
@ -44,7 +44,7 @@ namespace HeavenStudio.Games.Scripts_DoubleDate
game.ScheduleInput(beat, 1f, DoubleDate.InputAction_FlickPress, Just, Miss, Empty);
path = game.GetPath("SoccerIn");
UpdateLastRealPos();
pathStartBeat = beat - 1f;
pathStartBeat = Conductor.instance.GetUnSwungBeat(beat - 1f);
Vector3 pos = GetPathPositionFromBeat(path, pathStartBeat, pathStartBeat);
transform.position = pos;
@ -65,7 +65,7 @@ namespace HeavenStudio.Games.Scripts_DoubleDate
}),
});
UpdateLastRealPos();
pathStartBeat = conductor.songPositionInBeatsAsDouble;
pathStartBeat = conductor.unswungSongPositionInBeatsAsDouble;
if (state >= 1f || state <= -1f)
{
path = game.GetPath("SoccerNg" + (state > 0 ? "Late" : "Early"));
@ -80,7 +80,7 @@ namespace HeavenStudio.Games.Scripts_DoubleDate
void Hit()
{
UpdateLastRealPos();
pathStartBeat = conductor.songPositionInBeatsAsDouble;
pathStartBeat = conductor.unswungSongPositionInBeatsAsDouble;
path = game.GetPath("SoccerJust");
game.Kick(true, false, true, _jump);
SoundByte.PlayOneShotGame("doubleDate/kick");

View file

@ -389,7 +389,7 @@ namespace HeavenStudio.Games
//idol jumping physics
float jumpPos = conductor.GetPositionFromBeat(idolJumpStartTime, 1f);
float IDOL_SHADOW_SCALE = 1.18f;
if (conductor.songPositionInBeatsAsDouble >= idolJumpStartTime && conductor.songPositionInBeatsAsDouble < idolJumpStartTime + 1f)
if (conductor.unswungSongPositionInBeatsAsDouble >= idolJumpStartTime && conductor.unswungSongPositionInBeatsAsDouble < idolJumpStartTime + 1f)
{
hasJumped = true;
float yMul = jumpPos * 2f - 1f;
@ -579,7 +579,7 @@ namespace HeavenStudio.Games
{
DisableBop(beat, length);
DisableResponse(beat, length);
idolJumpStartTime = beat;
idolJumpStartTime = conductor.GetUnSwungBeat(beat);
//play anim
BeatAction.New(instance, new List<BeatAction.Action>()

View file

@ -69,7 +69,7 @@ namespace HeavenStudio.Games.Scripts_FanClub
//idol jumping physics
float jumpPos = cond.GetPositionFromBeat(startJumpTime, 1f);
float IDOL_SHADOW_SCALE = 1.18f;
if (cond.songPositionInBeatsAsDouble >= startJumpTime && cond.songPositionInBeatsAsDouble < startJumpTime + 1f)
if (cond.unswungSongPositionInBeatsAsDouble >= startJumpTime && cond.unswungSongPositionInBeatsAsDouble < startJumpTime + 1f)
{
hasJumped = true;
float yMul = jumpPos * 2f - 1f;
@ -77,7 +77,7 @@ namespace HeavenStudio.Games.Scripts_FanClub
rootTransform.transform.localPosition = new Vector3(startPostion + stepDistance * AnimCount, rootYPos + (2f * yWeight + 0.25f));
shadow.transform.localScale = new Vector3((1f-yWeight*0.8f) * IDOL_SHADOW_SCALE, (1f-yWeight*0.8f) * IDOL_SHADOW_SCALE, 1f);
anim.DoScaledAnimation("Jump", startJumpTime, 1f);
anim.DoScaledAnimation("Jump", startJumpTime, 1f, ignoreSwing: true);
}
else
{
@ -160,12 +160,11 @@ namespace HeavenStudio.Games.Scripts_FanClub
{
if (startStepBeat != double.MaxValue) return;
if (!gameObject.activeInHierarchy) return;
startJumpTime = beat;
startJumpTime = Conductor.instance.GetUnSwungBeat(beat);
//play anim
BeatAction.New(this, new List<BeatAction.Action>()
{
// new BeatAction.Action(beat, delegate { anim.Play("Jump", -1, 0); }),
new BeatAction.Action(beat + 1f, delegate { anim.Play("Land", -1, 0); }),
});
}

View file

@ -116,7 +116,7 @@ namespace HeavenStudio.Games.Scripts_FanClub
}
if (PlayerInput.GetIsAction(FanClub.InputAction_BasicPressing))
{
if (clappingStartTime != double.MinValue && cond.songPositionInBeatsAsDouble > clappingStartTime + 2f && !stopCharge)
if (clappingStartTime != double.MinValue && cond.unswungSongPositionInBeatsAsDouble > clappingStartTime + 2f && !stopCharge)
{
animator.speed = 1f;
animator.Play("FanClapCharge", -1, 0);
@ -131,7 +131,7 @@ namespace HeavenStudio.Games.Scripts_FanClub
nonTouchDelay = 0f;
stopCharge = true;
}
if (clappingStartTime != double.MinValue && cond.songPositionInBeatsAsDouble > clappingStartTime + nonTouchDelay && stopCharge
if (clappingStartTime != double.MinValue && cond.unswungSongPositionInBeatsAsDouble > clappingStartTime + nonTouchDelay && stopCharge
&& !FanClub.instance.IsExpectingInputNow(FanClub.InputAction_FlickRelease.inputLockCategory))
{
if (FanClub.instance.JudgementPaused)
@ -163,14 +163,14 @@ namespace HeavenStudio.Games.Scripts_FanClub
}
float jumpPos = cond.GetPositionFromBeat(jumpStartTime, 1f);
if (cond.songPositionInBeatsAsDouble >= jumpStartTime && cond.songPositionInBeatsAsDouble < jumpStartTime + 1f)
if (cond.unswungSongPositionInBeatsAsDouble >= jumpStartTime && cond.unswungSongPositionInBeatsAsDouble < jumpStartTime + 1f)
{
hasJumped = true;
float yMul = jumpPos * 2f - 1f;
float yWeight = -(yMul*yMul) + 1f;
motionRoot.transform.localPosition = new Vector3(0, 3f * yWeight);
shadow.transform.localScale = new Vector3((1f-yWeight*0.8f) * 1.4f, (1f-yWeight*0.8f) * 1.4f, 1f);
animator.DoScaledAnimation("FanJump", jumpStartTime);
animator.DoScaledAnimation("FanJump", jumpStartTime, ignoreSwing: true);
}
else
{
@ -205,12 +205,12 @@ namespace HeavenStudio.Games.Scripts_FanClub
var cond = Conductor.instance;
hasJumped = false;
stopBeat = true;
jumpStartTime = -99f;
jumpStartTime = double.MinValue;
animator.speed = 1f;
animator.Play("FanClap", -1, 0);
SoundByte.PlayOneShotGame("fanClub/play_clap");
SoundByte.PlayOneShotGame("fanClub/crap_impact");
clappingStartTime = cond.songPositionInBeatsAsDouble;
clappingStartTime = cond.unswungSongPositionInBeatsAsDouble;
if (doCharge)
BeatAction.New(this, new List<BeatAction.Action>()
@ -247,7 +247,7 @@ namespace HeavenStudio.Games.Scripts_FanClub
var cond = Conductor.instance;
animator.Play("FanJump", -1, 0);
SoundByte.PlayOneShotGame("fanClub/play_jump");
jumpStartTime = cond.songPositionInBeatsAsDouble;
jumpStartTime = cond.unswungSongPositionInBeatsAsDouble;
clappingStartTime = double.MinValue;
stopCharge = false;
}
@ -255,7 +255,7 @@ namespace HeavenStudio.Games.Scripts_FanClub
public bool IsJumping()
{
var cond = Conductor.instance;
return (cond.songPositionInBeatsAsDouble >= jumpStartTime && cond.songPositionInBeatsAsDouble < jumpStartTime + 1f);
return (cond.unswungSongPositionInBeatsAsDouble >= jumpStartTime && cond.unswungSongPositionInBeatsAsDouble < jumpStartTime + 1f);
}
public void Bop()

View file

@ -7,6 +7,7 @@ using HeavenStudio.Util;
using HeavenStudio.InputSystem;
using Jukebox;
using System.Linq;
using BurstLinq;
namespace HeavenStudio.Games.Loaders
{

View file

@ -38,7 +38,7 @@ namespace HeavenStudio.Games.Scripts_KarateMan
public bool KickBarrelContent = false;
public bool ShouldGlow = false;
public int OnHitExpression = (int) KarateMan.KarateManFaces.Normal;
public int OnHitExpression = (int)KarateMan.KarateManFaces.Normal;
public int comboId = -1;
static int _lastCombo = -1;
@ -266,8 +266,6 @@ namespace HeavenStudio.Games.Scripts_KarateMan
transform.rotation = Quaternion.Euler(0, 0, transform.rotation.eulerAngles.z + (-360f * Time.deltaTime) + UnityEngine.Random.Range(0f, 360f));
ShadowInstance = Instantiate(Shadow, KarateMan.instance.ItemHolder);
shadowRenderer = ShadowInstance.GetComponent<SpriteRenderer>();
shadowRenderer.color = KarateMan.instance.Joe.Shadows[0].color;
@ -350,7 +348,7 @@ namespace HeavenStudio.Games.Scripts_KarateMan
}
else if (type == ItemType.KickBall && cond.songPositionInBeatsAsDouble < startBeat + curveTargetBeat + 1f)
return;
Destroy(ShadowInstance.gameObject);
Destroy(gameObject);
return;
@ -585,9 +583,12 @@ namespace HeavenStudio.Games.Scripts_KarateMan
p.Play();
break;
case ItemType.KickBarrel:
if (KickBarrelContent) {
if (KickBarrelContent)
{
game.CreateItemInstance(startBeat + 1f, "Item03", OnHitExpression, ItemType.KickBall);
} else {
}
else
{
if (ShouldGlow) game.Joe.ApplyBombGlow();
game.CreateItemInstance(startBeat + 1f, "Item04", OnHitExpression, ItemType.KickBomb);
}
@ -629,7 +630,7 @@ namespace HeavenStudio.Games.Scripts_KarateMan
break;
}
startBeat = Conductor.instance.songPositionInBeatsAsDouble;
startBeat = Conductor.instance.unswungSongPositionInBeatsAsDouble;
status = FlyStatus.Hit;
}
@ -765,7 +766,7 @@ namespace HeavenStudio.Games.Scripts_KarateMan
if (state <= -1f || state >= 1f)
{
bool straight = joe.Punch(ItemPunchHand(), false, ItemPunchHand() == 2);
startBeat = Conductor.instance.songPositionInBeatsAsDouble;
startBeat = Conductor.instance.unswungSongPositionInBeatsAsDouble;
CurrentCurve = ItemCurves[6];
curveTargetBeat = 1f;
SoundByte.PlayOneShot("miss");
@ -788,7 +789,7 @@ namespace HeavenStudio.Games.Scripts_KarateMan
if (ItemNeedNori() && KarateMan.instance.NoriPerformance < 0.6f)
{
CreateHitMark(false);
startBeat = Conductor.instance.songPositionInBeatsAsDouble;
startBeat = Conductor.instance.unswungSongPositionInBeatsAsDouble;
status = FlyStatus.HitWeak;
SoundByte.PlayOneShotGame("karateman/hitNoNori", forcePlay: true);
joe.Punch(3);
@ -815,7 +816,7 @@ namespace HeavenStudio.Games.Scripts_KarateMan
joe.ForceFailCombo(Conductor.instance.songPositionInBeatsAsDouble);
if (state <= -1f || state >= 1f)
{
startBeat = Conductor.instance.songPositionInBeatsAsDouble;
startBeat = Conductor.instance.unswungSongPositionInBeatsAsDouble;
CurrentCurve = ItemCurves[6];
curveTargetBeat = 1f;
SoundByte.PlayOneShot("miss");
@ -885,7 +886,7 @@ namespace HeavenStudio.Games.Scripts_KarateMan
joe.SetShouldComboId(comboId);
if (state <= -1f || state >= 1f)
{
startBeat = Conductor.instance.songPositionInBeatsAsDouble;
startBeat = Conductor.instance.unswungSongPositionInBeatsAsDouble;
CurrentCurve = ItemCurves[6];
curveTargetBeat = 1f;
SoundByte.PlayOneShot("miss");
@ -932,7 +933,7 @@ namespace HeavenStudio.Games.Scripts_KarateMan
bool straight = joe.Punch(ItemPunchHand());
if (state <= -1f || state >= 1f)
{
startBeat = Conductor.instance.songPositionInBeatsAsDouble;
startBeat = Conductor.instance.unswungSongPositionInBeatsAsDouble;
CurrentCurve = ItemCurves[6];
curveTargetBeat = 1f;
SoundByte.PlayOneShot("miss");
@ -962,7 +963,7 @@ namespace HeavenStudio.Games.Scripts_KarateMan
joe.ComboSequence(3);
if (state <= -1f || state >= 1f)
{
startBeat = Conductor.instance.songPositionInBeatsAsDouble;
startBeat = Conductor.instance.unswungSongPositionInBeatsAsDouble;
CurrentCurve = ItemCurves[5];
curveTargetBeat = 1f;
SoundByte.PlayOneShot("miss");
@ -1052,7 +1053,7 @@ namespace HeavenStudio.Games.Scripts_KarateMan
joe.Punch(ItemPunchHand());
if (state <= -1f || state >= 1f)
{
startBeat = Conductor.instance.songPositionInBeatsAsDouble;
startBeat = Conductor.instance.unswungSongPositionInBeatsAsDouble;
CurrentCurve = ItemCurves[6];
curveTargetBeat = 1f;
SoundByte.PlayOneShot("miss");
@ -1114,7 +1115,7 @@ namespace HeavenStudio.Games.Scripts_KarateMan
joe.Kick(Conductor.instance.songPositionInBeatsAsDouble);
if (state <= -1f || state >= 1f)
{
startBeat = Conductor.instance.songPositionInBeatsAsDouble;
startBeat = Conductor.instance.unswungSongPositionInBeatsAsDouble;
CurrentCurve = ItemCurves[8];
curveTargetBeat = 1f;
SoundByte.PlayOneShot("miss");
@ -1140,7 +1141,7 @@ namespace HeavenStudio.Games.Scripts_KarateMan
ItemHitEffect();
status = FlyStatus.Hit;
CurrentCurve = ItemCurves[7];
startBeat = Conductor.instance.songPositionInBeatsAsDouble;
startBeat = Conductor.instance.unswungSongPositionInBeatsAsDouble;
curveTargetBeat = 3f;
KarateMan.instance.Nori.DoHit();
}

View file

@ -7,6 +7,7 @@ using HeavenStudio.Common;
using HeavenStudio.InputSystem;
using System;
using System.Linq;
using BurstLinq;
using Jukebox;
namespace HeavenStudio.Games

View file

@ -167,6 +167,8 @@ namespace HeavenStudio.Games
public int stepIterate = 0;
private static double startSteppingBeat = double.MaxValue;
private static double startBlippingBeat = double.MaxValue;
private string currentMetronomeDir = "Right";
private static double metronomeBeat = double.MaxValue;
private bool stopStepping;
public bool stopBlipping;
@ -240,6 +242,16 @@ namespace HeavenStudio.Games
man.RecursiveBlipping(startBlippingBeat);
startBlippingBeat = double.MaxValue;
}
if (songPos > metronomeBeat + 1)
{
metronomeAnim.Play("MetronomeGo" + currentMetronomeDir, -1, 1);
metronomeAnim.speed = 0;
}
else if (songPos >= metronomeBeat)
{
metronomeAnim.DoScaledAnimation("MetronomeGo" + currentMetronomeDir, metronomeBeat, 1, ignoreSwing: false);
}
}
}
@ -290,9 +302,9 @@ namespace HeavenStudio.Games
stopStepping = false;
return;
}
string dir = (stepIterate % 2 == 1) ? "Right" : "Left";
metronomeAnim.DoScaledAnimationAsync("MetronomeGo" + dir, 0.5f);
SoundByte.PlayOneShotGame("mrUpbeat/metronome" + dir);
currentMetronomeDir = (stepIterate % 2 == 1) ? "Right" : "Left";
SoundByte.PlayOneShotGame($"mrUpbeat/metronome{currentMetronomeDir}");
metronomeBeat = beat;
ScheduleStep(beat);
BeatAction.New(this, new List<BeatAction.Action>() {
new(beat + 1, delegate { RecursiveStepping(beat + 1); })
@ -305,11 +317,11 @@ namespace HeavenStudio.Games
var actions = new List<BeatAction.Action>();
for (int i = 0; i < length; i++)
{
ScheduleStep(beat);
ScheduleStep(beat + i);
actions.Add(new BeatAction.Action(beat + i, delegate {
string dir = (stepIterate % 2 == 1) ? "Right" : "Left";
metronomeAnim.DoScaledAnimationAsync("MetronomeGo" + dir, 0.5f);
SoundByte.PlayOneShotGame("mrUpbeat/metronome" + dir);
currentMetronomeDir = (stepIterate % 2 == 1) ? "Right" : "Left";
SoundByte.PlayOneShotGame($"mrUpbeat/metronome{currentMetronomeDir}");
metronomeBeat = beat + i;
stepIterate++;
}));
}

View file

@ -123,7 +123,7 @@ namespace HeavenStudio.Games.Scripts_PajamaParty
public void Jump(double beat, int alt = 1)
{
startJumpTime = beat;
startJumpTime = Conductor.instance.GetUnSwungBeat(beat);
jumpAlt = 0;
if (alt > 1)
{
@ -140,7 +140,7 @@ namespace HeavenStudio.Games.Scripts_PajamaParty
public void Throw(double beat, bool highCheck)
{
anim.DoUnscaledAnimation("MonkeyThrow" + animSuffix);
startThrowTime = beat;
startThrowTime = Conductor.instance.GetUnSwungBeat(beat);
Projectile.SetActive(true);
if (highCheck)

View file

@ -182,7 +182,7 @@ namespace HeavenStudio.Games.Scripts_PajamaParty
{
throwType = false;
throwLength = 0.5;
Projectile.GetComponent<Animator>().DoScaledAnimation("ThrowOut", startThrowTime, throwLength);
Projectile.GetComponent<Animator>().DoScaledAnimation("ThrowOut", Conductor.instance.GetUnSwungBeat(startThrowTime), throwLength);
Projectile.transform.rotation = Quaternion.Euler(0, 0, 360f * UnityEngine.Random.Range(0f, 1f));
}
else
@ -310,12 +310,12 @@ namespace HeavenStudio.Games.Scripts_PajamaParty
if (state <= -1f || state >= 1f)
{
SoundByte.PlayOneShot("miss");
PlayerJump(cond.songPositionInBeatsAsDouble, false, true);
PlayerJump(cond.unswungSongPositionInBeatsAsDouble, false, true);
}
else
{
SoundByte.PlayOneShotGame("pajamaParty/jumpJust");
PlayerJump(cond.songPositionInBeatsAsDouble, false, false);
PlayerJump(cond.unswungSongPositionInBeatsAsDouble, false, false);
}
caller.CanHit(false);
}
@ -328,7 +328,7 @@ namespace HeavenStudio.Games.Scripts_PajamaParty
if (canJump)
{
var cond = Conductor.instance;
PlayerThrough(cond.songPositionInBeatsAsDouble);
PlayerThrough(cond.unswungSongPositionInBeatsAsDouble);
}
}
//////
@ -359,12 +359,12 @@ namespace HeavenStudio.Games.Scripts_PajamaParty
{
SoundByte.PlayOneShot("miss");
throwNg = true;
EndCharge(cond.songPositionInBeatsAsDouble, true, throwNg);
EndCharge(cond.unswungSongPositionInBeatsAsDouble, true, throwNg);
}
else
{
SoundByte.PlayOneShotGame("pajamaParty/throw5");
EndCharge(cond.songPositionInBeatsAsDouble, true, throwNg);
EndCharge(cond.unswungSongPositionInBeatsAsDouble, true, throwNg);
}
caller.CanHit(false);
}
@ -374,7 +374,7 @@ namespace HeavenStudio.Games.Scripts_PajamaParty
if (canCharge)
{
var cond = Conductor.instance;
PlayerThrough(cond.songPositionInBeatsAsDouble);
PlayerThrough(cond.unswungSongPositionInBeatsAsDouble);
}
}
//

View file

@ -147,6 +147,7 @@ namespace HeavenStudio.Games
private bool CheckEventLock()
{
Conductor cond = Conductor.instance;
foreach (PlayerActionEvent toCompare in allEvents)
{
if (toCompare == this) continue;
@ -159,9 +160,9 @@ namespace HeavenStudio.Games
&& toCompare.InputAction.inputLockCategory[catIdx] != InputAction.inputLockCategory[catIdx]) continue;
}
double t1 = this.startBeat + this.timer;
double t2 = toCompare.startBeat + toCompare.timer;
double songPos = Conductor.instance.songPositionInBeatsAsDouble;
double t1 = cond.GetUnSwungBeat(this.startBeat + this.timer);
double t2 = cond.GetUnSwungBeat(toCompare.startBeat + toCompare.timer);
double songPos = cond.unswungSongPositionInBeatsAsDouble;
// compare distance between current time and the events
// events that happen at the exact same time with the exact same inputs will return true
@ -211,7 +212,7 @@ namespace HeavenStudio.Games
{
var cond = Conductor.instance;
double currTime = cond.songPositionAsDouble;
double targetTime = cond.GetSongPosFromBeat(startBeat + timer);
double targetTime = cond.GetSongPosFromBeat(cond.GetUnSwungBeat(startBeat + timer), true);
// HS timing window uses 1 as the middle point instead of 0
return 1 + (currTime - targetTime);

View file

@ -43,7 +43,7 @@ namespace HeavenStudio.Games.Scripts_RhythmTweezers
var hairDirection = new Vector3(tst.x + 0.173f, tst.y) - holder.transform.position;
holder.transform.rotation = Quaternion.FromToRotation(Vector3.down, hairDirection);
float normalizedBeat = Conductor.instance.GetPositionFromBeat(inputBeat, 0.5f);
float normalizedBeat = Conductor.instance.GetPositionFromBeat(inputBeat, 0.5f, ignoreSwing: false);
anim.Play("LoopPull", 0, normalizedBeat);
tweezers.anim.Play("Tweezers_LongPluck", 0, normalizedBeat);
if (!game.IsExpectingInputNow(RhythmTweezers.InputAction_Release) && PlayerInput.GetIsAction(RhythmTweezers.InputAction_Release) && normalizedBeat < 1f)
@ -73,7 +73,7 @@ namespace HeavenStudio.Games.Scripts_RhythmTweezers
public void EndEarly()
{
var normalized = Conductor.instance.GetPositionFromBeat(inputBeat, 0.5f);
var normalized = Conductor.instance.GetPositionFromBeat(inputBeat, 0.5f, ignoreSwing: false);
anim.Play("LoopPullReverse", 0, normalized);
tweezers.anim.Play("Tweezers_Idle", 0, 0);

View file

@ -292,7 +292,7 @@ namespace HeavenStudio.Games
spawnedHairs.Add(hair);
hair.gameObject.SetActive(true);
hair.GetComponent<Animator>().Play("SmallAppear", 0, 1);
float rot = -58f + 116 * crHandlerInstance.GetIntervalProgressFromBeat(beat, 1);
float rot = -58f + 116 * crHandlerInstance.GetIntervalProgressFromBeat(conductor.GetUnSwungBeat(beat), 1);
hair.transform.eulerAngles = new Vector3(0, 0, rot);
hair.createBeat = beat;
}
@ -305,7 +305,7 @@ namespace HeavenStudio.Games
spawnedLongs.Add(hair);
hair.gameObject.SetActive(true);
hair.GetComponent<Animator>().Play("LongAppear", 0, 1);
float rot = -58f + 116 * crHandlerInstance.GetIntervalProgressFromBeat(beat, 1);
float rot = -58f + 116 * crHandlerInstance.GetIntervalProgressFromBeat(conductor.GetUnSwungBeat(beat), 1);
hair.transform.eulerAngles = new Vector3(0, 0, rot);
hair.createBeat = beat;
}
@ -332,7 +332,7 @@ namespace HeavenStudio.Games
})
});
float rot = -58f + 116 * crHandlerInstance.GetIntervalProgressFromBeat(beat, 1);
float rot = -58f + 116 * crHandlerInstance.GetIntervalProgressFromBeat(conductor.GetUnSwungBeat(beat), 1);
hair.transform.eulerAngles = new Vector3(0, 0, rot);
hair.createBeat = beat;
}
@ -357,7 +357,7 @@ namespace HeavenStudio.Games
})
});
float rot = -58f + 116 * crHandlerInstance.GetIntervalProgressFromBeat(beat, 1);
float rot = -58f + 116 * crHandlerInstance.GetIntervalProgressFromBeat(conductor.GetUnSwungBeat(beat), 1);
hair.transform.eulerAngles = new Vector3(0, 0, rot);
hair.createBeat = beat;
}

View file

@ -68,7 +68,7 @@ namespace HeavenStudio.Games.Scripts_SeeSaw
{
var cond = Conductor.instance;
double currentBeat = cond.songPositionInBeatsAsDouble;
double currentBeat = cond.unswungSongPositionInBeatsAsDouble;
if (cond.isPlaying && !cond.isPaused)
{
@ -298,7 +298,7 @@ namespace HeavenStudio.Games.Scripts_SeeSaw
{
lastState = currentState;
currentState = state;
startBeat = beat;
startBeat = Conductor.instance.GetUnSwungBeat(beat);
heightLastFrame = 0;
hasChangedAnimMidAir = false;
switch (currentState)

View file

@ -101,7 +101,7 @@ namespace HeavenStudio.Games
}
if (Conductor.instance.isPlaying)
{
Conductor.instance.SetMinigamePitch(1f);
Conductor.instance.SetMinigamePitch(1f, true);
}
}

View file

@ -39,10 +39,11 @@ namespace HeavenStudio.Games.Scripts_SpaceSoccer
}
public void Init(Kicker kicker, double dispensedBeat)
{
Conductor conductor = Conductor.instance;
this.kicker = kicker;
kicker.ball = this;
kicker.dispenserBeat = dispensedBeat;
double currentBeat = Conductor.instance.songPositionInBeatsAsDouble;
double currentBeat = conductor.unswungSongPositionInBeatsAsDouble;
kickPath = SpaceSoccer.instance.GetPath("Kick");
dispensePath = SpaceSoccer.instance.GetPath("Dispense");
highKickPath = SpaceSoccer.instance.GetPath("HighKick");
@ -53,7 +54,7 @@ namespace HeavenStudio.Games.Scripts_SpaceSoccer
{
//Debug.Log("Dispensing");
state = State.Dispensing;
startBeat = dispensedBeat;
startBeat = conductor.GetUnSwungBeat(dispensedBeat);
nextAnimBeat = startBeat + GetAnimLength(State.Dispensing);
kicker.kickTimes = 0;
return;
@ -74,31 +75,32 @@ namespace HeavenStudio.Games.Scripts_SpaceSoccer
//Debug.Log("Setting state to kicked");
state = State.Kicked;
double relativeBeat = currentBeat - dispensedBeat;
startBeat = dispensedBeat + (int)(relativeBeat - 0.1); //this makes the startBeat be for the kick that is currently in progress, but it won't play the kicker's animation for that kick. the -0.1 makes it so that if playback is started right when the kicker kicks, it still plays the kicker's animation.
startBeat = conductor.GetUnSwungBeat(dispensedBeat) + (int)(relativeBeat - 0.1); //this makes the startBeat be for the kick that is currently in progress, but it won't play the kicker's animation for that kick. the -0.1 makes it so that if playback is started right when the kicker kicks, it still plays the kicker's animation.
nextAnimBeat = startBeat + GetAnimLength(State.Kicked);
kicker.kickTimes = (int)(relativeBeat - 0.1) - numHighKicks - 1; //every high kick has 2 kicks in the same time a regular keep-up does 3 kicks.
break;
}
else
{
highKickSwing = 0.5f;
if (highKicks[i].beat + GetAnimLength(State.HighKicked) > currentBeat)
{
highKickSwing = conductor.GetSwingRatioAtBeat(highKicks[i].beat, out _);
//Debug.Log("Setting state to high kick");
state = State.HighKicked;
double relativeBeat = highKicks[i].beat - dispensedBeat;
startBeat = dispensedBeat + Math.Ceiling(relativeBeat); //there is a chance this makes startBeat later than the current beat, but it shouldn't matter too much. It would only happen if the user places the high kicks incorrectly.
startBeat = conductor.GetUnSwungBeat(dispensedBeat) + Math.Ceiling(relativeBeat); //there is a chance this makes startBeat later than the current beat, but it shouldn't matter too much. It would only happen if the user places the high kicks incorrectly.
nextAnimBeat = startBeat + GetAnimLength(State.HighKicked);
kicker.kickTimes = (int)Math.Ceiling(relativeBeat) - numHighKicks - 1;
break;
}
else
{
highKickSwing = conductor.GetSwingRatioAtBeat(highKicks[i].beat + GetAnimLength(State.HighKicked), out _);
//Debug.Log("Setting state to toe");
state = State.Toe;
double relativeBeat = Math.Ceiling(highKicks[i].beat - dispensedBeat) + GetAnimLength(State.HighKicked); //there is a chance this makes startBeat later than the current beat, but it shouldn't matter too much. It would only happen if the user places the high kicks incorrectly.
startBeat = dispensedBeat + relativeBeat;
startBeat = conductor.GetUnSwungBeat(dispensedBeat) + relativeBeat;
nextAnimBeat = startBeat + GetAnimLength(State.Toe);
kicker.kickTimes = (int)(relativeBeat - GetAnimLength(State.HighKicked)) - numHighKicks;
break;
@ -110,7 +112,7 @@ namespace HeavenStudio.Games.Scripts_SpaceSoccer
//Debug.Log("Defaulting to kicked state");
state = State.Kicked;
double relativeBeat = currentBeat - dispensedBeat;
startBeat = dispensedBeat + (int)(relativeBeat - 0.1); //this makes the startBeat be for the kick that is currently in progress, but it won't play the kicker's animation for that kick. the -0.1 makes it so that if playback is started right when the kicker kicks, it still plays the kicker's animation.
startBeat = conductor.GetUnSwungBeat(dispensedBeat) + (int)(relativeBeat - 0.1); //this makes the startBeat be for the kick that is currently in progress, but it won't play the kicker's animation for that kick. the -0.1 makes it so that if playback is started right when the kicker kicks, it still plays the kicker's animation.
nextAnimBeat = startBeat + GetAnimLength(State.Kicked);
kicker.kickTimes = (int)(relativeBeat - 0.1) - numHighKicks - 1;
}
@ -178,7 +180,7 @@ namespace HeavenStudio.Games.Scripts_SpaceSoccer
private void Update()
{
double beat = Conductor.instance.songPositionInBeatsAsDouble;
double beat = Conductor.instance.unswungSongPositionInBeatsAsDouble;
switch (state) //handle animations
{
case State.None: //the only time any ball should ever have this state is if it's the unused offscreen ball (which is the only reason this state exists)
@ -270,7 +272,7 @@ namespace HeavenStudio.Games.Scripts_SpaceSoccer
case State.Kicked:
return 1f;
case State.HighKicked:
return 2f - highKickSwing;
return 1f + highKickSwing;
case State.Toe:
return 2f - (1f - highKickSwing);
default:

View file

@ -20,7 +20,7 @@ namespace HeavenStudio.Games.Scripts_WizardsWaltz
void Update()
{
songPos = (float)(Conductor.instance.songPositionInBeatsAsDouble - game.wizardBeatOffset);
songPos = (float)(Conductor.instance.unswungSongPositionInBeatsAsDouble - game.wizardBeatOffset);
var am = game.beatInterval / 2f;
var x = Mathf.Sin(Mathf.PI * songPos / am) * game.xRange;
var y = Mathf.Cos(Mathf.PI * songPos / am) * game.yRange;

View file

@ -223,7 +223,7 @@ namespace HeavenStudio.Games
intervalStartBeat = beat;
foreach (var plant in currentPlants)
{
var songPos = (float)(plant.createBeat - wizardBeatOffset);
var songPos = (float)(conductor.GetUnSwungBeat(plant.createBeat) - wizardBeatOffset);
var am = (beatInterval / 2f);
var x = Mathf.Sin(Mathf.PI * songPos / am) * xRange;
var y = plantYOffset + Mathf.Cos(Mathf.PI * songPos / am) * (yRange * 1.5f);
@ -260,7 +260,7 @@ namespace HeavenStudio.Games
if (!spawnedInactive) SoundByte.PlayOneShotGame("wizardsWaltz/plant", beat);
Plant plant = Instantiate(plantBase, plantHolder.transform).GetComponent<Plant>();
currentPlants.Add(plant);
var songPos = (float)(beat - wizardBeatOffset);
var songPos = (float)(conductor.GetUnSwungBeat(beat) - wizardBeatOffset);
var am = (beatInterval / 2f);
var x = Mathf.Sin(Mathf.PI * songPos / am) * xRange;
var y = plantYOffset + Mathf.Cos(Mathf.PI * songPos / am) * (yRange * 1.5f);

View file

@ -1,7 +1,4 @@
using System;
using System.Linq;
using System.Reflection;
using System.Collections.Generic;
using HeavenStudio.InputSystem;

View file

@ -15,6 +15,7 @@ using HeavenStudio.StudioDance;
using Jukebox;
using UnityEditor;
using System.Linq;
using BurstLinq;
namespace HeavenStudio.Editor
{
@ -269,6 +270,11 @@ namespace HeavenStudio.Editor
public void SelectMusic()
{
if (Timeline.instance != null)
Timeline.instance?.Stop(0);
else
GameManager.instance.Stop(0);
var extensions = new[]
{
new ExtensionFilter("Music Files", "mp3", "ogg", "wav", "aiff", "aif", "aifc")

View file

@ -160,6 +160,7 @@ namespace HeavenStudio.Editor.Track
lastTempo /= 2f;
}
RiqEntity tempoC = GameManager.instance.Beatmap.AddNewTempoChange(Timeline.instance.MousePos2BeatSnap, lastTempo);
tempoC.CreateProperty("swingDivision", 1f);
tempoTimelineObj.chartEntity = tempoC;
CommandManager.Instance.AddCommand(new Commands.AddMarker(tempoC, tempoC.guid, HoveringTypes.TempoChange));
}

View file

@ -14,6 +14,9 @@ public class TempoDialog : Dialog
[SerializeField] Button deleteButton;
[SerializeField] TMP_InputField tempoInput;
[SerializeField] TMP_InputField swingInput;
[SerializeField] Slider swingSlider;
[SerializeField] Toggle swingDivisionToggle;
public void SwitchTempoDialog()
{
@ -28,6 +31,9 @@ public class TempoDialog : Dialog
Editor.instance.inAuthorativeMenu = true;
ResetAllDialogs();
dialog.SetActive(true);
swingSlider.maxValue = 0.25f;
swingSlider.minValue = 0;
}
}
@ -45,6 +51,10 @@ public class TempoDialog : Dialog
deleteButton.gameObject.SetActive(!tempoObj.first);
tempoInput.text = tempoObj.chartEntity["tempo"].ToString("F");
swingInput.text = (tempoObj.chartEntity["swing"] * 400).ToString("F");
swingSlider.value = tempoObj.chartEntity["swing"];
swingDivisionToggle.isOn = tempoObj.chartEntity["swingDivision"] != 1f;
}
public void DeleteTempo()
@ -86,4 +96,33 @@ public class TempoDialog : Dialog
tempoInput.text = tempoObj.chartEntity["tempo"].ToString("F");
}
}
public void SwingSliderUpdate()
{
if (tempoObj != null)
{
tempoObj.SetSwing(System.MathF.Round(swingSlider.value, 4));
swingInput.text = (tempoObj.chartEntity["swing"] * 400).ToString("F");
swingSlider.value = tempoObj.chartEntity["swing"];
}
}
public void SetSwing()
{
if (tempoObj != null)
{
float swing = float.Parse(swingInput.text);
tempoObj.SetSwing(swing * 0.25f / 100f);
swingInput.text = (tempoObj.chartEntity["swing"] * 400).ToString("F");
swingSlider.value = tempoObj.chartEntity["swing"];
}
}
public void SwingDivisionToggle()
{
if (tempoObj != null)
{
tempoObj.SetSwingDivision(swingDivisionToggle.isOn);
}
}
}

View file

@ -62,6 +62,18 @@ namespace HeavenStudio.Editor.Track
SetX(chartEntity);
}
public void SetSwing(float swing)
{
chartEntity["swing"] = Mathf.Clamp(swing, 0, 0.5f);
UpdateTempo();
}
public void SetSwingDivision(bool sixteenth)
{
chartEntity["swingDivision"] = sixteenth ? 0.5f : 1f;
UpdateTempo();
}
public override void Init()
{
UpdateTempo();

View file

@ -9,6 +9,7 @@ using TMPro;
using Jukebox;
using Newtonsoft.Json;
using System.Linq;
using BurstLinq;
using HeavenStudio.Util;
@ -475,7 +476,7 @@ namespace HeavenStudio.Editor.Track
if (Conductor.instance.metronome)
{
var startBeat = Mathf.FloorToInt(Conductor.instance.songPositionInBeats - 0.5f);
var nm = Conductor.instance.GetLoopPositionFromBeat(0.5f, 1f);
var nm = Conductor.instance.GetLoopPositionFromBeat(0.5f, 1f, ignoreSwing: false);
var loop = (startBeat % 2 == 0) ? Mathf.SmoothStep(-1.1f, 1f, nm) : Mathf.SmoothStep(1f, -1f, nm);
rot = loop * 45f;
@ -630,7 +631,7 @@ namespace HeavenStudio.Editor.Track
{
TimelinePlaybackBeat.text = $"Beat {string.Format("{0:0.000}", PlaybackBeat)}";
if (TimelineSongPosLine != null)
if (TimelineSongPosLine != null && !Conductor.instance.WaitingForDsp)
{
TimelineSongPosLine.transform.localPosition = new Vector3(Conductor.instance.songPositionInBeats * PixelsPerBeat, TimelineSongPosLine.transform.localPosition.y);
}
@ -655,13 +656,13 @@ namespace HeavenStudio.Editor.Track
{
if (!Conductor.instance.isPlaying)
{
if (TimelineSongPosLine == null)
if (Conductor.instance.isPaused)
{
Play(false, PlaybackBeat);
Play(false, Conductor.instance.songPositionInBeats);
}
else
{
Play(false, Conductor.instance.songPositionInBeats);
Play(false, PlaybackBeat);
}
}
else if (!Conductor.instance.isPaused)
@ -673,16 +674,14 @@ namespace HeavenStudio.Editor.Track
public void Play(bool fromStart, float time)
{
// if (fromStart) Stop();
GameManager.instance.SafePlay(time, 0, false);
if (!Conductor.instance.isPaused)
{
TimelineSongPosLine = Instantiate(TimelineSongPosLineRef, TimelineSongPosLineRef.parent).GetComponent<RectTransform>();
TimelineSongPosLine.gameObject.SetActive(true);
TimelineSongPosLine.transform.localPosition = new Vector3(time * PixelsPerBeat, TimelineSongPosLine.transform.localPosition.y);
}
GameManager.instance.SafePlay(time, 0, false);
SetTimeButtonColors(false, true, true);
}

View file

@ -5,6 +5,7 @@ using UnityEngine.Pool;
using Jukebox;
using System.Linq;
using BurstLinq;
namespace HeavenStudio.Editor.Track
{

View file

@ -16,6 +16,7 @@ using SatorImaging.UnitySourceGenerator;
using System;
using System.IO;
using System.Linq;
using BurstLinq;
using UnityEngine.Assertions.Must;
using Newtonsoft.Json.Linq;
@ -98,6 +99,7 @@ namespace HeavenStudio
{
{"tempo", 120f},
{"swing", 0f},
{"swingDivision", 1f},
{"timeSignature", new Vector2(4, 4)},
};

View file

@ -8,6 +8,7 @@ using HeavenStudio.Common;
using HeavenStudio.InputSystem;
using System.Linq;
using BurstLinq;
using SFB;
using Jukebox;

View file

@ -34,10 +34,10 @@ namespace HeavenStudio.Util
/// <param name="length">duration of animation (progress 1.0)</param>
/// <param name="timeScale">multiplier for animation progress (smaller values make animation slower)</param>
/// <param name="animLayer">animator layer to play animation on</param>
public static void DoScaledAnimation(this Animator anim, string animName, double startTime, double length = 1, float timeScale = 1f, int animLayer = -1, bool clamp = false)
public static void DoScaledAnimation(this Animator anim, string animName, double startTime, double length = 1, float timeScale = 1f, int animLayer = -1, bool clamp = false, bool ignoreSwing = true)
{
if (anim == null) return;
float pos = Conductor.instance.GetPositionFromBeat(startTime, length) * timeScale;
float pos = Conductor.instance.GetPositionFromBeat(startTime, length, ignoreSwing: ignoreSwing) * timeScale;
if (clamp) pos = Mathf.Clamp01(pos);
anim.Play(animName, animLayer, pos);
anim.speed = 1f; //not 0 so these can still play their script events

View file

@ -106,5 +106,17 @@ namespace HeavenStudio.Util
}
Destroy(gameObject);
}
public void StopAll(bool destroy = false)
{
foreach (Util.Sound sound in playingSounds)
{
sound.Stop();
}
if (destroy)
{
Destroy(gameObject);
}
}
}
}

View file

@ -2,6 +2,7 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using BurstLinq;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using UnityEngine;

View file

@ -1,5 +1,6 @@
{
"dependencies": {
"com.annulusgames.burst-linq": "https://github.com/AnnulusGames/BurstLinq.git?path=/Assets/BurstLinq",
"com.coffee.softmask-for-ugui": "https://github.com/mob-sakai/SoftMaskForUGUI.git",
"com.cysharp.unitask": "https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask",
"com.nobi.roundedcorners": "https://github.com/kirevdokimov/Unity-UI-Rounded-Corners.git",
@ -9,7 +10,8 @@
"com.tayx.graphy": "https://github.com/Tayx94/graphy.git",
"com.unity.2d.sprite": "1.0.0",
"com.unity.assetbundlebrowser": "https://github.com/Unity-Technologies/AssetBundles-Browser.git",
"com.unity.collab-proxy": "2.0.1",
"com.unity.burst": "1.6.6",
"com.unity.collections": "1.2.4",
"com.unity.ide.rider": "3.0.18",
"com.unity.ide.visualstudio": "2.0.21",
"com.unity.nuget.newtonsoft-json": "3.0.2",

View file

@ -1,5 +1,12 @@
{
"dependencies": {
"com.annulusgames.burst-linq": {
"version": "https://github.com/AnnulusGames/BurstLinq.git?path=/Assets/BurstLinq",
"depth": 0,
"source": "git",
"dependencies": {},
"hash": "fc354905c8e40b1491ea8a750ee722ee07adf484"
},
"com.coffee.softmask-for-ugui": {
"version": "https://github.com/mob-sakai/SoftMaskForUGUI.git",
"depth": 0,
@ -67,11 +74,23 @@
"dependencies": {},
"hash": "b7c279278d1a343c6957c9f15b45173d3211f01c"
},
"com.unity.collab-proxy": {
"version": "2.0.1",
"com.unity.burst": {
"version": "1.6.6",
"depth": 0,
"source": "registry",
"dependencies": {},
"dependencies": {
"com.unity.mathematics": "1.2.1"
},
"url": "https://packages.unity.com"
},
"com.unity.collections": {
"version": "1.2.4",
"depth": 0,
"source": "registry",
"dependencies": {
"com.unity.burst": "1.6.6",
"com.unity.test-framework": "1.1.31"
},
"url": "https://packages.unity.com"
},
"com.unity.ext.nunit": {
@ -99,6 +118,13 @@
},
"url": "https://packages.unity.com"
},
"com.unity.mathematics": {
"version": "1.2.6",
"depth": 1,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.nuget.newtonsoft-json": {
"version": "3.2.1",
"depth": 1,

View file

@ -0,0 +1,17 @@
{
"MonoBehaviour": {
"Version": 4,
"EnableBurstCompilation": true,
"EnableOptimisations": true,
"EnableSafetyChecks": false,
"EnableDebugInAllBuilds": false,
"UsePlatformSDKLinker": false,
"CpuMinTargetX32": 0,
"CpuMaxTargetX32": 0,
"CpuMinTargetX64": 0,
"CpuMaxTargetX64": 0,
"CpuTargetsX32": 6,
"CpuTargetsX64": 72,
"OptimizeFor": 0
}
}

View file

@ -0,0 +1,6 @@
{
"MonoBehaviour": {
"Version": 4,
"DisabledWarnings": ""
}
}

View file

@ -134,7 +134,7 @@ PlayerSettings:
16:10: 1
16:9: 1
Others: 1
bundleVersion: 1.0.2
bundleVersion: 1.0.10
preloadedAssets:
- {fileID: 102900000, guid: 5348c08b82446e0478cee8bda6c02cfc, type: 3}
metroInputSource: 0
@ -158,11 +158,11 @@ PlayerSettings:
applicationIdentifier:
Standalone: com.RHeavenStudio.Heaven-Studio
buildNumber:
Standalone: 100002
Standalone: 100010
iPhone: 0
tvOS: 0
overrideDefaultApplicationIdentifier: 0
AndroidBundleVersionCode: 100002
AndroidBundleVersionCode: 100010
AndroidMinSdkVersion: 22
AndroidTargetSdkVersion: 0
AndroidPreferredInstallLocation: 1
@ -689,7 +689,11 @@ PlayerSettings:
Windows Store Apps: UNITY_POST_PROCESSING_STACK_V2
XboxOne: UNITY_POST_PROCESSING_STACK_V2
tvOS: UNITY_POST_PROCESSING_STACK_V2
additionalCompilerArguments: {}
additionalCompilerArguments:
Standalone:
- /nowarn:0168
- /nowarn:0219
- /nowarn:0414
platformArchitecture: {}
scriptingBackend: {}
il2cppCompilerConfiguration: {}

View file

@ -17,6 +17,30 @@ MonoBehaviour:
DenseViewWidthThreshold: 512
_disableAutoReloadInBackground: 0
ImportedScriptPaths:
- Assets/Scripts/Games/Tunnel/Tunnel.cs
- Assets/Scripts/Games/GleeClub/GleeClub.cs
- Assets/Scripts/Minigames.cs
- Assets/Scripts/LevelEditor/Editor.cs
- Assets/Scripts/Games/FreezeFrame/Car.cs
- Assets/Scripts/Games/Fillbots/Fillbots.cs
- Assets/Scripts/Games/Fillbots/FullBody.cs
- Assets/Scripts/Games/CatchOfTheDay/CatchOfTheDay.cs
- Assets/Scripts/Util/ParticleSystemHelpers.cs
- Assets/Scripts/Games/Fillbots/NtrFillbot.cs
- Assets/Scripts/USG.g/LoadMinigames.Minigames.MinigameLoaderGenerator.g.cs
- Assets/Scripts/Games/FreezeFrame/FreezeFrame.cs
- Assets/Scripts/Games/CatchOfTheDay/LakeScene.cs
- Assets/Scripts/Conductor.cs
- Assets/Scripts/GameManager.cs
- Assets/Scripts/LevelEditor/Timeline/TimelineBlockManager.cs
- Assets/Scripts/TitleManager.cs
- Assets/Scripts/Util/MultiSound.cs
- Assets/Scripts/LevelEditor/Timeline/Timeline.cs
- Assets/Scripts/EventCaller.cs
- Assets/Scripts/Games/Minigame.cs
- Assets/Scripts/InputSystem/PlayerInput.cs
- Assets/Scripts/GameCamera.cs
- Assets/Scripts/Util/SoundByte.cs
- Assets/Scripts/GameInitializer.cs
- Assets/Scripts/AppInfo.cs
PathsToSkipImportEvent: []
PathsToIgnoreOverwriteSettingOnAttribute: []