diff --git a/.github/workflows/linux-selfhosted.yml b/.github/workflows/linux-selfhosted.yml index 741d8434..842ffb7b 100644 --- a/.github/workflows/linux-selfhosted.yml +++ b/.github/workflows/linux-selfhosted.yml @@ -12,6 +12,8 @@ jobs: steps: - name: Pulling the new commit uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Setting up Haxe uses: krdlab/setup-haxe@v2 with: diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index f2e48a35..ab7f8ad0 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -12,6 +12,8 @@ jobs: steps: - name: Pulling the new commit uses: actions/checkout@v6 + with: + fetch-depth: 0 - name: Setting up Haxe uses: krdlab/setup-haxe@v2 with: diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index b9d391d0..79412650 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -12,6 +12,8 @@ jobs: steps: - name: Pulling the new commit uses: actions/checkout@v6 + with: + fetch-depth: 0 - name: Setting up Haxe uses: krdlab/setup-haxe@v2 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ee3b5586..3e78c83f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,6 +22,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v6 + with: + fetch-depth: 0 - name: Download Windows Full Build uses: dawidd6/action-download-artifact@v8 diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 9730fee6..be5dc8d2 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -12,6 +12,8 @@ jobs: steps: - name: Pulling the new commit uses: actions/checkout@v6 + with: + fetch-depth: 0 - name: Setting up Haxe uses: krdlab/setup-haxe@v2 with: diff --git a/source/funkin/backend/system/Flags.hx b/source/funkin/backend/system/Flags.hx index eb243ddd..c0a4331b 100644 --- a/source/funkin/backend/system/Flags.hx +++ b/source/funkin/backend/system/Flags.hx @@ -165,6 +165,8 @@ class Flags { // Font configuration public static var DEFAULT_FONT:String = "vcr.ttf"; public static var DEFAULT_FONT_SIZE:Int = 16; + + public static var DEFAULT_ALT_ANIM_SUFFIX:String = "-alt"; // to translate these you need to convert them into ids // Resume -> pause.resume diff --git a/source/funkin/backend/utils/CoolUtil.hx b/source/funkin/backend/utils/CoolUtil.hx index 098e755f..382c4760 100644 --- a/source/funkin/backend/utils/CoolUtil.hx +++ b/source/funkin/backend/utils/CoolUtil.hx @@ -440,11 +440,9 @@ final class CoolUtil * @param fadeIn */ @:noUsing public static function playMenuSong(fadeIn:Bool = false) { - if (FlxG.sound.music == null || !FlxG.sound.music.playing) - { + if (FlxG.sound.music == null || !FlxG.sound.music.playing) { playMusic(Paths.music(Flags.DEFAULT_MENU_MUSIC), true, fadeIn ? 0 : 1, true, 102); - if (fadeIn) - FlxG.sound.music.fadeIn(4, 0, 0.7); + if (fadeIn) FlxG.sound.music.fadeIn(4, 0, 1); } } diff --git a/source/funkin/editors/charter/CharterSelection.hx b/source/funkin/editors/charter/CharterSelection.hx index 420f3227..172a8a5c 100644 --- a/source/funkin/editors/charter/CharterSelection.hx +++ b/source/funkin/editors/charter/CharterSelection.hx @@ -146,11 +146,10 @@ class CharterSelectionScreen extends EditorTreeMenuScreen { var screen = parent.tree.last(); var idx = 0; - while (!(screen.members[idx] is Separator)) idx++; + while (!(screen.members[idx] is Separator || idx >= screen.members.length)) idx++; screen.insert(idx, makeChartOption(name, curSong.variant != null && curSong.variant != "" ? curSong.variant : null, curSong.name)); - // Add to Meta - var metaPath = '$songFolder/meta${curSong.variant != null && curSong.variant == "" ? "-" + curSong.variant : ""}.json'; + var metaPath = '$songFolder/meta${curSong.variant != null && curSong.variant != "" ? "-" + curSong.variant : ""}.json'; CoolUtil.safeSaveFile(metaPath, Chart.makeMetaSaveable(curSong)); } #end diff --git a/source/funkin/game/Note.hx b/source/funkin/game/Note.hx index 82879bd3..e3d88625 100644 --- a/source/funkin/game/Note.hx +++ b/source/funkin/game/Note.hx @@ -126,8 +126,7 @@ class Note extends FlxSprite static var DEFAULT_FIELDS:Array = ["time", "id", "type", "sLen"]; - public function new(strumLine:StrumLine, noteData:ChartNote, sustain:Bool = false, sustainLength:Float = 0, sustainOffset:Float = 0, ?prev:Note) - { + public function new(strumLine:StrumLine, noteData:ChartNote, sustain:Bool = false, sustainLength:Float = 0, sustainOffset:Float = 0, ?prev:Note) { super(); moves = false; @@ -241,23 +240,13 @@ class Note extends FlxSprite */ public var strumRelativePos:Bool = true; - override function drawComplex(camera:FlxCamera) { - var downscrollCam = (camera is HudCamera ? ({var _:HudCamera=cast camera;_;}).downscroll : false); - if (updateFlipY) flipY = (isSustainNote && flipSustain) && (downscrollCam != (__strum != null && __strum.getScrollSpeed(this) < 0)); - if (downscrollCam && __strum != null) { - final xx = x; - x += origin.x - offset.x; - x -= __strum.x; x *= -1; x += __strum.x; - x -= origin.x - offset.x; - x += __strum.width; // ??? maybe this isnt good - super.drawComplex(camera); - x = xx; - } else - super.drawComplex(camera); - } - - static var __notePosFrameOffset:FlxPoint = new FlxPoint(); - static var __posPoint:FlxPoint = new FlxPoint(); + @:dox(hide) static var __lastAngle:Float = Math.NaN; + @:dox(hide) static var __lastAngleSin:Float = 0; + @:dox(hide) static var __lastAngleCos:Float = 0; + @:dox(hide) static var __lastStrumW:Float = Math.NaN; + @:dox(hide) static var __lastStrumH:Float = Math.NaN; + @:dox(hide) static var __lastStrumHalfW:Float = 0; + @:dox(hide) static var __lastStrumHalfH:Float = 0; override function draw() { @:privateAccess var oldDefaultCameras = FlxCamera._defaultCameras; @@ -266,16 +255,28 @@ class Note extends FlxSprite var negativeScroll = isSustainNote && strumRelativePos && lastScrollSpeed < 0; if (negativeScroll) y -= height; if (__strum != null && strumRelativePos) { - final pos = __posPoint.set(x, y); - // distance = pos.y , we can use it safely like this - final xx = -origin.x + offset.x + (pos.y * Math.cos((__noteAngle + 90) * FlxAngle.TO_RAD)); - final yy = -origin.y + offset.y + (pos.y * Math.sin((__noteAngle + 90) * FlxAngle.TO_RAD)); - setPosition( - xx + __strum.x + (__strum.width * 0.5), - yy + __strum.y + (__strum.height * 0.5) - ); + final originalX = x; + final originalY = y; + + if (__noteAngle != __lastAngle) { + __lastAngle = __noteAngle; + final result = FlxMath.fastSinCos((__noteAngle + 90) * FlxAngle.TO_RAD); + __lastAngleSin = result.sin; + __lastAngleCos = result.cos; + } + + if (__strum.width != __lastStrumW || __strum.height != __lastStrumH) { + __lastStrumW = __strum.width; + __lastStrumH = __strum.height; + __lastStrumHalfW = __strum.width * 0.5; + __lastStrumHalfH = __strum.height * 0.5; + } + + x = -origin.x + offset.x + (originalY * __lastAngleCos) + __strum.x + __lastStrumHalfW; + y = -origin.y + offset.y + (originalY * __lastAngleSin) + __strum.y + __lastStrumHalfH; super.draw(); - setPosition(pos.x, pos.y); + x = originalX; + y = originalY; } else { super.draw(); } @@ -284,6 +285,38 @@ class Note extends FlxSprite @:privateAccess FlxCamera._defaultCameras = oldDefaultCameras; } + var __lastDownscrollCam:Bool = false; + var __lastX:Float = 0; + + @:noCompletion @:dox(hide) override function isOnScreen(?camera:FlxCamera):Bool { + var downscrollCam = (Std.isOfType(camera, HudCamera) ? cast(camera, HudCamera).downscroll : false); + + if (downscrollCam == __lastDownscrollCam) + return super.isOnScreen(camera); + else + __lastX = x; + + if (updateFlipY) flipY = (isSustainNote && flipSustain) && (downscrollCam != (__strum != null && __strum.getScrollSpeed(this) < 0)); + if (downscrollCam && __strum != null) { + x = -x + 2 * (__strum.x - origin.x + offset.x) + __strum.width; + } + final isOnScreen = super.isOnScreen(camera); + return isOnScreen; + } + + override function drawComplex(camera:FlxCamera):Void { + super.drawComplex(camera); + + if (__lastDownscrollCam) { + __lastDownscrollCam = false; + x = __lastX; + } + } + + public function isOnScreenOriginal(?camera:FlxCamera):Bool { + return super.isOnScreen(camera); + } + // The * 0.5 is so that it's easier to hit them too late, instead of too early public var earlyPressWindow:Float = 0.5; public var latePressWindow:Float = 1; @@ -294,7 +327,7 @@ class Note extends FlxSprite if (lastScrollSpeed != scrollSpeed) { lastScrollSpeed = scrollSpeed; if (nextSustain != null) { - scale.y = (sustainLength * 0.45 * Math.abs(scrollSpeed)) / frameHeight; + scale.y = (sustainLength * 0.45 * scrollSpeed) / frameHeight; updateHitbox(); scale.y += gapFix / frameHeight; } @@ -304,18 +337,28 @@ class Note extends FlxSprite } public function updateSustainClip() if (wasGoodHit && !noSustainClip) { - var t = CoolUtil.bound((Conductor.songPosition - strumTime) / height * 0.45 * Math.abs(lastScrollSpeed), 0, 1); - var rect = clipRect == null ? FlxRect.get() : clipRect; - clipRect = rect.set(0, frameHeight * t, frameWidth, frameHeight * (1 - t)); + var t = CoolUtil.bound((Conductor.songPosition - strumTime) / height * 0.45 * lastScrollSpeed, 0, 1); + @:bypassAccessor { + if (clipRect == null) clipRect = FlxRect.get(); + clipRect.set(0, frameHeight * t, frameWidth, frameHeight * (1 - t)); + } + @:privateAccess { + if (frame != null && _frame != null) + _frame = frame.clipTo(clipRect, _frame); + } } @:noCompletion - override function set_clipRect(rect:FlxRect):FlxRect - { - clipRect = rect; + override function set_clipRect(rect:FlxRect):FlxRect { + @:bypassAccessor clipRect = rect; - if (frames != null) - frame = frames.frames[animation.frameIndex]; + @:privateAccess if (frame != null) { + if (rect != null && _frame != null) + _frame = frame.clipTo(rect, _frame); + else if (_frame != null) + _frame = frame.copyTo(_frame); + dirty = true; + } return rect; } diff --git a/source/funkin/game/PlayState.hx b/source/funkin/game/PlayState.hx index d5bee0bf..344d2ed4 100644 --- a/source/funkin/game/PlayState.hx +++ b/source/funkin/game/PlayState.hx @@ -1657,7 +1657,7 @@ class PlayState extends MusicBeatState if (strLine.characters != null) // Alt anim Idle for (character in strLine.characters) { if (character == null) continue; - character.idleSuffix = event.params[1] ? "-alt" : ""; + character.idleSuffix = event.params[1] ? strLine.defaultAnimSuffix : ""; } } case "Play Animation": diff --git a/source/funkin/game/Strum.hx b/source/funkin/game/Strum.hx index b075aad8..ede6360f 100644 --- a/source/funkin/game/Strum.hx +++ b/source/funkin/game/Strum.hx @@ -2,6 +2,7 @@ package funkin.game; import flixel.math.FlxPoint; import flixel.math.FlxAngle; +import flixel.util.typeLimit.OneOfTwo; import funkin.backend.system.Conductor; class Strum extends FlxSprite { @@ -52,8 +53,27 @@ class Strum extends FlxSprite { public var updateNotesPosY:Bool = true; public var extraCopyFields(default, set):Array = []; - private inline function set_extraCopyFields(val:Array) - return extraCopyFields = val == null ? [] : val; + @:noCompletion public var __cachedCopyFields:Array>> = null; + + private function set_extraCopyFields(val:Array) { + extraCopyFields = val == null ? [] : val; + __cachedCopyFields = null; + return extraCopyFields; + } + + private inline function __initCachedCopyFields() { + if (__cachedCopyFields != null) return; + __cachedCopyFields = [for (field in extraCopyFields) CoolUtil.parsePropertyString(field)]; + } + + private inline function __applyCopyFields(daNote:Note) { + for (i in 0...extraCopyFields.length) { + final parsed = __cachedCopyFields[i]; + final fromProp = CoolUtil.parseProperty(this, parsed); + final toProp = CoolUtil.parseProperty(daNote, parsed); + toProp.setValue(fromProp.getValue()); + } + } /** * Whenever the strum is pressed. @@ -129,13 +149,28 @@ class Strum extends FlxSprite { } public override function draw() { - lastDrawCameras = cameras.copy(); + if (cameras.length == 1) { + if (lastDrawCameras.length != 1 || lastDrawCameras[0] != cameras[0]) { + lastDrawCameras = [cameras[0]]; + } + } else { + lastDrawCameras = cameras.copy(); + } super.draw(); } @:noCompletion public static inline final PIX180:Float = 565.4866776461628; // 180 * Math.PI @:noCompletion public static final N_WIDTHDIV2:Float = Note.swagWidth / 2; // DEPRECATED + static var __lastStrumW:Float = Math.NaN; + static var __lastStrumH:Float = Math.NaN; + static var __lastStrumHalfW:Float = 0; + static var __lastStrumHalfH:Float = 0; + static var __noteOffset:FlxPoint = FlxPoint.get(); + static var __lastNoteAngle:Float = Math.NaN; + static var __lastAngleCos:Float = 0; + static var __lastAngleSin:Float = 0; + /** * Updates the position of a note. * @param daNote The note @@ -153,8 +188,10 @@ class Strum extends FlxSprite { } updateNotePos(daNote); - for (field in extraCopyFields) - CoolUtil.cloneProperty(daNote, field, this); // TODO: make this cached to reduce the reflection calls - Neo + if (extraCopyFields.length > 0) { + __initCachedCopyFields(); + __applyCopyFields(daNote); + } } private inline function updateNotePos(daNote:Note) { @@ -169,24 +206,34 @@ class Strum extends FlxSprite { if (daNote.isSustainNote) daNote.y += daNote.height * 0.5; } } else { + if (width != __lastStrumW || height != __lastStrumH) { + __lastStrumW = width; + __lastStrumH = height; + __lastStrumHalfW = width * 0.5; + __lastStrumHalfH = height * 0.5; + } + + if (daNote.__noteAngle != __lastNoteAngle) { + __lastNoteAngle = daNote.__noteAngle; + final result = FlxMath.fastSinCos((__lastNoteAngle + 90) * FlxAngle.TO_RAD); + __lastAngleCos = result.cos; + __lastAngleSin = result.sin; + } + final speed = getScrollSpeed(daNote); final distance = (daNote.strumTime - Conductor.songPosition) * 0.45 * speed; - final __noteAngle = FlxMath.fastSinCos((daNote.__noteAngle + 90) * FlxAngle.TO_RAD); - final angleX = __noteAngle.cos; - final angleY = __noteAngle.sin; - final _noteOffset = FlxPoint.get(angleX * distance, angleY * distance); - _noteOffset.x += -daNote.origin.x + daNote.offset.x; - _noteOffset.y += -daNote.origin.y + daNote.offset.y; + __noteOffset.set(__lastAngleCos * distance, __lastAngleSin * distance); + __noteOffset.x += -daNote.origin.x + daNote.offset.x; + __noteOffset.y += -daNote.origin.y + daNote.offset.y; if (daNote.isSustainNote) { - final m = (daNote.height * 0.5 * (speed < 0 ? -1 : 1)); // daNote.height works better than this.height in this case ??? - _noteOffset.x += angleX * m; - _noteOffset.y += angleY * m; + final m = (daNote.height * 0.5 * (speed < 0 ? -1 : 1)); + __noteOffset.x += __lastAngleCos * m; + __noteOffset.y += __lastAngleSin * m; } - _noteOffset.x += x + (width * 0.5); - _noteOffset.y += y + (height * 0.5); - if (shouldX) daNote.x = _noteOffset.x; - if (shouldY) daNote.y = _noteOffset.y; - _noteOffset.put(); + __noteOffset.x += x + __lastStrumHalfW; + __noteOffset.y += y + __lastStrumHalfH; + if (shouldX) daNote.x = __noteOffset.x; + if (shouldY) daNote.y = __noteOffset.y; } } } diff --git a/source/funkin/game/StrumLine.hx b/source/funkin/game/StrumLine.hx index 319f64ac..9c00acd0 100644 --- a/source/funkin/game/StrumLine.hx +++ b/source/funkin/game/StrumLine.hx @@ -74,6 +74,10 @@ class StrumLine extends FlxTypedGroup { * Which animation suffix on characters that should be used when hitting notes. */ public var animSuffix(default, set):String = ""; + /** + * The current animation suffix the strumline should use. Note that setting this will only take effect upon the alt. animation being reset. + */ + public var defaultAnimSuffix:String = Flags.DEFAULT_ALT_ANIM_SUFFIX; /** * TODO: Write documentation about this being a variable that can help when making multi key */ @@ -468,11 +472,11 @@ class StrumLine extends FlxTypedGroup { return animSuffix = str; } private inline function set_altAnim(b:Bool):Bool { - animSuffix = b ? "-alt" : ""; + animSuffix = b ? defaultAnimSuffix : ""; return b; } private inline function get_altAnim():Bool { - return animSuffix == "-alt"; + return animSuffix == defaultAnimSuffix; } #end } \ No newline at end of file diff --git a/source/funkin/options/Options.hx b/source/funkin/options/Options.hx index 9f4e8ab9..06b558de 100644 --- a/source/funkin/options/Options.hx +++ b/source/funkin/options/Options.hx @@ -43,8 +43,8 @@ class Options public static var framerate:Int = 120; public static var gpuOnlyBitmaps:Bool = #if (mac || web) false #else true #end; // causes issues on mac and web public static var language = "en"; // default to english, Flags.DEFAULT_LANGUAGE should not modify this - public static var streamedMusic:Bool = true; - public static var streamedVocals:Bool = true; + public static var streamedMusic:Bool = false; + public static var streamedVocals:Bool = false; public static var quality:Int = 1; public static var allowConfigWarning:Bool = true; #if MODCHARTING_FEATURES diff --git a/source/funkin/options/categories/GameplayOptions.hx b/source/funkin/options/categories/GameplayOptions.hx index 868c3c4c..4b69ccd3 100644 --- a/source/funkin/options/categories/GameplayOptions.hx +++ b/source/funkin/options/categories/GameplayOptions.hx @@ -67,7 +67,14 @@ class AdvancedGameplayOptions extends TreeMenuScreen { public function new() { super('optionsMenu.advanced', 'optionsTree.gameplay.advanced-desc', 'GameplayOptions.Advanced.'); - add(new Checkbox(getNameID('streamedMusic'), getDescID('streamedMusic'), 'streamedMusic')); - add(new Checkbox(getNameID('streamedVocals'), getDescID('streamedVocals'), 'streamedVocals')); + // Remove locked whenever this PR from FunkinCrew is merged. + // https://github.com/FunkinCrew/lime/pull/57 + for (checkbox in [ + new Checkbox(getNameID('streamedMusic'), getDescID('streamedMusic'), 'streamedMusic'), + new Checkbox(getNameID('streamedVocals'), getDescID('streamedVocals'), 'streamedVocals') + ]) { + checkbox.locked = true; + add(checkbox); + } } } \ No newline at end of file