diff --git a/Assets/Art/Fonts/CreditSprites.asset b/Assets/Art/Fonts/CreditSprites.asset new file mode 100644 index 000000000..975168b2b --- /dev/null +++ b/Assets/Art/Fonts/CreditSprites.asset @@ -0,0 +1,171 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 84a92b25f83d49b9bc132d206b370281, type: 3} + m_Name: CreditSprites + m_EditorClassIdentifier: + hashCode: 1227223863 + material: {fileID: 6669119319299450675} + materialHashCode: 0 + m_Version: 1.1.0 + m_FaceInfo: + m_FaceIndex: 0 + m_FamilyName: + m_StyleName: + m_PointSize: 0 + m_Scale: 0 + m_UnitsPerEM: 0 + m_LineHeight: 0 + m_AscentLine: 0 + m_CapLine: 0 + m_MeanLine: 0 + m_Baseline: 0 + m_DescentLine: 0 + m_SuperscriptOffset: 0 + m_SuperscriptSize: 0 + m_SubscriptOffset: 0 + m_SubscriptSize: 0 + m_UnderlineOffset: 0 + m_UnderlineThickness: 0 + m_StrikethroughOffset: 0 + m_StrikethroughThickness: 0 + m_TabWidth: 0 + spriteSheet: {fileID: 2800000, guid: 9a7443e591e54de4cb9bc5796a8ab687, type: 3} + m_SpriteCharacterTable: + - m_ElementType: 2 + m_Unicode: 65534 + m_GlyphIndex: 0 + m_Scale: 0.9 + m_Name: developer + m_HashCode: -1500130122 + - m_ElementType: 2 + m_Unicode: 65534 + m_GlyphIndex: 1 + m_Scale: 0.9 + m_Name: artist + m_HashCode: -365106807 + - m_ElementType: 2 + m_Unicode: 65534 + m_GlyphIndex: 2 + m_Scale: 0.9 + m_Name: charter + m_HashCode: -1818670821 + - m_ElementType: 2 + m_Unicode: 65534 + m_GlyphIndex: 3 + m_Scale: 0.9 + m_Name: supporter + m_HashCode: 1202887288 + m_SpriteGlyphTable: + - m_Index: 0 + m_Metrics: + m_Width: 128 + m_Height: 128 + m_HorizontalBearingX: 25 + m_HorizontalBearingY: 114 + m_HorizontalAdvance: 150 + m_GlyphRect: + m_X: 0 + m_Y: 128 + m_Width: 128 + m_Height: 128 + m_Scale: 1 + m_AtlasIndex: 0 + m_ClassDefinitionType: 0 + sprite: {fileID: 248047085, guid: 9a7443e591e54de4cb9bc5796a8ab687, type: 3} + - m_Index: 1 + m_Metrics: + m_Width: 128 + m_Height: 128 + m_HorizontalBearingX: 25 + m_HorizontalBearingY: 114 + m_HorizontalAdvance: 150 + m_GlyphRect: + m_X: 128 + m_Y: 128 + m_Width: 128 + m_Height: 128 + m_Scale: 1 + m_AtlasIndex: 0 + m_ClassDefinitionType: 0 + sprite: {fileID: 73802287, guid: 9a7443e591e54de4cb9bc5796a8ab687, type: 3} + - m_Index: 2 + m_Metrics: + m_Width: 128 + m_Height: 128 + m_HorizontalBearingX: 25 + m_HorizontalBearingY: 114 + m_HorizontalAdvance: 150 + m_GlyphRect: + m_X: 0 + m_Y: 0 + m_Width: 128 + m_Height: 128 + m_Scale: 1 + m_AtlasIndex: 0 + m_ClassDefinitionType: 0 + sprite: {fileID: 761286160, guid: 9a7443e591e54de4cb9bc5796a8ab687, type: 3} + - m_Index: 3 + m_Metrics: + m_Width: 128 + m_Height: 128 + m_HorizontalBearingX: 25 + m_HorizontalBearingY: 114 + m_HorizontalAdvance: 150 + m_GlyphRect: + m_X: 128 + m_Y: 0 + m_Width: 128 + m_Height: 128 + m_Scale: 1 + m_AtlasIndex: 0 + m_ClassDefinitionType: 0 + sprite: {fileID: 676381074, guid: 9a7443e591e54de4cb9bc5796a8ab687, type: 3} + spriteInfoList: [] + fallbackSpriteAssets: [] +--- !u!21 &6669119319299450675 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: TextMeshPro/Sprite + m_Shader: {fileID: 4800000, guid: cf81c85f95fe47e1a27f6ae460cf182c, type: 3} + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _MainTex: + m_Texture: {fileID: 2800000, guid: 9a7443e591e54de4cb9bc5796a8ab687, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _ColorMask: 15 + - _CullMode: 0 + - _Stencil: 0 + - _StencilComp: 8 + - _StencilOp: 0 + - _StencilReadMask: 255 + - _StencilWriteMask: 255 + - _UseUIAlphaClip: 0 + m_Colors: + - _ClipRect: {r: -32767, g: -32767, b: 32767, a: 32767} + - _Color: {r: 1, g: 1, b: 1, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Art/Fonts/CreditSprites.asset.meta b/Assets/Art/Fonts/CreditSprites.asset.meta new file mode 100644 index 000000000..bb74413f5 --- /dev/null +++ b/Assets/Art/Fonts/CreditSprites.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b39a751af0d49d04abbce647601a4aa3 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Art/UI/CreditSprites.png b/Assets/Art/UI/CreditSprites.png new file mode 100644 index 000000000..93395b1d6 --- /dev/null +++ b/Assets/Art/UI/CreditSprites.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:13a9ef3ec9ac6e7995127a2a9755f8b5feff5084b47ef7a986466a3600a507be +size 68759 diff --git a/Assets/Art/UI/CreditSprites.png.meta b/Assets/Art/UI/CreditSprites.png.meta new file mode 100644 index 000000000..86da15415 --- /dev/null +++ b/Assets/Art/UI/CreditSprites.png.meta @@ -0,0 +1,211 @@ +fileFormatVersion: 2 +guid: 9a7443e591e54de4cb9bc5796a8ab687 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 2 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 2 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: developer + rect: + serializedVersion: 2 + x: 0 + y: 128 + width: 128 + height: 128 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + outline: [] + physicsShape: [] + tessellationDetail: 0 + bones: [] + spriteID: 5c1ed72259c057c498f3552944d735df + internalID: 248047085 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: artist + rect: + serializedVersion: 2 + x: 128 + y: 128 + width: 128 + height: 128 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + outline: [] + physicsShape: [] + tessellationDetail: 0 + bones: [] + spriteID: 36ed3adc56224a44f8da3b2cedfeec76 + internalID: 73802287 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: charter + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 128 + height: 128 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + outline: [] + physicsShape: [] + tessellationDetail: 0 + bones: [] + spriteID: 7302c3cb575b77844904a9d4a1a3fef1 + internalID: 761286160 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: supporter + rect: + serializedVersion: 2 + x: 128 + y: 0 + width: 128 + height: 128 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + outline: [] + physicsShape: [] + tessellationDetail: 0 + bones: [] + spriteID: 5b8d064cc36b97542a0d8be9d980ef56 + internalID: 676381074 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: + artist: 73802287 + charter: 761286160 + developer: 248047085 + supporter: 676381074 + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Credits.json b/Assets/Credits.json index eb970345f..9b711f9b0 100644 --- a/Assets/Credits.json +++ b/Assets/Credits.json @@ -1,7 +1,7 @@ { "gameStartedBy": { "EliteAsian": { - "roles": [ "developer", "artist" ], + "roles": [ "developer", "artist", "charter" ], "twitter": "EliteAsian123", "twitch": "eliteasian123", "github": "EliteAsian123", @@ -17,17 +17,24 @@ "twitch": "kaduwaengertner", "github": "kaduwaengertner", "videoService": "@kaduwaengertner", - "discord": "Kadu#7712", + "discord": "kadu", "website": "https://kadu.live" } }, "leadCharter": { "Synthesize": { - "roles": [ "charter" ] + "roles": [ "charter" ], + "twitter": "SynthesizeTime", + "twitch": "synthesizetime", + "github": "SynthesizeTime", + "videoService": "UCDGGCLLZxSXrYQtDGFy0BiQ", + "discord": "Synthesize#2853", + "email": "aaronhubbard081503@outlook.com" } }, "contributors": { "The Fat Bastid": { + "roles": [ "developer" ], "github": "TheFatBastid", "videoService": "UCCmx6jiTO-353X8KNaOgb3Q", "discord": "The Fat Bastid#7712", diff --git a/Assets/Scenes/MenuScene.unity b/Assets/Scenes/MenuScene.unity index b6600e315..d348b4b59 100644 --- a/Assets/Scenes/MenuScene.unity +++ b/Assets/Scenes/MenuScene.unity @@ -11523,7 +11523,7 @@ MonoBehaviour: bottomLeft: {r: 1, g: 1, b: 1, a: 1} bottomRight: {r: 1, g: 1, b: 1, a: 1} m_fontColorGradientPreset: {fileID: 0} - m_spriteAsset: {fileID: 0} + m_spriteAsset: {fileID: 11400000, guid: b39a751af0d49d04abbce647601a4aa3, type: 2} m_tintAllSprites: 0 m_StyleSheet: {fileID: 0} m_TextStyleHashCode: -1183493901 diff --git a/Assets/Scenes/PersistantScene.unity b/Assets/Scenes/PersistantScene.unity index f1fb8c500..1ba8e4e18 100644 --- a/Assets/Scenes/PersistantScene.unity +++ b/Assets/Scenes/PersistantScene.unity @@ -2269,9 +2269,21 @@ MonoBehaviour: m_EditorClassIdentifier: songStartObject: {fileID: 0} applicationID: 1091177744416637028 - defaultDetails: Hello there ladies and gentlemen! - defaultState: Are you ready to rock? - defaultLargeText: Yet Another Rhythm Game + stableDetails: + defaultDetails: Hello there ladies and gentlemen! + defaultState: Are you ready to rock? + defaultLargeImage: icon_stable + defaultLargeText: Yet Another Rhythm Game + nightlyDetails: + defaultDetails: Hello there ladies and gentlemen! + defaultState: Are you ready to test? + defaultLargeImage: icon_nightly + defaultLargeText: Yet Another Rhythm Game - Nightly Build + devDetails: + defaultDetails: Hello there ladies and gentlemen! + defaultState: Are you ready to develop? + defaultLargeImage: icon_dev + defaultLargeText: Yet Another Rhythm Game - Developer Build defaultSmallImage: defaultSmallText: currentDetails: diff --git a/Assets/Script/Audio/Bass/BassAudioManager.cs b/Assets/Script/Audio/Bass/BassAudioManager.cs index 1cc3d2727..fa8b62bc3 100644 --- a/Assets/Script/Audio/Bass/BassAudioManager.cs +++ b/Assets/Script/Audio/Bass/BassAudioManager.cs @@ -122,7 +122,10 @@ public IList GetAllInputDevices() { continue; } - if (info.Type != DeviceType.Microphone) { + // We do not check the device type since there are too many that a recording device can be, + // instead we only exclude loopback devices + // The "Default" device is also excluded here since we want the user to explicitly pick which microphone to use + if (info.IsLoopback || info.Name == "Default") { continue; } diff --git a/Assets/Script/Audio/Bass/BassMicDevice.cs b/Assets/Script/Audio/Bass/BassMicDevice.cs index a34bc5b5d..a60ff44ca 100644 --- a/Assets/Script/Audio/Bass/BassMicDevice.cs +++ b/Assets/Script/Audio/Bass/BassMicDevice.cs @@ -129,6 +129,11 @@ public void SetMonitoringLevel(float volume) { } private bool ProcessCleanRecordData(int handle, IntPtr buffer, int length, IntPtr user) { + // Wait for initialization to complete before processing data + if (!_initialized) { + return true; + } + // Copies the data from the recording buffer to the monitor playback buffer. if (IsMonitoring) { Bass.StreamPutData(_monitorPlaybackHandle, buffer, length); @@ -138,6 +143,11 @@ private bool ProcessCleanRecordData(int handle, IntPtr buffer, int length, IntPt } private bool ProcessRecordData(int handle, IntPtr buffer, int length, IntPtr user) { + // Wait for initialization to complete before processing data + if (!_initialized) { + return true; + } + CalculatePitchAndAmplitude(buffer, length); return true; } diff --git a/Assets/Script/Constants.cs b/Assets/Script/Constants.cs index f4f9f80ab..c71d84f30 100644 --- a/Assets/Script/Constants.cs +++ b/Assets/Script/Constants.cs @@ -2,7 +2,7 @@ namespace YARG { public static class Constants { - public static readonly YargVersion VERSION_TAG = YargVersion.Parse("v0.10.5"); + public static readonly YargVersion VERSION_TAG = YargVersion.Parse("v0.10.6"); // General public const float HIT_MARGIN_FRONT = 0.095f; diff --git a/Assets/Script/Input/DrumsInputStrategy.cs b/Assets/Script/Input/DrumsInputStrategy.cs index f01a64718..d10cf2f6c 100644 --- a/Assets/Script/Input/DrumsInputStrategy.cs +++ b/Assets/Script/Input/DrumsInputStrategy.cs @@ -136,13 +136,13 @@ protected override void UpdateNavigationMode() { NavigationEventForMapping(MenuAction.Shortcut1, YELLOW_CYMBAL); NavigationEventForMapping(MenuAction.Shortcut2, BLUE_CYMBAL); - NavigationEventForMapping(MenuAction.Shortcut3, GREEN_CYMBAL); + NavigationEventForMapping(MenuAction.More, GREEN_CYMBAL); NavigationEventForMapping(MenuAction.Up, YELLOW_PAD); NavigationEventForMapping(MenuAction.Down, BLUE_PAD); - NavigationEventForMapping(MenuAction.More, KICK); - NavigationEventForMapping(MenuAction.More, KICK_ALT); + NavigationHoldableForMapping(MenuAction.Shortcut3, KICK); + NavigationHoldableForMapping(MenuAction.Shortcut3, KICK_ALT); if (WasMappingPressed(PAUSE)) { CallPauseEvent(); @@ -160,4 +160,4 @@ public override string GetTrackPath() { return "Tracks/Drums"; } } -} \ No newline at end of file +} diff --git a/Assets/Script/PlayMode/AbstractTrack.cs b/Assets/Script/PlayMode/AbstractTrack.cs index 75c88e2e2..8bbd06810 100644 --- a/Assets/Script/PlayMode/AbstractTrack.cs +++ b/Assets/Script/PlayMode/AbstractTrack.cs @@ -47,6 +47,9 @@ public abstract class AbstractTrack : MonoBehaviour { protected int visualChartIndex = 0; protected int inputChartIndex = 0; protected int hitChartIndex = 0; + public NoteInfo CurrentNote => + hitChartIndex < Chart.Count ? Chart[hitChartIndex] : null; + protected int currentBeatIndex = 0; protected CommonTrack commonTrack; @@ -80,7 +83,7 @@ public abstract class AbstractTrack : MonoBehaviour { protected Light comboSunburstEmbeddedLight; // Solo stuff - private bool soloInProgress = false; + protected bool soloInProgress = false; protected int soloNoteCount = -1; protected int soloNotesHit = 0; private int soloHitPercent = 0; @@ -119,7 +122,7 @@ protected int Combo { } // End starpower if combo ends - if (CurrentStarpower?.time <= CurrentTime && value == 0) { + if (value == 0 && CurrentStarpower?.time <= HitMarginStartTime && CurrentNote?.time >= CurrentStarpower?.time) { StarpowerMissEvent?.Invoke(CurrentStarpower); // Only move to the next visual phrase if it is also the current logical phrase if (starpowerVisualIndex == starpowerIndex) { @@ -712,11 +715,7 @@ protected float CalcLagCompensation(float currentTime, float noteTime) { } protected bool IsStarpowerHit() { - if (Chart.Count > hitChartIndex) { - return Chart[hitChartIndex].time >= CurrentStarpower?.EndTime; - } - - return false; + return CurrentNote?.time >= CurrentStarpower?.EndTime; } public abstract void SetReverb(bool on); diff --git a/Assets/Script/PlayMode/DrumsTrack.cs b/Assets/Script/PlayMode/DrumsTrack.cs index acbd41d1f..b80d10ca3 100644 --- a/Assets/Script/PlayMode/DrumsTrack.cs +++ b/Assets/Script/PlayMode/DrumsTrack.cs @@ -296,13 +296,14 @@ private void DrumHitAction(int drum, bool cymbal) { drums[drum].Pulse(); } else { PlayKickFretAnimation(); - - if (shakeOnKick) { - //commonTrack.PlayKickCameraAnimation(); - trackAnims.PlayKickShakeCameraAnim(); + // Only play kick flash/shake now when outside of the chart, + // otherwise only play it when actually hitting a kick + if (Chart.Count < 1 || CurrentTime < Chart[0].time || CurrentTime >= Chart[^1].time) { + commonTrack.kickFlash.PlayAnimation(); + if (shakeOnKick) { + trackAnims.PlayKickShakeCameraAnim(); + } } - - commonTrack.kickFlash.PlayAnimation(); } // Overstrum if no expected @@ -329,6 +330,13 @@ private void DrumHitAction(int drum, bool cymbal) { if (note.isActivator) { (input as DrumsInputStrategy).ActivateStarpower(); } + // Play kick flash/shake + if (note.fret == kickIndex) { + commonTrack.kickFlash.PlayAnimation(); + if (shakeOnKick) { + trackAnims.PlayKickShakeCameraAnim(); + } + } break; } } diff --git a/Assets/Script/PlayMode/FiveFretTrack.cs b/Assets/Script/PlayMode/FiveFretTrack.cs index 830260987..1e7e5e1f5 100644 --- a/Assets/Script/PlayMode/FiveFretTrack.cs +++ b/Assets/Script/PlayMode/FiveFretTrack.cs @@ -371,9 +371,10 @@ private void UpdateInput() { lastHitNote = chord; // Solo stuff - if (CurrentTime >= CurrentSolo?.time && CurrentTime <= CurrentSolo?.EndTime) { + if (soloInProgress) { soloNotesHit++; } + foreach (var hit in chord) { hitChartIndex++; // Hit notes diff --git a/Assets/Script/PlayMode/KickFlashAnimation.cs b/Assets/Script/PlayMode/KickFlashAnimation.cs index 42fe84fec..c1adbf021 100644 --- a/Assets/Script/PlayMode/KickFlashAnimation.cs +++ b/Assets/Script/PlayMode/KickFlashAnimation.cs @@ -23,16 +23,11 @@ private void UpdateTexture() { } private void Update() { - if (_currentSprite >= _textures.Length) { - return; - } - - if (_updateTimer > SecondsPerFrame) { - _updateTimer = 0f; + _updateTimer += Time.deltaTime; + while (_updateTimer >= SecondsPerFrame && _currentSprite < _textures.Length) { + _updateTimer -= SecondsPerFrame; UpdateTexture(); _currentSprite++; - } else { - _updateTimer += Time.deltaTime; } } diff --git a/Assets/Script/PlayMode/MicPlayer.cs b/Assets/Script/PlayMode/MicPlayer.cs index 91050f63f..908c7c3ac 100644 --- a/Assets/Script/PlayMode/MicPlayer.cs +++ b/Assets/Script/PlayMode/MicPlayer.cs @@ -708,6 +708,7 @@ private void UpdateEndPhrase() { // Skip if there is no singing if (_sectionSingTime.Max() <= 0f) { + CalculateSectionSingTime(CurrentTime); return; } @@ -793,12 +794,12 @@ private void UpdateEndPhrase() { } // Clear out passed star power - while (CurrentStarpower?.EndTime < TrackStartTime) { + while (CurrentStarpower?.EndTime < CurrentTime) { _starpowerIndex++; } // Calculate the new sing time - CalculateSectionSingTime(Play.Instance.SongTime); + CalculateSectionSingTime(CurrentTime); } private void SpawnLyric(LyricInfo lyricInfo, EventInfo starpowerInfo, float time, int harmIndex) { diff --git a/Assets/Script/PlayMode/RealGuitarTrack.cs b/Assets/Script/PlayMode/RealGuitarTrack.cs index bed3f9f1a..624104fd9 100644 --- a/Assets/Script/PlayMode/RealGuitarTrack.cs +++ b/Assets/Script/PlayMode/RealGuitarTrack.cs @@ -172,10 +172,8 @@ private void UpdateInput() { scoreKeeper.Add(PTS_PER_NOTE * Multiplier); // Solo stuff - if (CurrentTime >= CurrentSolo?.time && CurrentTime <= CurrentSolo?.EndTime) { + if (soloInProgress) { soloNotesHit++; - } else if (CurrentTime >= CurrentSolo?.EndTime + 10) { - soloNotesHit = 0; } // Play particles diff --git a/Assets/Script/Serialization/Parser/LegacyVenueConverter.cs b/Assets/Script/Serialization/Parser/LegacyVenueConverter.cs deleted file mode 100644 index 1659a6694..000000000 --- a/Assets/Script/Serialization/Parser/LegacyVenueConverter.cs +++ /dev/null @@ -1,194 +0,0 @@ -using System; -using System.Collections.Generic; -using Melanchall.DryWetMidi.Core; -using Melanchall.DryWetMidi.Interaction; - -namespace YARG.Serialization.Parser { - public static class LegacyVenueConverter { - public static TrackChunk ConvertVenue(TrackChunk OldVenueTrack){ - var NewVenueEvents = new List(); - var OldVenueDict = new Dictionary>(); - var AllowedNoteOffNums = new HashSet { 37, 38, 39, 40, 85, 86, 87 }; - long time = 0; - - // first, parse the current RB2 style venue for all its relevant events - foreach(var trackEvent in OldVenueTrack.Events){ - time += trackEvent.DeltaTime; - - if(trackEvent is NoteOffEvent noteOffEvent){ - // ignore the NoteOffEvents that have pitches that are not 37-40 or 85-87 - if(!AllowedNoteOffNums.Contains(noteOffEvent.NoteNumber)) continue; - } - - if(OldVenueDict.TryGetValue(time, out var EventList)) EventList.Add(trackEvent); - else OldVenueDict.Add(time, new List(){ trackEvent }); - } - - // now that OldVenueDict has been populated, process these RB2 events and add them to NewVenueEvents - long time_prev = 0; - foreach(var oldEv in OldVenueDict){ - NewVenueEvents.AddRange(ProcessEventsAtTime(oldEv.Value, oldEv.Key - time_prev)); - time_prev = oldEv.Key; - } - // TODO: endoftrack event isn't appended - will this cause problems? - // if it turns out it DOES, append it to NewVenueEvents here - - return new TrackChunk(NewVenueEvents); - } - - private static List ProcessEventsAtTime(List list, long deltaTime) { - var new_list = new List(); - // 8 bits, from MSB to LSB: camera parameters found - // then, toggles for location behind, location near, location far - // finally, toggles for vocals, guitar, drums, bass - byte cameraInfo = 0x70; - foreach (var ev in list) { - if (new_list.Count > 0) deltaTime = 0; - switch (ev) { - case SequenceTrackNameEvent evName: new_list.Add(new SequenceTrackNameEvent() { Text = evName.Text, DeltaTime = deltaTime }); break; - case TextEvent textEv: - if (textEv.Text == "[verse]") new_list.Add(new TextEvent() { Text = "[lighting (verse)]", DeltaTime = deltaTime }); - else if (textEv.Text == "[chorus]") new_list.Add(new TextEvent() { Text = "[lighting (chorus)]", DeltaTime = deltaTime }); - else if (textEv.Text == "[lighting ()]") new_list.Add(new TextEvent() { Text = "[lighting (harmony)]", DeltaTime = deltaTime }); - else if (textEv.Text.Contains("do_directed_cut ")) { - string new_text = textEv.Text.Replace("do_directed_cut ", ""); - if (new_text == "[directed_vocals_cam]") new_text = "[directed_vocals_cam_pt]"; - if (new_text == "[directed_guitar_cam]") new_text = "[directed_guitar_cam_pt]"; - new_list.Add(new TextEvent() { Text = new_text, DeltaTime = deltaTime }); - } - else new_list.Add(new TextEvent() { Text = textEv.Text, DeltaTime = deltaTime }); - break; - case NoteOnEvent noteOnEv: - switch (noteOnEv.NoteNumber) { - case 37: case 38: case 39: case 40: case 85: case 86: case 87: - new_list.Add(new NoteOnEvent() { NoteNumber = noteOnEv.NoteNumber, Velocity = noteOnEv.Velocity, Channel = noteOnEv.Channel, DeltaTime = deltaTime }); - break; - case 48: new_list.Add(new TextEvent() { Text = "[next]", DeltaTime = deltaTime }); break; - case 49: new_list.Add(new TextEvent() { Text = "[prev]", DeltaTime = deltaTime }); break; - case 50: new_list.Add(new TextEvent() { Text = "[first]", DeltaTime = deltaTime }); break; - case 60: cameraInfo |= 0x80; break; // enable the "camera parameters found" bit - case 61: cameraInfo |= 0x81; break; // ditto, plus the "bass focus" bit - case 62: cameraInfo |= 0x82; break; // plus the "drums focus" bit - case 63: cameraInfo |= 0x84; break; // plus the "guitar focus" bit - case 64: cameraInfo |= 0x88; break; // plus the "vocals focus" bit - // then, toggles for location behind, location near, location far - case 70: cameraInfo = (byte)((cameraInfo | 0x80) & 0xBF); break; // zero out the 7th bit (behind = false) - case 71: cameraInfo = (byte)((cameraInfo | 0x80) & 0x9F); break; // zero out the 7th and 6th bits (behind = false, near = false) - case 72: cameraInfo = (byte)((cameraInfo | 0x80) & 0xAF); break; // zero out the 7th and 5th bits (behind = false, far = false) - case 73: cameraInfo = (byte)((cameraInfo | 0x80) & 0xDF); break; // zero out the 6th bit (near = false) - case 96: new_list.Add(new TextEvent() { Text = "[ProFilm_a.pp]", DeltaTime = deltaTime }); break; - case 97: new_list.Add(new TextEvent() { Text = "[contrast_a.pp]", DeltaTime = deltaTime }); break; - case 98: new_list.Add(new TextEvent() { Text = "[film_16mm.pp]", DeltaTime = deltaTime }); break; - case 99: new_list.Add(new TextEvent() { Text = "[film_sepia_ink.pp]", DeltaTime = deltaTime }); break; - case 100: new_list.Add(new TextEvent() { Text = "[film_silvertone.pp]", DeltaTime = deltaTime }); break; - case 101: new_list.Add(new TextEvent() { Text = "[photo_negative.pp]", DeltaTime = deltaTime }); break; - case 102: new_list.Add(new TextEvent() { Text = "[photocopy.pp]", DeltaTime = deltaTime }); break; - case 103: new_list.Add(new TextEvent() { Text = "[ProFilm_a.pp]", DeltaTime = deltaTime }); break; - case 104: new_list.Add(new TextEvent() { Text = "[ProFilm_b.pp]", DeltaTime = deltaTime }); break; - case 105: new_list.Add(new TextEvent() { Text = "[ProFilm_mirror_a.pp]", DeltaTime = deltaTime }); break; - case 106: new_list.Add(new TextEvent() { Text = "[film_blue_filter.pp]", DeltaTime = deltaTime }); break; - case 107: new_list.Add(new TextEvent() { Text = "[video_a.pp]", DeltaTime = deltaTime }); break; - case 108: new_list.Add(new TextEvent() { Text = "[video_bw.pp]", DeltaTime = deltaTime }); break; - case 109: new_list.Add(new TextEvent() { Text = "[video_security.pp]", DeltaTime = deltaTime }); break; - case 110: new_list.Add(new TextEvent() { Text = "[video_trails.pp]", DeltaTime = deltaTime }); break; - default: throw new Exception($"Invalid note pitch {noteOnEv.NoteNumber} found!"); - } - break; - case NoteOffEvent noteOffEv: - new_list.Add(new NoteOffEvent() { NoteNumber = noteOffEv.NoteNumber, Velocity = noteOffEv.Velocity, Channel = noteOffEv.Channel, DeltaTime = deltaTime }); - break; - default: throw new Exception($"Invalid MIDI event {ev} found!"); - } - } - - // this is the part where you add a camera cut text event based off the note_ons you found - List textsFromNotes = GetCameraCutFromNotes(cameraInfo); - foreach (var note in textsFromNotes) { - if (new_list.Count > 0) deltaTime = 0; - new_list.Add(new TextEvent() { Text = note, DeltaTime = deltaTime }); - } - - return new_list; - } - - private static List GetCameraCutFromNotes(byte notes) { - byte instruments = (byte)(notes & 0xF); // from MSB to LSB: vox, guitar, drums, bass - bool cameraParametersFound = (notes & 0x80) == 0x80; - bool behind = (notes & 0x40) == 0x40; - bool near = (notes & 0x20) == 0x20; - bool far = (notes & 0x10) == 0x10; - var newTextEvents = new List(); - - switch (instruments) { - case 0x0: // no focus on any particular instrument - make sure any other camera relevant notes were also called! - if (cameraParametersFound) { - if (behind) newTextEvents.Add("[coop_all_behind]"); - if (far) newTextEvents.Add("[coop_all_far]"); - if (near) newTextEvents.Add("[coop_all_near]"); - } - break; - case 0x1: // focus on the bass ONLY - if (behind) newTextEvents.Add("[coop_b_behind]"); - if (near || far) { - if (!behind && !far) newTextEvents.Add("[coop_b_closeup_hand]"); - else newTextEvents.Add("[coop_b_near]"); - } - break; - case 0x2: // focus on the drums ONLY - if (behind) newTextEvents.Add("[coop_d_behind]"); - if (near || far) { - if (!behind && !far) newTextEvents.Add("[coop_d_closeup_hand]"); - else newTextEvents.Add("[coop_d_near]"); - } - break; - case 0x3: // focus on bass AND drums - if (near || far) newTextEvents.Add("[coop_bd_near]"); - break; - case 0x4: // focus on the guitar ONLY - if (behind) newTextEvents.Add("[coop_g_behind]"); - if (near || far) { - if (!behind && !far) newTextEvents.Add("[coop_g_closeup_hand]"); - else newTextEvents.Add("[coop_g_near]"); - } - break; - case 0x5: // focus on bass AND guitar - if (behind) newTextEvents.Add("[coop_bg_behind]"); - if (near || far) newTextEvents.Add("[coop_bg_near]"); - break; - case 0x6: // focus on drums AND guitar - if (near || far) newTextEvents.Add("[coop_dg_near]"); - break; - case 0x8: // focus on the vocals ONLY - if (behind) newTextEvents.Add("[coop_v_behind]"); - if (near || far) { - if (!behind && !far) newTextEvents.Add("[coop_v_closeup]"); - else newTextEvents.Add("[coop_v_near]"); - } - break; - case 0x9: // focus on bass AND vocals - if (behind) newTextEvents.Add("[coop_bv_behind]"); - if (near || far) newTextEvents.Add("[coop_bv_near]"); - break; - case 0xA: // focus on drums AND vocals - if (near || far) newTextEvents.Add("[coop_dv_near]"); - break; - case 0xC: // focus on guitar AND vocals - if (behind) newTextEvents.Add("[coop_gv_behind]"); - if (near || far) newTextEvents.Add("[coop_gv_near]"); - break; - case 0xD: // focus on every instrument except drums - if (behind) newTextEvents.Add("[coop_front_behind]"); - if (near || far) newTextEvents.Add("[coop_front_near]"); - break; - case 0xF: // focus on every instrument - if (behind) newTextEvents.Add("[coop_all_behind]"); - if (far) newTextEvents.Add("[coop_all_far]"); - if (near) newTextEvents.Add("[coop_all_near]"); - break; - default: throw new Exception("Encountered an invalid combination of focused instruments!"); - } - - return newTextEvents; - } - } -} \ No newline at end of file diff --git a/Assets/Script/Serialization/Parser/MidiParser.FiveFret.cs b/Assets/Script/Serialization/Parser/MidiParser.FiveFret.cs index 3d602954b..c7420f9df 100644 --- a/Assets/Script/Serialization/Parser/MidiParser.FiveFret.cs +++ b/Assets/Script/Serialization/Parser/MidiParser.FiveFret.cs @@ -29,7 +29,7 @@ private enum ForceState { private class FiveFretIR { public long startTick; // This is an array due to extended sustains - public long[] endTick; + public long[] endTick = new long[6]; public FretFlag fretFlag; public FretFlag prevFretFlag; @@ -272,7 +272,6 @@ private List FiveFretNotePass(TrackChunk trackChunk, int difficulty, noteIR.Add(currentChord); currentChord = new FiveFretIR { startTick = fretState[fret].Value, - endTick = new long[6], fretFlag = fretFlag, hopo = false }; diff --git a/Assets/Script/Serialization/Parser/MidiParser.Venue.cs b/Assets/Script/Serialization/Parser/MidiParser.Venue.cs index d2667b730..8013efd3a 100644 --- a/Assets/Script/Serialization/Parser/MidiParser.Venue.cs +++ b/Assets/Script/Serialization/Parser/MidiParser.Venue.cs @@ -1,71 +1,167 @@ +using System; using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; using Melanchall.DryWetMidi.Core; +/* TODO +Parsing: +- Camera cuts, thinking we'll need a new info type for this one + +Handling: +- Post-processing handling +- Performer spotlights +- Performer sing-alongs +- Bonus effects +*/ + namespace YARG.Serialization.Parser { public partial class MidiParser : AbstractParser { + // Matches lighting events and groups the text inside (parentheses), not including the parentheses + // 'lighting (verse)' -> 'verse', lighting (flare_fast)' -> 'flare_fast', 'lighting ()' -> '' + private static readonly Regex lightingRegex = new(@"lighting\s+\((.*?)\)", RegexOptions.Compiled | RegexOptions.Singleline); + private void ParseVenue(List eventIR, TrackChunk trackChunk) { long totalDelta = 0; + var noteQueue = new List<(NoteOnEvent note, long tick)>(); // Convert track events into intermediate representation foreach (var trackEvent in trackChunk.Events) { totalDelta += trackEvent.DeltaTime; - // Track the lighting keyframe but in the new style - if(trackEvent is TextEvent textEv){ - if(textEv.Text == "[next]"){ - eventIR.Add(new EventIR { - startTick = totalDelta, - name = "venue_lightFrame_next" - }); - } - } + if (trackEvent is BaseTextEvent textEvent) { + ProcessText(eventIR, textEvent.Text, totalDelta); + } else if (trackEvent is NoteOnEvent noteOn) { + if (noteQueue.Any((queued) => queued.note.NoteNumber == noteOn.NoteNumber + && queued.note.Channel == noteOn.Channel)) { + // Duplicate note + continue; + } + noteQueue.Add((noteOn, totalDelta)); + } else if (trackEvent is NoteOffEvent noteOff) { + // Get note on event + long noteOnTime = 0; + var queued = noteQueue.FirstOrDefault((queued) => queued.note.NoteNumber == noteOff.NoteNumber + && queued.note.Channel == noteOff.Channel); + (noteOn, noteOnTime) = queued; + if (noteOn == null) { + // No corresponding note-on + continue; + } - // Sometimes events are stored as normal text events :/ - if (trackEvent is not BaseTextEvent textEvent) { - continue; + noteQueue.Remove(queued); + ProcessNoteEvent(eventIR, noteOn, noteOnTime, totalDelta - noteOnTime); } + } + } - // Only look for lighting (for now) - if (!textEvent.Text.StartsWith("[lighting (") || !textEvent.Text.EndsWith(")]")) { - continue; - } + private void ProcessNoteEvent(List eventIR, NoteOnEvent noteEvent, long startTick, long endTick) { + // Handle notes that are equivalent to other text events + string eventText = (byte)noteEvent.NoteNumber switch { + // Post-processing + 110 => "[video_trails.pp]", + 109 => "[video_security.pp]", + 108 => "[video_bw.pp]", + 107 => "[video_a.pp]", + 106 => "[film_blue_filter.pp]", + 105 => "[ProFilm_mirror_a.pp]", + 104 => "[ProFilm_b.pp]", + 103 => "[ProFilm_a.pp]", + 102 => "[photocopy.pp]", + 101 => "[photo_negative.pp]", + 100 => "[film_silvertone.pp]", + 99 => "[film_sepia_ink.pp]", + 98 => "[film_16mm.pp]", + 97 => "[contrast_a.pp]", + 96 => "[ProFilm_a.pp]", - var argument = textEvent.Text[11..^2]; - - // Connect midi lighting name to YARG lighting name - string eventName = argument switch { - "" => "venue_light_default", - "strobe_fast" => "venue_light_strobeFast", - "verse" => "venue_light_verse", - "chorus" => "venue_light_chorus", - "manual_cool" => "venue_light_manualCool", - "manual_warm" => "venue_light_manualWarm", - "dischord" => "venue_light_dischord", - "loop_cool" => "venue_light_loopCool", - "silhouettes" => "venue_light_silhouettes", - "loop_warm" => "venue_light_loopWarm", - "silhouettes_spot" => "venue_light_silhouettesSpot", - "frenzy" => "venue_light_frenzy", - "blackout_fast" => "venue_light_blackoutFast", - "flare_fast" => "venue_light_flareFast", - "searchlights" => "venue_light_searchlights", - "flare_slow" => "venue_light_flareSlow", - "harmony" => "venue_light_harmony", - "sweep" => "venue_light_sweep", - "bre" => "venue_light_bre", - "strobe_slow" => "venue_light_strobeSlow", - "blackout_slow" => "venue_light_blackoutSlow", - "stomp" => "venue_light_stomp", - _ => null - }; - - if (eventName == null) { - continue; - } + // Lighting keyframes + 50 => "[first]", + 49 => "[prev]", + 48 => "[next]", + + _ => null + }; + + if (eventText != null) { + ProcessText(eventIR, eventText, startTick); + return; + } + + // Handle events with length + eventText = (byte)noteEvent.NoteNumber switch { + // Performer sing-alongs + 87 => "venue_singalong_guitarOrKeys", + 86 => "venue_singalong_drums", + 85 => "venue_singalong_bassOrKeys", + + // Performer spotlights + 41 => "venue_spotlight_keys", + 40 => "venue_spotlight_vocals", + 39 => "venue_spotlight_guitar", + 38 => "venue_spotlight_drums", + 37 => "venue_spotlight_bass", + + _ => null + }; + + if (eventText != null) { + eventIR.Add(new EventIR { + startTick = startTick, + endTick = endTick, + name = eventText + }); + return; + } + + // TODO: Camera cuts + } + + private void ProcessText(List eventIR, string text, long eventTick) { + // Strip away the [brackets] from events (and any garbage outside them) + var match = textEventRegex.Match(text); + if (match.Success) { + text = match.Groups[1].Value; + } + + // Turn text event into the event name the game should use + string finalText = null; + switch (text) { + case "next": finalText = "venue_lightFrame_next"; break; + case "prev": finalText = "venue_lightFrame_previous"; break; + case "first": finalText = "venue_lightFrame_first"; break; + + case "verse": finalText = "venue_light_verse"; break; + case "chorus": finalText = "venue_light_chorus"; break; + + case "bonusfx": finalText = "venue_bonus_fx"; break; + case "bonusfx_optional": finalText = "venue_bonus_fx_optional"; break; + + default: + // Venue lighting + match = lightingRegex.Match(text); + if (match.Success) { + string lightingType = match.Groups[1].Value; + if (string.IsNullOrWhiteSpace(lightingType)) { + lightingType = "default"; + } + finalText = $"venue_light_{lightingType}"; + break; + } + + // Post-processing + if (text.EndsWith(".pp")) { + finalText = $"venue_postProcess_{text.Replace(".pp", "")}"; + break; + } + + break; + } + if (finalText != null) { eventIR.Add(new EventIR { - startTick = totalDelta, - name = eventName + startTick = eventTick, + name = finalText }); } } diff --git a/Assets/Script/Serialization/Parser/MidiParser.cs b/Assets/Script/Serialization/Parser/MidiParser.cs index e77a2771f..5427c8928 100644 --- a/Assets/Script/Serialization/Parser/MidiParser.cs +++ b/Assets/Script/Serialization/Parser/MidiParser.cs @@ -99,29 +99,6 @@ public MidiParser(SongEntry songEntry) : base(songEntry) { } - // if this is a RB song and the venue version < 30, we have the old RB2 style venue - // we must give the YARG parser the new, updated, RB3 style venue equivalent! - if(oof.VenueVersion < 30){ - var midiWithNewVenue = new MidiFile(); - midiWithNewVenue.ReplaceTempoMap(midi.GetTempoMap()); - foreach(var trackChunk in midi.GetTrackChunks()){ - foreach(var trackEvent in trackChunk.Events){ - if (trackEvent is not SequenceTrackNameEvent trackName) continue; - if(trackName.Text == "VENUE"){ - midiWithNewVenue.Chunks.Add(LegacyVenueConverter.ConvertVenue(trackChunk)); - Debug.Log("Legacy VENUE track detected and converted to the newer style."); - Debug.Log(LegacyVenueConverter.ConvertVenue(trackChunk).Events.Count); - break; - } - else{ - midiWithNewVenue.Chunks.Add(trackChunk); - break; - } - } - } - midi = midiWithNewVenue; - } - var ForbiddenVenueSrcs = new HashSet { "tbrb", "beatles", "tbrbdlc", "tbrbcdlc" }; if(!ForbiddenVenueSrcs.Contains(oof.Source)){ // skip beatles venues cuz they're built different // get midi tracks based from the milo, and append them to the midi to use diff --git a/Assets/Script/Settings/SettingsManager.Settings.cs b/Assets/Script/Settings/SettingsManager.Settings.cs index ba9dc1a30..b433eed70 100644 --- a/Assets/Script/Settings/SettingsManager.Settings.cs +++ b/Assets/Script/Settings/SettingsManager.Settings.cs @@ -145,9 +145,9 @@ private static void ResolutionCallback(Resolution? value) { }; foreach (var r in Screen.resolutions) { - if (r.refreshRate >= highest.refreshRate && - r.width >= highest.width && - r.height >= highest.height) { + if (r.refreshRate >= highest.refreshRate || + r.width >= highest.width || + r.height >= highest.height) { highest = r; } diff --git a/Assets/Script/Song/BooleanConverter.cs b/Assets/Script/Song/BooleanConverter.cs new file mode 100644 index 000000000..cdcdc0bcb --- /dev/null +++ b/Assets/Script/Song/BooleanConverter.cs @@ -0,0 +1,34 @@ +using EasySharpIni.Converters; + +namespace YARG.Song { + public class BooleanConverter : Converter { + public override string GetDefaultName() { + return "Boolean"; + } + + public override bool GetDefaultValue() { + return false; + } + + public override bool Parse(string arg, out bool result) { + arg = arg.ToLower(); + switch (arg) { + case "true": + case "1": + result = true; + break; + + case "false": + case "0": + result = false; + break; + + default: + result = false; + return false; + }; + + return true; + } + } +} diff --git a/Assets/Script/Serialization/Parser/LegacyVenueConverter.cs.meta b/Assets/Script/Song/BooleanConverter.cs.meta similarity index 83% rename from Assets/Script/Serialization/Parser/LegacyVenueConverter.cs.meta rename to Assets/Script/Song/BooleanConverter.cs.meta index 75e9d222b..0f476729c 100644 --- a/Assets/Script/Serialization/Parser/LegacyVenueConverter.cs.meta +++ b/Assets/Script/Song/BooleanConverter.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 67d58ccacf094a9459c71b928190e687 +guid: b872b7bc978ac194981d3bf8f24013ac MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Script/Song/Preparsers/MidPreparser.cs b/Assets/Script/Song/Preparsers/MidPreparser.cs index 19e64132a..bfddf4c26 100644 --- a/Assets/Script/Song/Preparsers/MidPreparser.cs +++ b/Assets/Script/Song/Preparsers/MidPreparser.cs @@ -28,6 +28,12 @@ public static class MidPreparser { { MidIOHelper.VOCALS_TRACK, Instrument.VOCALS }, { "PART REAL_GUITAR", Instrument.REAL_GUITAR }, { "PART REAL_BASS", Instrument.REAL_BASS }, + { "HARM1", Instrument.HARMONY }, + { "HARM2", Instrument.HARMONY }, + { "HARM3", Instrument.HARMONY }, + { "PART HARM1", Instrument.HARMONY }, + { "PART HARM2", Instrument.HARMONY }, + { "PART HARM3", Instrument.HARMONY }, }; diff --git a/Assets/Script/Song/SongCache.cs b/Assets/Script/Song/SongCache.cs index a82c90189..a77099cfe 100644 --- a/Assets/Script/Song/SongCache.cs +++ b/Assets/Script/Song/SongCache.cs @@ -12,9 +12,11 @@ namespace YARG.Song { public class SongCache { /// - /// The date in which the cache version is based on (and cache revision) + /// The date revision of the cache format. + /// Format is YY_MM_DD_RR: Y = year, M = month, D = day, R = revision (reset across dates, only increment + /// if multiple cache version changes happen in a single day). /// - private const int CACHE_VERSION = 01_06_23_01; + private const int CACHE_VERSION = 23_06_05_01; private readonly string _folder; private readonly string _cacheFile; diff --git a/Assets/Script/Song/Types/IniSongEntry.cs b/Assets/Script/Song/Types/IniSongEntry.cs index 9430ec483..9b027fe58 100644 --- a/Assets/Script/Song/Types/IniSongEntry.cs +++ b/Assets/Script/Song/Types/IniSongEntry.cs @@ -6,6 +6,7 @@ namespace YARG.Song { public class IniSongEntry : SongEntry { private static readonly IntConverter IntConverter = new(); + private static readonly BooleanConverter BooleanConverter = new(); public string Playlist { get; private set; } = string.Empty; public string SubPlaylist { get; private set; } = string.Empty; @@ -91,7 +92,7 @@ public ScanResult ParseIni() { } HopoThreshold = section.GetField("hopo_frequency", "170").Get(IntConverter); - EighthNoteHopo = section.GetField("eighthnote_hopo", "false").Get().ToLower() == "true"; + EighthNoteHopo = section.GetField("eighthnote_hopo", "false").Get(BooleanConverter); MultiplierNote = section.GetField("multiplier_note", "116").Get(IntConverter); PartDifficulties = new() { @@ -123,26 +124,16 @@ public ScanResult ParseIni() { } DrumType = DrumType.Unknown; - if (section.ContainsField("pro_drums")) { - switch (section.GetField("pro_drums")) { - case "true": - case "1": - DrumType = DrumType.FourLane; - break; - } - } else if (section.ContainsField("five_lane_drums")) { - switch (section.GetField("five_lane_drums")) { - case "true": - case "1": - DrumType = DrumType.FiveLane; - break; - } + if (section.GetField("pro_drums", "false").Get(BooleanConverter)) { + DrumType = DrumType.FourLane; + } else if (section.GetField("five_lane_drums", "false").Get(BooleanConverter)) { + DrumType = DrumType.FiveLane; } LoadingPhrase = section.GetField("loading_phrase"); Source = section.GetField("icon"); - HasLyrics = section.GetField("lyrics").Get().ToLower() == "true"; - IsModChart = section.GetField("modchart").Get().ToLower() == "true"; + HasLyrics = section.GetField("lyrics").Get(BooleanConverter); + IsModChart = section.GetField("modchart").Get(BooleanConverter); VideoStartOffset = section.GetField("video_start_time", "0").Get(IntConverter); return ScanResult.Ok; } diff --git a/Assets/Script/ThirdParty/DiscordController.cs b/Assets/Script/ThirdParty/DiscordController.cs index f50d7b4fd..4788debba 100644 --- a/Assets/Script/ThirdParty/DiscordController.cs +++ b/Assets/Script/ThirdParty/DiscordController.cs @@ -1,6 +1,9 @@ using System; +using System.Collections.Generic; using Discord; +using Unity.Collections; using UnityEngine; +using YARG; using YARG.Data; using YARG.PlayMode; using YARG.Song; @@ -43,6 +46,16 @@ public Activity CurrentActivity { } } + [System.Serializable] + private struct distinctDetails { + public string defaultDetails; + public string defaultState; + public string defaultLargeImage; + public string defaultLargeText; + } + + private distinctDetails defaultDetails; + [SerializeField] private GameObject songStartObject; @@ -52,13 +65,26 @@ public Activity CurrentActivity { [Space] [Header("Default Values")] [SerializeField] - private string defaultDetails = "Hello there ladies and gentlemen!"; //Line of text just below the game name + private distinctDetails stableDetails = new distinctDetails { + defaultDetails = "Hello there ladies and gentlemen!", + defaultState = "Are you ready to rock?", + defaultLargeImage = "icon_stable", + defaultLargeText = "Yet Another Rhythm Game" + }; [SerializeField] - private string defaultState = "Are you ready to rock?"; //smaller 2nd line of text - private string defaultLargeImage = "logo"; // string name comes from the assets uploaded to the app - //private string defaultLargeImage = "https://cld.pt/dl/download/6e981054-9955-427a-9e4a-80b92a503a01/Icon.gif"; // URL to an animated Logo + private distinctDetails nightlyDetails = new distinctDetails { + defaultDetails = "Hello there ladies and gentlemen!", + defaultState = "Are you ready to test?", + defaultLargeImage = "icon_nightly", + defaultLargeText = "Yet Another Rhythm Game - Nightly Build" + }; [SerializeField] - private string defaultLargeText = "Yet Another Rhythm Game"; //Tooltip text for the large icon + private distinctDetails devDetails = new distinctDetails { + defaultDetails = "Hello there ladies and gentlemen!", + defaultState = "Are you ready to develop?", + defaultLargeImage = "icon_dev", + defaultLargeText = "Yet Another Rhythm Game - Developer Build" + }; [SerializeField] private string defaultSmallImage = ""; // little overlay image on the bottom right of the Large image [SerializeField] @@ -89,6 +115,20 @@ public Activity CurrentActivity { private void Start() { Instance = this; + // if it's a Nightly build, use the Nightly logo, otherwise use the Stable logo + if (Constants.VERSION_TAG.beta) { + defaultDetails = nightlyDetails; + } else { + defaultDetails = stableDetails; + } + + // if it's running in the editor, use the Dev logo + #if UNITY_EDITOR + defaultDetails = devDetails; + #endif + + + // Listen to the changing of songs Play.OnSongStart += OnSongStart; Play.OnSongEnd += OnSongEnd; @@ -137,7 +177,7 @@ private void OnPauseToggle(bool pause) { // Time data pause ? 0 : DateTimeOffset.Now.ToUnixTimeMilliseconds(), - pause ? 0 : DateTimeOffset.Now.AddSeconds(songLengthSeconds - Play.Instance.SongTime).ToUnixTimeMilliseconds() + pause ? 0 : DateTimeOffset.Now.AddSeconds(Play.Instance.SongLength- Play.Instance.SongTime).ToUnixTimeMilliseconds() ); } @@ -151,7 +191,7 @@ private void OnSongStart(SongEntry song) { songName, "by " + artistName, DateTimeOffset.Now.ToUnixTimeMilliseconds(), - DateTimeOffset.Now.AddSeconds(songLengthSeconds).ToUnixTimeMilliseconds() + DateTimeOffset.Now.AddSeconds(Play.Instance.SongLength- Play.Instance.SongTime).ToUnixTimeMilliseconds() ); } @@ -221,13 +261,13 @@ private void OnApplicationQuit() { private void SetDefaultActivity() { CurrentActivity = new Activity { Assets = { - LargeImage = defaultLargeImage, - LargeText = defaultLargeText, + LargeImage = defaultDetails.defaultLargeImage, + LargeText = defaultDetails.defaultLargeText, SmallImage = defaultSmallImage, SmallText = defaultSmallText }, - Details = defaultDetails, - State = defaultState, + Details = defaultDetails.defaultDetails, + State = defaultDetails.defaultState, Timestamps = { Start = gameStartTime } @@ -237,8 +277,8 @@ private void SetDefaultActivity() { private void SetActivity(string smallImage, string smallText, string details, string state, long startTimeStamp, long endTimeStamp) { CurrentActivity = new Activity { Assets = { - LargeImage = defaultLargeImage, //the YARG logo and tooltip does not change, at this point in time. - LargeText = defaultLargeText, + LargeImage = defaultDetails.defaultLargeImage, //the YARG logo and tooltip does not change, at this point in time. + LargeText = defaultDetails.defaultLargeText, SmallImage = smallImage, SmallText = smallText, }, diff --git a/Assets/Script/UI/AddPlayer.cs b/Assets/Script/UI/AddPlayer.cs index db5859561..57edfc538 100644 --- a/Assets/Script/UI/AddPlayer.cs +++ b/Assets/Script/UI/AddPlayer.cs @@ -202,7 +202,11 @@ private void StartSelectDevice(bool micSelected = false) { var mics = GameManager.AudioManager.GetAllInputDevices(); foreach (var mic in mics) { var button = Instantiate(deviceButtonPrefab, devicesContainer); - button.GetComponentInChildren().text = $"(MIC) {mic.DisplayName}"; + var textBox = button.GetComponentInChildren(); + textBox.text = $"(MIC) {mic.DisplayName}"; + if (mic.IsDefault) { + textBox.text += " (Default)"; + } var capture = mic; button.GetComponentInChildren