mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2024-11-30 03:25:47 -05:00
assets submod
This commit is contained in:
commit
c5c22b245d
55 changed files with 612 additions and 273 deletions
6
.vscode/launch.json
vendored
6
.vscode/launch.json
vendored
|
@ -7,6 +7,12 @@
|
|||
"type": "lime",
|
||||
"request": "launch"
|
||||
},
|
||||
{
|
||||
"name": "Debug",
|
||||
"type": "lime",
|
||||
"request": "launch",
|
||||
"preLaunchTask": null
|
||||
},
|
||||
{
|
||||
// Launch in browser
|
||||
"name": "HTML5 Debug",
|
||||
|
|
22
.vscode/tasks.json
vendored
22
.vscode/tasks.json
vendored
|
@ -1,13 +1,13 @@
|
|||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "lime",
|
||||
"command": "test",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
}
|
||||
}
|
||||
]
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "lime",
|
||||
"command": "test",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -5,6 +5,9 @@ import flixel.util.FlxSignal;
|
|||
import flixel.math.FlxMath;
|
||||
import funkin.data.song.SongData.SongTimeChange;
|
||||
import funkin.data.song.SongDataUtils;
|
||||
import funkin.save.Save;
|
||||
import haxe.Timer;
|
||||
import flixel.sound.FlxSound;
|
||||
|
||||
/**
|
||||
* A core class which handles musical timing throughout the game,
|
||||
|
@ -89,6 +92,9 @@ class Conductor
|
|||
*/
|
||||
public var songPosition(default, null):Float = 0;
|
||||
|
||||
var prevTimestamp:Float = 0;
|
||||
var prevTime:Float = 0;
|
||||
|
||||
/**
|
||||
* Beats per minute of the current song at the current time.
|
||||
*/
|
||||
|
@ -233,8 +239,41 @@ class Conductor
|
|||
|
||||
/**
|
||||
* An offset set by the user to compensate for input lag.
|
||||
* No matter if you're using a local conductor or not, this always loads
|
||||
* to/from the save file
|
||||
*/
|
||||
public var inputOffset:Float = 0;
|
||||
public var inputOffset(get, set):Int;
|
||||
|
||||
/**
|
||||
* An offset set by the user to compensate for audio/visual lag
|
||||
* No matter if you're using a local conductor or not, this always loads
|
||||
* to/from the save file
|
||||
*/
|
||||
public var audioVisualOffset(get, set):Int;
|
||||
|
||||
function get_inputOffset():Int
|
||||
{
|
||||
return Save.instance.options.inputOffset;
|
||||
}
|
||||
|
||||
function set_inputOffset(value:Int):Int
|
||||
{
|
||||
Save.instance.options.inputOffset = value;
|
||||
Save.instance.flush();
|
||||
return Save.instance.options.inputOffset;
|
||||
}
|
||||
|
||||
function get_audioVisualOffset():Int
|
||||
{
|
||||
return Save.instance.options.audioVisualOffset;
|
||||
}
|
||||
|
||||
function set_audioVisualOffset(value:Int):Int
|
||||
{
|
||||
Save.instance.options.audioVisualOffset = value;
|
||||
Save.instance.flush();
|
||||
return Save.instance.options.audioVisualOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of beats in a measure. May be fractional depending on the time signature.
|
||||
|
@ -353,16 +392,19 @@ class Conductor
|
|||
* BPM, current step, etc. will be re-calculated based on the song position.
|
||||
*
|
||||
* @param songPosition The current position in the song in milliseconds.
|
||||
* Leave blank to use the `FlxG.sound.music` position.
|
||||
* Leave blank to use the FlxG.sound.music position.
|
||||
* @param applyOffsets If it should apply the instrumentalOffset + formatOffset + audioVisualOffset
|
||||
*/
|
||||
public function update(?songPos:Float):Void
|
||||
public function update(?songPos:Float, applyOffsets:Bool = true, forceDispatch:Bool = false)
|
||||
{
|
||||
if (songPos == null)
|
||||
{
|
||||
// Take into account instrumental and file format song offsets.
|
||||
songPos = (FlxG.sound.music != null) ? (FlxG.sound.music.time + instrumentalOffset + formatOffset) : 0.0;
|
||||
songPos = (FlxG.sound.music != null) ? FlxG.sound.music.time : 0.0;
|
||||
}
|
||||
|
||||
// Take into account instrumental and file format song offsets.
|
||||
songPos += applyOffsets ? (instrumentalOffset + formatOffset + audioVisualOffset) : 0;
|
||||
|
||||
var oldMeasure:Float = this.currentMeasure;
|
||||
var oldBeat:Float = this.currentBeat;
|
||||
var oldStep:Float = this.currentStep;
|
||||
|
@ -421,6 +463,35 @@ class Conductor
|
|||
{
|
||||
this.onMeasureHit.dispatch();
|
||||
}
|
||||
|
||||
// only update the timestamp if songPosition actually changed
|
||||
// which it doesn't do every frame!
|
||||
if (prevTime != this.songPosition)
|
||||
{
|
||||
// Update the timestamp for use in-between frames
|
||||
prevTime = this.songPosition;
|
||||
prevTimestamp = Std.int(Timer.stamp() * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be called in-between frames, usually for input related things
|
||||
* that can potentially get processed on exact milliseconds/timestmaps.
|
||||
* If you need song position, use `Conductor.instance.songPosition` instead
|
||||
* for use in update() related functions.
|
||||
* @param soundToCheck Which FlxSound object to check, defaults to FlxG.sound.music if no input
|
||||
* @return Float
|
||||
*/
|
||||
public function getTimeWithDiff(?soundToCheck:FlxSound):Float
|
||||
{
|
||||
if (soundToCheck == null) soundToCheck = FlxG.sound.music;
|
||||
// trace(this.songPosition);
|
||||
|
||||
@:privateAccess
|
||||
this.songPosition = soundToCheck._channel.position;
|
||||
// return this.songPosition + (Std.int(Timer.stamp() * 1000) - prevTimestamp);
|
||||
// trace("\t--> " + this.songPosition);
|
||||
return this.songPosition;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -468,7 +539,7 @@ class Conductor
|
|||
}
|
||||
|
||||
// Update currentStepTime
|
||||
this.update(Conductor.instance.songPosition);
|
||||
this.update(this.songPosition, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -587,7 +658,8 @@ class Conductor
|
|||
}
|
||||
|
||||
/**
|
||||
* Add variables of the current Conductor instance to the Flixel debugger.
|
||||
* Adds Conductor fields to the Flixel debugger variable display.
|
||||
* @param conductorToUse The conductor to use. Defaults to `Conductor.instance`.
|
||||
*/
|
||||
public static function watchQuick(?target:Conductor):Void
|
||||
{
|
||||
|
|
|
@ -16,14 +16,14 @@ import funkin.util.macro.MacroUtil;
|
|||
import funkin.util.WindowUtil;
|
||||
import funkin.play.PlayStatePlaylist;
|
||||
import openfl.display.BitmapData;
|
||||
import funkin.data.level.LevelRegistry;
|
||||
import funkin.data.story.level.LevelRegistry;
|
||||
import funkin.data.notestyle.NoteStyleRegistry;
|
||||
import funkin.data.event.SongEventRegistry;
|
||||
import funkin.data.stage.StageRegistry;
|
||||
import funkin.data.dialogue.ConversationRegistry;
|
||||
import funkin.data.dialogue.DialogueBoxRegistry;
|
||||
import funkin.data.dialogue.SpeakerRegistry;
|
||||
import funkin.data.freeplay.AlbumRegistry;
|
||||
import funkin.data.dialogue.conversation.ConversationRegistry;
|
||||
import funkin.data.dialogue.dialoguebox.DialogueBoxRegistry;
|
||||
import funkin.data.dialogue.speaker.SpeakerRegistry;
|
||||
import funkin.data.freeplay.album.AlbumRegistry;
|
||||
import funkin.data.song.SongRegistry;
|
||||
import funkin.play.character.CharacterData.CharacterDataParser;
|
||||
import funkin.modding.module.ModuleHandler;
|
||||
|
@ -304,7 +304,7 @@ class InitState extends FlxState
|
|||
*/
|
||||
function startLevel(levelId:String, difficultyId:String = 'normal'):Void
|
||||
{
|
||||
var currentLevel:funkin.ui.story.Level = funkin.data.level.LevelRegistry.instance.fetchEntry(levelId);
|
||||
var currentLevel:funkin.ui.story.Level = funkin.data.story.level.LevelRegistry.instance.fetchEntry(levelId);
|
||||
|
||||
if (currentLevel == null)
|
||||
{
|
||||
|
|
|
@ -120,7 +120,7 @@ class DataParse
|
|||
}
|
||||
}
|
||||
|
||||
public static function backdropData(json:Json, name:String):funkin.data.dialogue.ConversationData.BackdropData
|
||||
public static function backdropData(json:Json, name:String):funkin.data.dialogue.conversation.ConversationData.BackdropData
|
||||
{
|
||||
switch (json.value)
|
||||
{
|
||||
|
@ -152,7 +152,7 @@ class DataParse
|
|||
}
|
||||
}
|
||||
|
||||
public static function outroData(json:Json, name:String):Null<funkin.data.dialogue.ConversationData.OutroData>
|
||||
public static function outroData(json:Json, name:String):Null<funkin.data.dialogue.conversation.ConversationData.OutroData>
|
||||
{
|
||||
switch (json.value)
|
||||
{
|
||||
|
|
9
source/funkin/data/dialogue/conversation/CHANGELOG.md
Normal file
9
source/funkin/data/dialogue/conversation/CHANGELOG.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Dialogue Conversation Data Schema Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.0.0]
|
||||
Initial release.
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.data.dialogue;
|
||||
package funkin.data.dialogue.conversation;
|
||||
|
||||
import funkin.data.animation.AnimationData;
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package funkin.data.dialogue;
|
||||
package funkin.data.dialogue.conversation;
|
||||
|
||||
import funkin.play.cutscene.dialogue.Conversation;
|
||||
import funkin.data.dialogue.ConversationData;
|
||||
import funkin.data.dialogue.conversation.ConversationData;
|
||||
import funkin.play.cutscene.dialogue.ScriptedConversation;
|
||||
|
||||
class ConversationRegistry extends BaseRegistry<Conversation, ConversationData>
|
13
source/funkin/data/dialogue/dialoguebox/CHANGELOG.md
Normal file
13
source/funkin/data/dialogue/dialoguebox/CHANGELOG.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Dialogue Box Data Schema Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.1.0]
|
||||
### Added
|
||||
- Added an option to specify the font used by the dialogue box. Defaults to `Arial` if unspecified.
|
||||
|
||||
## [1.0.0]
|
||||
Initial release.
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.data.dialogue;
|
||||
package funkin.data.dialogue.dialoguebox;
|
||||
|
||||
import funkin.data.animation.AnimationData;
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package funkin.data.dialogue;
|
||||
package funkin.data.dialogue.dialoguebox;
|
||||
|
||||
import funkin.play.cutscene.dialogue.DialogueBox;
|
||||
import funkin.data.dialogue.DialogueBoxData;
|
||||
import funkin.data.dialogue.dialoguebox.DialogueBoxData;
|
||||
import funkin.play.cutscene.dialogue.ScriptedDialogueBox;
|
||||
|
||||
class DialogueBoxRegistry extends BaseRegistry<DialogueBox, DialogueBoxData>
|
9
source/funkin/data/dialogue/speaker/CHANGELOG.md
Normal file
9
source/funkin/data/dialogue/speaker/CHANGELOG.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Dialogue Speaker Data Schema Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.0.0]
|
||||
Initial release.
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.data.dialogue;
|
||||
package funkin.data.dialogue.speaker;
|
||||
|
||||
import funkin.data.animation.AnimationData;
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package funkin.data.dialogue;
|
||||
package funkin.data.dialogue.speaker;
|
||||
|
||||
import funkin.play.cutscene.dialogue.Speaker;
|
||||
import funkin.data.dialogue.SpeakerData;
|
||||
import funkin.data.dialogue.speaker.SpeakerData;
|
||||
import funkin.play.cutscene.dialogue.ScriptedSpeaker;
|
||||
|
||||
class SpeakerRegistry extends BaseRegistry<Speaker, SpeakerData>
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.data.freeplay;
|
||||
package funkin.data.freeplay.album;
|
||||
|
||||
import funkin.data.animation.AnimationData;
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package funkin.data.freeplay;
|
||||
package funkin.data.freeplay.album;
|
||||
|
||||
import funkin.ui.freeplay.Album;
|
||||
import funkin.data.freeplay.AlbumData;
|
||||
import funkin.data.freeplay.album.AlbumData;
|
||||
import funkin.ui.freeplay.ScriptedAlbum;
|
||||
|
||||
class AlbumRegistry extends BaseRegistry<Album, AlbumData>
|
9
source/funkin/data/freeplay/album/CHANGELOG.md
Normal file
9
source/funkin/data/freeplay/album/CHANGELOG.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Freeplay Album Data Schema Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.0.0]
|
||||
Initial release.
|
36
source/funkin/data/song/CHANGELOG.md
Normal file
36
source/funkin/data/song/CHANGELOG.md
Normal file
|
@ -0,0 +1,36 @@
|
|||
# Song Chart Data Schema Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [2.2.2]
|
||||
### Added
|
||||
- Added `playData.previewStart` and `playData.previewEnd` fields to specify when in the song should the song's audio should be played as a preview in Freeplay.
|
||||
|
||||
## [2.2.1]
|
||||
### Added
|
||||
- Added `playData.offsets` field to specify instrumental and vocal offsets.
|
||||
|
||||
## [2.2.0]
|
||||
### Added
|
||||
- Added `playData.album` to specify the album art to display in Freeplay.
|
||||
- Added `playData.ratings` for difficulty ratings displayed in Freeplay.
|
||||
### Changed
|
||||
- Renamed `playData.noteSkin` to `playData.noteStyle`.
|
||||
|
||||
## [2.1.0]
|
||||
### Changed
|
||||
- Rearranged the `playData` field.
|
||||
- Refactored the `playableChars`
|
||||
### Removed
|
||||
- Removed the `variation` field.
|
||||
|
||||
## [2.0.0]
|
||||
Full refactor of the chart format for improved structure.
|
||||
### Added
|
||||
- Added a semantic version field for migration tracking.
|
||||
|
||||
## [1.0.0]
|
||||
Initial version from 2020.
|
14
source/funkin/data/stage/CHANGELOG.md
Normal file
14
source/funkin/data/stage/CHANGELOG.md
Normal file
|
@ -0,0 +1,14 @@
|
|||
# Story Mode Level Data Schema Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.0.1]
|
||||
### Added
|
||||
- Added the ability to specify a hexadecimal color in the `assetPath` field instead of a texture key.
|
||||
- In this case, the `scale` property will be used to determine the size of the rectangle in pixels.
|
||||
|
||||
## [1.0.0]
|
||||
Initial release.
|
|
@ -11,7 +11,7 @@ class StageRegistry extends BaseRegistry<Stage, StageData>
|
|||
* Handle breaking changes by incrementing this value
|
||||
* and adding migration to the `migrateStageData()` function.
|
||||
*/
|
||||
public static final STAGE_DATA_VERSION:thx.semver.Version = "1.0.1";
|
||||
public static final STAGE_DATA_VERSION:thx.semver.Version = "1.0.0";
|
||||
|
||||
public static final STAGE_DATA_VERSION_RULE:thx.semver.VersionRule = "1.0.x";
|
||||
|
||||
|
|
9
source/funkin/data/story/level/CHANGELOG.md
Normal file
9
source/funkin/data/story/level/CHANGELOG.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Story Mode Level Data Schema Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.0.0]
|
||||
Initial release.
|
|
@ -1,4 +1,4 @@
|
|||
package funkin.data.level;
|
||||
package funkin.data.story.level;
|
||||
|
||||
import funkin.data.animation.AnimationData;
|
||||
|
||||
|
@ -13,7 +13,7 @@ typedef LevelData =
|
|||
* When making changes to the level data format, this should be incremented,
|
||||
* and a migration function should be added to LevelDataParser to handle old versions.
|
||||
*/
|
||||
@:default(funkin.data.level.LevelRegistry.LEVEL_DATA_VERSION)
|
||||
@:default(funkin.data.story.level.LevelRegistry.LEVEL_DATA_VERSION)
|
||||
var version:String;
|
||||
|
||||
/**
|
|
@ -1,7 +1,7 @@
|
|||
package funkin.data.level;
|
||||
package funkin.data.story.level;
|
||||
|
||||
import funkin.ui.story.Level;
|
||||
import funkin.data.level.LevelData;
|
||||
import funkin.data.story.level.LevelData;
|
||||
import funkin.ui.story.ScriptedLevel;
|
||||
|
||||
class LevelRegistry extends BaseRegistry<Level, LevelData>
|
|
@ -29,7 +29,7 @@ class HSVShader extends FlxRuntimeShader
|
|||
|
||||
function set_saturation(value:Float):Float
|
||||
{
|
||||
this.setFloat('sat', value);
|
||||
this.setFloat('_sat', value);
|
||||
this.saturation = value;
|
||||
|
||||
return this.saturation;
|
||||
|
@ -37,7 +37,7 @@ class HSVShader extends FlxRuntimeShader
|
|||
|
||||
function set_value(value:Float):Float
|
||||
{
|
||||
this.setFloat('val', value);
|
||||
this.setFloat('_val', value);
|
||||
this.value = value;
|
||||
|
||||
return this.value;
|
||||
|
|
|
@ -293,8 +293,9 @@ class PreciseInputManager extends FlxKeyManager<FlxKey, PreciseInputList>
|
|||
|
||||
// TODO: Remove this line with SDL3 when timestamps change meaning.
|
||||
// This is because SDL3's timestamps are measured in nanoseconds, not milliseconds.
|
||||
timestamp *= Constants.NS_PER_MS;
|
||||
|
||||
timestamp *= Constants.NS_PER_MS; // 18126000000 38367000000
|
||||
timestamp -= Conductor.instance.inputOffset * Constants.NS_PER_MS;
|
||||
// trace(timestamp);
|
||||
updateKeyStates(key, true);
|
||||
|
||||
if (getInputByKey(key)?.justPressed ?? false)
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
package funkin.modding;
|
||||
|
||||
import funkin.data.dialogue.ConversationRegistry;
|
||||
import funkin.data.dialogue.DialogueBoxRegistry;
|
||||
import funkin.data.dialogue.SpeakerRegistry;
|
||||
import funkin.data.dialogue.conversation.ConversationRegistry;
|
||||
import funkin.data.dialogue.dialoguebox.DialogueBoxRegistry;
|
||||
import funkin.data.dialogue.speaker.SpeakerRegistry;
|
||||
import funkin.data.event.SongEventRegistry;
|
||||
import funkin.data.level.LevelRegistry;
|
||||
import funkin.data.story.level.LevelRegistry;
|
||||
import funkin.data.notestyle.NoteStyleRegistry;
|
||||
import funkin.data.song.SongRegistry;
|
||||
import funkin.data.stage.StageRegistry;
|
||||
import funkin.data.freeplay.AlbumRegistry;
|
||||
import funkin.data.freeplay.album.AlbumRegistry;
|
||||
import funkin.modding.module.ModuleHandler;
|
||||
import funkin.play.character.CharacterData.CharacterDataParser;
|
||||
import funkin.save.Save;
|
||||
|
|
|
@ -2,14 +2,16 @@ package funkin.play;
|
|||
|
||||
import flixel.addons.transition.FlxTransitionableState;
|
||||
import flixel.FlxG;
|
||||
import flixel.util.FlxTimer;
|
||||
import flixel.FlxSprite;
|
||||
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||
import flixel.group.FlxSpriteGroup;
|
||||
import flixel.math.FlxMath;
|
||||
import flixel.sound.FlxSound;
|
||||
import flixel.text.FlxText;
|
||||
import flixel.tweens.FlxEase;
|
||||
import flixel.tweens.FlxTween;
|
||||
import flixel.util.FlxColor;
|
||||
import flixel.util.FlxTimer;
|
||||
import funkin.audio.FunkinSound;
|
||||
import funkin.data.song.SongRegistry;
|
||||
import funkin.ui.freeplay.FreeplayState;
|
||||
|
@ -17,6 +19,7 @@ import funkin.graphics.FunkinSprite;
|
|||
import funkin.play.cutscene.VideoCutscene;
|
||||
import funkin.play.PlayState;
|
||||
import funkin.ui.AtlasText;
|
||||
import funkin.ui.debug.latency.LatencyState;
|
||||
import funkin.ui.MusicBeatSubState;
|
||||
import funkin.ui.transition.StickerSubState;
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ import flixel.util.FlxTimer;
|
|||
import funkin.api.newgrounds.NGio;
|
||||
import funkin.audio.FunkinSound;
|
||||
import funkin.audio.VoicesGroup;
|
||||
import funkin.data.dialogue.ConversationRegistry;
|
||||
import funkin.data.dialogue.conversation.ConversationRegistry;
|
||||
import funkin.data.event.SongEventRegistry;
|
||||
import funkin.data.notestyle.NoteStyleData;
|
||||
import funkin.data.notestyle.NoteStyleRegistry;
|
||||
|
@ -890,7 +890,8 @@ class PlayState extends MusicBeatSubState
|
|||
{
|
||||
if (isInCountdown)
|
||||
{
|
||||
Conductor.instance.update(Conductor.instance.songPosition + elapsed * 1000);
|
||||
// Do NOT apply offsets at this point, because they already got applied the previous frame!
|
||||
Conductor.instance.update(Conductor.instance.songPosition + elapsed * 1000, false);
|
||||
if (Conductor.instance.songPosition >= (startTimestamp)) startSong();
|
||||
}
|
||||
}
|
||||
|
@ -2049,10 +2050,10 @@ class PlayState extends MusicBeatSubState
|
|||
{
|
||||
if (note == null) continue;
|
||||
|
||||
// TODO: Does this properly account for offsets?
|
||||
var hitWindowStart = note.strumTime - Constants.HIT_WINDOW_MS;
|
||||
var hitWindowCenter = note.strumTime;
|
||||
var hitWindowEnd = note.strumTime + Constants.HIT_WINDOW_MS;
|
||||
// TODO: Are offsets being accounted for in the correct direction?
|
||||
var hitWindowStart = note.strumTime + Conductor.instance.inputOffset - Constants.HIT_WINDOW_MS;
|
||||
var hitWindowCenter = note.strumTime + Conductor.instance.inputOffset;
|
||||
var hitWindowEnd = note.strumTime + Conductor.instance.inputOffset + Constants.HIT_WINDOW_MS;
|
||||
|
||||
if (Conductor.instance.songPosition > hitWindowEnd)
|
||||
{
|
||||
|
|
|
@ -42,7 +42,7 @@ class PopUpStuff extends FlxTypedGroup<FlxSprite>
|
|||
|
||||
if (PlayState.instance.currentStageId.startsWith('school'))
|
||||
{
|
||||
rating.setGraphicSize(Std.int(rating.width * Constants.PIXEL_ART_SCALE * 0.65));
|
||||
rating.setGraphicSize(Std.int(rating.width * Constants.PIXEL_ART_SCALE * 0.7));
|
||||
rating.antialiasing = false;
|
||||
}
|
||||
else
|
||||
|
@ -133,7 +133,7 @@ class PopUpStuff extends FlxTypedGroup<FlxSprite>
|
|||
|
||||
if (PlayState.instance.currentStageId.startsWith('school'))
|
||||
{
|
||||
numScore.setGraphicSize(Std.int(numScore.width * Constants.PIXEL_ART_SCALE));
|
||||
numScore.setGraphicSize(Std.int(numScore.width * Constants.PIXEL_ART_SCALE * 0.7));
|
||||
numScore.antialiasing = false;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -8,13 +8,13 @@ import flixel.tweens.FlxTween;
|
|||
import flixel.util.FlxColor;
|
||||
import flixel.util.FlxSort;
|
||||
import funkin.audio.FunkinSound;
|
||||
import funkin.data.dialogue.ConversationData;
|
||||
import funkin.data.dialogue.ConversationData.DialogueEntryData;
|
||||
import funkin.data.dialogue.ConversationRegistry;
|
||||
import funkin.data.dialogue.DialogueBoxData;
|
||||
import funkin.data.dialogue.DialogueBoxRegistry;
|
||||
import funkin.data.dialogue.SpeakerData;
|
||||
import funkin.data.dialogue.SpeakerRegistry;
|
||||
import funkin.data.dialogue.conversation.ConversationData;
|
||||
import funkin.data.dialogue.conversation.ConversationData.DialogueEntryData;
|
||||
import funkin.data.dialogue.conversation.ConversationRegistry;
|
||||
import funkin.data.dialogue.dialoguebox.DialogueBoxData;
|
||||
import funkin.data.dialogue.dialoguebox.DialogueBoxRegistry;
|
||||
import funkin.data.dialogue.speaker.SpeakerData;
|
||||
import funkin.data.dialogue.speaker.SpeakerRegistry;
|
||||
import funkin.data.IRegistryEntry;
|
||||
import funkin.graphics.FunkinSprite;
|
||||
import funkin.modding.events.ScriptEvent;
|
||||
|
|
|
@ -11,8 +11,8 @@ import funkin.modding.events.ScriptEvent;
|
|||
import funkin.audio.FunkinSound;
|
||||
import funkin.modding.IScriptedClass.IDialogueScriptedClass;
|
||||
import flixel.util.FlxColor;
|
||||
import funkin.data.dialogue.DialogueBoxData;
|
||||
import funkin.data.dialogue.DialogueBoxRegistry;
|
||||
import funkin.data.dialogue.dialoguebox.DialogueBoxData;
|
||||
import funkin.data.dialogue.dialoguebox.DialogueBoxRegistry;
|
||||
|
||||
class DialogueBox extends FlxSpriteGroup implements IDialogueScriptedClass implements IRegistryEntry<DialogueBoxData>
|
||||
{
|
||||
|
|
|
@ -6,8 +6,8 @@ import funkin.modding.events.ScriptEvent;
|
|||
import flixel.graphics.frames.FlxFramesCollection;
|
||||
import funkin.util.assets.FlxAnimationUtil;
|
||||
import funkin.modding.IScriptedClass.IDialogueScriptedClass;
|
||||
import funkin.data.dialogue.SpeakerData;
|
||||
import funkin.data.dialogue.SpeakerRegistry;
|
||||
import funkin.data.dialogue.speaker.SpeakerData;
|
||||
import funkin.data.dialogue.speaker.SpeakerRegistry;
|
||||
|
||||
/**
|
||||
* The character sprite which displays during dialogue.
|
||||
|
|
|
@ -127,7 +127,7 @@ class FocusCameraSongEvent extends SongEvent
|
|||
switch (ease)
|
||||
{
|
||||
case 'CLASSIC': // Old-school. No ease. Just set follow point.
|
||||
PlayState.instance.resetCamera();
|
||||
PlayState.instance.resetCamera(false, true);
|
||||
PlayState.instance.cameraFollowPoint.setPosition(targetX, targetY);
|
||||
case 'INSTANT': // Instant ease. Duration is automatically 0.
|
||||
PlayState.instance.tweenCameraToPosition(targetX, targetY, 0);
|
||||
|
|
|
@ -15,6 +15,7 @@ import funkin.play.notes.SustainTrail;
|
|||
import funkin.data.song.SongData.SongNoteData;
|
||||
import funkin.ui.options.PreferencesMenu;
|
||||
import funkin.util.SortUtil;
|
||||
import funkin.modding.events.ScriptEvent;
|
||||
|
||||
/**
|
||||
* A group of sprites which handles the receptor, the note splashes, and the notes (with sustains) for a given player.
|
||||
|
@ -45,6 +46,25 @@ class Strumline extends FlxSpriteGroup
|
|||
*/
|
||||
public var isPlayer:Bool;
|
||||
|
||||
/**
|
||||
* Usually you want to keep this as is, but if you are using a Strumline and
|
||||
* playing a sound that has it's own conductor, set this (LatencyState for example)
|
||||
*/
|
||||
public var conductorInUse(get, set):Conductor;
|
||||
|
||||
var _conductorInUse:Null<Conductor>;
|
||||
|
||||
function get_conductorInUse():Conductor
|
||||
{
|
||||
if (_conductorInUse == null) return Conductor.instance;
|
||||
return _conductorInUse;
|
||||
}
|
||||
|
||||
function set_conductorInUse(value:Conductor):Conductor
|
||||
{
|
||||
return _conductorInUse = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The notes currently being rendered on the strumline.
|
||||
* This group iterates over this every frame to update note positions.
|
||||
|
@ -151,24 +171,10 @@ class Strumline extends FlxSpriteGroup
|
|||
updateNotes();
|
||||
}
|
||||
|
||||
var frameMax:Int;
|
||||
var animFinishedEver:Bool;
|
||||
|
||||
/**
|
||||
* Get a list of notes within + or - the given strumtime.
|
||||
* @param strumTime The current time.
|
||||
* @param hitWindow The hit window to check.
|
||||
* Return notes that are within `Constants.HIT_WINDOW` ms of the strumline.
|
||||
* @return An array of `NoteSprite` objects.
|
||||
*/
|
||||
public function getNotesInRange(strumTime:Float, hitWindow:Float):Array<NoteSprite>
|
||||
{
|
||||
var hitWindowStart:Float = strumTime - hitWindow;
|
||||
var hitWindowEnd:Float = strumTime + hitWindow;
|
||||
|
||||
return notes.members.filter(function(note:NoteSprite) {
|
||||
return note != null && note.alive && !note.hasBeenHit && note.strumTime >= hitWindowStart && note.strumTime <= hitWindowEnd;
|
||||
});
|
||||
}
|
||||
|
||||
public function getNotesMayHit():Array<NoteSprite>
|
||||
{
|
||||
return notes.members.filter(function(note:NoteSprite) {
|
||||
|
@ -176,6 +182,10 @@ class Strumline extends FlxSpriteGroup
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return hold notes that are within `Constants.HIT_WINDOW` ms of the strumline.
|
||||
* @return An array of `SustainTrail` objects.
|
||||
*/
|
||||
public function getHoldNotesHitOrMissed():Array<SustainTrail>
|
||||
{
|
||||
return holdNotes.members.filter(function(holdNote:SustainTrail) {
|
||||
|
@ -183,19 +193,6 @@ class Strumline extends FlxSpriteGroup
|
|||
});
|
||||
}
|
||||
|
||||
public function getHoldNotesInRange(strumTime:Float, hitWindow:Float):Array<SustainTrail>
|
||||
{
|
||||
var hitWindowStart:Float = strumTime - hitWindow;
|
||||
var hitWindowEnd:Float = strumTime + hitWindow;
|
||||
|
||||
return holdNotes.members.filter(function(note:SustainTrail) {
|
||||
return note != null
|
||||
&& note.alive
|
||||
&& note.strumTime >= hitWindowStart
|
||||
&& (note.strumTime + note.fullSustainLength) <= hitWindowEnd;
|
||||
});
|
||||
}
|
||||
|
||||
public function getNoteSprite(noteData:SongNoteData):NoteSprite
|
||||
{
|
||||
if (noteData == null) return null;
|
||||
|
@ -280,7 +277,7 @@ class Strumline extends FlxSpriteGroup
|
|||
* @param strumTime
|
||||
* @return Float
|
||||
*/
|
||||
static function calculateNoteYPos(strumTime:Float, vwoosh:Bool = true):Float
|
||||
public function calculateNoteYPos(strumTime:Float, vwoosh:Bool = true):Float
|
||||
{
|
||||
// Make the note move faster visually as it moves offscreen.
|
||||
// var vwoosh:Float = (strumTime < Conductor.songPosition) && vwoosh ? 2.0 : 1.0;
|
||||
|
@ -288,7 +285,8 @@ class Strumline extends FlxSpriteGroup
|
|||
var vwoosh:Float = 1.0;
|
||||
var scrollSpeed:Float = PlayState.instance?.currentChart?.scrollSpeed ?? 1.0;
|
||||
|
||||
return Constants.PIXELS_PER_MS * (Conductor.instance.songPosition - strumTime) * scrollSpeed * vwoosh * (Preferences.downscroll ? 1 : -1);
|
||||
return
|
||||
Constants.PIXELS_PER_MS * (conductorInUse.songPosition - strumTime - Conductor.instance.inputOffset) * scrollSpeed * vwoosh * (Preferences.downscroll ? 1 : -1);
|
||||
}
|
||||
|
||||
function updateNotes():Void
|
||||
|
@ -301,8 +299,8 @@ class Strumline extends FlxSpriteGroup
|
|||
// if (conductorInUse.currentStep == 0) nextNoteIndex = 0;
|
||||
|
||||
var songStart:Float = PlayState.instance?.startTimestamp ?? 0.0;
|
||||
var hitWindowStart:Float = Conductor.instance.songPosition - Constants.HIT_WINDOW_MS;
|
||||
var renderWindowStart:Float = Conductor.instance.songPosition + RENDER_DISTANCE_MS;
|
||||
var hitWindowStart:Float = conductorInUse.songPosition - Constants.HIT_WINDOW_MS;
|
||||
var renderWindowStart:Float = conductorInUse.songPosition + RENDER_DISTANCE_MS;
|
||||
|
||||
for (noteIndex in nextNoteIndex...noteData.length)
|
||||
{
|
||||
|
@ -351,7 +349,7 @@ class Strumline extends FlxSpriteGroup
|
|||
{
|
||||
if (holdNote == null || !holdNote.alive) continue;
|
||||
|
||||
if (Conductor.instance.songPosition > holdNote.strumTime && holdNote.hitNote && !holdNote.missedNote)
|
||||
if (conductorInUse.songPosition > holdNote.strumTime && holdNote.hitNote && !holdNote.missedNote)
|
||||
{
|
||||
if (isPlayer && !isKeyHeld(holdNote.noteDirection))
|
||||
{
|
||||
|
@ -365,7 +363,7 @@ class Strumline extends FlxSpriteGroup
|
|||
|
||||
var renderWindowEnd = holdNote.strumTime + holdNote.fullSustainLength + Constants.HIT_WINDOW_MS + RENDER_DISTANCE_MS / 8;
|
||||
|
||||
if (holdNote.missedNote && Conductor.instance.songPosition >= renderWindowEnd)
|
||||
if (holdNote.missedNote && conductorInUse.songPosition >= renderWindowEnd)
|
||||
{
|
||||
// Hold note is offscreen, kill it.
|
||||
holdNote.visible = false;
|
||||
|
@ -422,13 +420,13 @@ class Strumline extends FlxSpriteGroup
|
|||
holdNote.cover.kill();
|
||||
}
|
||||
}
|
||||
else if (Conductor.instance.songPosition > holdNote.strumTime && holdNote.hitNote)
|
||||
else if (conductorInUse.songPosition > holdNote.strumTime && holdNote.hitNote)
|
||||
{
|
||||
// Hold note is currently being hit, clip it off.
|
||||
holdConfirm(holdNote.noteDirection);
|
||||
holdNote.visible = true;
|
||||
|
||||
holdNote.sustainLength = (holdNote.strumTime + holdNote.fullSustainLength) - Conductor.instance.songPosition;
|
||||
holdNote.sustainLength = (holdNote.strumTime + holdNote.fullSustainLength) - conductorInUse.songPosition;
|
||||
|
||||
if (holdNote.sustainLength <= 10)
|
||||
{
|
||||
|
|
|
@ -87,6 +87,8 @@ class Save
|
|||
zoomCamera: true,
|
||||
debugDisplay: false,
|
||||
autoPause: true,
|
||||
inputOffset: 0,
|
||||
audioVisualOffset: 0,
|
||||
|
||||
controls:
|
||||
{
|
||||
|
@ -866,6 +868,18 @@ typedef SaveDataOptions =
|
|||
*/
|
||||
var autoPause:Bool;
|
||||
|
||||
/**
|
||||
* Offset the users inputs by this many ms.
|
||||
* @default `0`
|
||||
*/
|
||||
var inputOffset:Int;
|
||||
|
||||
/**
|
||||
* Affects the delay between the audio and the visuals during gameplay
|
||||
* @default `0`
|
||||
*/
|
||||
var audioVisualOffset:Int;
|
||||
|
||||
var controls:
|
||||
{
|
||||
var p1:
|
||||
|
|
12
source/funkin/save/changelog.md
Normal file
12
source/funkin/save/changelog.md
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
|
||||
## [2.0.3] - 2024-01-09
|
||||
### Added
|
||||
- `inputOffset:Float` to `SongDataOptions`
|
||||
- `audioVisualOffset:Float` to `SongDataOptions`
|
|
@ -29,6 +29,21 @@ class MusicBeatState extends FlxTransitionableState implements IEventHandler
|
|||
public var leftWatermarkText:FlxText = null;
|
||||
public var rightWatermarkText:FlxText = null;
|
||||
|
||||
public var conductorInUse(get, set):Conductor;
|
||||
|
||||
var _conductorInUse:Null<Conductor>;
|
||||
|
||||
function get_conductorInUse():Conductor
|
||||
{
|
||||
if (_conductorInUse == null) return Conductor.instance;
|
||||
return _conductorInUse;
|
||||
}
|
||||
|
||||
function set_conductorInUse(value:Conductor):Conductor
|
||||
{
|
||||
return _conductorInUse = value;
|
||||
}
|
||||
|
||||
public function new()
|
||||
{
|
||||
super();
|
||||
|
@ -111,7 +126,7 @@ class MusicBeatState extends FlxTransitionableState implements IEventHandler
|
|||
|
||||
public function stepHit():Bool
|
||||
{
|
||||
var event = new SongTimeScriptEvent(SONG_STEP_HIT, Conductor.instance.currentBeat, Conductor.instance.currentStep);
|
||||
var event = new SongTimeScriptEvent(SONG_STEP_HIT, conductorInUse.currentBeat, conductorInUse.currentStep);
|
||||
|
||||
dispatchEvent(event);
|
||||
|
||||
|
@ -122,7 +137,7 @@ class MusicBeatState extends FlxTransitionableState implements IEventHandler
|
|||
|
||||
public function beatHit():Bool
|
||||
{
|
||||
var event = new SongTimeScriptEvent(SONG_BEAT_HIT, Conductor.instance.currentBeat, Conductor.instance.currentStep);
|
||||
var event = new SongTimeScriptEvent(SONG_BEAT_HIT, conductorInUse.currentBeat, conductorInUse.currentStep);
|
||||
|
||||
dispatchEvent(event);
|
||||
|
||||
|
|
|
@ -21,6 +21,21 @@ class MusicBeatSubState extends FlxSubState implements IEventHandler
|
|||
public var leftWatermarkText:FlxText = null;
|
||||
public var rightWatermarkText:FlxText = null;
|
||||
|
||||
public var conductorInUse(get, set):Conductor;
|
||||
|
||||
var _conductorInUse:Null<Conductor>;
|
||||
|
||||
function get_conductorInUse():Conductor
|
||||
{
|
||||
if (_conductorInUse == null) return Conductor.instance;
|
||||
return _conductorInUse;
|
||||
}
|
||||
|
||||
function set_conductorInUse(value:Conductor):Conductor
|
||||
{
|
||||
return _conductorInUse = value;
|
||||
}
|
||||
|
||||
public function new(bgColor:FlxColor = FlxColor.TRANSPARENT)
|
||||
{
|
||||
super();
|
||||
|
@ -51,7 +66,6 @@ class MusicBeatSubState extends FlxSubState implements IEventHandler
|
|||
|
||||
override function update(elapsed:Float):Void
|
||||
{
|
||||
// 3.59% CPU Usage (100% is FlxTypedGroup#update() and most of that is updating each member.)
|
||||
super.update(elapsed);
|
||||
|
||||
// Emergency exit button.
|
||||
|
@ -62,11 +76,8 @@ class MusicBeatSubState extends FlxSubState implements IEventHandler
|
|||
|
||||
// Display Conductor info in the watch window.
|
||||
FlxG.watch.addQuick("musicTime", FlxG.sound.music?.time ?? 0.0);
|
||||
Conductor.watchQuick(conductorInUse);
|
||||
|
||||
// 0.09% CPU Usage?
|
||||
Conductor.watchQuick();
|
||||
|
||||
// 4.31% CPU Usage
|
||||
dispatchEvent(new UpdateScriptEvent(elapsed));
|
||||
}
|
||||
|
||||
|
@ -94,7 +105,7 @@ class MusicBeatSubState extends FlxSubState implements IEventHandler
|
|||
*/
|
||||
public function stepHit():Bool
|
||||
{
|
||||
var event:ScriptEvent = new SongTimeScriptEvent(SONG_STEP_HIT, Conductor.instance.currentBeat, Conductor.instance.currentStep);
|
||||
var event:ScriptEvent = new SongTimeScriptEvent(SONG_STEP_HIT, conductorInUse.currentBeat, conductorInUse.currentStep);
|
||||
|
||||
dispatchEvent(event);
|
||||
|
||||
|
@ -110,7 +121,7 @@ class MusicBeatSubState extends FlxSubState implements IEventHandler
|
|||
*/
|
||||
public function beatHit():Bool
|
||||
{
|
||||
var event:ScriptEvent = new SongTimeScriptEvent(SONG_BEAT_HIT, Conductor.instance.currentBeat, Conductor.instance.currentStep);
|
||||
var event:ScriptEvent = new SongTimeScriptEvent(SONG_BEAT_HIT, conductorInUse.currentBeat, conductorInUse.currentStep);
|
||||
|
||||
dispatchEvent(event);
|
||||
|
||||
|
|
|
@ -23,7 +23,9 @@ class DebugMenuSubState extends MusicBeatSubState
|
|||
|
||||
override function create():Void
|
||||
{
|
||||
FlxTransitionableState.skipNextTransIn = true;
|
||||
super.create();
|
||||
|
||||
bgColor = 0x00000000;
|
||||
|
||||
// Create an object for the camera to track.
|
||||
|
@ -48,9 +50,12 @@ class DebugMenuSubState extends MusicBeatSubState
|
|||
items.onChange.add(onMenuChange);
|
||||
add(items);
|
||||
|
||||
FlxTransitionableState.skipNextTransIn = true;
|
||||
|
||||
// Create each menu item.
|
||||
// Call onMenuChange when the first item is created to move the camera .
|
||||
onMenuChange(createItem("CHART EDITOR", openChartEditor));
|
||||
createItem("Input Offset Testing", openInputOffsetTesting);
|
||||
createItem("ANIMATION EDITOR", openAnimationEditor);
|
||||
createItem("STAGE EDITOR", openStageEditor);
|
||||
createItem("TEST STICKERS", testStickers);
|
||||
|
@ -92,6 +97,12 @@ class DebugMenuSubState extends MusicBeatSubState
|
|||
FlxG.switchState(() -> new ChartEditorState());
|
||||
}
|
||||
|
||||
function openInputOffsetTesting()
|
||||
{
|
||||
openSubState(new funkin.ui.debug.latency.LatencyState());
|
||||
trace('Input Offset Testing');
|
||||
}
|
||||
|
||||
function openAnimationEditor()
|
||||
{
|
||||
FlxG.switchState(() -> new funkin.ui.debug.anim.DebugBoundingState());
|
||||
|
|
|
@ -5,13 +5,13 @@ import funkin.modding.events.ScriptEventDispatcher;
|
|||
import funkin.modding.events.ScriptEvent;
|
||||
import flixel.util.FlxColor;
|
||||
import funkin.ui.MusicBeatState;
|
||||
import funkin.data.dialogue.ConversationData;
|
||||
import funkin.data.dialogue.ConversationRegistry;
|
||||
import funkin.data.dialogue.DialogueBoxData;
|
||||
import funkin.data.dialogue.DialogueBoxRegistry;
|
||||
import funkin.data.dialogue.SpeakerData;
|
||||
import funkin.data.dialogue.SpeakerRegistry;
|
||||
import funkin.data.freeplay.AlbumRegistry;
|
||||
import funkin.data.dialogue.conversation.ConversationData;
|
||||
import funkin.data.dialogue.conversation.ConversationRegistry;
|
||||
import funkin.data.dialogue.dialoguebox.DialogueBoxData;
|
||||
import funkin.data.dialogue.dialoguebox.DialogueBoxRegistry;
|
||||
import funkin.data.dialogue.speaker.SpeakerData;
|
||||
import funkin.data.dialogue.speaker.SpeakerRegistry;
|
||||
import funkin.data.freeplay.album.AlbumRegistry;
|
||||
import funkin.play.cutscene.dialogue.Conversation;
|
||||
import funkin.play.cutscene.dialogue.DialogueBox;
|
||||
import funkin.play.cutscene.dialogue.Speaker;
|
||||
|
|
|
@ -7,7 +7,6 @@ import flash.text.TextField;
|
|||
import flash.text.TextFormatAlign;
|
||||
import flixel.math.FlxMath;
|
||||
import flixel.system.debug.DebuggerUtil;
|
||||
import flixel.system.debug.stats.Stats;
|
||||
import flixel.util.FlxColor;
|
||||
import flixel.util.FlxDestroyUtil;
|
||||
|
||||
|
@ -16,13 +15,31 @@ import flixel.util.FlxDestroyUtil;
|
|||
* SHAMELESSLY STOLEN FROM FLIXEL
|
||||
* https://github.com/HaxeFlixel/flixel/blob/master/flixel/system/debug/stats/StatsGraph.hx
|
||||
*/
|
||||
#if FLX_DEBUG
|
||||
class CoolStatsGraph extends Sprite
|
||||
{
|
||||
static inline var AXIS_COLOR:FlxColor = 0xffffff;
|
||||
static inline var AXIS_ALPHA:Float = 0.5;
|
||||
static inline var HISTORY_MAX:Int = 500;
|
||||
|
||||
/**
|
||||
* How often to update the stats, in ms. The lower, the more performance-intense!
|
||||
*/
|
||||
static inline var UPDATE_DELAY:Int = 250;
|
||||
|
||||
/**
|
||||
* The initial width of the stats window.
|
||||
*/
|
||||
static inline var INITIAL_WIDTH:Int = 160;
|
||||
|
||||
static inline var FPS_COLOR:FlxColor = 0xff96ff00;
|
||||
static inline var MEMORY_COLOR:FlxColor = 0xff009cff;
|
||||
static inline var DRAW_TIME_COLOR:FlxColor = 0xffA60004;
|
||||
static inline var UPDATE_TIME_COLOR:FlxColor = 0xffdcd400;
|
||||
|
||||
public static inline var LABEL_COLOR:FlxColor = 0xaaffffff;
|
||||
public static inline var TEXT_SIZE:Int = 11;
|
||||
public static inline var DECIMALS:Int = 1;
|
||||
|
||||
public var minLabel:TextField;
|
||||
public var curLabel:TextField;
|
||||
public var maxLabel:TextField;
|
||||
|
@ -45,6 +62,7 @@ class CoolStatsGraph extends Sprite
|
|||
public function new(X:Int, Y:Int, Width:Int, Height:Int, GraphColor:FlxColor, Unit:String, LabelWidth:Int = 45, ?Label:String)
|
||||
{
|
||||
super();
|
||||
|
||||
x = X;
|
||||
y = Y;
|
||||
_width = Width - LabelWidth;
|
||||
|
@ -57,11 +75,11 @@ class CoolStatsGraph extends Sprite
|
|||
_axis = new Shape();
|
||||
_axis.x = _labelWidth + 10;
|
||||
|
||||
maxLabel = DebuggerUtil.createTextField(0, 0, Stats.LABEL_COLOR, Stats.TEXT_SIZE);
|
||||
curLabel = DebuggerUtil.createTextField(0, (_height / 2) - (Stats.TEXT_SIZE / 2), graphColor, Stats.TEXT_SIZE);
|
||||
minLabel = DebuggerUtil.createTextField(0, _height - Stats.TEXT_SIZE, Stats.LABEL_COLOR, Stats.TEXT_SIZE);
|
||||
maxLabel = DebuggerUtil.createTextField(0, 0, LABEL_COLOR, TEXT_SIZE);
|
||||
curLabel = DebuggerUtil.createTextField(0, (_height / 2) - (TEXT_SIZE / 2), graphColor, TEXT_SIZE);
|
||||
minLabel = DebuggerUtil.createTextField(0, _height - TEXT_SIZE, LABEL_COLOR, TEXT_SIZE);
|
||||
|
||||
avgLabel = DebuggerUtil.createTextField(_labelWidth + 20, (_height / 2) - (Stats.TEXT_SIZE / 2) - 10, Stats.LABEL_COLOR, Stats.TEXT_SIZE);
|
||||
avgLabel = DebuggerUtil.createTextField(_labelWidth + 20, (_height / 2) - (TEXT_SIZE / 2) - 10, LABEL_COLOR, TEXT_SIZE);
|
||||
avgLabel.width = _width;
|
||||
avgLabel.defaultTextFormat.align = TextFormatAlign.CENTER;
|
||||
avgLabel.alpha = 0.5;
|
||||
|
@ -136,7 +154,7 @@ class CoolStatsGraph extends Sprite
|
|||
|
||||
function formatValue(value:Float):String
|
||||
{
|
||||
return FlxMath.roundDecimal(value, Stats.DECIMALS) + " " + _unit;
|
||||
return FlxMath.roundDecimal(value, DECIMALS) + " " + _unit;
|
||||
}
|
||||
|
||||
public function average():Float
|
||||
|
@ -157,4 +175,3 @@ class CoolStatsGraph extends Sprite
|
|||
history = null;
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
|
|
@ -8,20 +8,27 @@ import flixel.group.FlxGroup.FlxTypedGroup;
|
|||
import flixel.math.FlxMath;
|
||||
import funkin.ui.MusicBeatSubState;
|
||||
import flixel.sound.FlxSound;
|
||||
import flixel.system.debug.stats.StatsGraph;
|
||||
import flixel.text.FlxText;
|
||||
import flixel.util.FlxColor;
|
||||
import funkin.audio.visualize.PolygonSpectogram;
|
||||
import funkin.play.notes.NoteSprite;
|
||||
import funkin.ui.debug.latency.CoolStatsGraph;
|
||||
import haxe.Timer;
|
||||
import openfl.events.KeyboardEvent;
|
||||
import funkin.input.PreciseInputManager;
|
||||
import funkin.play.notes.Strumline;
|
||||
import funkin.play.notes.notestyle.NoteStyle;
|
||||
import funkin.data.notestyle.NoteStyleData;
|
||||
import funkin.data.notestyle.NoteStyleRegistry;
|
||||
import funkin.data.song.SongData.SongNoteData;
|
||||
import haxe.Timer;
|
||||
import flixel.FlxCamera;
|
||||
|
||||
class LatencyState extends MusicBeatSubState
|
||||
{
|
||||
var visualOffsetText:FlxText;
|
||||
var offsetText:FlxText;
|
||||
var noteGrp:FlxTypedGroup<NoteSprite>;
|
||||
var strumLine:FlxSprite;
|
||||
var noteGrp:Array<SongNoteData> = [];
|
||||
var strumLine:Strumline;
|
||||
|
||||
var blocks:FlxTypedGroup<FlxSprite>;
|
||||
|
||||
|
@ -31,76 +38,81 @@ class LatencyState extends MusicBeatSubState
|
|||
|
||||
var beatTrail:FlxSprite;
|
||||
var diffGrp:FlxTypedGroup<FlxText>;
|
||||
var offsetsPerBeat:Array<Int> = [];
|
||||
var offsetsPerBeat:Array<Null<Int>> = [];
|
||||
var swagSong:HomemadeMusic;
|
||||
|
||||
#if FLX_DEBUG
|
||||
var funnyStatsGraph:CoolStatsGraph;
|
||||
var realStats:CoolStatsGraph;
|
||||
#end
|
||||
var previousVolume:Float;
|
||||
|
||||
var stateCamera:FlxCamera;
|
||||
|
||||
/**
|
||||
* A local conductor instance for this testing class, in-case we are in a PlayState
|
||||
* because I'm too lazy to set the old variables for conductor stuff !
|
||||
*/
|
||||
var localConductor:Conductor;
|
||||
|
||||
// stores values of what the previous persistent draw/update stuff was, example if opened
|
||||
// from pause menu, we want to NOT draw persistently, but then resume drawing once closed
|
||||
var prevPersistentDraw:Bool;
|
||||
var prevPersistentUpdate:Bool;
|
||||
|
||||
override function create()
|
||||
{
|
||||
super.create();
|
||||
|
||||
prevPersistentDraw = FlxG.state.persistentDraw;
|
||||
prevPersistentUpdate = FlxG.state.persistentUpdate;
|
||||
|
||||
FlxG.state.persistentDraw = false;
|
||||
FlxG.state.persistentUpdate = false;
|
||||
|
||||
localConductor = new Conductor();
|
||||
conductorInUse = localConductor;
|
||||
|
||||
stateCamera = new FlxCamera(0, 0, FlxG.width, FlxG.height);
|
||||
stateCamera.bgColor = FlxColor.BLACK;
|
||||
FlxG.cameras.add(stateCamera);
|
||||
|
||||
var bg:FlxSprite = new FlxSprite().makeGraphic(FlxG.width, FlxG.height, FlxColor.BLACK);
|
||||
add(bg);
|
||||
|
||||
if (FlxG.sound.music != null)
|
||||
{
|
||||
previousVolume = FlxG.sound.music.volume;
|
||||
FlxG.sound.music.volume = 0; // only want to mute the volume, incase we are coming from pause menu
|
||||
}
|
||||
else
|
||||
previousVolume = 1; // defaults to 1 if no music is playing 🤔 also fuck it, emoji in code comment
|
||||
|
||||
swagSong = new HomemadeMusic();
|
||||
swagSong.loadEmbedded(Paths.sound('soundTest'), true);
|
||||
swagSong.looped = true;
|
||||
swagSong.play();
|
||||
FlxG.sound.list.add(swagSong);
|
||||
|
||||
FlxG.sound.music = swagSong;
|
||||
FlxG.sound.music.play();
|
||||
PreciseInputManager.instance.onInputPressed.add(preciseInputPressed);
|
||||
|
||||
#if FLX_DEBUG
|
||||
funnyStatsGraph = new CoolStatsGraph(0, Std.int(FlxG.height / 2), FlxG.width, Std.int(FlxG.height / 2), FlxColor.PINK, "time");
|
||||
FlxG.addChildBelowMouse(funnyStatsGraph);
|
||||
PreciseInputManager.instance.onInputReleased.add(preciseInputReleased);
|
||||
|
||||
realStats = new CoolStatsGraph(0, Std.int(FlxG.height / 2), FlxG.width, Std.int(FlxG.height / 2), FlxColor.YELLOW, "REAL");
|
||||
FlxG.addChildBelowMouse(realStats);
|
||||
#end
|
||||
|
||||
FlxG.stage.addEventListener(KeyboardEvent.KEY_DOWN, key -> {
|
||||
trace(key.charCode);
|
||||
|
||||
if (key.charCode == 120) generateBeatStuff();
|
||||
|
||||
trace("\tEVENT PRESS: \t" + FlxG.sound.music.time + " " + Timer.stamp());
|
||||
// trace(FlxG.sound.music.prevTimestamp);
|
||||
trace(FlxG.sound.music.time);
|
||||
trace("\tFR FR PRESS: \t" + swagSong.getTimeWithDiff());
|
||||
|
||||
// trace("\tREDDIT: \t" + swagSong.frfrTime + " " + Timer.stamp());
|
||||
@:privateAccess
|
||||
trace("\tREDDIT: \t" + FlxG.sound.music._channel.position + " " + Timer.stamp());
|
||||
// trace("EVENT LISTENER: " + key);
|
||||
});
|
||||
|
||||
// funnyStatsGraph.hi
|
||||
localConductor.forceBPM(60);
|
||||
|
||||
Conductor.instance.forceBPM(60);
|
||||
|
||||
noteGrp = new FlxTypedGroup<NoteSprite>();
|
||||
add(noteGrp);
|
||||
|
||||
diffGrp = new FlxTypedGroup<FlxText>();
|
||||
add(diffGrp);
|
||||
|
||||
// var musSpec:PolygonSpectogram = new PolygonSpectogram(FlxG.sound.music, FlxColor.RED, FlxG.height, Math.floor(FlxG.height / 2));
|
||||
// musSpec.x += 170;
|
||||
// musSpec.scrollFactor.set();
|
||||
// musSpec.waveAmplitude = 100;
|
||||
// musSpec.realtimeVisLenght = 0.45;
|
||||
// // musSpec.visType = FREQUENCIES;
|
||||
// add(musSpec);
|
||||
|
||||
for (beat in 0...Math.floor(FlxG.sound.music.length / Conductor.instance.beatLengthMs))
|
||||
for (beat in 0...Math.floor(swagSong.length / (localConductor.stepLengthMs * 2)))
|
||||
{
|
||||
var beatTick:FlxSprite = new FlxSprite(songPosToX(beat * Conductor.instance.beatLengthMs), FlxG.height - 15);
|
||||
var beatTick:FlxSprite = new FlxSprite(songPosToX(beat * (localConductor.stepLengthMs * 2)), FlxG.height - 15);
|
||||
beatTick.makeGraphic(2, 15);
|
||||
beatTick.alpha = 0.3;
|
||||
add(beatTick);
|
||||
|
||||
var offsetTxt:FlxText = new FlxText(songPosToX(beat * Conductor.instance.beatLengthMs), FlxG.height - 26, 0, "swag");
|
||||
var offsetTxt:FlxText = new FlxText(songPosToX(beat * (localConductor.stepLengthMs * 2)), FlxG.height - 26, 0, "");
|
||||
offsetTxt.alpha = 0.5;
|
||||
diffGrp.add(offsetTxt);
|
||||
|
||||
offsetsPerBeat.push(0);
|
||||
offsetsPerBeat.push(null);
|
||||
}
|
||||
|
||||
songVisFollowAudio = new FlxSprite(0, FlxG.height - 20).makeGraphic(2, 20, FlxColor.YELLOW);
|
||||
|
@ -121,32 +133,92 @@ class LatencyState extends MusicBeatSubState
|
|||
|
||||
for (i in 0...8)
|
||||
{
|
||||
var block = new FlxSprite(2, 50 * i).makeGraphic(48, 48);
|
||||
block.alpha = 0;
|
||||
var block = new FlxSprite(2, ((FlxG.height / 8) + 2) * i).makeGraphic(Std.int(FlxG.height / 8), Std.int((FlxG.height / 8) - 4));
|
||||
block.alpha = 0.1;
|
||||
blocks.add(block);
|
||||
}
|
||||
|
||||
for (i in 0...32)
|
||||
{
|
||||
var note:NoteSprite = new NoteSprite(NoteStyleRegistry.instance.fetchDefault());
|
||||
noteGrp.add(note);
|
||||
}
|
||||
var strumlineBG:FlxSprite = new FlxSprite();
|
||||
add(strumlineBG);
|
||||
|
||||
offsetText = new FlxText();
|
||||
offsetText.screenCenter();
|
||||
add(offsetText);
|
||||
|
||||
strumLine = new FlxSprite(FlxG.width / 2, 100).makeGraphic(FlxG.width, 5);
|
||||
strumLine = new Strumline(NoteStyleRegistry.instance.fetchDefault(), true);
|
||||
strumLine.conductorInUse = localConductor;
|
||||
strumLine.screenCenter();
|
||||
add(strumLine);
|
||||
|
||||
super.create();
|
||||
strumlineBG.x = strumLine.x;
|
||||
strumlineBG.makeGraphic(Std.int(strumLine.width), FlxG.height, 0xFFFFFFFF);
|
||||
strumlineBG.alpha = 0.1;
|
||||
|
||||
visualOffsetText = new FlxText();
|
||||
visualOffsetText.setFormat(Paths.font("vcr.ttf"), 20);
|
||||
visualOffsetText.x = (FlxG.height / 8) + 10;
|
||||
visualOffsetText.y = 10;
|
||||
visualOffsetText.fieldWidth = strumLine.x - visualOffsetText.x - 10;
|
||||
add(visualOffsetText);
|
||||
|
||||
offsetText = new FlxText();
|
||||
offsetText.setFormat(Paths.font("vcr.ttf"), 20);
|
||||
offsetText.x = strumLine.x + strumLine.width + 10;
|
||||
offsetText.y = 10;
|
||||
offsetText.fieldWidth = FlxG.width - offsetText.x - 10;
|
||||
add(offsetText);
|
||||
|
||||
var helpText:FlxText = new FlxText();
|
||||
helpText.setFormat(Paths.font("vcr.ttf"), 20);
|
||||
helpText.text = "Press BACK to return to main menu";
|
||||
helpText.x = FlxG.width - helpText.width;
|
||||
helpText.y = FlxG.height - (helpText.height * 2) - 2;
|
||||
add(helpText);
|
||||
|
||||
regenNoteData();
|
||||
}
|
||||
|
||||
function preciseInputPressed(event:PreciseInputEvent)
|
||||
{
|
||||
generateBeatStuff(event);
|
||||
strumLine.pressKey(event.noteDirection);
|
||||
strumLine.playPress(event.noteDirection);
|
||||
}
|
||||
|
||||
function preciseInputReleased(event:PreciseInputEvent)
|
||||
{
|
||||
strumLine.playStatic(event.noteDirection);
|
||||
strumLine.releaseKey(event.noteDirection);
|
||||
}
|
||||
|
||||
override public function close():Void
|
||||
{
|
||||
PreciseInputManager.instance.onInputPressed.remove(preciseInputPressed);
|
||||
PreciseInputManager.instance.onInputReleased.remove(preciseInputReleased);
|
||||
|
||||
FlxG.sound.music.volume = previousVolume;
|
||||
swagSong.stop();
|
||||
FlxG.sound.list.remove(swagSong);
|
||||
|
||||
FlxG.cameras.remove(stateCamera);
|
||||
|
||||
FlxG.state.persistentDraw = prevPersistentDraw;
|
||||
FlxG.state.persistentUpdate = prevPersistentUpdate;
|
||||
super.close();
|
||||
}
|
||||
|
||||
function regenNoteData()
|
||||
{
|
||||
for (i in 0...32)
|
||||
{
|
||||
var note:SongNoteData = new SongNoteData((localConductor.stepLengthMs * 2) * i, 1);
|
||||
noteGrp.push(note);
|
||||
}
|
||||
|
||||
strumLine.applyNoteData(noteGrp);
|
||||
}
|
||||
|
||||
override function stepHit():Bool
|
||||
{
|
||||
if (Conductor.instance.currentStep % 4 == 2)
|
||||
if (localConductor.currentStep % 4 == 2)
|
||||
{
|
||||
blocks.members[((Conductor.instance.currentBeat % 8) + 1) % 8].alpha = 0.5;
|
||||
blocks.members[((localConductor.currentBeat % 8) + 1) % 8].alpha = 0.5;
|
||||
}
|
||||
|
||||
return super.stepHit();
|
||||
|
@ -154,11 +226,11 @@ class LatencyState extends MusicBeatSubState
|
|||
|
||||
override function beatHit():Bool
|
||||
{
|
||||
if (Conductor.instance.currentBeat % 8 == 0) blocks.forEach(blok -> {
|
||||
blok.alpha = 0;
|
||||
if (localConductor.currentBeat % 8 == 0) blocks.forEach(blok -> {
|
||||
blok.alpha = 0.1;
|
||||
});
|
||||
|
||||
blocks.members[Conductor.instance.currentBeat % 8].alpha = 1;
|
||||
blocks.members[localConductor.currentBeat % 8].alpha = 1;
|
||||
// block.visible = !block.visible;
|
||||
|
||||
return super.beatHit();
|
||||
|
@ -171,117 +243,114 @@ class LatencyState extends MusicBeatSubState
|
|||
trace(FlxG.sound.music._channel.position);
|
||||
*/
|
||||
|
||||
// localConductor.update(swagSong.time, false);
|
||||
localConductor.update(swagSong.time, false);
|
||||
|
||||
if (FlxG.keys.justPressed.S)
|
||||
{
|
||||
trace("\tUPDATE PRESS: \t" + FlxG.sound.music.time + " " + Timer.stamp());
|
||||
}
|
||||
// localConductor.songPosition += (Timer.stamp() * 1000) - FlxG.sound.music.prevTimestamp;
|
||||
|
||||
if (FlxG.keys.justPressed.SPACE)
|
||||
{
|
||||
if (FlxG.sound.music.playing) FlxG.sound.music.pause();
|
||||
else
|
||||
FlxG.sound.music.resume();
|
||||
}
|
||||
songPosVis.x = songPosToX(localConductor.songPosition);
|
||||
songVisFollowAudio.x = songPosToX(localConductor.songPosition - localConductor.audioVisualOffset);
|
||||
songVisFollowVideo.x = songPosToX(localConductor.songPosition - localConductor.inputOffset);
|
||||
|
||||
if (FlxG.keys.pressed.D) FlxG.sound.music.time += 1000 * FlxG.elapsed;
|
||||
visualOffsetText.text = "Visual Offset: " + localConductor.audioVisualOffset + "ms";
|
||||
visualOffsetText.text += "\n\nYou can press SPACE+Left/Right to change this value.";
|
||||
visualOffsetText.text += "\n\nYou can hold SHIFT to step 1ms at a time";
|
||||
|
||||
Conductor.instance.update(swagSong.getTimeWithDiff() - Conductor.instance.inputOffset);
|
||||
// Conductor.instance.songPosition += (Timer.stamp() * 1000) - FlxG.sound.music.prevTimestamp;
|
||||
|
||||
songPosVis.x = songPosToX(Conductor.instance.songPosition);
|
||||
songVisFollowAudio.x = songPosToX(Conductor.instance.songPosition - Conductor.instance.instrumentalOffset);
|
||||
songVisFollowVideo.x = songPosToX(Conductor.instance.songPosition - Conductor.instance.inputOffset);
|
||||
|
||||
offsetText.text = "INST Offset: " + Conductor.instance.instrumentalOffset + "ms";
|
||||
offsetText.text += "\nINPUT Offset: " + Conductor.instance.inputOffset + "ms";
|
||||
offsetText.text += "\ncurrentStep: " + Conductor.instance.currentStep;
|
||||
offsetText.text += "\ncurrentBeat: " + Conductor.instance.currentBeat;
|
||||
offsetText.text = "INPUT Offset (Left/Right to change): " + localConductor.inputOffset + "ms";
|
||||
offsetText.text += "\n\nYou can hold SHIFT to step 1ms at a time";
|
||||
|
||||
var avgOffsetInput:Float = 0;
|
||||
|
||||
var loopInd:Int = 0;
|
||||
for (offsetThing in offsetsPerBeat)
|
||||
{
|
||||
if (offsetThing == null) continue;
|
||||
avgOffsetInput += offsetThing;
|
||||
loopInd++;
|
||||
}
|
||||
|
||||
avgOffsetInput /= offsetsPerBeat.length;
|
||||
avgOffsetInput /= loopInd;
|
||||
|
||||
offsetText.text += "\naverage input offset needed: " + avgOffsetInput;
|
||||
offsetText.text += "\n\nEstimated average input offset needed: " + avgOffsetInput;
|
||||
|
||||
var multiply:Float = 10;
|
||||
var multiply:Int = 10;
|
||||
|
||||
if (FlxG.keys.pressed.SHIFT) multiply = 1;
|
||||
|
||||
if (FlxG.keys.pressed.CONTROL)
|
||||
if (FlxG.keys.pressed.CONTROL || FlxG.keys.pressed.SPACE)
|
||||
{
|
||||
if (FlxG.keys.justPressed.RIGHT)
|
||||
{
|
||||
Conductor.instance.instrumentalOffset += 1.0 * multiply;
|
||||
localConductor.audioVisualOffset += 1 * multiply;
|
||||
}
|
||||
|
||||
if (FlxG.keys.justPressed.LEFT)
|
||||
{
|
||||
Conductor.instance.instrumentalOffset -= 1.0 * multiply;
|
||||
localConductor.audioVisualOffset -= 1 * multiply;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FlxG.keys.justPressed.RIGHT)
|
||||
if (FlxG.keys.anyJustPressed([LEFT, RIGHT]))
|
||||
{
|
||||
Conductor.instance.inputOffset += 1.0 * multiply;
|
||||
}
|
||||
if (FlxG.keys.justPressed.RIGHT)
|
||||
{
|
||||
localConductor.inputOffset += 1 * multiply;
|
||||
}
|
||||
|
||||
if (FlxG.keys.justPressed.LEFT)
|
||||
{
|
||||
Conductor.instance.inputOffset -= 1.0 * multiply;
|
||||
if (FlxG.keys.justPressed.LEFT)
|
||||
{
|
||||
localConductor.inputOffset -= 1 * multiply;
|
||||
}
|
||||
|
||||
// reset the average, so you don't need to wait a full loop to start getting averages
|
||||
// also reset each text member
|
||||
offsetsPerBeat = [];
|
||||
diffGrp.forEach(memb -> memb.text = "");
|
||||
}
|
||||
}
|
||||
|
||||
noteGrp.forEach(function(daNote:NoteSprite) {
|
||||
daNote.y = (strumLine.y - ((Conductor.instance.songPosition - Conductor.instance.instrumentalOffset) - daNote.noteData.time) * 0.45);
|
||||
daNote.x = strumLine.x + 30;
|
||||
|
||||
if (daNote.y < strumLine.y) daNote.alpha = 0.5;
|
||||
|
||||
if (daNote.y < 0 - daNote.height)
|
||||
{
|
||||
daNote.alpha = 1;
|
||||
// daNote.data.strumTime += Conductor.instance.beatLengthMs * 8;
|
||||
}
|
||||
});
|
||||
if (controls.BACK)
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
super.update(elapsed);
|
||||
}
|
||||
|
||||
function generateBeatStuff()
|
||||
function generateBeatStuff(event:PreciseInputEvent)
|
||||
{
|
||||
Conductor.instance.update(swagSong.getTimeWithDiff());
|
||||
// localConductor.update(swagSong.getTimeWithDiff());
|
||||
|
||||
var closestBeat:Int = Math.round(Conductor.instance.songPosition / Conductor.instance.beatLengthMs) % diffGrp.members.length;
|
||||
var getDiff:Float = Conductor.instance.songPosition - (closestBeat * Conductor.instance.beatLengthMs);
|
||||
getDiff -= Conductor.instance.inputOffset;
|
||||
var inputLatencyMs:Float = haxe.Int64.toInt(PreciseInputManager.getCurrentTimestamp() - event.timestamp) / 1000.0 / 1000.0;
|
||||
// trace("input latency: " + inputLatencyMs + "ms");
|
||||
// trace("cur timestamp: " + PreciseInputManager.getCurrentTimestamp() + "ns");
|
||||
// trace("event timestamp: " + event.timestamp + "ns");
|
||||
// trace("songtime: " + localConductor.getTimeWithDiff(swagSong) + "ms");
|
||||
|
||||
var closestBeat:Int = Math.round(localConductor.getTimeWithDiff(swagSong) / (localConductor.stepLengthMs * 2)) % diffGrp.members.length;
|
||||
var getDiff:Float = localConductor.getTimeWithDiff(swagSong) - (closestBeat * (localConductor.stepLengthMs * 2));
|
||||
// getDiff -= localConductor.inputOffset;
|
||||
getDiff -= inputLatencyMs;
|
||||
getDiff -= localConductor.audioVisualOffset;
|
||||
|
||||
// lil fix for end of song
|
||||
if (closestBeat == 0 && getDiff >= Conductor.instance.beatLengthMs * 2) getDiff -= FlxG.sound.music.length;
|
||||
if (closestBeat == 0 && getDiff >= localConductor.stepLengthMs * 2) getDiff -= swagSong.length;
|
||||
|
||||
trace("\tDISTANCE TO CLOSEST BEAT: " + getDiff + "ms");
|
||||
trace("\tCLOSEST BEAT: " + closestBeat);
|
||||
beatTrail.x = songPosVis.x;
|
||||
|
||||
diffGrp.members[closestBeat].text = getDiff + "ms";
|
||||
offsetsPerBeat[closestBeat] = Std.int(getDiff);
|
||||
offsetsPerBeat[closestBeat] = Math.round(getDiff);
|
||||
}
|
||||
|
||||
function songPosToX(pos:Float):Float
|
||||
{
|
||||
return FlxMath.remapToRange(pos, 0, FlxG.sound.music.length, 0, FlxG.width);
|
||||
return FlxMath.remapToRange(pos, 0, swagSong.length, 0, FlxG.width);
|
||||
}
|
||||
}
|
||||
|
||||
class HomemadeMusic extends FlxSound
|
||||
{
|
||||
public var prevTimestamp:Int = 0;
|
||||
public var timeWithDiff:Float = 0;
|
||||
|
||||
public function new()
|
||||
{
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package funkin.ui.freeplay;
|
||||
|
||||
import funkin.data.freeplay.AlbumData;
|
||||
import funkin.data.freeplay.album.AlbumData;
|
||||
import funkin.data.freeplay.album.AlbumRegistry;
|
||||
import funkin.data.animation.AnimationData;
|
||||
import funkin.data.freeplay.AlbumRegistry;
|
||||
import funkin.data.IRegistryEntry;
|
||||
import flixel.graphics.FlxGraphic;
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import flixel.util.FlxSort;
|
|||
import flixel.tweens.FlxTween;
|
||||
import flixel.util.FlxTimer;
|
||||
import flixel.tweens.FlxEase;
|
||||
import funkin.data.freeplay.AlbumRegistry;
|
||||
import funkin.data.freeplay.album.AlbumRegistry;
|
||||
import funkin.util.assets.FlxAnimationUtil;
|
||||
import funkin.graphics.FunkinSprite;
|
||||
import funkin.util.SortUtil;
|
||||
|
|
|
@ -18,7 +18,7 @@ import flixel.util.FlxColor;
|
|||
import flixel.util.FlxSpriteUtil;
|
||||
import flixel.util.FlxTimer;
|
||||
import funkin.audio.FunkinSound;
|
||||
import funkin.data.level.LevelRegistry;
|
||||
import funkin.data.story.level.LevelRegistry;
|
||||
import funkin.data.song.SongRegistry;
|
||||
import funkin.graphics.FunkinCamera;
|
||||
import funkin.graphics.FunkinSprite;
|
||||
|
|
|
@ -20,6 +20,7 @@ class FunkinSoundTray extends FlxSoundTray
|
|||
{
|
||||
var graphicScale:Float = 0.30;
|
||||
var lerpYPos:Float = 0;
|
||||
var alphaTarget:Float = 0;
|
||||
|
||||
var volumeMaxSound:String;
|
||||
|
||||
|
@ -40,7 +41,7 @@ class FunkinSoundTray extends FlxSoundTray
|
|||
|
||||
// makes an alpha'd version of all the bars (bar_10.png)
|
||||
var backingBar:Bitmap = new Bitmap(Assets.getBitmapData(Paths.image("soundtray/bars_10")));
|
||||
backingBar.x = 10;
|
||||
backingBar.x = 9;
|
||||
backingBar.y = 5;
|
||||
backingBar.scaleX = graphicScale;
|
||||
backingBar.scaleY = graphicScale;
|
||||
|
@ -56,7 +57,7 @@ class FunkinSoundTray extends FlxSoundTray
|
|||
for (i in 1...11)
|
||||
{
|
||||
var bar:Bitmap = new Bitmap(Assets.getBitmapData(Paths.image("soundtray/bars_" + i)));
|
||||
bar.x = 10;
|
||||
bar.x = 9;
|
||||
bar.y = 5;
|
||||
bar.scaleX = graphicScale;
|
||||
bar.scaleY = graphicScale;
|
||||
|
@ -77,15 +78,18 @@ class FunkinSoundTray extends FlxSoundTray
|
|||
override public function update(MS:Float):Void
|
||||
{
|
||||
y = MathUtil.coolLerp(y, lerpYPos, 0.1);
|
||||
alpha = MathUtil.coolLerp(alpha, alphaTarget, 0.25);
|
||||
|
||||
// Animate sound tray thing
|
||||
if (_timer > 0)
|
||||
{
|
||||
_timer -= (MS / 1000);
|
||||
alphaTarget = 1;
|
||||
}
|
||||
else if (y > -height)
|
||||
{
|
||||
lerpYPos = -height - 10;
|
||||
alphaTarget = 0;
|
||||
|
||||
if (y <= -height)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package funkin.ui.options;
|
||||
|
||||
import funkin.ui.debug.latency.LatencyState;
|
||||
import flixel.FlxSprite;
|
||||
import flixel.FlxSubState;
|
||||
import flixel.addons.transition.FlxTransitionableState;
|
||||
|
@ -190,6 +191,9 @@ class OptionsMenu extends Page
|
|||
add(items = new TextMenuList());
|
||||
createItem("PREFERENCES", function() switchPage(Preferences));
|
||||
createItem("CONTROLS", function() switchPage(Controls));
|
||||
createItem("INPUT OFFSETS", function() {
|
||||
FlxG.state.openSubState(new LatencyState());
|
||||
});
|
||||
|
||||
#if newgrounds
|
||||
if (NGio.isLoggedIn) createItem("LOGOUT", selectLogout);
|
||||
|
|
|
@ -6,8 +6,8 @@ import flixel.util.FlxColor;
|
|||
import funkin.play.song.Song;
|
||||
import funkin.data.IRegistryEntry;
|
||||
import funkin.data.song.SongRegistry;
|
||||
import funkin.data.level.LevelRegistry;
|
||||
import funkin.data.level.LevelData;
|
||||
import funkin.data.story.level.LevelRegistry;
|
||||
import funkin.data.story.level.LevelData;
|
||||
|
||||
/**
|
||||
* An object used to retrieve data about a story mode level (also known as "weeks").
|
||||
|
|
|
@ -2,7 +2,7 @@ package funkin.ui.story;
|
|||
|
||||
import funkin.play.stage.Bopper;
|
||||
import funkin.util.assets.FlxAnimationUtil;
|
||||
import funkin.data.level.LevelData;
|
||||
import funkin.data.story.level.LevelData;
|
||||
|
||||
class LevelProp extends Bopper
|
||||
{
|
||||
|
|
|
@ -9,7 +9,7 @@ import flixel.tweens.FlxTween;
|
|||
import flixel.util.FlxColor;
|
||||
import flixel.util.FlxTimer;
|
||||
import funkin.audio.FunkinSound;
|
||||
import funkin.data.level.LevelRegistry;
|
||||
import funkin.data.story.level.LevelRegistry;
|
||||
import funkin.data.song.SongRegistry;
|
||||
import funkin.graphics.FunkinSprite;
|
||||
import funkin.modding.events.ScriptEvent;
|
||||
|
|
|
@ -295,6 +295,8 @@ class Constants
|
|||
|
||||
/**
|
||||
* Constant for the number of seconds in a minute.
|
||||
*
|
||||
* sex per min
|
||||
*/
|
||||
public static final SECS_PER_MIN:Int = 60;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package funkin.data.level;
|
||||
package funkin.data.story.level;
|
||||
|
||||
import funkin.data.level.LevelRegistry;
|
||||
import funkin.data.story.level.LevelRegistry;
|
||||
import funkin.ui.story.Level;
|
||||
import massive.munit.Assert;
|
||||
import massive.munit.async.AsyncFactory;
|
||||
|
@ -8,7 +8,7 @@ import massive.munit.util.Timer;
|
|||
|
||||
@:nullSafety
|
||||
@:access(funkin.ui.story.Level)
|
||||
@:access(funkin.data.level.LevelRegistry)
|
||||
@:access(funkin.data.story.level.LevelRegistry)
|
||||
class LevelRegistryTest extends FunkinTest
|
||||
{
|
||||
public function new()
|
||||
|
|
Loading…
Reference in a new issue