Merge remote-tracking branch 'dev/main'
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
name: Linux Build
|
||||
on:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
build:
|
||||
name: Linux Build
|
||||
@@ -34,16 +35,18 @@ jobs:
|
||||
- name: Building the game
|
||||
run: |
|
||||
haxelib run lime build linux
|
||||
- name: Tar files
|
||||
run: tar -zcvf CodenameEngine.tar.gz export/release/linux/bin
|
||||
- name: Uploading artifact (entire build)
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Codename Engine
|
||||
path: export/release/linux/bin
|
||||
- name: Uploading artifact (executable)
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Update-Linux
|
||||
path: export/release/linux/bin/CodenameEngine
|
||||
path: CodenameEngine.tar.gz
|
||||
# - name: Uploading artifact (executable)
|
||||
# uses: actions/upload-artifact@v2
|
||||
# with:
|
||||
# name: Update-Linux
|
||||
# path: export/release/linux/bin/CodenameEngine
|
||||
- name: Clearing already existing cache
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name: Mac OS Build
|
||||
on:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
build:
|
||||
name: Mac OS Build
|
||||
@@ -31,16 +32,18 @@ jobs:
|
||||
- name: Building the game
|
||||
run: |
|
||||
haxelib run lime build mac
|
||||
- name: Tar files
|
||||
run: tar -zcvf CodenameEngine.tar.gz export/release/macos/bin
|
||||
- name: Uploading artifact (entire build)
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Codename Engine
|
||||
path: export/release/macos/bin
|
||||
- name: Uploading artifact (executable)
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Update-Mac
|
||||
path: export/release/macos/bin/CodenameEngine
|
||||
path: CodenameEngine.tar.gz
|
||||
# - name: Uploading artifact (executable)
|
||||
# uses: actions/upload-artifact@v2
|
||||
# with:
|
||||
# name: Update-Mac
|
||||
# path: export/release/macos/bin/CodenameEngine
|
||||
- name: Clearing already existing cache
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
|
||||
@@ -37,11 +37,11 @@ jobs:
|
||||
with:
|
||||
name: Codename Engine
|
||||
path: export/release/windows/bin
|
||||
- name: Uploading artifact (executable)
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Update-Windows
|
||||
path: export/release/windows/bin/CodenameEngine.exe
|
||||
# - name: Uploading artifact (executable)
|
||||
# uses: actions/upload-artifact@v2
|
||||
# with:
|
||||
# name: Update-Windows
|
||||
# path: export/release/windows/bin/CodenameEngine.exe
|
||||
- name: Clearing already existing cache
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
|
||||
Vendored
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"editor.detectIndentation": false,
|
||||
"editor.insertSpaces": false,
|
||||
"editor.detectIndentation": false,
|
||||
"editor.insertSpaces": false,
|
||||
"files.associations": {
|
||||
"*.hx": "haxe",
|
||||
"*.hscript": "haxe",
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@ _**QOL = Quality of Life**_
|
||||
|
||||
<details>
|
||||
<summary><h2>Player QOL Features</h2></summary>
|
||||
|
||||
|
||||
- New input system
|
||||
- New accuracy and misses system, added to fix the base game UI.
|
||||
- New options, including:
|
||||
@@ -72,7 +72,7 @@ _**QOL = Quality of Life**_
|
||||
- Weeks are located in `data/weeks/weeks/`
|
||||
- If you need to rearrange the weeks in-game, you can use the `data/weeks/weeks.txt` file.
|
||||
- Editors for Charts and Characters (Stage coming soon)
|
||||
- Undos/Redos supported
|
||||
- Undos/Redos supported
|
||||
- Warning on closing unsaved work
|
||||
- Clean UI (for ocd freaks)
|
||||
- Mature Chart editor (Character editor rework soon)
|
||||
|
||||
@@ -30,22 +30,10 @@ In the future (when the engine won't be a WIP anymore) we're gonna also publish
|
||||
|
||||
##### Tested on Windows 10 21H2
|
||||
1. Install [version 4.2.5 of Haxe](https://haxe.org/download/version/4.2.5/).
|
||||
2. Download [Visual Studio Build Tools](https://aka.ms/vs/17/release/vs_BuildTools.exe)
|
||||
3. Wait for the Visual Studio Installer to install
|
||||
4. On the Visual Studio installer screen, go to the "Individual components" tab and only select those options:
|
||||
- MSVC v143 VS 2022 C++ x64/x86 build tools (Latest)
|
||||
- Windows 10/11 SDK (any works)
|
||||
5. This is what your Installation details panel should look like. Once correct, press "Install".
|
||||
- ⚠ This will download around 1.07 GB of data from the internet, and will require around 5.5 GB of available space on your computer.
|
||||
|
||||
<p align="center">
|
||||
<img src="https://github.com/YoshiCrafter29/CodenameEngine/blob/main/art/github/windows-installation-details.png?raw=true" />
|
||||
</p>
|
||||
|
||||
6. Once you finish downloading those components, download and install [`git-scm`](https://git-scm.com/download/win).
|
||||
2. Download and install [`git-scm`](https://git-scm.com/download/win).
|
||||
- Leave all installation options as default.
|
||||
7. Run `update.bat` using cmd or double-clicking it, and wait for the libraries to install.
|
||||
8. Once the libraries are installed, run `haxelib run lime test windows` to compile and launch the game (may take a long time)
|
||||
3. Run `update.bat` using cmd or double-clicking it, and wait for the libraries to install.
|
||||
4. Once the libraries are installed, run `haxelib run lime test windows` to compile and launch the game (may take a long time)
|
||||
- ℹ You can run `haxelib run lime setup` to make the lime command global, allowing you to execute `lime test windows` directly.
|
||||
</details>
|
||||
<details>
|
||||
@@ -97,6 +85,5 @@ In the future (when the engine won't be a WIP anymore) we're gonna also publish
|
||||
- Credits to [Ne_Eo](https://twitter.com/Ne_Eo_Twitch) and the [3D-HaxeFlixel](https://github.com/lunarcleint/3D-HaxeFlixel) repository for Away3D Flixel support
|
||||
- Credits to the [FlxAnimate](https://github.com/Dot-Stuff/flxanimate) team for the Animate Atlas support
|
||||
- Credits to Smokey555 for the backup Animate Atlas to spritesheet code
|
||||
- Credits to MAJigsaw77 for [hxvlc](https://github.com/MAJigsaw77/hxvlc) for video cutscene/mp4 support
|
||||
- Credits to Aidan63 for [discord-rpc](https://github.com/Aidan63/linc_discord-rpc) for discord rpc integration
|
||||
- Credits to MAJigsaw77 for [hxvlc](https://github.com/MAJigsaw77/hxvlc) (video cutscene/mp4 support) and [hxdiscord_rpc](https://github.com/MAJigsaw77/hxdiscord_rpc) (discord rpc integration)
|
||||
</details>
|
||||
|
||||
+27
-27
@@ -1,30 +1,30 @@
|
||||
__ /
|
||||
/ _ _ |_ |_ . _
|
||||
\__) (- |_ |_ | | )
|
||||
|
||||
__
|
||||
|_ _ _ _ |
|
||||
| | (- (_| |( \/
|
||||
/
|
||||
|
||||
_ _ _
|
||||
(_) | ) (_|
|
||||
|
||||
__
|
||||
|_ _ . _| _ _ . _ |_ |_ _ _ |_
|
||||
| | | (_| (_| \/ | ) | (_) | ) |_ \/ (- (_| | )
|
||||
/ _/ /
|
||||
__ /
|
||||
/ _ _ |_ |_ . _
|
||||
\__) (- |_ |_ | | )
|
||||
|
||||
__
|
||||
|_ _ _ _ |
|
||||
| | (- (_| |( \/
|
||||
/
|
||||
|
||||
_ _ _
|
||||
(_) | ) (_|
|
||||
|
||||
__
|
||||
|_ _ . _| _ _ . _ |_ |_ _ _ |_
|
||||
| | | (_| (_| \/ | ) | (_) | ) |_ \/ (- (_| | )
|
||||
/ _/ /
|
||||
|
||||
HEY
|
||||
Thanks for downloadin Friday Night FUNKIN'
|
||||
If you downloaded this from any other place than ninja-muffin24.itch.io/FUNKIN
|
||||
You might be in DANGER!!!
|
||||
You might be in DANGER!!!
|
||||
|
||||
The Itch.io release is the only official source for the desktop (PC, Mac, Linux) versions of the game!
|
||||
As of right now, the game is FREE! If you paid for it, you got SCAMMED!
|
||||
|
||||
Now that that's out of the way....
|
||||
THANKS FOR DOWNLOADIN.
|
||||
THANKS FOR DOWNLOADIN.
|
||||
|
||||
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-
|
||||
PERMISSIONS XDDDD
|
||||
@@ -77,16 +77,16 @@ I love Tom Fulp.
|
||||
- Cameron ♪(´▽`)
|
||||
|
||||
##################################################################################
|
||||
|
||||
_ _ _____ _ _ ____ ____ ___ _ _ _ _ ____ ____
|
||||
| \ | | | ____| | | | | / ___| | _ \ / _ \ | | | | | \ | | | _ \ / ___|
|
||||
| \| | | _| | | /\ | | | | _ | |_) | | | | | | | | | | \| | | | | | \___ \
|
||||
|
||||
_ _ _____ _ _ ____ ____ ___ _ _ _ _ ____ ____
|
||||
| \ | | | ____| | | | | / ___| | _ \ / _ \ | | | | | \ | | | _ \ / ___|
|
||||
| \| | | _| | | /\ | | | | _ | |_) | | | | | | | | | | \| | | | | | \___ \
|
||||
| |\ | | |___ \ V V / | |_| | | _ < | |_| | | |_| | | |\ | | |_| | ___) |
|
||||
|_| \_| |_____| \_/\_/ \____| |_| \_\ \___/ \___/ |_| \_| |____/ |____/
|
||||
_ _ _ ___ ___ __ _ _ _ _ _
|
||||
|_ | | |_ |_) \_/ | |_| | |\ | /__ |_ |_ | | |_ |_) \_/ / \ |\ | |_
|
||||
|_| \_| |_____| \_/\_/ \____| |_| \_\ \___/ \___/ |_| \_| |____/ |____/
|
||||
_ _ _ ___ ___ __ _ _ _ _ _
|
||||
|_ | | |_ |_) \_/ | |_| | |\ | /__ |_ |_ | | |_ |_) \_/ / \ |\ | |_
|
||||
|_ \/ |_ | \ | | | | _|_ | \| \_| o |_)\/ |_ \/ |_ | \ | \_/ | \| |_ o
|
||||
/ /
|
||||
|
||||
/ /
|
||||
|
||||
##################################################################################
|
||||
i stole this from stamper.
|
||||
@@ -7,7 +7,7 @@
|
||||
<anim name="singDOWN" anim="GF Down Note" fps="24" loop="false" x="0" y="0" />
|
||||
<anim name="danceLeft" anim="GF Dancing Beat" fps="24" loop="false" x="0" y="0" indices="30,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14" />
|
||||
<anim name="danceRight" anim="GF Dancing Beat" fps="24" loop="false" x="0" y="0" indices="15,16,17,18,19,20,21,22,23,24,25,26,27,28,29" />
|
||||
<anim name="hairBlow" anim="GF Dancing Beat Hair blowing" fps="24" loop="false" x="0" y="0" indices="0,1,2,3" />
|
||||
<anim name="hairBlow" anim="GF Dancing Beat Hair blowing" fps="24" loop="true" x="0" y="0" indices="0,1,2,3" />
|
||||
<anim name="hairFall" anim="GF Dancing Beat Hair Landing" fps="24" loop="false" x="0" y="0" indices="0,1,2,3,4,5,6,7,8,9,10,11" />
|
||||
<anim name="scared" anim="GF FEAR" fps="24" loop="true" x="0" y="0" />
|
||||
<anim name="sad" anim="gf sad" fps="24" loop="true" x="0" y="0" indices="0,1,2,3,4,5,6,7,8,9,10,11,12" />
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import funkin.backend.utils.DiscordUtil;
|
||||
|
||||
function onGameOver() {
|
||||
DiscordUtil.changePresence('Game Over', PlayState.SONG.meta.displayName + " (" + PlayState.difficulty + ")");
|
||||
}
|
||||
|
||||
function onDiscordPresenceUpdate(e) {
|
||||
var data = e.presence;
|
||||
|
||||
if(data.button1Label == null)
|
||||
data.button1Label = "Codename Engine Discord";
|
||||
if(data.button1Url == null)
|
||||
data.button1Url = "https://discord.gg/2NTCdsQvx4";
|
||||
}
|
||||
|
||||
function onPlayStateUpdate() {
|
||||
DiscordUtil.changeSongPresence(
|
||||
PlayState.instance.detailsText,
|
||||
(PlayState.instance.paused ? "Paused - " : "") + PlayState.SONG.meta.displayName + " (" + PlayState.difficulty + ")",
|
||||
PlayState.instance.inst,
|
||||
PlayState.instance.getIconRPC()
|
||||
);
|
||||
}
|
||||
|
||||
function onMenuLoaded(name:String) {
|
||||
// Name is either "Main Menu", "Freeplay", "Title Screen", "Options Menu", "Credits Menu", "Beta Warning", "Update Available Screen", "Update Screen"
|
||||
DiscordUtil.changePresenceSince("In the Menus", null);
|
||||
}
|
||||
|
||||
function onEditorTreeLoaded(name:String) {
|
||||
switch(name) {
|
||||
case "Character Editor":
|
||||
DiscordUtil.changePresenceSince("Choosing a Character", null);
|
||||
case "Chart Editor":
|
||||
DiscordUtil.changePresenceSince("Choosing a Chart", null);
|
||||
case "Stage Editor":
|
||||
DiscordUtil.changePresenceSince("Choosing a Stage", null);
|
||||
}
|
||||
}
|
||||
|
||||
function onEditorLoaded(name:String, editingThing:String) {
|
||||
switch(name) {
|
||||
case "Character Editor":
|
||||
DiscordUtil.changePresenceSince("Editing a Character", editingThing);
|
||||
case "Chart Editor":
|
||||
DiscordUtil.changePresenceSince("Editing a Chart", editingThing);
|
||||
case "Stage Editor":
|
||||
DiscordUtil.changePresenceSince("Editing a Stage", editingThing);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
//
|
||||
function update(elapsed:Float)
|
||||
if (FlxG.keys.justPressed.F5) FlxG.resetState();
|
||||
if (FlxG.keys.justPressed.F5) FlxG.resetState();
|
||||
@@ -35,8 +35,8 @@ function onNoteCreation(event) {
|
||||
note.updateHitbox();
|
||||
}
|
||||
|
||||
function onPostNoteCreation(event) {
|
||||
var splashes = event.note;
|
||||
function onPostNoteCreation(event) {
|
||||
var splashes = event.note;
|
||||
if (pixelSplashes)
|
||||
splashes.splash = "pixel-default";
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE codename-engine-splashes>
|
||||
<splashes sprite="game/splashes/default" alpha="0.6">
|
||||
<splashes sprite="game/splashes/default" alpha="0.6">
|
||||
<strum id="0"> <!-- LEFT -->
|
||||
<anim name="splashleft1" anim="note impact 1 purple" fps="24" x="0" y="0" />
|
||||
<anim name="splashleft2" anim="note impact 2 purple" fps="24" x="0" y="0" />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!DOCTYPE codename-engine-splashes>
|
||||
<!--Pixel Splashes by APurples!!-->
|
||||
<splashes sprite="stages/school/ui/pixel-splashes" alpha="0.6" antialiasing="false" scale="3.5">
|
||||
<splashes sprite="stages/school/ui/pixel-splashes" alpha="0.6" antialiasing="false" scale="3.5">
|
||||
<strum id="0"> <!-- LEFT -->
|
||||
<anim name="splashleft1" anim="splash purple 1" fps="24" x="-1" y="-2" />
|
||||
<anim name="splashleft2" anim="splash purple 2" fps="24" x="-1" y="-2" />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!DOCTYPE codename-engine-splashes>
|
||||
<!--Pixel Splashes by APurples!!-->
|
||||
<splashes sprite="stages/school/ui/pixel-secret-splashes" alpha="0.6" antialiasing="false" scale="3.5">
|
||||
<splashes sprite="stages/school/ui/pixel-secret-splashes" alpha="0.6" antialiasing="false" scale="3.5">
|
||||
<strum id="0"> <!-- LEFT -->
|
||||
<anim name="splashleft1" anim="splash purple 1" fps="24" x="-3"/>
|
||||
</strum>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE codename-engine-splashes>
|
||||
<splashes sprite="game/splashes/secret" alpha="0.6" scale="0.75">
|
||||
<splashes sprite="game/splashes/secret" alpha="0.6" scale="0.75">
|
||||
<strum id="0"> <!-- LEFT -->
|
||||
<anim name="splash purple" anim="splash purple" fps="24" x="0" y="0" />
|
||||
</strum>
|
||||
|
||||
@@ -7,23 +7,23 @@
|
||||
<!-- ONLY FOR INSTANCES WITH LOW MEMORY MODE DISABLED -->
|
||||
<high-memory>
|
||||
<!-- DANCERS !-->
|
||||
<sprite name="dancer1" x="130" y="80" sprite="limoDancer" scroll="0.4" zoomfactor="0.55" type="onbeat">
|
||||
<sprite name="dancer1" x="130" y="80" sprite="limoDancer" scroll="0.4" zoomfactor="0.55" type="onbeat" beatInterval="1">
|
||||
<anim name="danceLeft" anim="bg dancer sketch PINK" loop="false" indices="0,1,2,3,4,5,6,7,8,9,10,11,12,13,14" />
|
||||
<anim name="danceRight" anim="bg dancer sketch PINK" loop="false" indices="15,16,17,18,19,20,21,22,23,24,25,26,27,28,29" />
|
||||
</sprite>
|
||||
<sprite name="dancer2" x="500" y="80" sprite="limoDancer" scroll="0.4" zoomfactor="0.55" type="onbeat">
|
||||
<sprite name="dancer2" x="500" y="80" sprite="limoDancer" scroll="0.4" zoomfactor="0.55" type="onbeat" beatInterval="1">
|
||||
<anim name="danceLeft" anim="bg dancer sketch PINK" loop="false" indices="0,1,2,3,4,5,6,7,8,9,10,11,12,13,14" />
|
||||
<anim name="danceRight" anim="bg dancer sketch PINK" loop="false" indices="15,16,17,18,19,20,21,22,23,24,25,26,27,28,29" />
|
||||
</sprite>
|
||||
<sprite name="dancer3" x="870" y="80" sprite="limoDancer" scroll="0.4" zoomfactor="0.55" type="onbeat">
|
||||
<sprite name="dancer3" x="870" y="80" sprite="limoDancer" scroll="0.4" zoomfactor="0.55" type="onbeat" beatInterval="1">
|
||||
<anim name="danceLeft" anim="bg dancer sketch PINK" loop="false" indices="0,1,2,3,4,5,6,7,8,9,10,11,12,13,14" />
|
||||
<anim name="danceRight" anim="bg dancer sketch PINK" loop="false" indices="15,16,17,18,19,20,21,22,23,24,25,26,27,28,29" />
|
||||
</sprite>
|
||||
<sprite name="dancer4" x="1240" y="80" sprite="limoDancer" scroll="0.4" zoomfactor="0.55" type="onbeat">
|
||||
<sprite name="dancer4" x="1240" y="80" sprite="limoDancer" scroll="0.4" zoomfactor="0.55" type="onbeat" beatInterval="1">
|
||||
<anim name="danceLeft" anim="bg dancer sketch PINK" loop="false" indices="0,1,2,3,4,5,6,7,8,9,10,11,12,13,14" />
|
||||
<anim name="danceRight" anim="bg dancer sketch PINK" loop="false" indices="15,16,17,18,19,20,21,22,23,24,25,26,27,28,29" />
|
||||
</sprite>
|
||||
<sprite name="dancer5" x="1610" y="80" sprite="limoDancer" scroll="0.4" zoomfactor="0.55" type="onbeat">
|
||||
<sprite name="dancer5" x="1610" y="80" sprite="limoDancer" scroll="0.4" zoomfactor="0.55" type="onbeat" beatInterval="1">
|
||||
<anim name="danceLeft" anim="bg dancer sketch PINK" loop="false" indices="0,1,2,3,4,5,6,7,8,9,10,11,12,13,14" />
|
||||
<anim name="danceRight" anim="bg dancer sketch PINK" loop="false" indices="15,16,17,18,19,20,21,22,23,24,25,26,27,28,29" />
|
||||
</sprite>
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<!DOCTYPE codename-engine-stage>
|
||||
<stage zoom="0.8" name="mall" folder="stages/mall/" startCamPosY="450" startCamPosX="500">
|
||||
<sprite name="bg" x="-1000" y="-500" sprite="bgWalls" scroll="0.2"/>
|
||||
|
||||
|
||||
<high-memory>
|
||||
<sprite name="upperBoppers" x="-240" y="-90" sprite="upperBop" scroll="0.2" type="onbeat"/>
|
||||
<sprite name="upperBoppers" x="-240" y="-90" sprite="upperBop" scroll="0.2" type="onbeat" beatInterval="1"/>
|
||||
</high-memory>
|
||||
<sprite name="bgEscalator" x="-1100" y="-600" sprite="bgEscalator" scroll="0.3" scale="0.9" updateHitbox="true"/>
|
||||
<sprite name="tree" x="370" y="-250" sprite="christmasTree" scroll="0.4"/>
|
||||
<sprite name="bottomBoppers" x="-300" y="140" sprite="bottomBop" scroll="0.9" type="onbeat" />
|
||||
<sprite name="bottomBoppers" x="-300" y="140" sprite="bottomBop" scroll="0.9" type="onbeat" beatInterval="1"/>
|
||||
<sprite name="fgSnow" x="-600" y="700" sprite="fgSnow"/>
|
||||
|
||||
|
||||
<high-memory>
|
||||
<sprite name="santa" x="-840" y="150" sprite="santa" type="onbeat"/>
|
||||
<sprite name="santa" x="-840" y="150" sprite="santa" type="onbeat" beatInterval="1"/>
|
||||
</high-memory>
|
||||
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ function updateTrainPos():Void
|
||||
|
||||
function trainReset():Void
|
||||
{
|
||||
gf.playAnim('hairFall');
|
||||
gf.playAnim('hairFall', true);
|
||||
phillyTrain.x = FlxG.width + 200;
|
||||
trainMoving = false;
|
||||
// trainSound.stop();
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
antialiasing="false" scale="6" scroll="0.85" updateHitbox="true" type="loop"/>
|
||||
</high-memory>
|
||||
|
||||
<sprite name="bgGirls" x="-100" y="190" sprite="bgFreaks" scroll="0.9" scale="6" antialiasing="false" updateHitbox="true" type="onbeat">
|
||||
<sprite name="bgGirls" x="-100" y="190" sprite="bgFreaks" scroll="0.9" scale="6" antialiasing="false" updateHitbox="true" type="onbeat" beatInterval="1">
|
||||
<anim name="danceLeft" anim="BG girls group" indices="0,1,2,3,4,5,6,7,8,9,10,11,12,13" fps="24" loop="false"/>
|
||||
<anim name="danceRight" anim="BG girls group" indices="15,16,17,18,19,20,21,22,23,24,25,26,27,28,29" fps="24" loop="false"/>
|
||||
</sprite>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<high-memory>
|
||||
<sprite name="smokeLeft" x="-200" y="-100" sprite="smokeLeft" scroll="0.4" zoomfactor="0.6"/>
|
||||
<sprite name="smokeRight" x="1100" y="-100" sprite="smokeRight" scroll="0.4" zoomfactor="0.6"/>
|
||||
<sprite name="tankWatchtower" x="100" y="50" sprite="tankWatchtower" scroll="0.5" type="onbeat" beatInterval="2" zoomfactor="0.7"/>
|
||||
<sprite name="tankWatchtower" x="100" y="50" sprite="tankWatchtower" scroll="0.5" type="onbeat" zoomfactor="0.7"/>
|
||||
</high-memory>
|
||||
<sprite name="tankRolling" x="300" y="300" sprite="tankRolling" scroll="0.5" zoomfactor="0.8" type="loop"/>
|
||||
<sprite name="tankGround" x="-420" y="-150" sprite="tankGround" scale="1.15" updateHitbox="true" zoomfactor="1.0"/>
|
||||
@@ -26,13 +26,13 @@
|
||||
<boyfriend x="810"/>
|
||||
|
||||
<!-- FOREGROUND TANKMANS -->
|
||||
|
||||
|
||||
<high-memory>
|
||||
<sprite name="tank0" x="-500" y="650" sprite="tank0" scrollx="1.7" scrolly="1.5" type="onbeat" beatInterval="2" zoomfactor="1.25"/>
|
||||
<sprite name="tank1" x="-300" y="750" sprite="tank1" scrollx="2" scrolly="0.2" type="onbeat" beatInterval="2" zoomfactor="1.25"/>
|
||||
<sprite name="tank2" x="450" y="940" sprite="tank2" scroll="1.5" type="onbeat" beatInterval="2" zoomfactor="1.25"/>
|
||||
<sprite name="tank4" x="1300" y="900" sprite="tank4" scroll="1.5" type="onbeat" beatInterval="2" zoomfactor="1.25"/>
|
||||
<sprite name="tank5" x="1620" y="700" sprite="tank5" scroll="1.5" type="onbeat" beatInterval="2" zoomfactor="1.25"/>
|
||||
<sprite name="tank3" x="1300" y="1200" sprite="tank3" scrollx="3.5" scrolly="2.5" type="onbeat" beatInterval="2" zoomfactor="1.25"/>
|
||||
<sprite name="tank0" x="-500" y="650" sprite="tank0" scrollx="1.7" scrolly="1.5" type="onbeat" zoomfactor="1.25"/>
|
||||
<sprite name="tank1" x="-300" y="750" sprite="tank1" scrollx="2" scrolly="0.2" type="onbeat" zoomfactor="1.25"/>
|
||||
<sprite name="tank2" x="450" y="940" sprite="tank2" scroll="1.5" type="onbeat" zoomfactor="1.25"/>
|
||||
<sprite name="tank4" x="1300" y="900" sprite="tank4" scroll="1.5" type="onbeat" zoomfactor="1.25"/>
|
||||
<sprite name="tank5" x="1620" y="700" sprite="tank5" scroll="1.5" type="onbeat" zoomfactor="1.25"/>
|
||||
<sprite name="tank3" x="1300" y="1200" sprite="tank3" scrollx="3.5" scrolly="2.5" type="onbeat" zoomfactor="1.25"/>
|
||||
</high-memory>
|
||||
</stage>
|
||||
@@ -1,8 +1,8 @@
|
||||
<!DOCTYPE codename-titlestate >
|
||||
<titlestate>
|
||||
<sprites folder="menus/titlescreen">
|
||||
<sprite name="logo" sprite="logo" x="-150" y="-100" />
|
||||
<sprite name="gf" sprite="gf" x="512" y="50">
|
||||
<sprite name="logo" sprite="logo" x="-150" y="-100" beatInterval="1"/>
|
||||
<sprite name="gf" sprite="gf" x="512" y="50" beatInterval="1">
|
||||
<anim name="danceLeft" anim="gfDance" indices="30,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14" />
|
||||
<anim name="danceRight" anim="gfDance" indices="15,16,17,18,19,20,21,22,23,24,25,26,27,28,29" />
|
||||
</sprite>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 174 B |
Binary file not shown.
|
After Width: | Height: | Size: 519 B |
@@ -10,7 +10,7 @@
|
||||
<SubTexture name="add-bottomleft" x="0" y="30" width="11" height="4"/>
|
||||
<SubTexture name="add-bottom" x="11" y="30" width="19" height="4"/>
|
||||
<SubTexture name="add-bottomright" x="30" y="30" width="18" height="4"/>
|
||||
|
||||
|
||||
<SubTexture name="edit-topleft" x="0" y="34" width="11" height="4"/>
|
||||
<SubTexture name="edit-top" x="11" y="34" width="19" height="4"/>
|
||||
<SubTexture name="edit-topright" x="30" y="34" width="18" height="4"/>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 243 B |
Binary file not shown.
|
After Width: | Height: | Size: 199 B |
Binary file not shown.
|
Before Width: | Height: | Size: 1021 B After Width: | Height: | Size: 1.3 KiB |
@@ -8,7 +8,7 @@
|
||||
<SubTexture name="middleleft" x="0" y="1" width="1" height="21"/>
|
||||
<SubTexture name="middle" x="1" y="1" width="94" height="21"/>
|
||||
<SubTexture name="middleright" x="95" y="1" width="1" height="21"/>
|
||||
|
||||
|
||||
<SubTexture name="bottomleft" x="0" y="22" width="1" height="1"/>
|
||||
<SubTexture name="bottom" x="1" y="22" width="94" height="1"/>
|
||||
<SubTexture name="bottomright" x="95" y="22" width="1" height="1"/>
|
||||
|
||||
@@ -6,12 +6,12 @@ uniform vec2 blueOff;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 uv = getCamPos(openfl_TextureCoordv);
|
||||
vec4 col;
|
||||
col.r = textureCam(bitmap, uv + redOff).r;
|
||||
col.g = textureCam(bitmap, uv + greenOff).g;
|
||||
col.b = textureCam(bitmap, uv + blueOff).b;
|
||||
col.a = texture2D(bitmap, openfl_TextureCoordv).a;
|
||||
vec2 uv = getCamPos(openfl_TextureCoordv);
|
||||
vec4 col;
|
||||
col.r = textureCam(bitmap, uv + redOff).r;
|
||||
col.g = textureCam(bitmap, uv + greenOff).g;
|
||||
col.b = textureCam(bitmap, uv + blueOff).b;
|
||||
col.a = texture2D(bitmap, openfl_TextureCoordv).a;
|
||||
|
||||
gl_FragColor = col;
|
||||
gl_FragColor = col;
|
||||
}
|
||||
@@ -6,10 +6,10 @@ uniform float strength;
|
||||
|
||||
void main() {
|
||||
vec2 uv = getCamPos(openfl_TextureCoordv);
|
||||
vec3 col = pow(textureCam(bitmap, uv).rgb, vec3(1.0 / strength));
|
||||
vec3 col = pow(textureCam(bitmap, uv).rgb, vec3(1.0 / strength));
|
||||
|
||||
float vignette = mix(1.0, 1.0 - amount, distance(uv, vec2(0.5)));
|
||||
col = pow(mix(col * color, col, vignette), vec3(strength));
|
||||
float vignette = mix(1.0, 1.0 - amount, distance(uv, vec2(0.5)));
|
||||
col = pow(mix(col * color, col, vignette), vec3(strength));
|
||||
|
||||
gl_FragColor = vec4(col, 1.0);
|
||||
}
|
||||
@@ -6,6 +6,6 @@ void main() {
|
||||
float len = length(openfl_TextureCoordv - vec2(0.5, 0.5));
|
||||
float r = 0.5 - (1.0 / openfl_TextureSize.x);
|
||||
vec4 c = flixel_texture2D(bitmap, openfl_TextureCoordv);
|
||||
vec4 color = mix(vec4(0, 0, 0, 0.5), c, c.a);
|
||||
gl_FragColor = color * clamp(1 - ((len - r) * openfl_TextureSize.x), 0, 1);
|
||||
vec4 color = mix(vec4(0.0, 0.0, 0.0, 0.5), c, c.a);
|
||||
gl_FragColor = color * clamp(1.0 - ((len - r) * openfl_TextureSize.x), 0.0, 1.0);
|
||||
}
|
||||
@@ -3,9 +3,9 @@
|
||||
// Used in colorwheel
|
||||
|
||||
vec3 hsvToRgb(vec3 c) { //hsv.x = hue, hsv.y = saturation, hsv.z = value
|
||||
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
|
||||
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
|
||||
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
|
||||
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
|
||||
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
|
||||
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
|
||||
}
|
||||
|
||||
uniform float hue;
|
||||
|
||||
@@ -7,9 +7,9 @@ int steps = 16;
|
||||
int stepsInside = 2;
|
||||
float strength = 0.0075;
|
||||
vec4 getColor(vec2 pos) {
|
||||
if (pos.x < 0) pos.x = 0;
|
||||
if (pos.x < 0.0) pos.x = 0.0;
|
||||
else if (pos.x > 1.0 - (1.0 / openfl_TextureSize.x)) pos.x = 1.0 - (1.0 / openfl_TextureSize.x);
|
||||
if (pos.y < 0) pos.y = 0;
|
||||
if (pos.y < 0.0) pos.y = 0.0;
|
||||
else if (pos.y > 1.0 - (1.0 / openfl_TextureSize.y)) pos.y = 1.0 - (1.0 / openfl_TextureSize.y);
|
||||
// return textureCam(bitmap, pos);
|
||||
return flixel_texture2D(bitmap, pos);
|
||||
@@ -17,15 +17,18 @@ vec4 getColor(vec2 pos) {
|
||||
void main() {
|
||||
// vec2 camPos = getCamPos(openfl_TextureCoordv);
|
||||
vec2 camPos = openfl_TextureCoordv;
|
||||
if (camPos.x < 0 || camPos.x > 1 || camPos.y < 0 || camPos.y > 1)
|
||||
if (camPos.x < 0.0 || camPos.x > 1.0 || camPos.y < 0.0 || camPos.y > 1.0)
|
||||
return;
|
||||
|
||||
vec4 color = getColor(camPos);
|
||||
float fsteps = steps;
|
||||
for(float inside = 1; inside < stepsInside+1; inside++) {
|
||||
for(float inside = 1.0; inside < stepsInside+1.0; inside++) {
|
||||
for(int i = 0; i < steps; i++) {
|
||||
float fi = i;
|
||||
color += getColor(camPos + vec2(strength * (inside / stepsInside) * cos(fi / fsteps * (PI * 2.0)), strength * (inside / stepsInside) * sin(fi / fsteps * (PI * 2.0))));
|
||||
color += getColor(camPos + vec2(
|
||||
strength * (inside / stepsInside) * cos(fi / fsteps * (PI * 2.0)),
|
||||
strength * (inside / stepsInside) * sin(fi / fsteps * (PI * 2.0))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
#pragma header
|
||||
|
||||
// Used in charter by waveforms
|
||||
|
||||
const vec3 gradient1 = vec3(114.0/255.0, 81.0/255.0, 135.0/255.0);
|
||||
const vec3 gradient2 = vec3(144.0/255.0, 80.0/255.0, 186.0/255.0);
|
||||
|
||||
const vec4 outlinecolor = vec4(0.1);
|
||||
const vec3 lowdetailcol = vec3(0.0, 0.0, 1.0);
|
||||
|
||||
uniform vec2 textureRes;
|
||||
uniform float pixelOffset;
|
||||
|
||||
uniform float playerPosition;
|
||||
|
||||
uniform sampler2D waveformTexture;
|
||||
uniform ivec2 waveformSize;
|
||||
|
||||
uniform bool lowDetail;
|
||||
|
||||
float getAmplitude(vec2 pixel) {
|
||||
float pixelID = floor((pixel.y+pixelOffset)/3.0);
|
||||
|
||||
// TODO: INVESTIGATE THE 1.+ AND WHY IT WORKS (SRSLY I GOT NO CLUE) -lunar
|
||||
vec2 wavePixel = vec2(mod(pixelID,waveformSize.x), 1.0+floor(pixelID/waveformSize.x));
|
||||
vec4 waveData = texture2D(waveformTexture, wavePixel / waveformSize);
|
||||
|
||||
int id = int(mod(wavePixel.x, 3.0));
|
||||
if(id == 0) return waveData.r;
|
||||
if(id == 1) return waveData.g;
|
||||
if(id == 2) return waveData.b;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
float getAmpWidth(float amplitude) {
|
||||
return (1.0-amplitude) * textureRes.x;
|
||||
}
|
||||
|
||||
bool inWaveForm(vec2 pixel, float width) {
|
||||
float widthdiv2 = width/2.0;
|
||||
return pixel.x > widthdiv2 && pixel.x < textureRes.x-widthdiv2;
|
||||
}
|
||||
|
||||
float getHightlight(float ampwidth) {
|
||||
float remapCoord = (ampwidth/textureRes.x)/2.0;
|
||||
float mappedCoord = map(openfl_TextureCoordv.x, remapCoord, 1.0-remapCoord, 0.0, 1.0);
|
||||
return 1.0-(abs(mappedCoord-0.5)*2.0);
|
||||
}
|
||||
|
||||
void outlineWaveform(vec2 pixel, vec2 offset) {
|
||||
float amplitude = getAmplitude(pixel - offset);
|
||||
float ampwidth = (1.0-amplitude) * textureRes.x;
|
||||
|
||||
if (!inWaveForm(pixel, ampwidth))
|
||||
gl_FragColor -= outlinecolor*mix(0.5, 0.8, amplitude);
|
||||
}
|
||||
|
||||
void highDetailWaveform(vec2 pixel, float amplitude, float ampwidth) {
|
||||
vec3 gradientColor = mix(gradient1, gradient2, openfl_TextureCoordv.x);
|
||||
gradientColor *= pixel.y+pixelOffset>playerPosition ? 0.7 : 1.0;
|
||||
gradientColor = mix(gradientColor, gradientColor * vec3(1.8), map(getHightlight(amplitude), 0.0, 1.0, 0.5, 1.0));
|
||||
|
||||
float ampwidthHighlight = getAmpWidth(amplitude/3.0);
|
||||
if (inWaveForm(pixel, ampwidthHighlight))
|
||||
gradientColor = mix(gradientColor, gradientColor * vec3(1.8), map(getHightlight(ampwidthHighlight), 0.0, 1.0, 0.5, 1.0));
|
||||
|
||||
gl_FragColor = vec4(vec3(gradientColor * mix(0.5, 0.8, amplitude))*openfl_Alphav, openfl_Alphav);
|
||||
|
||||
outlineWaveform(pixel, vec2(0.0, -1.0));
|
||||
outlineWaveform(pixel, vec2(0.0, 1.0));
|
||||
}
|
||||
|
||||
void lowDetailWaveform(vec2 pixel, float amplitude, float ampwidth) {
|
||||
gl_FragColor = vec4(lowdetailcol * (pixel.y+pixelOffset>playerPosition ? 0.7 : 1.0), 1.0);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 pixel = openfl_TextureCoordv * textureRes;
|
||||
float amplitude = getAmplitude(pixel);
|
||||
float ampwidth = getAmpWidth(amplitude);
|
||||
|
||||
gl_FragColor = vec4(0.0);
|
||||
if (!inWaveForm(pixel, ampwidth)) return;
|
||||
|
||||
if (lowDetail) lowDetailWaveform(pixel, amplitude, ampwidth);
|
||||
else highDetailWaveform(pixel, amplitude, ampwidth);
|
||||
}
|
||||
@@ -28,7 +28,7 @@ void main() {
|
||||
|
||||
hsv.g = (1.0/3.0) * strength * coords.y;
|
||||
|
||||
hsv.r = mod(elapsed + coords.x + coords.y, 1);
|
||||
hsv.r = mod(elapsed + coords.x + coords.y, 1.0);
|
||||
|
||||
gl_FragColor = vec4(hsv2rgb(hsv), color.a);
|
||||
}
|
||||
@@ -21,7 +21,7 @@ function postUpdate(elapsed) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// for(s in strumLines) {
|
||||
// for(i in 0...4) {
|
||||
// var n = s.members[i];
|
||||
@@ -29,7 +29,7 @@ function postUpdate(elapsed) {
|
||||
// n.angle = 180;
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (curSection != null)
|
||||
// defaultCamZoom = curSection.mustHitSection ? 0.9 : 0.5;
|
||||
|
||||
// if (curSection != null)
|
||||
// defaultCamZoom = curSection.mustHitSection ? 0.9 : 0.5;
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
{"events":[{"params":[1],"time":0,"type":1},{"params":[0],"time":9600,"type":1},{"params":[1],"time":14400,"type":1},{"params":[0],"time":19200,"type":1},{"params":[1],"time":24000,"type":1},{"params":[0],"time":28800,"type":1},{"params":[1],"time":33600,"type":1},{"params":[0],"time":38400,"type":1},{"params":[1],"time":43200,"type":1},{"params":[0],"time":48000,"type":1},{"params":[1],"time":50400,"type":1}],"strumLines":[{"notes":[{"id":0,"sLen":0,"time":9600,"type":0},{"id":3,"sLen":0,"time":10800,"type":0},{"id":0,"sLen":0,"time":12000,"type":0},{"id":3,"sLen":0,"time":13200,"type":0},{"id":2,"sLen":0,"time":19200,"type":0},{"id":1,"sLen":0,"time":20400,"type":0},{"id":2,"sLen":0,"time":21600,"type":0},{"id":1,"sLen":0,"time":22800,"type":0},{"id":0,"sLen":0,"time":28800,"type":0},{"id":2,"sLen":0,"time":30000,"type":0},{"id":1,"sLen":0,"time":31200,"type":0},{"id":3,"sLen":0,"time":32400,"type":0},{"id":1,"sLen":0,"time":38400,"type":0},{"id":1,"sLen":0,"time":39000,"type":0},{"id":2,"sLen":0,"time":39600,"type":0},{"id":1,"sLen":0,"time":40800,"type":0},{"id":1,"sLen":0,"time":41400,"type":0},{"id":3,"sLen":0,"time":42000,"type":0},{"id":1,"sLen":0,"time":48000,"type":0},{"id":2,"sLen":0,"time":48300,"type":0},{"id":3,"sLen":0,"time":48600,"type":0},{"id":2,"sLen":0,"time":48900,"type":0},{"id":3,"sLen":0,"time":49800,"type":0}],"position":"girlfriend","type":0,"characters":["gf"]},{"notes":[{"id":0,"sLen":0,"time":14400,"type":0},{"id":3,"sLen":0,"time":15600,"type":0},{"id":0,"sLen":0,"time":16800,"type":0},{"id":3,"sLen":0,"time":18000,"type":0},{"id":2,"sLen":0,"time":24000,"type":0},{"id":1,"sLen":0,"time":25200,"type":0},{"id":2,"sLen":0,"time":26400,"type":0},{"id":1,"sLen":0,"time":27600,"type":0},{"id":0,"sLen":0,"time":33600,"type":0},{"id":2,"sLen":0,"time":34800,"type":0},{"id":1,"sLen":0,"time":36000,"type":0},{"id":3,"sLen":0,"time":37200,"type":0},{"id":1,"sLen":0,"time":43200,"type":0},{"id":1,"sLen":0,"time":43800,"type":0},{"id":2,"sLen":0,"time":44400,"type":0},{"id":1,"sLen":0,"time":45600,"type":0},{"id":1,"sLen":0,"time":46200,"type":0},{"id":3,"sLen":0,"time":46800,"type":0},{"id":1,"sLen":0,"time":50400,"type":0},{"id":2,"sLen":0,"time":50700,"type":0},{"id":3,"sLen":0,"time":51000,"type":0},{"id":2,"sLen":0,"time":51300,"type":0},{"id":3,"sLen":0,"time":52200,"type":0},{"id":3,"sLen":0,"time":52800,"type":0},{"id":1,"sLen":0,"time":53400,"type":0},{"id":0,"sLen":0,"time":54000,"type":0},{"id":1,"sLen":0,"time":54600,"type":0},{"id":2,"sLen":0,"time":55200,"type":0},{"id":3,"sLen":0,"time":55800,"type":0},{"id":0,"sLen":0,"time":56400,"type":0},{"id":2,"sLen":0,"time":57000,"type":0},{"id":1,"sLen":750,"time":57600,"type":0}],"position":"boyfriend","type":1,"characters":["bf"]}],"codenameChart":true,"scrollSpeed":1,"noteTypes":[]}
|
||||
{"codenameChart":true,"strumLines":[{"position":"girlfriend","notes":[{"id":0,"sLen":0,"time":9600,"type":0},{"id":3,"sLen":0,"time":10800,"type":0},{"id":0,"sLen":0,"time":12000,"type":0},{"id":3,"sLen":0,"time":13200,"type":0},{"id":2,"sLen":0,"time":19200,"type":0},{"id":1,"sLen":0,"time":20400,"type":0},{"id":2,"sLen":0,"time":21600,"type":0},{"id":1,"sLen":0,"time":22800,"type":0},{"id":0,"sLen":0,"time":28800,"type":0},{"id":2,"sLen":0,"time":30000,"type":0},{"id":1,"sLen":0,"time":31200,"type":0},{"id":3,"sLen":0,"time":32400,"type":0},{"id":1,"sLen":0,"time":38400,"type":0},{"id":1,"sLen":0,"time":39000,"type":0},{"id":2,"sLen":0,"time":39600,"type":0},{"id":1,"sLen":0,"time":40800,"type":0},{"id":1,"sLen":0,"time":41400,"type":0},{"id":3,"sLen":0,"time":42000,"type":0},{"id":1,"sLen":0,"time":48000,"type":0},{"id":2,"sLen":0,"time":48300,"type":0},{"id":3,"sLen":0,"time":48600,"type":0},{"id":2,"sLen":0,"time":48900,"type":0},{"id":3,"sLen":0,"time":49800,"type":0}],"visible":true,"type":0,"characters":["gf"]},{"position":"boyfriend","notes":[{"id":0,"sLen":0,"time":14400,"type":0},{"id":3,"sLen":0,"time":15600,"type":0},{"id":0,"sLen":0,"time":16800,"type":0},{"id":3,"sLen":0,"time":18000,"type":0},{"id":2,"sLen":0,"time":24000,"type":0},{"id":1,"sLen":0,"time":25200,"type":0},{"id":2,"sLen":0,"time":26400,"type":0},{"id":1,"sLen":0,"time":27600,"type":0},{"id":0,"sLen":0,"time":33600,"type":0},{"id":2,"sLen":0,"time":34800,"type":0},{"id":1,"sLen":0,"time":36000,"type":0},{"id":3,"sLen":0,"time":37200,"type":0},{"id":1,"sLen":0,"time":43200,"type":0},{"id":1,"sLen":0,"time":43800,"type":0},{"id":2,"sLen":0,"time":44400,"type":0},{"id":1,"sLen":0,"time":45600,"type":0},{"id":1,"sLen":0,"time":46200,"type":0},{"id":3,"sLen":0,"time":46800,"type":0},{"id":1,"sLen":0,"time":50400,"type":0},{"id":2,"sLen":0,"time":50700,"type":0},{"id":3,"sLen":0,"time":51000,"type":0},{"id":2,"sLen":0,"time":51300,"type":0},{"id":3,"sLen":0,"time":52200,"type":0},{"id":3,"sLen":0,"time":52800,"type":0},{"id":1,"sLen":0,"time":53400,"type":0},{"id":0,"sLen":0,"time":54000,"type":0},{"id":1,"sLen":0,"time":54600,"type":0},{"id":2,"sLen":0,"time":55200,"type":0},{"id":3,"sLen":0,"time":55800,"type":0},{"id":0,"sLen":0,"time":56400,"type":0},{"id":2,"sLen":0,"time":57000,"type":0},{"id":1,"sLen":750,"time":57600,"type":0}],"visible":true,"type":1,"characters":["bf"]}],"scrollSpeed":1,"noteTypes":[]}
|
||||
@@ -1 +1 @@
|
||||
{"events":[{"params":[1],"time":0,"type":1},{"params":[0],"time":9600,"type":1},{"params":[1],"time":14400,"type":1},{"params":[0],"time":19200,"type":1},{"params":[1],"time":24000,"type":1},{"params":[0],"time":28800,"type":1},{"params":[1],"time":33600,"type":1},{"params":[0],"time":38400,"type":1},{"params":[1],"time":43200,"type":1},{"params":[0],"time":48000,"type":1},{"params":[1],"time":50400,"type":1}],"strumLines":[{"notes":[{"id":0,"sLen":0,"time":9600,"type":0},{"id":3,"sLen":0,"time":10800,"type":0},{"id":0,"sLen":0,"time":12000,"type":0},{"id":3,"sLen":0,"time":13200,"type":0},{"id":2,"sLen":0,"time":19200,"type":0},{"id":1,"sLen":0,"time":20400,"type":0},{"id":2,"sLen":0,"time":21600,"type":0},{"id":1,"sLen":0,"time":22800,"type":0},{"id":0,"sLen":0,"time":28800,"type":0},{"id":2,"sLen":0,"time":30000,"type":0},{"id":1,"sLen":0,"time":31200,"type":0},{"id":3,"sLen":0,"time":32400,"type":0},{"id":1,"sLen":0,"time":38400,"type":0},{"id":1,"sLen":0,"time":39000,"type":0},{"id":2,"sLen":0,"time":39600,"type":0},{"id":1,"sLen":0,"time":40800,"type":0},{"id":1,"sLen":0,"time":41400,"type":0},{"id":3,"sLen":0,"time":42000,"type":0},{"id":1,"sLen":0,"time":48000,"type":0},{"id":2,"sLen":0,"time":48300,"type":0},{"id":3,"sLen":0,"time":48600,"type":0},{"id":2,"sLen":0,"time":48900,"type":0},{"id":3,"sLen":0,"time":49800,"type":0}],"position":"girlfriend","type":0,"characters":["gf"]},{"notes":[{"id":0,"sLen":0,"time":14400,"type":0},{"id":3,"sLen":0,"time":15600,"type":0},{"id":0,"sLen":0,"time":16800,"type":0},{"id":3,"sLen":0,"time":18000,"type":0},{"id":2,"sLen":0,"time":24000,"type":0},{"id":1,"sLen":0,"time":25200,"type":0},{"id":2,"sLen":0,"time":26400,"type":0},{"id":1,"sLen":0,"time":27600,"type":0},{"id":0,"sLen":0,"time":33600,"type":0},{"id":2,"sLen":0,"time":34800,"type":0},{"id":1,"sLen":0,"time":36000,"type":0},{"id":3,"sLen":0,"time":37200,"type":0},{"id":1,"sLen":0,"time":43200,"type":0},{"id":1,"sLen":0,"time":43800,"type":0},{"id":2,"sLen":0,"time":44400,"type":0},{"id":1,"sLen":0,"time":45600,"type":0},{"id":1,"sLen":0,"time":46200,"type":0},{"id":3,"sLen":0,"time":46800,"type":0},{"id":1,"sLen":0,"time":50400,"type":0},{"id":2,"sLen":0,"time":50700,"type":0},{"id":3,"sLen":0,"time":51000,"type":0},{"id":2,"sLen":0,"time":51300,"type":0},{"id":3,"sLen":0,"time":52200,"type":0},{"id":3,"sLen":0,"time":52800,"type":0},{"id":1,"sLen":0,"time":53400,"type":0},{"id":0,"sLen":0,"time":54000,"type":0},{"id":1,"sLen":0,"time":54600,"type":0},{"id":2,"sLen":0,"time":55200,"type":0},{"id":3,"sLen":0,"time":55800,"type":0},{"id":0,"sLen":0,"time":56400,"type":0},{"id":2,"sLen":0,"time":57000,"type":0},{"id":1,"sLen":750,"time":57600,"type":0},{"id":0,"sLen":0,"time":62400,"type":0},{"id":1,"sLen":0,"time":62550,"type":0},{"id":2,"sLen":0,"time":62700,"type":0},{"id":3,"sLen":0,"time":62850,"type":0},{"id":2,"sLen":0,"time":63000,"type":0},{"id":1,"sLen":0,"time":63150,"type":0},{"id":0,"sLen":0,"time":63300,"type":0},{"id":1,"sLen":0,"time":63450,"type":0},{"id":2,"sLen":0,"time":63600,"type":0},{"id":3,"sLen":0,"time":63750,"type":0},{"id":2,"sLen":0,"time":63900,"type":0},{"id":3,"sLen":0,"time":64050,"type":0},{"id":2,"sLen":0,"time":64200,"type":0},{"id":3,"sLen":0,"time":64350,"type":0},{"id":0,"sLen":0,"time":64650,"type":0},{"id":1,"sLen":0,"time":64500,"type":0}],"position":"boyfriend","type":1,"characters":["bf"]}],"codenameChart":true,"scrollSpeed":1,"noteTypes":[]}
|
||||
{"codenameChart":true,"strumLines":[{"position":"girlfriend","notes":[{"id":0,"sLen":0,"time":9600,"type":0},{"id":3,"sLen":0,"time":10800,"type":0},{"id":0,"sLen":0,"time":12000,"type":0},{"id":3,"sLen":0,"time":13200,"type":0},{"id":2,"sLen":0,"time":19200,"type":0},{"id":1,"sLen":0,"time":20400,"type":0},{"id":2,"sLen":0,"time":21600,"type":0},{"id":1,"sLen":0,"time":22800,"type":0},{"id":0,"sLen":0,"time":28800,"type":0},{"id":2,"sLen":0,"time":30000,"type":0},{"id":1,"sLen":0,"time":31200,"type":0},{"id":3,"sLen":0,"time":32400,"type":0},{"id":1,"sLen":0,"time":38400,"type":0},{"id":1,"sLen":0,"time":39000,"type":0},{"id":2,"sLen":0,"time":39600,"type":0},{"id":1,"sLen":0,"time":40800,"type":0},{"id":1,"sLen":0,"time":41400,"type":0},{"id":3,"sLen":0,"time":42000,"type":0},{"id":1,"sLen":0,"time":48000,"type":0},{"id":2,"sLen":0,"time":48300,"type":0},{"id":3,"sLen":0,"time":48600,"type":0},{"id":2,"sLen":0,"time":48900,"type":0},{"id":3,"sLen":0,"time":49800,"type":0}],"visible":true,"type":0,"characters":["gf"]},{"position":"boyfriend","notes":[{"id":0,"sLen":0,"time":14400,"type":0},{"id":3,"sLen":0,"time":15600,"type":0},{"id":0,"sLen":0,"time":16800,"type":0},{"id":3,"sLen":0,"time":18000,"type":0},{"id":2,"sLen":0,"time":24000,"type":0},{"id":1,"sLen":0,"time":25200,"type":0},{"id":2,"sLen":0,"time":26400,"type":0},{"id":1,"sLen":0,"time":27600,"type":0},{"id":0,"sLen":0,"time":33600,"type":0},{"id":2,"sLen":0,"time":34800,"type":0},{"id":1,"sLen":0,"time":36000,"type":0},{"id":3,"sLen":0,"time":37200,"type":0},{"id":1,"sLen":0,"time":43200,"type":0},{"id":1,"sLen":0,"time":43800,"type":0},{"id":2,"sLen":0,"time":44400,"type":0},{"id":1,"sLen":0,"time":45600,"type":0},{"id":1,"sLen":0,"time":46200,"type":0},{"id":3,"sLen":0,"time":46800,"type":0},{"id":1,"sLen":0,"time":50400,"type":0},{"id":2,"sLen":0,"time":50700,"type":0},{"id":3,"sLen":0,"time":51000,"type":0},{"id":2,"sLen":0,"time":51300,"type":0},{"id":3,"sLen":0,"time":52200,"type":0},{"id":3,"sLen":0,"time":52800,"type":0},{"id":1,"sLen":0,"time":53400,"type":0},{"id":0,"sLen":0,"time":54000,"type":0},{"id":1,"sLen":0,"time":54600,"type":0},{"id":2,"sLen":0,"time":55200,"type":0},{"id":3,"sLen":0,"time":55800,"type":0},{"id":0,"sLen":0,"time":56400,"type":0},{"id":2,"sLen":0,"time":57000,"type":0},{"id":1,"sLen":750,"time":57600,"type":0},{"id":0,"sLen":0,"time":62400,"type":0},{"id":1,"sLen":0,"time":62550,"type":0},{"id":2,"sLen":0,"time":62700,"type":0},{"id":3,"sLen":0,"time":62850,"type":0},{"id":2,"sLen":0,"time":63000,"type":0},{"id":1,"sLen":0,"time":63150,"type":0},{"id":0,"sLen":0,"time":63300,"type":0},{"id":1,"sLen":0,"time":63450,"type":0},{"id":2,"sLen":0,"time":63600,"type":0},{"id":3,"sLen":0,"time":63750,"type":0},{"id":2,"sLen":0,"time":63900,"type":0},{"id":3,"sLen":0,"time":64050,"type":0},{"id":2,"sLen":0,"time":64200,"type":0},{"id":3,"sLen":0,"time":64350,"type":0},{"id":1,"sLen":0,"time":64500,"type":0},{"id":0,"sLen":0,"time":64650,"type":0}],"visible":true,"type":1,"characters":["bf"]}],"scrollSpeed":1,"noteTypes":[]}
|
||||
@@ -1 +1 @@
|
||||
{"events":[{"params":[1],"time":0,"type":1},{"params":[0],"time":9600,"type":1},{"params":[1],"time":14400,"type":1},{"params":[0],"time":19200,"type":1},{"params":[1],"time":24000,"type":1},{"params":[0],"time":28800,"type":1},{"params":[1],"time":33600,"type":1},{"params":[0],"time":38400,"type":1},{"params":[1],"time":43200,"type":1},{"params":[0],"time":48000,"type":1},{"params":[1],"time":50400,"type":1}],"strumLines":[{"notes":[{"id":0,"sLen":0,"time":9600,"type":0},{"id":3,"sLen":0,"time":10800,"type":0},{"id":0,"sLen":0,"time":12000,"type":0},{"id":3,"sLen":0,"time":13200,"type":0},{"id":2,"sLen":0,"time":19200,"type":0},{"id":1,"sLen":0,"time":20400,"type":0},{"id":2,"sLen":0,"time":21600,"type":0},{"id":1,"sLen":0,"time":22800,"type":0},{"id":0,"sLen":0,"time":28800,"type":0},{"id":2,"sLen":0,"time":30000,"type":0},{"id":1,"sLen":0,"time":31200,"type":0},{"id":3,"sLen":0,"time":32400,"type":0},{"id":1,"sLen":0,"time":38400,"type":0},{"id":1,"sLen":0,"time":39000,"type":0},{"id":2,"sLen":0,"time":39600,"type":0},{"id":1,"sLen":0,"time":40800,"type":0},{"id":1,"sLen":0,"time":41400,"type":0},{"id":3,"sLen":0,"time":42000,"type":0},{"id":1,"sLen":0,"time":48000,"type":0},{"id":2,"sLen":0,"time":48300,"type":0},{"id":3,"sLen":0,"time":48600,"type":0},{"id":2,"sLen":0,"time":48900,"type":0},{"id":3,"sLen":0,"time":49800,"type":0}],"position":"girlfriend","type":0,"characters":["gf"]},{"notes":[{"id":0,"sLen":0,"time":14400,"type":0},{"id":3,"sLen":0,"time":15600,"type":0},{"id":0,"sLen":0,"time":16800,"type":0},{"id":3,"sLen":0,"time":18000,"type":0},{"id":2,"sLen":0,"time":24000,"type":0},{"id":1,"sLen":0,"time":25200,"type":0},{"id":2,"sLen":0,"time":26400,"type":0},{"id":1,"sLen":0,"time":27600,"type":0},{"id":0,"sLen":0,"time":33600,"type":0},{"id":2,"sLen":0,"time":34800,"type":0},{"id":1,"sLen":0,"time":36000,"type":0},{"id":3,"sLen":0,"time":37200,"type":0},{"id":1,"sLen":0,"time":43200,"type":0},{"id":1,"sLen":0,"time":43800,"type":0},{"id":2,"sLen":0,"time":44400,"type":0},{"id":1,"sLen":0,"time":45600,"type":0},{"id":1,"sLen":0,"time":46200,"type":0},{"id":3,"sLen":0,"time":46800,"type":0},{"id":1,"sLen":0,"time":50400,"type":0},{"id":2,"sLen":0,"time":50700,"type":0},{"id":3,"sLen":0,"time":51000,"type":0},{"id":2,"sLen":0,"time":51300,"type":0},{"id":3,"sLen":0,"time":52200,"type":0},{"id":3,"sLen":0,"time":52800,"type":0},{"id":1,"sLen":0,"time":53400,"type":0},{"id":0,"sLen":0,"time":54000,"type":0},{"id":1,"sLen":0,"time":54600,"type":0},{"id":2,"sLen":0,"time":55200,"type":0},{"id":3,"sLen":0,"time":55800,"type":0},{"id":0,"sLen":0,"time":56400,"type":0},{"id":2,"sLen":0,"time":57000,"type":0},{"id":1,"sLen":750,"time":57600,"type":0}],"position":"boyfriend","type":1,"characters":["bf"]}],"codenameChart":true,"scrollSpeed":1,"noteTypes":[]}
|
||||
{"codenameChart":true,"strumLines":[{"position":"girlfriend","notes":[{"id":0,"sLen":0,"time":9600,"type":0},{"id":3,"sLen":0,"time":10800,"type":0},{"id":0,"sLen":0,"time":12000,"type":0},{"id":3,"sLen":0,"time":13200,"type":0},{"id":2,"sLen":0,"time":19200,"type":0},{"id":1,"sLen":0,"time":20400,"type":0},{"id":2,"sLen":0,"time":21600,"type":0},{"id":1,"sLen":0,"time":22800,"type":0},{"id":0,"sLen":0,"time":28800,"type":0},{"id":2,"sLen":0,"time":30000,"type":0},{"id":1,"sLen":0,"time":31200,"type":0},{"id":3,"sLen":0,"time":32400,"type":0},{"id":1,"sLen":0,"time":38400,"type":0},{"id":1,"sLen":0,"time":39000,"type":0},{"id":2,"sLen":0,"time":39600,"type":0},{"id":1,"sLen":0,"time":40800,"type":0},{"id":1,"sLen":0,"time":41400,"type":0},{"id":3,"sLen":0,"time":42000,"type":0},{"id":1,"sLen":0,"time":48000,"type":0},{"id":2,"sLen":0,"time":48300,"type":0},{"id":3,"sLen":0,"time":48600,"type":0},{"id":2,"sLen":0,"time":48900,"type":0},{"id":3,"sLen":0,"time":49800,"type":0}],"visible":true,"type":0,"characters":["gf"]},{"position":"boyfriend","notes":[{"id":0,"sLen":0,"time":14400,"type":0},{"id":3,"sLen":0,"time":15600,"type":0},{"id":0,"sLen":0,"time":16800,"type":0},{"id":3,"sLen":0,"time":18000,"type":0},{"id":2,"sLen":0,"time":24000,"type":0},{"id":1,"sLen":0,"time":25200,"type":0},{"id":2,"sLen":0,"time":26400,"type":0},{"id":1,"sLen":0,"time":27600,"type":0},{"id":0,"sLen":0,"time":33600,"type":0},{"id":2,"sLen":0,"time":34800,"type":0},{"id":1,"sLen":0,"time":36000,"type":0},{"id":3,"sLen":0,"time":37200,"type":0},{"id":1,"sLen":0,"time":43200,"type":0},{"id":1,"sLen":0,"time":43800,"type":0},{"id":2,"sLen":0,"time":44400,"type":0},{"id":1,"sLen":0,"time":45600,"type":0},{"id":1,"sLen":0,"time":46200,"type":0},{"id":3,"sLen":0,"time":46800,"type":0},{"id":1,"sLen":0,"time":50400,"type":0},{"id":2,"sLen":0,"time":50700,"type":0},{"id":3,"sLen":0,"time":51000,"type":0},{"id":2,"sLen":0,"time":51300,"type":0},{"id":3,"sLen":0,"time":52200,"type":0},{"id":3,"sLen":0,"time":52800,"type":0},{"id":1,"sLen":0,"time":53400,"type":0},{"id":0,"sLen":0,"time":54000,"type":0},{"id":1,"sLen":0,"time":54600,"type":0},{"id":2,"sLen":0,"time":55200,"type":0},{"id":3,"sLen":0,"time":55800,"type":0},{"id":0,"sLen":0,"time":56400,"type":0},{"id":2,"sLen":0,"time":57000,"type":0},{"id":1,"sLen":750,"time":57600,"type":0}],"visible":true,"type":1,"characters":["bf"]}],"scrollSpeed":1,"noteTypes":[]}
|
||||
@@ -0,0 +1 @@
|
||||
{"events":[{"params":[1],"name":"Camera Movement","time":0},{"params":[0],"name":"Camera Movement","time":9600},{"params":[1],"name":"Camera Movement","time":14400},{"params":[0,"cheer"],"name":"Play Animation","time":18000},{"params":[1,"hey"],"name":"Play Animation","time":18600},{"params":[0],"name":"Camera Movement","time":19200},{"params":[1],"name":"Camera Movement","time":24000},{"params":[0,"cheer"],"time":27600,"name":"Play Animation"},{"params":[1,"hey"],"time":28200,"name":"Play Animation"},{"params":[0],"name":"Camera Movement","time":28800},{"params":[1],"name":"Camera Movement","time":33600},{"params":[0],"name":"Camera Movement","time":38400},{"params":[1],"name":"Camera Movement","time":43200},{"params":[0],"name":"Camera Movement","time":48000},{"params":[1],"name":"Camera Movement","time":50400}]}
|
||||
@@ -0,0 +1,8 @@
|
||||
var lastFocused:Int = null;
|
||||
var zoomin:FlxTween = null;
|
||||
|
||||
function onNoteHit(event)
|
||||
event.enableCamZooming = false;
|
||||
|
||||
function onCameraMove(_) if(zoomin == null && lastFocused != (lastFocused = curCameraTarget))
|
||||
zoomin = FlxTween.tween(FlxG.camera, {zoom: curCameraTarget == 0 ? 1.3 : 1}, (Conductor.stepCrochet * 4 / 1000), {ease: FlxEase.elasticInOut, onComplete: function(_) zoomin = null});
|
||||
@@ -20,7 +20,7 @@ class Compiler {
|
||||
Sys.command("lime", arg);
|
||||
}
|
||||
|
||||
private static function getBuildTarget() {
|
||||
public static function getBuildTarget() {
|
||||
return switch(Sys.systemName()) {
|
||||
case "Windows":
|
||||
"windows";
|
||||
|
||||
@@ -71,6 +71,20 @@ class Update {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// vswhere.exe its used to find any visual studio related installations on the system, including full visual studio ide installations, visual studio build tools installations, and other related components - Nex
|
||||
if (Compiler.getBuildTarget().toLowerCase() == "windows" && new Process('"C:/Program Files (x86)/Microsoft Visual Studio/Installer/vswhere.exe" -property catalog_productDisplayVersion').exitCode(true) == 1) {
|
||||
prettyPrint("Installing Microsoft Visual Studio Community (Dependency)");
|
||||
|
||||
// thanks to @crowplexus for these two lines! - Nex
|
||||
Sys.command("curl -# -O https://download.visualstudio.microsoft.com/download/pr/3105fcfe-e771-41d6-9a1c-fc971e7d03a7/8eb13958dc429a6e6f7e0d6704d43a55f18d02a253608351b6bf6723ffdaf24e/vs_Community.exe");
|
||||
Sys.command("vs_Community.exe --add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 --add Microsoft.VisualStudio.Component.Windows10SDK.19041 -p");
|
||||
|
||||
FileSystem.deleteFile("vs_Community.exe");
|
||||
prettyPrint('If it didn\'t say it before: Because of this component if you want to compile you have to restart the device.');
|
||||
Sys.print("Do you wish to do it now [y/n]? ");
|
||||
if(Sys.stdin().readLine().toLowerCase() == "y") Sys.command("shutdown /r /t 0 /f");
|
||||
}
|
||||
}
|
||||
|
||||
public static function prettyPrint(text:String) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<libraries>
|
||||
<!-- OpenFL & Lime (Required for Flixel) -->
|
||||
<lib name="openfl" version="9.2.2"/>
|
||||
<lib name="lime" version="8.0.2"/>
|
||||
<lib name="openfl" version="9.2.2" />
|
||||
<lib name="lime" version="8.1.2" />
|
||||
|
||||
<!-- Flixel -->
|
||||
<git name="flixel" url="https://github.com/FNF-CNE-Devs/flixel" />
|
||||
@@ -10,13 +10,13 @@
|
||||
|
||||
<!-- Other Libraries -->
|
||||
<git name="hscript-improved" url="https://github.com/FNF-CNE-Devs/hscript-improved" ref="custom-classes" />
|
||||
<git name="discord-rpc" url="https://github.com/Aidan63/linc_discord-rpc" />
|
||||
<git name="flxanimate" url="https://github.com/FNF-CNE-Devs/flxanimate" />
|
||||
<git name="hxdiscord_rpc" url="https://github.com/FNF-CNE-Devs/hxdiscord_rpc" />
|
||||
<lib name="hxvlc" />
|
||||
|
||||
<!-- Documentation and other features -->
|
||||
<lib name="away3d" />
|
||||
<git name="away3d" url="https://github.com/FNF-CNE-Devs/away3d" />
|
||||
<!-- <lib name="dox" /> -->
|
||||
<lib name="format" />
|
||||
<lib name="markdown" />
|
||||
</libraries>
|
||||
</libraries>
|
||||
|
||||
+9
-4
@@ -7,7 +7,7 @@
|
||||
package="com.yoshman29.codenameengine"
|
||||
version="0.1.0" company="Yoshman29" />
|
||||
|
||||
<!--
|
||||
<!--
|
||||
CHANGE THE SAVE PATH & NAME FOR YOUR MOD HERE!
|
||||
-->
|
||||
<app save-path="YoshiCrafter29/CodenameEngine" save-name="save-default" mod-saves="true" />
|
||||
@@ -161,6 +161,13 @@
|
||||
|
||||
<!-- _______________________________ Libraries ______________________________ -->
|
||||
|
||||
<!-- KEEP BOTH OF THESE AS THERE ARE SOME PARTICULAR CASES! -->
|
||||
<define name="disable-version-check"/>
|
||||
<haxedef name="disable-version-check"/>
|
||||
|
||||
<haxedef name="no-deprecation-warnings"/>
|
||||
<haxedef name="DISCORD_DISABLE_IO_THREAD" if="DISCORD_RPC"/>
|
||||
|
||||
<haxelib name="flixel" />
|
||||
<haxelib name="flixel-addons" />
|
||||
|
||||
@@ -170,11 +177,9 @@
|
||||
<haxelib name="flxanimate" />
|
||||
|
||||
<haxelib name="hscript-improved" />
|
||||
<haxelib name="discord-rpc" if="DISCORD_RPC"/>
|
||||
<haxelib name="hxdiscord_rpc" if="DISCORD_RPC"/>
|
||||
<haxelib name="markdown" />
|
||||
|
||||
<haxedef name="no-deprecation-warnings"/>
|
||||
|
||||
<!-- _________________________________ Additional stuff _______________________________ -->
|
||||
|
||||
<section if="COMPILE_ALL_CLASSES">
|
||||
|
||||
@@ -41,7 +41,10 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
||||
public var debugMode:Bool = false;
|
||||
public var animDatas:Map<String, AnimData> = [];
|
||||
|
||||
public var beatInterval:Int = 1;
|
||||
/**
|
||||
* ODD interval -> asynced; EVEN interval -> synced
|
||||
*/
|
||||
public var beatInterval(default, set):Int = 2;
|
||||
public var beatOffset:Int = 0;
|
||||
public var skipNegativeBeats:Bool = false;
|
||||
|
||||
@@ -358,4 +361,13 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
||||
return animateAtlas != null ? (animateAtlas.anim.finished) : (animation.curAnim != null ? animation.curAnim.finished : true);
|
||||
}
|
||||
#end
|
||||
|
||||
// Getter / Setters
|
||||
|
||||
@:noCompletion private function set_beatInterval(v:Int) {
|
||||
if (v < 1)
|
||||
v = 1;
|
||||
|
||||
return beatInterval = v;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ class MusicBeatTransition extends MusicBeatSubstate {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
super.create();
|
||||
}
|
||||
|
||||
|
||||
@@ -51,10 +51,11 @@ class ModsFolder {
|
||||
*/
|
||||
private static var __firstTime:Bool = true;
|
||||
/**
|
||||
* Initialises `mods` folder by adding callbacks and such.
|
||||
* Initialises `mods` folder.
|
||||
*/
|
||||
public static function init() {
|
||||
|
||||
if(!getModsList().contains(Options.lastLoadedMod))
|
||||
Options.lastLoadedMod = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,6 +90,24 @@ class ModsFolder {
|
||||
#end
|
||||
}
|
||||
|
||||
public static function getModsList():Array<String> {
|
||||
var mods:Array<String> = [];
|
||||
#if MOD_SUPPORT
|
||||
for(modFolder in FileSystem.readDirectory(modsPath)) {
|
||||
if (FileSystem.isDirectory('${modsPath}${modFolder}')) {
|
||||
mods.push(modFolder);
|
||||
} else {
|
||||
var ext = Path.extension(modFolder).toLowerCase();
|
||||
switch(ext) {
|
||||
case 'zip':
|
||||
// is a zip mod!!
|
||||
mods.push(Path.withoutExtension(modFolder));
|
||||
}
|
||||
}
|
||||
}
|
||||
#end
|
||||
return mods;
|
||||
}
|
||||
public static function getLoadedMods():Array<String> {
|
||||
var libs = [];
|
||||
for (i in Paths.assetsTree.libraries) {
|
||||
|
||||
@@ -100,7 +100,7 @@ class Paths
|
||||
}
|
||||
return getPath('images/$key.$ext', library);
|
||||
}
|
||||
|
||||
|
||||
inline static public function script(key:String, ?library:String, isAssetsPath:Bool = false) {
|
||||
var scriptPath = isAssetsPath ? key : getPath(key, library);
|
||||
if (!OpenFlAssets.exists(scriptPath)) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package funkin.backend.chart;
|
||||
|
||||
import funkin.backend.system.Conductor;
|
||||
import funkin.backend.chart.ChartData;
|
||||
import flixel.util.FlxColor;
|
||||
import haxe.io.Path;
|
||||
@@ -143,7 +144,7 @@ class Chart {
|
||||
base = data;
|
||||
} else {
|
||||
// base game chart
|
||||
BaseGameParser.parse(data, base);
|
||||
FNFLegacyParser.parse(data, base);
|
||||
}
|
||||
#end
|
||||
}
|
||||
@@ -200,17 +201,19 @@ class Chart {
|
||||
var meta = filteredChart.meta;
|
||||
|
||||
#if sys
|
||||
if (!FileSystem.exists('${songFolderPath}/charts/'))
|
||||
FileSystem.createDirectory('${songFolderPath}/charts/');
|
||||
var saveFolder:String = saveSettings.folder == null ? "charts" : saveSettings.folder;
|
||||
|
||||
var chartPath = '${songFolderPath}/charts/${difficulty.trim()}.json';
|
||||
if (!FileSystem.exists('${songFolderPath}/$saveFolder/'))
|
||||
FileSystem.createDirectory('${songFolderPath}/$saveFolder/');
|
||||
|
||||
var chartPath = '${songFolderPath}/$saveFolder/${difficulty.trim()}.json';
|
||||
var metaPath = '${songFolderPath}/meta.json';
|
||||
|
||||
File.saveContent(chartPath, Json.stringify(filteredChart, null, saveSettings.prettyPrint == true ? "\t" : null));
|
||||
CoolUtil.safeSaveFile(chartPath, Json.stringify(filteredChart, null, saveSettings.prettyPrint == true ? "\t" : null));
|
||||
|
||||
// idk how null reacts to it so better be sure
|
||||
if (saveSettings.overrideExistingMeta == true || !FileSystem.exists(metaPath))
|
||||
File.saveContent(metaPath, Json.stringify(meta, null, saveSettings.prettyPrint == true ? "\t" : null));
|
||||
CoolUtil.safeSaveFile(metaPath, Json.stringify(meta, null, saveSettings.prettyPrint == true ? "\t" : null));
|
||||
#end
|
||||
return filteredChart;
|
||||
}
|
||||
@@ -242,4 +245,5 @@ typedef ChartSaveSettings = {
|
||||
var ?saveMetaInChart:Bool;
|
||||
var ?saveEventsInChart:Bool;
|
||||
var ?prettyPrint:Bool;
|
||||
var ?folder:String;
|
||||
}
|
||||
|
||||
@@ -59,8 +59,7 @@ typedef ChartEvent = {
|
||||
var params:Array<Dynamic>;
|
||||
}
|
||||
|
||||
@:enum
|
||||
abstract ChartStrumLineType(Int) from Int to Int {
|
||||
enum abstract ChartStrumLineType(Int) from Int to Int {
|
||||
/**
|
||||
* STRUMLINE IS MARKED AS OPPONENT - WILL BE PLAYED BY CPU, OR PLAYED BY PLAYER IF OPPONENT MODE IS ON
|
||||
*/
|
||||
|
||||
@@ -13,7 +13,7 @@ class EventsData {
|
||||
public static var defaultEventsList:Array<String> = ["HScript Call", "Camera Movement", "Add Camera Zoom", "Camera Modulo Change", "Camera Flash", "BPM Change", "Scroll Speed Change", "Alt Animation Toggle", "Play Animation"];
|
||||
public static var defaultEventsParams:Map<String, Array<EventParamInfo>> = [
|
||||
"HScript Call" => [
|
||||
{name: "Function Name", type: TString, defValue: "myFunc"},
|
||||
{name: "Function Name", type: TString, defValue: "myFunc"},
|
||||
{name: "Function Parameters (String split with commas)", type: TString, defValue: ""}
|
||||
],
|
||||
"Camera Movement" => [{name: "Camera Target", type: TStrumLine, defValue: 0}],
|
||||
|
||||
+101
-6
@@ -1,6 +1,9 @@
|
||||
package funkin.backend.chart;
|
||||
|
||||
class BaseGameParser {
|
||||
import funkin.backend.chart.ChartData.ChartEvent;
|
||||
import funkin.backend.system.Conductor;
|
||||
|
||||
class FNFLegacyParser {
|
||||
public static function parse(data:Dynamic, result:ChartData) {
|
||||
// base fnf chart parsing
|
||||
var data:SwagSong = data;
|
||||
@@ -109,7 +112,95 @@ class BaseGameParser {
|
||||
curTime += curCrochet * beatsPerMeasure;
|
||||
}
|
||||
}
|
||||
|
||||
// have conductor set up BEFORE you run this :D -lunar
|
||||
public static function encode(chart:ChartData):Dynamic {
|
||||
var base:SwagSong = __convertToSwagSong(chart);
|
||||
base.notes = __convertToSwagSections(chart);
|
||||
|
||||
for (strumLine in chart.strumLines)
|
||||
for (note in strumLine.notes) {
|
||||
var section:Int = Math.floor(Conductor.getStepForTime(note.time) / Conductor.getMeasureLength());
|
||||
var swagSection:SwagSection = base.notes[section];
|
||||
if (section > 0 && section < base.notes.length) {
|
||||
var sectionNote:Array<Dynamic> = [
|
||||
note.time, // TIME
|
||||
note.id, // DATA
|
||||
note.sLen // SUSTAIN LENGTH
|
||||
];
|
||||
|
||||
if ((swagSection.mustHitSection && strumLine.type == OPPONENT) ||
|
||||
(!swagSection.mustHitSection && strumLine.type == PLAYER))
|
||||
sectionNote[1] += 4;
|
||||
swagSection.sectionNotes.push(note);
|
||||
}
|
||||
}
|
||||
|
||||
return {song: base};
|
||||
}
|
||||
|
||||
// To make it easier to write the psych parser... -lunar
|
||||
@:noCompletion public static function __convertToSwagSong(chart:ChartData):SwagSong {
|
||||
var base:SwagSong = {
|
||||
song: chart.meta.name,
|
||||
notes: null,
|
||||
bpm: chart.meta.bpm,
|
||||
needsVoices: chart.meta.needsVoices,
|
||||
speed: chart.scrollSpeed,
|
||||
|
||||
player1: null,
|
||||
player2: null,
|
||||
validScore: true
|
||||
};
|
||||
|
||||
for (strumLine in chart.strumLines)
|
||||
switch (strumLine.type) {
|
||||
case OPPONENT:
|
||||
if (base.player2 == null) base.player2 = strumLine.characters.getDefault(["dad"])[0];
|
||||
case PLAYER:
|
||||
if (base.player1 == null) base.player1 = strumLine.characters.getDefault(["bf"])[0];
|
||||
case ADDITIONAL: // do nothing
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
@:noCompletion public static function __convertToSwagSections(chart:ChartData):Array<SwagSection> {
|
||||
var events:Array<ChartEvent> = [for (event in chart.events) Reflect.copy(event)];
|
||||
|
||||
var measures:Float = Conductor.getMeasuresLength();
|
||||
var sections:Int = Math.floor(measures) + (measures % 1 > 0 ? 1 : 0);
|
||||
|
||||
var notes:Array<SwagSection> = cast new haxe.ds.Vector<SwagSection>(sections);
|
||||
for (section in 0...sections) {
|
||||
var baseSection:SwagSection = {
|
||||
sectionNotes: [],
|
||||
lengthInSteps: Std.int(Conductor.getMeasureLength()),
|
||||
mustHitSection: notes[section-1] != null ? notes[section-1].mustHitSection : false,
|
||||
bpm: notes[section-1] != null ? notes[section-1].bpm : chart.meta.bpm,
|
||||
changeBPM: false,
|
||||
altAnim: notes[section-1] != null ? notes[section-1].altAnim : false
|
||||
};
|
||||
|
||||
var sectionEndTime:Float = Conductor.getTimeForStep(Conductor.getMeasureLength() * (section+1));
|
||||
while(events.length > 0 && events[0].time < sectionEndTime) {
|
||||
var event:ChartEvent = events.shift();
|
||||
switch (event.name) {
|
||||
case "Camera Movement":
|
||||
baseSection.mustHitSection = chart.strumLines[event.params[0]].type == PLAYER;
|
||||
case "Alt Animation Toggle":
|
||||
baseSection.altAnim = event.params[0] || event.params[1];
|
||||
case "BPM Change":
|
||||
baseSection.changeBPM = true;
|
||||
baseSection.bpm = event.params[0];
|
||||
}
|
||||
}
|
||||
notes[section] = baseSection;
|
||||
}
|
||||
return notes;
|
||||
}
|
||||
}
|
||||
|
||||
typedef SwagSong =
|
||||
{
|
||||
var song:String;
|
||||
@@ -117,13 +208,14 @@ typedef SwagSong =
|
||||
var bpm:Float;
|
||||
var needsVoices:Bool;
|
||||
var speed:Float;
|
||||
var stage:String;
|
||||
var noteTypes:Array<String>;
|
||||
var ?stage:String;
|
||||
var ?noteTypes:Array<String>;
|
||||
var ?events:Array<Dynamic>;
|
||||
|
||||
var player1:String;
|
||||
var player2:String;
|
||||
var gf:String;
|
||||
var gfVersion:String;
|
||||
var ?gf:String;
|
||||
var ?gfVersion:String;
|
||||
var validScore:Bool;
|
||||
|
||||
// ADDITIONAL STUFF THAT MAY NOT BE PRESENT IN CHART
|
||||
@@ -136,9 +228,12 @@ typedef SwagSection =
|
||||
{
|
||||
var sectionNotes:Array<Dynamic>;
|
||||
var lengthInSteps:Int;
|
||||
var ?sectionBeats:Float;
|
||||
var ?typeOfSection:Int;
|
||||
var mustHitSection:Bool;
|
||||
var ?gfSection:Bool;
|
||||
var bpm:Float;
|
||||
var changeBPM:Bool;
|
||||
var altAnim:Null<Bool>;
|
||||
@:optional var camTarget:Null<Float>;
|
||||
var ?camTarget:Null<Float>;
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package funkin.backend.chart;
|
||||
|
||||
import funkin.backend.chart.FNFLegacyParser.SwagSection;
|
||||
import funkin.backend.chart.ChartData.ChartEvent;
|
||||
import funkin.backend.chart.FNFLegacyParser.SwagSong;
|
||||
import funkin.backend.system.Conductor;
|
||||
|
||||
class PsychParser {
|
||||
// Alreadly parsed in sections
|
||||
public static var ignoreEvents:Array<String> = [
|
||||
"Camera Movement",
|
||||
"Alt Animation Toggle",
|
||||
"BPM Change"
|
||||
];
|
||||
|
||||
public static function parse(data:Dynamic, result:ChartData)
|
||||
FNFLegacyParser.parse(data, result);
|
||||
|
||||
public static function encode(chart:ChartData):Dynamic {
|
||||
var base:SwagSong = FNFLegacyParser.__convertToSwagSong(chart);
|
||||
base.notes = FNFLegacyParser.__convertToSwagSections(chart);
|
||||
base.stage = chart.stage;
|
||||
|
||||
for (section in base.notes)
|
||||
section.sectionBeats = Conductor.beatsPerMeasure;
|
||||
|
||||
for (strumLine in chart.strumLines)
|
||||
if (strumLine.type == ADDITIONAL && base.gfVersion == null)
|
||||
base.gfVersion = strumLine.characters.getDefault(["gf"])[0];
|
||||
|
||||
for (strumLine in chart.strumLines)
|
||||
for (note in strumLine.notes) {
|
||||
var section:Int = Math.floor(Conductor.getStepForTime(note.time) / Conductor.getMeasureLength());
|
||||
var swagSection:SwagSection = base.notes[section];
|
||||
|
||||
if (section >= 0 && section < base.notes.length) {
|
||||
var sectionNote:Array<Dynamic> = [
|
||||
note.time, // TIME
|
||||
note.id, // DATA
|
||||
note.sLen, // SUSTAIN LENGTH
|
||||
chart.noteTypes.getDefault([""])[note.type] // NOTE TYPE
|
||||
];
|
||||
|
||||
if ((swagSection.mustHitSection && strumLine.type == OPPONENT) ||
|
||||
(!swagSection.mustHitSection && strumLine.type == PLAYER))
|
||||
sectionNote[1] += 4;
|
||||
swagSection.sectionNotes.push(sectionNote);
|
||||
}
|
||||
}
|
||||
|
||||
var groupedEvents:Array<Array<ChartEvent>> = [];
|
||||
var __last:Array<ChartEvent> = null;
|
||||
var __lastTime:Float = Math.NaN;
|
||||
for (e in [for (event in chart.events) Reflect.copy(event)]) {
|
||||
if (e == null || ignoreEvents.contains(e.name)) continue;
|
||||
|
||||
if (__last != null && __lastTime == e.time)
|
||||
__last.push(e);
|
||||
else {
|
||||
__last = [e];
|
||||
__lastTime = e.time;
|
||||
groupedEvents.push(__last);
|
||||
}
|
||||
}
|
||||
|
||||
base.events = [];
|
||||
for (events in groupedEvents) {
|
||||
var psychEvents:Array<Dynamic> = [];
|
||||
for (event in events)
|
||||
switch (event.name) {
|
||||
case "Add Camera Zoom":
|
||||
psychEvents.push([
|
||||
event.name,
|
||||
event.params[1] == "camGame" ? event.params[0] : 0, // CAMERA ZOOM
|
||||
event.params[1] == "camHUD" ? event.params[0] : 0, // UI ZOOM
|
||||
]);
|
||||
case "Play Animation":
|
||||
psychEvents.push([
|
||||
event.name,
|
||||
event.params[1], // ANIMATION TO PLAY
|
||||
switch (chart.strumLines[event.params[0]].type) { // CHARACTER
|
||||
case PLAYER: "bf";
|
||||
case OPPONENT: "dad";
|
||||
case ADDITIONAL: "gf";
|
||||
}
|
||||
]);
|
||||
case "Scroll Speed Change":
|
||||
var eventStep:Float = Conductor.getStepForTime(event.time);
|
||||
psychEvents.push([
|
||||
"Change Scroll Speed",
|
||||
FlxMath.roundDecimal(event.params[1]/chart.scrollSpeed, 2), // SCROLL SPEED MULTIPLER
|
||||
FlxMath.roundDecimal( // TIME
|
||||
event.params[0] ? // IS TWEENED?
|
||||
(Conductor.getTimeForStep(eventStep+event.params[2]) - Conductor.getTimeForStep(eventStep))/1000
|
||||
: 0, 2)
|
||||
]);
|
||||
default:
|
||||
// TODO: allow custom formats in event.json
|
||||
var split:Float = event.params.length / 2;
|
||||
|
||||
var val1:String = [for (arg in 0...Math.ceil(split)) event.params[arg]].join(",");
|
||||
var val2:String = [for (arg in Math.ceil(split)...event.params.length) event.params[arg]].join(",");
|
||||
|
||||
psychEvents.push([event.name, val1, val2]);
|
||||
}
|
||||
|
||||
for (psychEvent in psychEvents)
|
||||
for (i in 1...3) // Turn both vals into strings
|
||||
if (!(psychEvent[i] is String))
|
||||
psychEvent[i] = Std.string(psychEvent[i]);
|
||||
|
||||
base.events.push([events[0].time, psychEvents]);
|
||||
}
|
||||
return {song: base};
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ package funkin.backend.scripting;
|
||||
*/
|
||||
class DummyScript extends Script {
|
||||
public var variables:Map<String, Dynamic> = [];
|
||||
|
||||
|
||||
public override function get(v:String) {return variables.get(v);}
|
||||
public override function set(v:String, v2:Dynamic) {return variables.set(v, v2);}
|
||||
public override function onCall(method:String, parameters:Array<Dynamic>):Dynamic {
|
||||
|
||||
@@ -79,12 +79,14 @@ class GlobalScript {
|
||||
}
|
||||
|
||||
public static function event<T:CancellableEvent>(name:String, event:T):T {
|
||||
if (scripts != null) scripts.call(name, [event]);
|
||||
if (scripts != null)
|
||||
scripts.event(name, event);
|
||||
return event;
|
||||
}
|
||||
|
||||
public static function call(name:String, ?args:Array<Dynamic>) {
|
||||
if (scripts != null) scripts.call(name, args);
|
||||
if (scripts != null)
|
||||
scripts.call(name, args);
|
||||
}
|
||||
public static function onModSwitch(newMod:String) {
|
||||
call("destroy");
|
||||
@@ -93,7 +95,8 @@ class GlobalScript {
|
||||
for (i in funkin.backend.assets.ModsFolder.getLoadedMods()) {
|
||||
var path = Paths.script('data/global/LIB_$i');
|
||||
var script = Script.create(path);
|
||||
if (script is DummyScript) continue;
|
||||
if (script is DummyScript)
|
||||
continue;
|
||||
script.remappedNames.set(script.fileName, '$i:${script.fileName}');
|
||||
scripts.add(script);
|
||||
script.load();
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
package funkin.backend.scripting.events;
|
||||
|
||||
#if DISCORD_RPC
|
||||
import discord_rpc.DiscordRpc.DiscordPresenceOptions;
|
||||
#end
|
||||
|
||||
final class DiscordPresenceUpdateEvent extends CancellableEvent {
|
||||
/**
|
||||
* Object containing all of the data for the presence. Can be altered.
|
||||
*/
|
||||
public var presenceData:#if DISCORD_RPC DiscordPresenceOptions #else Dynamic #end;
|
||||
public var presence:funkin.backend.utils.DiscordUtil.DPresence;
|
||||
}
|
||||
@@ -370,15 +370,18 @@ class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
|
||||
var field = Reflect.field(data, name);
|
||||
var cl = Type.getClassName(Type.getClass(field));
|
||||
|
||||
// cant do "field is ShaderInput" for some reason
|
||||
if (cl.startsWith("openfl.display.ShaderParameter")) {
|
||||
var sp = cast(field, ShaderParameter<Dynamic>);
|
||||
@:privateAccess
|
||||
return (sp.__length > 1) ? sp.value : sp.value[0];
|
||||
} else if (cl.startsWith("openfl.display.ShaderInput")) {
|
||||
var si = cast(field, ShaderInput<Dynamic>);
|
||||
return si.input;
|
||||
}
|
||||
// little problem we are facing boys...
|
||||
|
||||
// cant do "field is ShaderInput" because ShaderInput has the @:generic metadata
|
||||
// aka instead of ShaderInput<Float> it gets built as ShaderInput_Float
|
||||
// this should be fine tho because we check the class, and the fields dont vary based on the type
|
||||
|
||||
// thanks for looking in the code cne fans :D!! -lunar
|
||||
|
||||
if (cl.startsWith("openfl.display.ShaderParameter"))
|
||||
return (field.__length > 1) ? field.value : field.value[0];
|
||||
else if (cl.startsWith("openfl.display.ShaderInput"))
|
||||
return field.input;
|
||||
return field;
|
||||
}
|
||||
|
||||
|
||||
@@ -120,8 +120,6 @@ class Main extends Sprite
|
||||
ShaderResizeFix.init();
|
||||
Logs.init();
|
||||
Paths.init();
|
||||
ModsFolder.init();
|
||||
DiscordUtil.init();
|
||||
#if GLOBAL_SCRIPT
|
||||
funkin.backend.scripting.GlobalScript.init();
|
||||
#end
|
||||
@@ -159,6 +157,7 @@ class Main extends Sprite
|
||||
|
||||
FlxG.mouse.useSystemCursor = true;
|
||||
|
||||
ModsFolder.init();
|
||||
#if MOD_SUPPORT
|
||||
ModsFolder.switchMod(modToLoad.getDefault(Options.lastLoadedMod));
|
||||
#end
|
||||
|
||||
@@ -41,7 +41,7 @@ class MainState extends FlxState {
|
||||
else if (addon.startsWith("[HIGH]")) _highPriorityAddons.insert(0, addon);
|
||||
else _noPriorityAddons.insert(0, addon);
|
||||
}
|
||||
for (addon in _lowPriorityAddons)
|
||||
for (addon in _lowPriorityAddons)
|
||||
Paths.assetsTree.addLibrary(ModsFolder.loadModLib('${ModsFolder.addonsPath}$addon', StringTools.ltrim(addon.substr("[LOW]".length))));
|
||||
}
|
||||
if (ModsFolder.currentModFolder != null)
|
||||
@@ -55,7 +55,7 @@ class MainState extends FlxState {
|
||||
|
||||
Main.refreshAssets();
|
||||
ModsFolder.onModSwitch.dispatch(ModsFolder.currentModFolder);
|
||||
DiscordUtil.reloadJsonData();
|
||||
DiscordUtil.init();
|
||||
EventsData.reloadEvents();
|
||||
TitleState.initialized = false;
|
||||
|
||||
@@ -68,7 +68,7 @@ class MainState extends FlxState {
|
||||
|
||||
#if sys
|
||||
sys.FileSystem.createDirectory('./.temp/');
|
||||
#if windows Sys.command("attrib +h .temp"); #end
|
||||
#if windows new funkin.backend.utils.native.HiddenProcess("attrib +h .temp"); #end
|
||||
#end
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ class FlixelInfo extends FramerateCategory {
|
||||
var c:Int = 0;
|
||||
for(_ in FlxG.bitmap._cache.keys())
|
||||
c++;
|
||||
|
||||
|
||||
_text = 'State: ${Type.getClassName(Type.getClass(FlxG.state))}';
|
||||
_text += '\nObject Count: ${FlxG.state.members.length}';
|
||||
_text += '\nCamera Count: ${FlxG.cameras.list.length}';
|
||||
@@ -27,7 +27,7 @@ class FlixelInfo extends FramerateCategory {
|
||||
_text += '\nPoint Count: ${points._count}';
|
||||
#end
|
||||
}
|
||||
|
||||
|
||||
this.text.text = _text;
|
||||
super.__enterFrame(t);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import openfl.text.TextField;
|
||||
class MemoryCounter extends Sprite {
|
||||
public var memoryText:TextField;
|
||||
public var memoryPeakText:TextField;
|
||||
|
||||
|
||||
public var memory:Float = 0;
|
||||
public var memoryPeak:Float = 0;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ class StatsInfo extends FramerateCategory {
|
||||
_text = "totalDC: " + Context3DStats.totalDrawCalls();
|
||||
_text += "\nstageDC: " + Context3DStats.contextDrawCalls(DrawCallContext.STAGE);
|
||||
_text += "\nstage3DDC: " + Context3DStats.contextDrawCalls(DrawCallContext.STAGE3D);
|
||||
|
||||
|
||||
this.text.text = _text;
|
||||
super.__enterFrame(t);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package funkin.backend.system.github;
|
||||
#if GITHUB_API
|
||||
import haxe.Json;
|
||||
import haxe.Exception;
|
||||
import haxe.Http;
|
||||
#end
|
||||
|
||||
// TODO: Document further and perhaps make this a Haxelib.
|
||||
@@ -18,7 +17,7 @@ class GitHub {
|
||||
public static function getReleases(user:String, repository:String, ?onError:Exception->Void):Array<GitHubRelease> {
|
||||
#if GITHUB_API
|
||||
try {
|
||||
var data = Json.parse(__requestOnGitHubServers('https://api.github.com/repos/${user}/${repository}/releases'));
|
||||
var data = Json.parse(HttpUtil.requestText('https://api.github.com/repos/${user}/${repository}/releases'));
|
||||
if (!(data is Array))
|
||||
throw __parseGitHubException(data);
|
||||
|
||||
@@ -41,7 +40,7 @@ class GitHub {
|
||||
public static function getContributors(user:String, repository:String, ?onError:Exception->Void):Array<GitHubContributor> {
|
||||
#if GITHUB_API
|
||||
try {
|
||||
var data = Json.parse(__requestOnGitHubServers('https://api.github.com/repos/${user}/${repository}/contributors'));
|
||||
var data = Json.parse(HttpUtil.requestText('https://api.github.com/repos/${user}/${repository}/contributors'));
|
||||
if (!(data is Array))
|
||||
throw __parseGitHubException(data);
|
||||
|
||||
@@ -63,7 +62,7 @@ class GitHub {
|
||||
public static function getOrganization(org:String, ?onError:Exception->Void):GitHubOrganization {
|
||||
#if GITHUB_API
|
||||
try {
|
||||
var data = Json.parse(__requestOnGitHubServers('https://api.github.com/orgs/$org'));
|
||||
var data = Json.parse(HttpUtil.requestText('https://api.github.com/orgs/$org'));
|
||||
if (Reflect.hasField(data, "documentation_url"))
|
||||
throw __parseGitHubException(data);
|
||||
|
||||
@@ -86,7 +85,7 @@ class GitHub {
|
||||
public static function getOrganizationMembers(org:String, ?onError:Exception->Void):Array<GitHubContributor> {
|
||||
#if GITHUB_API
|
||||
try {
|
||||
var data = Json.parse(__requestOnGitHubServers('https://api.github.com/orgs/$org/members'));
|
||||
var data = Json.parse(HttpUtil.requestText('https://api.github.com/orgs/$org/members'));
|
||||
if (Reflect.hasField(data, "documentation_url"))
|
||||
throw __parseGitHubException(data);
|
||||
|
||||
@@ -111,7 +110,7 @@ class GitHub {
|
||||
try {
|
||||
var url = 'https://api.github.com/users/$user';
|
||||
|
||||
var data = Json.parse(__requestOnGitHubServers(url));
|
||||
var data = Json.parse(HttpUtil.requestText(url));
|
||||
if (Reflect.hasField(data, "documentation_url"))
|
||||
throw __parseGitHubException(data);
|
||||
|
||||
@@ -134,59 +133,6 @@ class GitHub {
|
||||
public static inline function filterReleases(releases:Array<GitHubRelease>, keepPrereleases:Bool = true, keepDrafts:Bool = false)
|
||||
return #if GITHUB_API [for(release in releases) if (release != null && (!release.prerelease || (release.prerelease && keepPrereleases)) && (!release.draft || (release.draft && keepDrafts))) release] #else releases #end;
|
||||
|
||||
public static function __requestOnGitHubServers(url:String) {
|
||||
var r = null;
|
||||
#if GITHUB_API
|
||||
var h = new Http(url);
|
||||
h.setHeader("User-Agent", "request");
|
||||
|
||||
h.onStatus = function(s) {
|
||||
if(isRedirect(s))
|
||||
r = __requestOnGitHubServers(h.responseHeaders.get("Location"));
|
||||
};
|
||||
|
||||
h.onData = function(d) {
|
||||
if(r == null) r = d;
|
||||
}
|
||||
h.onError = function(e) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
h.request(false);
|
||||
#end
|
||||
return r;
|
||||
}
|
||||
public static function __requestBytesOnGitHubServers(url:String) {
|
||||
var r = null;
|
||||
#if GITHUB_API
|
||||
var h = new Http(url);
|
||||
h.setHeader("User-Agent", "request");
|
||||
|
||||
h.onStatus = function(s) {
|
||||
if(isRedirect(s))
|
||||
r = __requestBytesOnGitHubServers(h.responseHeaders.get("Location"));
|
||||
};
|
||||
|
||||
h.onBytes = function(d) {
|
||||
if(r == null) r = d;
|
||||
}
|
||||
h.onError = function(e) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
h.request(false);
|
||||
#end
|
||||
return r;
|
||||
}
|
||||
private static function isRedirect(status:Int):Bool {
|
||||
switch (status) {
|
||||
// 301: Moved Permanently, 302: Found (Moved Temporarily), 307: Temporary Redirect, 308: Permanent Redirect - Nex
|
||||
case 301 | 302 | 307 | 308 :
|
||||
trace("Redirected with status code: " + status);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private static function __parseGitHubException(obj:Dynamic):GitHubException {
|
||||
#if GITHUB_API
|
||||
var msg:String = "(No message)";
|
||||
|
||||
@@ -37,4 +37,21 @@ class Utils {
|
||||
return expr;
|
||||
#end
|
||||
}
|
||||
|
||||
public static macro function safeSet(variable:Null<Expr>, value:Null<Expr>):Null<Expr> {
|
||||
#if macro
|
||||
return macro if (${value} != null) ${variable} = ${value};
|
||||
#end
|
||||
}
|
||||
public static macro function safeSetWrapper(variable:Null<Expr>, value:Null<Expr>, wrapper:Null<Expr>):Null<Expr> {
|
||||
#if macro
|
||||
return macro if (${value} != null) ${variable} = ${wrapper}(${value});
|
||||
#end
|
||||
}
|
||||
|
||||
public static macro function safeReflection(variable:Null<Expr>, value:Null<Expr>, field:Null<Expr>):Null<Expr> {
|
||||
#if macro
|
||||
return macro if (Reflect.hasField(${value}, ${field})) ${variable} = Reflect.field(${value}, ${field});
|
||||
#end
|
||||
}
|
||||
}
|
||||
@@ -21,14 +21,14 @@ class AsyncUpdater {
|
||||
public function new(releases:Array<GitHubRelease>) {
|
||||
this.releases = releases;
|
||||
}
|
||||
|
||||
|
||||
public function execute() {
|
||||
Main.execAsync(installUpdates);
|
||||
}
|
||||
#end
|
||||
|
||||
|
||||
#if windows
|
||||
|
||||
|
||||
#if windows
|
||||
public static var executableGitHubName:String = "update-windows.exe";
|
||||
public static var executableName:String = "CodenameEngine.exe";
|
||||
#end
|
||||
@@ -49,7 +49,7 @@ class AsyncUpdater {
|
||||
|
||||
public var lastTime:Float = 0;
|
||||
public var oldBytesLoaded:Float = 0;
|
||||
|
||||
|
||||
public function installUpdates() {
|
||||
prepareInstallationEnvironment();
|
||||
downloadFiles();
|
||||
@@ -64,7 +64,7 @@ class AsyncUpdater {
|
||||
progress.curFileName = e;
|
||||
trace('extracting file ${path}');
|
||||
var reader = ZipUtil.openZip(path);
|
||||
|
||||
|
||||
progress.curZipProgress = new ZipProgress();
|
||||
ZipUtil.uncompressZip(reader, './', null, progress.curZipProgress);
|
||||
// FileSystem.deleteFile(path);
|
||||
@@ -72,7 +72,7 @@ class AsyncUpdater {
|
||||
if (executableReplaced = FileSystem.exists('$path$executableName')) {
|
||||
progress.curFile = files.length;
|
||||
progress.curFileName = executableName;
|
||||
|
||||
|
||||
var progPath = Sys.programPath();
|
||||
var bakFile = '${Path.withoutExtension(progPath)}.bak';
|
||||
if (FileSystem.exists(bakFile))
|
||||
@@ -133,7 +133,7 @@ class AsyncUpdater {
|
||||
downloadStream.addEventListener(ProgressEvent.PROGRESS, function(e) {
|
||||
progress.bytesLoaded = e.bytesLoaded;
|
||||
progress.bytesTotal = e.bytesTotal;
|
||||
|
||||
|
||||
var curTime = Lib.getTimer();
|
||||
|
||||
progress.downloadSpeed = (e.bytesLoaded - oldBytesLoaded) / ((curTime - lastTime) / 1000);
|
||||
@@ -160,7 +160,7 @@ class AsyncUpdater {
|
||||
|
||||
public function prepareInstallationEnvironment() {
|
||||
progress.step = PREPARING;
|
||||
|
||||
|
||||
#if windows
|
||||
path = '${Sys.getEnv("TEMP")}\\Codename Engine\\Updater\\';
|
||||
#else
|
||||
|
||||
@@ -92,6 +92,8 @@ class UpdateAvailableScreen extends MusicBeatState {
|
||||
add(skipButton);
|
||||
|
||||
oldPos = FlxG.mouse.getScreenPosition();
|
||||
|
||||
DiscordUtil.call("onMenuLoaded", ["Update Available Screen"]);
|
||||
}
|
||||
|
||||
var destY:Float = 0;
|
||||
|
||||
@@ -59,8 +59,10 @@ class UpdateScreen extends MusicBeatState {
|
||||
overSound = FlxG.sound.load(Paths.sound('gameOverEnd'));
|
||||
|
||||
updater.execute();
|
||||
|
||||
|
||||
FlxG.camera.addShader(rainbowShader = new CustomShader("engine/updaterShader"));
|
||||
|
||||
DiscordUtil.call("onMenuLoaded", ["Update Screen"]);
|
||||
}
|
||||
|
||||
|
||||
@@ -104,7 +106,7 @@ class UpdateScreen extends MusicBeatState {
|
||||
// update is done, play bf's anim
|
||||
FlxG.sound.music.stop();
|
||||
overSound.play();
|
||||
|
||||
|
||||
remove(generalProgress);
|
||||
remove(partProgress);
|
||||
generalProgress = FlxDestroyUtil.destroy(generalProgress);
|
||||
|
||||
@@ -11,7 +11,7 @@ using funkin.backend.system.github.GitHub;
|
||||
class UpdateUtil {
|
||||
public static final repoOwner:String = "YoshiCrafter29";
|
||||
public static final repoName:String = "CodenameTestRepo";
|
||||
|
||||
|
||||
public static function init() {
|
||||
// deletes old bak file if it exists
|
||||
#if sys
|
||||
@@ -22,11 +22,11 @@ class UpdateUtil {
|
||||
}
|
||||
|
||||
public static function checkForUpdates():UpdateCheckCallback {
|
||||
var curTag = 'v${Application.current.meta.get('version')}';
|
||||
var curTag = 'v${Application.current.meta.get('version')}';
|
||||
trace(curTag);
|
||||
|
||||
|
||||
var error = false;
|
||||
|
||||
|
||||
var newUpdates = __doReleaseFiltering(GitHub.getReleases(repoOwner, repoName, function(e) {
|
||||
error = true;
|
||||
}), curTag);
|
||||
@@ -35,7 +35,7 @@ class UpdateUtil {
|
||||
success: false,
|
||||
newUpdate: false
|
||||
};
|
||||
|
||||
|
||||
if (newUpdates.length <= 0) {
|
||||
return {
|
||||
success: true,
|
||||
|
||||
@@ -2,6 +2,7 @@ package funkin.backend.utils;
|
||||
|
||||
import flixel.text.FlxText;
|
||||
import funkin.backend.utils.XMLUtil.TextFormat;
|
||||
import flixel.util.typeLimit.OneOfTwo;
|
||||
import flixel.tweens.FlxTween;
|
||||
import flixel.system.frontEnds.SoundFrontEnd;
|
||||
import flixel.sound.FlxSound;
|
||||
@@ -9,6 +10,7 @@ import funkin.backend.system.Conductor;
|
||||
import flixel.sound.FlxSoundGroup;
|
||||
import haxe.Json;
|
||||
import haxe.io.Path;
|
||||
import haxe.io.Bytes;
|
||||
import haxe.xml.Access;
|
||||
import flixel.input.keyboard.FlxKey;
|
||||
import lime.utils.Assets;
|
||||
@@ -77,6 +79,48 @@ class CoolUtil
|
||||
#end
|
||||
}
|
||||
|
||||
/**
|
||||
* Safe saves a file (even adding eventual missing folders) and shows a warning box instead of making the program crash
|
||||
* @param path Path to save the file at.
|
||||
* @param content Content of the file to save (as String or Bytes).
|
||||
*/
|
||||
@:noUsing public static function safeSaveFile(path:String, content:OneOfTwo<String, Bytes>, showErrorBox:Bool = true) {
|
||||
#if sys
|
||||
try {
|
||||
addMissingFolders(Path.directory(path));
|
||||
if(content is Bytes) sys.io.File.saveBytes(path, content);
|
||||
else sys.io.File.saveContent(path, content);
|
||||
} catch(e) {
|
||||
var errMsg:String = 'Error while trying to save the file: ${Std.string(e).replace('\n', ' ')}';
|
||||
Logs.traceColored([Logs.logText(errMsg, RED)], ERROR);
|
||||
if(showErrorBox) funkin.backend.utils.NativeAPI.showMessageBox("Codename Engine Warning", errMsg, MSG_WARNING);
|
||||
}
|
||||
#end
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates eventual missing folders to the specified `path`
|
||||
*
|
||||
* WARNING: eventual files in `path` will be considered as folders! Just to make possible folders be named as `songs.json` for example
|
||||
*
|
||||
* @param path Path to check.
|
||||
* @return The initial Path.
|
||||
*/
|
||||
@:noUsing public static function addMissingFolders(path:String):String {
|
||||
#if sys
|
||||
var folders:Array<String> = path.split("/");
|
||||
var currentPath:String = "";
|
||||
|
||||
for (folder in folders) {
|
||||
currentPath += folder + "/";
|
||||
if (!sys.FileSystem.exists(currentPath)) {
|
||||
sys.FileSystem.createDirectory(currentPath);
|
||||
}
|
||||
}
|
||||
#end
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut to parse a JSON string
|
||||
* @param str Path to the JSON string
|
||||
|
||||
@@ -1,62 +1,122 @@
|
||||
package funkin.backend.utils;
|
||||
|
||||
import funkin.backend.scripting.events.DiscordPresenceUpdateEvent;
|
||||
import funkin.backend.scripting.events.CancellableEvent;
|
||||
import funkin.backend.scripting.*; // lazy
|
||||
import flixel.util.typeLimit.OneOfTwo;
|
||||
import openfl.display.BitmapData;
|
||||
import funkin.backend.system.macros.Utils;
|
||||
import haxe.Json;
|
||||
import flixel.sound.FlxSound;
|
||||
#if DISCORD_RPC
|
||||
import discord_rpc.DiscordRpc;
|
||||
import hxdiscord_rpc.Discord;
|
||||
import hxdiscord_rpc.Types;
|
||||
import sys.thread.Thread;
|
||||
import Sys;
|
||||
import lime.app.Application;
|
||||
#end
|
||||
|
||||
class DiscordUtil {
|
||||
public static var currentID:String = null;
|
||||
class DiscordUtil
|
||||
{
|
||||
public static var currentID(default, set):String = null;
|
||||
public static var discordThread:#if DISCORD_RPC Thread #else Dynamic #end = null;
|
||||
public static var ready:Bool = false;
|
||||
public static var data:DiscordJson = null;
|
||||
public static var initialized:Bool = false;
|
||||
private static var stopThread:Bool = false;
|
||||
|
||||
public static function init() {
|
||||
public static var user:#if DISCORD_RPC DUser #else Dynamic #end = null;
|
||||
public static var lastPresence:#if DISCORD_RPC DPresence #else Dynamic #end = null;
|
||||
public static var config:#if DISCORD_RPC DiscordJson #else Dynamic #end = null;
|
||||
|
||||
public static var script:Script;
|
||||
|
||||
// Constants
|
||||
public static var REPLY_NO:Int = Discord.REPLY_NO;
|
||||
public static var REPLY_YES:Int = Discord.REPLY_YES;
|
||||
public static var REPLY_IGNORE:Int = Discord.REPLY_IGNORE;
|
||||
public static var PARTY_PRIVATE:Int = Discord.PARTY_PRIVATE;
|
||||
public static var PARTY_PUBLIC:Int = Discord.PARTY_PUBLIC;
|
||||
|
||||
public static function init()
|
||||
{
|
||||
#if DISCORD_RPC
|
||||
reloadJsonData();
|
||||
discordThread = Thread.create(function() {
|
||||
if (initialized)
|
||||
return;
|
||||
initialized = true;
|
||||
|
||||
discordThread = Thread.create(function()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
while(!ready) {
|
||||
Sys.sleep(1/60);
|
||||
while (!stopThread)
|
||||
{
|
||||
#if DISCORD_DISABLE_IO_THREAD
|
||||
Discord.UpdateConnection();
|
||||
#end
|
||||
Discord.RunCallbacks();
|
||||
|
||||
Sys.sleep(2);
|
||||
}
|
||||
trace("Processing Discord RPC...");
|
||||
DiscordRpc.process();
|
||||
Sys.sleep(2);
|
||||
|
||||
Sys.sleep(1); // to reduce cpu
|
||||
}
|
||||
});
|
||||
|
||||
Application.current.onExit.add(function(exitCode) {
|
||||
shutdown();
|
||||
});
|
||||
Application.current.onExit.add(function(_) shutdown());
|
||||
#end
|
||||
}
|
||||
|
||||
public static function reloadJsonData() {
|
||||
public static function reloadJsonData()
|
||||
{
|
||||
#if DISCORD_RPC
|
||||
data = {};
|
||||
var jsonPath = Paths.json("config/discord");
|
||||
if (Assets.exists(jsonPath)) {
|
||||
try {
|
||||
data = Json.parse(Assets.getText(jsonPath));
|
||||
} catch(e) {
|
||||
if (Assets.exists(jsonPath))
|
||||
{
|
||||
try
|
||||
config = Json.parse(Assets.getText(jsonPath))
|
||||
catch (e)
|
||||
Logs.trace('Couldn\'t load Discord RPC configuration: ${e.toString()}', ERROR);
|
||||
}
|
||||
}
|
||||
data.setFieldDefault("clientID", "1027994136193810442");
|
||||
data.setFieldDefault("logoKey", "icon");
|
||||
data.setFieldDefault("logoText", Application.current.meta.get('title'));
|
||||
else
|
||||
{
|
||||
config = {};
|
||||
}
|
||||
|
||||
changeClientID(data.clientID);
|
||||
config.logoKey = config.logoKey.getDefault("icon");
|
||||
config.logoText = config.logoText.getDefault(Application.current.meta.get('title'));
|
||||
config.clientID = config.clientID.getDefault("1027994136193810442");
|
||||
currentID = config.clientID;
|
||||
#end
|
||||
}
|
||||
|
||||
public static function changePresence(details:String, state:String, ?smallImageKey : String) {
|
||||
public static function event<T:CancellableEvent>(name:String, event:T):T
|
||||
{
|
||||
if (script != null)
|
||||
script.call(name, [event]);
|
||||
return event;
|
||||
}
|
||||
|
||||
public static function call(name:String, ?args:Array<Dynamic>)
|
||||
{
|
||||
if (script != null)
|
||||
script.call(name, args);
|
||||
}
|
||||
|
||||
public static function loadScript()
|
||||
{
|
||||
if (script != null)
|
||||
{
|
||||
call("destroy");
|
||||
script = FlxDestroyUtil.destroy(script);
|
||||
}
|
||||
script = Script.create(Paths.script('data/discord'));
|
||||
// script.setParent(DiscordUtil);
|
||||
script.load();
|
||||
}
|
||||
|
||||
public static function changePresence(details:String, state:String, ?smallImageKey:String)
|
||||
{
|
||||
#if DISCORD_RPC
|
||||
changePresenceAdvanced({
|
||||
state: state,
|
||||
@@ -66,12 +126,14 @@ class DiscordUtil {
|
||||
#end
|
||||
}
|
||||
|
||||
public static function changeSongPresence(details:String, state:String, audio:FlxSound, ?smallImageKey : String) {
|
||||
public static function changeSongPresence(details:String, state:String, audio:FlxSound, ?smallImageKey:String)
|
||||
{
|
||||
#if DISCORD_RPC
|
||||
var start:Float = 0;
|
||||
var end:Float = 0;
|
||||
|
||||
if (audio != null && audio.playing) {
|
||||
if (audio != null && audio.playing)
|
||||
{
|
||||
start = Date.now().getTime();
|
||||
end = start + (audio.length - audio.time);
|
||||
}
|
||||
@@ -86,66 +148,335 @@ class DiscordUtil {
|
||||
#end
|
||||
}
|
||||
|
||||
public static function changePresenceAdvanced(data:#if DISCORD_RPC DiscordPresenceOptions #else Dynamic #end) {
|
||||
public static function changePresenceSince(details:String, state:String, ?smallImageKey:String, ?time:Float)
|
||||
{
|
||||
#if DISCORD_RPC
|
||||
if (data == null) return;
|
||||
if(time == null)
|
||||
time = Date.now().getTime();
|
||||
|
||||
if (data.largeImageKey == null)
|
||||
data.largeImageKey = DiscordUtil.data.logoKey;
|
||||
if (data.largeImageText == null)
|
||||
data.largeImageText = DiscordUtil.data.logoText;
|
||||
|
||||
#if GLOBAL_SCRIPT
|
||||
var event = funkin.backend.scripting.GlobalScript.event("onDiscordPresenceUpdate", EventManager.get(DiscordPresenceUpdateEvent).recycle(data));
|
||||
if (event.cancelled) return;
|
||||
#end
|
||||
|
||||
DiscordRpc.presence(data);
|
||||
changePresenceAdvanced({
|
||||
state: state,
|
||||
details: details,
|
||||
smallImageKey: smallImageKey,
|
||||
startTimestamp: Std.int(time / 1000)
|
||||
});
|
||||
#end
|
||||
}
|
||||
public static function changeClientID(id:String) {
|
||||
|
||||
@:noCompletion public static function fixString(str:String)
|
||||
{
|
||||
return new cpp.ConstCharStar(cast(str, String));
|
||||
}
|
||||
|
||||
@:noCompletion public static function toString(str:cpp.ConstCharStar)
|
||||
{
|
||||
return cast(str, String);
|
||||
}
|
||||
|
||||
public static function changePresenceAdvanced(data:DPresence)
|
||||
{
|
||||
#if DISCORD_RPC
|
||||
if (currentID != null) {
|
||||
DiscordRpc.shutdown();
|
||||
if (data == null)
|
||||
return;
|
||||
|
||||
// copy last presence
|
||||
if (data.largeImageKey == null)
|
||||
data.largeImageKey = config.logoKey;
|
||||
if (data.largeImageText == null)
|
||||
data.largeImageText = config.logoText;
|
||||
|
||||
var evt = EventManager.get(DiscordPresenceUpdateEvent).recycle(data);
|
||||
#if GLOBAL_SCRIPT
|
||||
// kept for "backwards compat"
|
||||
funkin.backend.scripting.GlobalScript.event("onDiscordPresenceUpdate", evt);
|
||||
#end
|
||||
event("onDiscordPresenceUpdate", evt);
|
||||
if (evt.cancelled)
|
||||
return;
|
||||
data = evt.presence;
|
||||
lastPresence = data;
|
||||
|
||||
var dp:DiscordRichPresence = DiscordRichPresence.create();
|
||||
// TODO: make this use a reflection-like macro
|
||||
Utils.safeSetWrapper(dp.state, data.state, fixString);
|
||||
Utils.safeSetWrapper(dp.details, data.details, fixString);
|
||||
Utils.safeSet(dp.startTimestamp, data.startTimestamp);
|
||||
Utils.safeSet(dp.endTimestamp, data.endTimestamp);
|
||||
Utils.safeSetWrapper(dp.largeImageKey, data.largeImageKey, fixString);
|
||||
Utils.safeSetWrapper(dp.largeImageText, data.largeImageText, fixString);
|
||||
Utils.safeSetWrapper(dp.smallImageKey, data.smallImageKey, fixString);
|
||||
Utils.safeSetWrapper(dp.smallImageText, data.smallImageText, fixString);
|
||||
Utils.safeSetWrapper(dp.partyId, data.partyId, fixString);
|
||||
Utils.safeSet(dp.partySize, data.partySize);
|
||||
Utils.safeSet(dp.partyMax, data.partyMax);
|
||||
Utils.safeSet(dp.partyPrivacy, data.partyPrivacy);
|
||||
Utils.safeSetWrapper(dp.matchSecret, data.matchSecret, fixString);
|
||||
Utils.safeSetWrapper(dp.joinSecret, data.joinSecret, fixString);
|
||||
Utils.safeSetWrapper(dp.spectateSecret, data.spectateSecret, fixString);
|
||||
Utils.safeSet(dp.instance, data.instance);
|
||||
if (data.matchSecret == null && data.joinSecret == null && data.spectateSecret == null)
|
||||
{
|
||||
Utils.safeSetWrapper(dp.button1Label, data.button1Label, fixString);
|
||||
Utils.safeSetWrapper(dp.button1Url, data.button1Url, fixString);
|
||||
Utils.safeSetWrapper(dp.button2Label, data.button2Label, fixString);
|
||||
Utils.safeSetWrapper(dp.button2Url, data.button2Url, fixString);
|
||||
}
|
||||
|
||||
ready = false;
|
||||
|
||||
DiscordRpc.start({
|
||||
clientID: id,
|
||||
onReady: function() {
|
||||
Logs.trace('Discord RPC started');
|
||||
ready = true;
|
||||
},
|
||||
onError: onError,
|
||||
onDisconnected: onDisconnected
|
||||
});
|
||||
currentID = id;
|
||||
|
||||
Discord.UpdatePresence(cpp.RawConstPointer.addressOf(dp));
|
||||
#end
|
||||
}
|
||||
|
||||
public static function shutdown() {
|
||||
public static function clearPresence() {
|
||||
#if DISCORD_RPC
|
||||
DiscordRpc.shutdown();
|
||||
Discord.ClearPresence();
|
||||
#end
|
||||
}
|
||||
|
||||
private static function set_currentID(id:String):String
|
||||
{
|
||||
if (currentID == id)
|
||||
return id;
|
||||
#if DISCORD_RPC
|
||||
if (currentID != null)
|
||||
shutdown();
|
||||
|
||||
var handlers:DiscordEventHandlers = DiscordEventHandlers.create();
|
||||
handlers.ready = cpp.Function.fromStaticFunction(onReady);
|
||||
handlers.disconnected = cpp.Function.fromStaticFunction(onDisconnected);
|
||||
handlers.errored = cpp.Function.fromStaticFunction(onError);
|
||||
handlers.joinGame = cpp.Function.fromStaticFunction(onJoin);
|
||||
handlers.joinRequest = cpp.Function.fromStaticFunction(onJoinReq);
|
||||
handlers.spectateGame = cpp.Function.fromStaticFunction(onSpectate);
|
||||
Discord.Initialize(id, cpp.RawPointer.addressOf(handlers), 1, null);
|
||||
stopThread = false;
|
||||
|
||||
loadScript();
|
||||
#end
|
||||
|
||||
return currentID = id;
|
||||
}
|
||||
|
||||
public static function shutdown()
|
||||
{
|
||||
ready = false;
|
||||
stopThread = true;
|
||||
#if DISCORD_RPC
|
||||
Discord.Shutdown();
|
||||
#end
|
||||
|
||||
call("destroy");
|
||||
script = FlxDestroyUtil.destroy(script);
|
||||
}
|
||||
|
||||
public static function respond(userId:String, reply:Int)
|
||||
{
|
||||
#if DISCORD_RPC
|
||||
Discord.Respond(fixString(userId), reply);
|
||||
#end
|
||||
}
|
||||
|
||||
// HANDLERS
|
||||
#if DISCORD_RPC
|
||||
static function onError(_code:Int, _message:String) {
|
||||
Logs.trace('Discord RPC Error: ${_message} (Code: $_code)', ERROR);
|
||||
private static function onReady(request:cpp.RawConstPointer<DiscordUser>):Void
|
||||
{
|
||||
user = DUser.initRaw(request);
|
||||
|
||||
Logs.traceColored([
|
||||
Logs.logText("[Discord] ", BLUE),
|
||||
Logs.logText("Connected to User " + user.globalName + " ("),
|
||||
Logs.logText(user.handle, GRAY),
|
||||
Logs.logText(")")
|
||||
], INFO);
|
||||
|
||||
ready = true;
|
||||
|
||||
call("onReady", [user]);
|
||||
}
|
||||
|
||||
static function onDisconnected(_code:Int, _message:String) {
|
||||
Logs.trace('Discord RPC Disconnected: ${_message} (Code: $_code)', WARNING);
|
||||
private static function onDisconnected(errorCode:Int, message:cpp.ConstCharStar):Void
|
||||
{
|
||||
var finalMsg:String = cast(message, String);
|
||||
|
||||
Logs.traceColored([
|
||||
Logs.logText("[Discord] ", BLUE),
|
||||
Logs.logText("Disconnected ("),
|
||||
Logs.logText('$errorCode: $finalMsg', RED),
|
||||
Logs.logText(")")
|
||||
], INFO);
|
||||
|
||||
call("onReady", [errorCode, cast(finalMsg, String)]);
|
||||
}
|
||||
|
||||
private static function onError(errorCode:Int, message:cpp.ConstCharStar):Void
|
||||
{
|
||||
var finalMsg:String = cast(message, String);
|
||||
|
||||
Logs.traceColored([
|
||||
Logs.logText("[Discord] ", BLUE),
|
||||
Logs.logText('Error ($errorCode: $finalMsg)', RED)
|
||||
], ERROR);
|
||||
|
||||
call("onError", [errorCode, cast(finalMsg, String)]);
|
||||
}
|
||||
|
||||
private static function onJoin(joinSecret:cpp.ConstCharStar):Void
|
||||
{
|
||||
Logs.traceColored([Logs.logText("[Discord] ", BLUE), Logs.logText("Someone has just joined", GREEN)], INFO);
|
||||
|
||||
call("onJoinGame", [cast(joinSecret, String)]);
|
||||
}
|
||||
|
||||
private static function onSpectate(spectateSecret:cpp.ConstCharStar):Void
|
||||
{
|
||||
Logs.traceColored([
|
||||
Logs.logText("[Discord] ", BLUE),
|
||||
Logs.logText("Someone started spectating your game", YELLOW)
|
||||
], INFO);
|
||||
|
||||
call("onSpectateGame", [cast(spectateSecret, String)]);
|
||||
}
|
||||
|
||||
private static function onJoinReq(request:cpp.RawConstPointer<DiscordUser>):Void
|
||||
{
|
||||
Logs.traceColored([
|
||||
Logs.logText("[Discord] ", BLUE),
|
||||
Logs.logText("Someone has just requested to join", YELLOW)
|
||||
], WARNING);
|
||||
|
||||
var req:DUser = DUser.initRaw(request);
|
||||
call("onJoinRequest", [req]);
|
||||
}
|
||||
#end
|
||||
}
|
||||
|
||||
typedef DiscordJson = {
|
||||
typedef DiscordJson =
|
||||
{
|
||||
var ?clientID:String;
|
||||
var ?logoKey:String;
|
||||
var ?logoText:String;
|
||||
}
|
||||
}
|
||||
|
||||
@:noCustomClass
|
||||
final class DUser
|
||||
{
|
||||
/**
|
||||
* The username + discriminator if they have it
|
||||
**/
|
||||
public var handle:String;
|
||||
|
||||
/**
|
||||
* The user id, aka 860561967383445535
|
||||
**/
|
||||
public var userId:String;
|
||||
|
||||
/**
|
||||
* The user's username
|
||||
**/
|
||||
public var username:String;
|
||||
|
||||
/**
|
||||
* The #number from before discord changed to usernames only, if the user has changed to a username them its just a 0
|
||||
**/
|
||||
public var discriminator:Int;
|
||||
|
||||
/**
|
||||
* The user's avatar filename
|
||||
**/
|
||||
public var avatar:String;
|
||||
|
||||
/**
|
||||
* The user's display name
|
||||
**/
|
||||
public var globalName:String;
|
||||
|
||||
/**
|
||||
* If the user is a bot or not
|
||||
**/
|
||||
public var bot:Bool;
|
||||
|
||||
/**
|
||||
* Idk check discord docs
|
||||
**/
|
||||
public var flags:Int;
|
||||
|
||||
/**
|
||||
* If the user has nitro
|
||||
**/
|
||||
public var premiumType:NitroType;
|
||||
|
||||
private function new()
|
||||
{
|
||||
}
|
||||
|
||||
public static function initRaw(req:cpp.RawConstPointer<DiscordUser>)
|
||||
{
|
||||
return init(cpp.ConstPointer.fromRaw(req).ptr);
|
||||
}
|
||||
|
||||
public static function init(userData:cpp.Star<DiscordUser>)
|
||||
{
|
||||
var d = new DUser();
|
||||
d.userId = userData.userId;
|
||||
d.username = userData.username;
|
||||
d.discriminator = Std.parseInt(userData.discriminator);
|
||||
d.avatar = userData.avatar;
|
||||
d.globalName = userData.globalName;
|
||||
d.bot = userData.bot;
|
||||
d.flags = userData.flags;
|
||||
d.premiumType = userData.premiumType;
|
||||
|
||||
if (d.discriminator != 0)
|
||||
d.handle = '${d.username}#${d.discriminator}';
|
||||
else
|
||||
d.handle = '${d.username}';
|
||||
return d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calling this function gets the BitmapData of the user
|
||||
**/
|
||||
public function getAvatar(size:Int = 256):BitmapData
|
||||
return BitmapData.fromBytes(HttpUtil.requestBytes('https://cdn.discordapp.com/avatars/$userId/$avatar.png?size=$size'));
|
||||
}
|
||||
|
||||
enum abstract NitroType(Int) to Int from Int
|
||||
{
|
||||
var NONE = 0;
|
||||
var NITRO_CLASSIC = 1;
|
||||
var NITRO = 2;
|
||||
var NITRO_BASIC = 3;
|
||||
}
|
||||
|
||||
typedef DPresence =
|
||||
{
|
||||
var ?state:String; /* max 128 bytes */
|
||||
var ?details:String; /* max 128 bytes */
|
||||
var ?startTimestamp:OneOfTwo<Int, haxe.Int64>;
|
||||
var ?endTimestamp:OneOfTwo<Int, haxe.Int64>;
|
||||
var ?largeImageKey:String; /* max 32 bytes */
|
||||
var ?largeImageText:String; /* max 128 bytes */
|
||||
var ?smallImageKey:String; /* max 32 bytes */
|
||||
var ?smallImageText:String; /* max 128 bytes */
|
||||
var ?partyId:String; /* max 128 bytes */
|
||||
var ?partySize:Int;
|
||||
var ?partyMax:Int;
|
||||
var ?partyPrivacy:Int;
|
||||
var ?matchSecret:String; /* max 128 bytes */
|
||||
var ?joinSecret:String; /* max 128 bytes */
|
||||
var ?spectateSecret:String; /* max 128 bytes */
|
||||
var ?instance:OneOfTwo<Int, cpp.Int8>;
|
||||
var ?button1Label:String; /* max 32 bytes */
|
||||
var ?button1Url:String; /* max 512 bytes */
|
||||
var ?button2Label:String; /* max 32 bytes */
|
||||
var ?button2Url:String; /* max 512 bytes */
|
||||
}
|
||||
|
||||
typedef DEvents =
|
||||
{
|
||||
var ?ready:DUser->Void;
|
||||
var ?disconnected:(errorCode:Int, message:String) -> Void;
|
||||
var ?errored:(errorCode:Int, message:String) -> Void;
|
||||
var ?joinGame:String->Void;
|
||||
var ?spectateGame:String->Void;
|
||||
var ?joinRequest:DUser->Void;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package funkin.backend.utils;
|
||||
|
||||
import haxe.Http;
|
||||
|
||||
class HttpUtil
|
||||
{
|
||||
public static var userAgent:String = "request";
|
||||
public static function requestText(url:String)
|
||||
{
|
||||
var r = null;
|
||||
var h = new Http(url);
|
||||
h.setHeader("User-Agent", userAgent);
|
||||
|
||||
h.onStatus = function(s)
|
||||
{
|
||||
if (isRedirect(s))
|
||||
r = requestText(h.responseHeaders.get("Location"));
|
||||
};
|
||||
|
||||
h.onData = function(d)
|
||||
{
|
||||
if (r == null)
|
||||
r = d;
|
||||
}
|
||||
h.onError = function(e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
|
||||
h.request(false);
|
||||
return r;
|
||||
}
|
||||
|
||||
public static function requestBytes(url:String)
|
||||
{
|
||||
var r = null;
|
||||
var h = new Http(url);
|
||||
h.setHeader("User-Agent", userAgent);
|
||||
|
||||
h.onStatus = function(s)
|
||||
{
|
||||
if (isRedirect(s))
|
||||
r = requestBytes(h.responseHeaders.get("Location"));
|
||||
};
|
||||
|
||||
h.onBytes = function(d)
|
||||
{
|
||||
if (r == null)
|
||||
r = d;
|
||||
}
|
||||
h.onError = function(e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
|
||||
h.request(false);
|
||||
return r;
|
||||
}
|
||||
|
||||
private static function isRedirect(status:Int):Bool
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
// 301: Moved Permanently, 302: Found (Moved Temporarily), 307: Temporary Redirect, 308: Permanent Redirect - Nex
|
||||
case 301 | 302 | 307 | 308:
|
||||
Logs.traceColored([Logs.logText('[Connection Status] ', BLUE), Logs.logText('Redirected with status code: ', YELLOW), Logs.logText('$status', GREEN)], WARNING);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -79,6 +79,8 @@ class MemoryUtil {
|
||||
public static inline function currentMemUsage() {
|
||||
#if cpp
|
||||
return Gc.memInfo64(Gc.MEM_INFO_USAGE);
|
||||
#elseif hl
|
||||
return Gc.stats().currentMemory;
|
||||
#elseif sys
|
||||
return cast(cast(System.totalMemory, UInt), Float);
|
||||
#else
|
||||
|
||||
@@ -180,13 +180,13 @@ class XMLUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new sprite based on a XML node.
|
||||
*/
|
||||
* Creates a new sprite based on a XML node.
|
||||
*/
|
||||
public static inline function createSpriteFromXML(node:Access, parentFolder:String = "", defaultAnimType:XMLAnimType = BEAT, ?cl:Class<FunkinSprite>, ?args:Array<Dynamic>):FunkinSprite {
|
||||
if(cl == null) cl = FunkinSprite;
|
||||
if(args == null) args = [];
|
||||
return loadSpriteFromXML(Type.createInstance(cl, args), node, parentFolder, defaultAnimType);
|
||||
}
|
||||
if(cl == null) cl = FunkinSprite;
|
||||
if(args == null) args = [];
|
||||
return loadSpriteFromXML(Type.createInstance(cl, args), node, parentFolder, defaultAnimType);
|
||||
}
|
||||
|
||||
public static function extractAnimFromXML(anim:Access, animType:XMLAnimType = NONE, loop:Bool = false):AnimData {
|
||||
var animData:AnimData = {
|
||||
|
||||
@@ -36,16 +36,36 @@ class DebugOptionsScreen extends OptionsScreen {
|
||||
}));
|
||||
#end
|
||||
add(new Checkbox(
|
||||
"Enable Editor SFXs",
|
||||
"Editor SFXs",
|
||||
"If checked, will play sound effects when working on editors (ex: will play sfxs when checking checkboxes...)",
|
||||
"editorSFX"));
|
||||
add(new Checkbox(
|
||||
"Resizable Editors",
|
||||
"If checked, editors will be resizable and extensible like other programs instead of zooming in upon maximization.",
|
||||
"resizableEditors"));
|
||||
"Pretty Print",
|
||||
"If checked, the saved files from the editor will be formatted to be easily viewable (does not apply to xmls...)",
|
||||
"editorPrettyPrint"));
|
||||
add(new Checkbox(
|
||||
"Intensive Blur",
|
||||
"If checked, will use more intensive blur that may be laggier but look better.",
|
||||
"intensiveBlur"));
|
||||
add(new Checkbox(
|
||||
"Editor Autosaves",
|
||||
"If checked, this will autosave your files in the editor, with the settings listed below.",
|
||||
"charterAutoSaves"));
|
||||
add(new NumOption(
|
||||
"Autosaving Time",
|
||||
"This controls how often the editor will autosave your file (in seconds...)",
|
||||
60, 60*10, 30,
|
||||
"charterAutoSaveTime"
|
||||
));
|
||||
add(new NumOption(
|
||||
"Save Warning Time",
|
||||
"This controls how long the editor will warn you before it autosaves (in seconds..., 0 to disable)",
|
||||
0, 15, 1,
|
||||
"charterAutoSaveWarningTime"
|
||||
));
|
||||
add(new Checkbox(
|
||||
"Autosaves Folder",
|
||||
"If checked, this will autosave your file in a seperate folder with a time stamp instead of overriding your current file. (song/autosaves/)",
|
||||
"charterAutoSavesSeperateFolder"));
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,5 @@
|
||||
package funkin.editors;
|
||||
|
||||
#if desktop
|
||||
import sys.io.File;
|
||||
#end
|
||||
import haxe.io.Path;
|
||||
import lime.ui.FileDialog;
|
||||
|
||||
@@ -30,13 +27,9 @@ class SaveSubstate extends MusicBeatSubstate {
|
||||
super.create();
|
||||
|
||||
var fileDialog = new FileDialog();
|
||||
fileDialog.onCancel.add(function() {
|
||||
close();
|
||||
});
|
||||
fileDialog.onCancel.add(function() close());
|
||||
fileDialog.onSelect.add(function(str) {
|
||||
#if desktop
|
||||
File.saveContent(str, data);
|
||||
#end
|
||||
CoolUtil.safeSaveFile(str, data);
|
||||
close();
|
||||
});
|
||||
fileDialog.browse(SAVE, options.saveExt.getDefault(Path.extension(options.defaultSaveFile)), options.defaultSaveFile);
|
||||
@@ -46,11 +39,6 @@ class SaveSubstate extends MusicBeatSubstate {
|
||||
super.update(elapsed);
|
||||
parent.persistentUpdate = false;
|
||||
}
|
||||
|
||||
private function onError(_) {
|
||||
// TODO: error handling
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
typedef SaveSubstateData = {
|
||||
|
||||
@@ -21,7 +21,7 @@ class SaveWarning {
|
||||
if (warningFunc != null) warningFunc(closingWindow);
|
||||
|
||||
if (FlxG.state != null && FlxG.state is UIState) {
|
||||
FlxG.state.openSubState(new UIWarningSubstate("Unsaved Changes!", "Your changes will be lost if you don't save them. (Can't be recovered)\n\n\nWould you like to Cancel?",
|
||||
FlxG.state.openSubState(new UIWarningSubstate("Unsaved Changes!", "Your changes will be lost if you don't save them. (Can't be recovered)\n\n\nWould you like to Cancel?",
|
||||
[
|
||||
{
|
||||
label: "Cancel",
|
||||
|
||||
@@ -52,7 +52,7 @@ class CharacterEditor extends UIState {
|
||||
WindowUtils.endfix = " (Character Editor)";
|
||||
SaveWarning.selectionClass = CharacterSelection;
|
||||
SaveWarning.saveFunc = () -> {_file_save(null);};
|
||||
|
||||
|
||||
topMenu = [
|
||||
{
|
||||
label: "File",
|
||||
@@ -224,7 +224,7 @@ class CharacterEditor extends UIState {
|
||||
FlxG.cameras.add(uiCamera);
|
||||
FlxG.cameras.add(animsCamera);
|
||||
|
||||
character = new Character(0,0,__character, false, false);
|
||||
character = new Character(0,0, __character, false, false);
|
||||
character.debugMode = true;
|
||||
character.cameras = [charCamera];
|
||||
|
||||
@@ -257,6 +257,8 @@ class CharacterEditor extends UIState {
|
||||
Framerate.memoryCounter.alpha = 0.4;
|
||||
Framerate.codenameBuildField.alpha = 0.4;
|
||||
}
|
||||
|
||||
DiscordUtil.call("onEditorLoaded", ["Character Editor", __character]);
|
||||
}
|
||||
|
||||
override function destroy() {
|
||||
@@ -328,14 +330,14 @@ class CharacterEditor extends UIState {
|
||||
|
||||
function _file_save(_) {
|
||||
#if sys
|
||||
sys.io.File.saveContent(
|
||||
CoolUtil.safeSaveFile(
|
||||
'${Paths.getAssetsRoot()}/data/characters/${character.curCharacter}.xml',
|
||||
buildCharacter()
|
||||
);
|
||||
undos.save();
|
||||
return;
|
||||
#end
|
||||
#else
|
||||
_file_saveas(_);
|
||||
#end
|
||||
}
|
||||
|
||||
function _file_saveas(_) {
|
||||
|
||||
@@ -181,8 +181,8 @@ class CharacterInfoScreen extends UISubstateWindow {
|
||||
xml.set("antialiasing", antialiasingCheckbox.checked ? "true" : "false");
|
||||
xml.set("sprite", spriteTextBox.label.text);
|
||||
if (iconColorWheel.colorChanged)
|
||||
xml.set("color", iconColorWheel.curColor.toHexString(false).replace("0x", "#"));
|
||||
for (val in customPropertiesButtonList.buttons.members)
|
||||
xml.set("color", iconColorWheel.curColor.toWebString());
|
||||
for (val in customPropertiesButtonList.buttons.members)
|
||||
xml.set(val.propertyText.label.text, val.valueText.label.text);
|
||||
|
||||
for (anim in character.animDatas)
|
||||
|
||||
@@ -33,6 +33,8 @@ class CharacterSelection extends EditorTreeMenu
|
||||
}));
|
||||
|
||||
main = new OptionsScreen("Character Editor", "Select a character to edit", list);
|
||||
|
||||
DiscordUtil.call("onEditorTreeLoaded", ["Character Editor"]);
|
||||
}
|
||||
|
||||
override function createPost() {
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
package funkin.editors.charter;
|
||||
// ! FUCK YOU CHUF (your biggest fan -lunar) <3
|
||||
|
||||
import flixel.input.FlxPointer;
|
||||
import openfl.geom.Point;
|
||||
import openfl.geom.Rectangle;
|
||||
import flixel.graphics.FlxGraphic;
|
||||
import flixel.addons.display.FlxTiledSprite;
|
||||
import funkin.editors.ui.UIContextMenu.UIContextMenuOptionSpr;
|
||||
import funkin.editors.ui.UITopMenu.UITopMenuButton;
|
||||
import funkin.editors.charter.CharterStrumline;
|
||||
@@ -16,6 +22,9 @@ import funkin.backend.chart.ChartData;
|
||||
import flixel.addons.display.FlxBackdrop;
|
||||
import funkin.editors.ui.UIContextMenu.UIContextMenuOption;
|
||||
import funkin.editors.ui.UIState;
|
||||
import flixel.util.FlxColor;
|
||||
import openfl.display.BitmapData;
|
||||
import funkin.backend.shaders.CustomShader;
|
||||
|
||||
class Charter extends UIState {
|
||||
public static var __song:String;
|
||||
@@ -52,6 +61,7 @@ class Charter extends UIState {
|
||||
|
||||
public var gridBackdropDummy:CharterBackdropDummy;
|
||||
public var noteHoverer:CharterNoteHoverer;
|
||||
public var noteDeleteAnims:CharterDeleteAnim;
|
||||
|
||||
public var strumlineInfoBG:FlxSprite;
|
||||
public var strumlineAddButton:CharterStrumlineButton;
|
||||
@@ -76,6 +86,8 @@ class Charter extends UIState {
|
||||
public var charterCamera:FlxCamera;
|
||||
public var uiCamera:FlxCamera;
|
||||
public var selectionBox:UISliceSprite;
|
||||
public var autoSaveNotif:CharterAutoSaveUI;
|
||||
public static var autoSaveTimer:Float = 0;
|
||||
|
||||
public static var selection:Selection;
|
||||
|
||||
@@ -83,6 +95,7 @@ class Charter extends UIState {
|
||||
public static var undos:UndoList<CharterChange>;
|
||||
|
||||
public static var clipboard:Array<CharterCopyboardObject> = [];
|
||||
public static var waveformHandler:CharterWaveformHandler;
|
||||
|
||||
public function new(song:String, diff:String, reload:Bool = true) {
|
||||
super();
|
||||
@@ -99,7 +112,7 @@ class Charter extends UIState {
|
||||
WindowUtils.endfix = " (Chart Editor)";
|
||||
SaveWarning.selectionClass = CharterSelection;
|
||||
SaveWarning.saveFunc = () -> {_file_save(null);};
|
||||
|
||||
|
||||
topMenu = [
|
||||
{
|
||||
label: "File",
|
||||
@@ -151,6 +164,15 @@ class Charter extends UIState {
|
||||
onSelect: _file_meta_saveas,
|
||||
},
|
||||
null,
|
||||
{
|
||||
label: "Export For FNF Legacy...",
|
||||
onSelect: _file_saveas_fnflegacy,
|
||||
},
|
||||
{
|
||||
label: "Export For Psych Engine...",
|
||||
onSelect: _file_saveas_psych,
|
||||
},
|
||||
null,
|
||||
{
|
||||
label: "Exit",
|
||||
onSelect: _file_exit
|
||||
@@ -267,6 +289,12 @@ class Charter extends UIState {
|
||||
label: 'Show Beats Separator',
|
||||
onSelect: _view_showeventBeatSeparator,
|
||||
icon: Options.charterShowBeats ? 1 : 0
|
||||
},
|
||||
null,
|
||||
{
|
||||
label: 'Low Detail Waveforms',
|
||||
onSelect: _view_switchWaveformDetail,
|
||||
icon: Options.charterLowDetailWaveforms ? 1 : 0
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -379,8 +407,10 @@ class Charter extends UIState {
|
||||
selectionBox.incorporeal = true;
|
||||
|
||||
noteHoverer = new CharterNoteHoverer();
|
||||
noteDeleteAnims = new CharterDeleteAnim();
|
||||
|
||||
selectionBox.cameras = notesGroup.cameras = gridBackdrops.cameras = noteHoverer.cameras = [charterCamera];
|
||||
selectionBox.cameras = notesGroup.cameras = gridBackdrops.cameras =
|
||||
noteHoverer.cameras = noteDeleteAnims.cameras = [charterCamera];
|
||||
|
||||
topMenuSpr = new UITopMenu(topMenu);
|
||||
topMenuSpr.cameras = uiGroup.cameras = [uiCamera];
|
||||
@@ -420,6 +450,9 @@ class Charter extends UIState {
|
||||
strumlineInfoBG.y = 23;
|
||||
strumlineInfoBG.scrollFactor.set();
|
||||
|
||||
autoSaveNotif = new CharterAutoSaveUI(20, strumlineInfoBG.y + strumlineInfoBG.height + 20);
|
||||
uiGroup.add(autoSaveNotif);
|
||||
|
||||
strumlineAddButton = new CharterStrumlineButton("editors/new", "Create New");
|
||||
strumlineAddButton.onClick = createStrumWithUI;
|
||||
strumlineAddButton.animationOnClick = false;
|
||||
@@ -448,6 +481,7 @@ class Charter extends UIState {
|
||||
add(addEventSpr);
|
||||
add(eventsGroup);
|
||||
add(noteHoverer);
|
||||
add(noteDeleteAnims);
|
||||
add(notesGroup);
|
||||
add(selectionBox);
|
||||
add(strumlineInfoBG);
|
||||
@@ -468,6 +502,16 @@ class Charter extends UIState {
|
||||
Framerate.codenameBuildField.alpha = 0.4;
|
||||
}
|
||||
updateDisplaySprites();
|
||||
|
||||
// ! IF YOU EVER WANNA VIEW IN THE FUTURE, JUST USE A FLXSPRITE :D -lunar
|
||||
/*var dataDisplay:FlxSprite = new FlxSprite().loadGraphic(waveformHandler.waveDatas.get("Voices.ogg"));
|
||||
dataDisplay.scrollFactor.set(1, 0);
|
||||
dataDisplay.scale.set(2, 2);
|
||||
dataDisplay.updateHitbox();
|
||||
dataDisplay.screenCenter(Y);
|
||||
dataDisplay.cameras = [charterCamera]; dataDisplay.x = -dataDisplay.width; add(dataDisplay);*/
|
||||
|
||||
DiscordUtil.call("onEditorLoaded", ["Chart Editor", __song + " (" + __diff + ")"]);
|
||||
}
|
||||
|
||||
override function destroy() {
|
||||
@@ -501,12 +545,12 @@ class Charter extends UIState {
|
||||
|
||||
for(strL in PlayState.SONG.strumLines)
|
||||
createStrumline(strumLines.members.length, strL, false, false);
|
||||
|
||||
|
||||
// create notes
|
||||
notesGroup.autoSort = false;
|
||||
var noteCount:Int = 0;
|
||||
for (strL in PlayState.SONG.strumLines)
|
||||
for (note in strL.notes) noteCount++;
|
||||
noteCount += strL.notes.length;
|
||||
notesGroup.preallocate(noteCount);
|
||||
|
||||
var notesCreated:Int = 0;
|
||||
@@ -544,8 +588,10 @@ class Charter extends UIState {
|
||||
buildNoteTypesUI();
|
||||
refreshBPMSensitive();
|
||||
|
||||
// Undo Stuffs :D
|
||||
__relinkUndos();
|
||||
// Just for now until i add event stacking -lunar
|
||||
try {__relinkUndos();}
|
||||
catch (e) {Logs.trace('Failed to relink undos: ${Std.string(e)}', ERROR);}
|
||||
|
||||
__applyPlaytestInfo();
|
||||
}
|
||||
|
||||
@@ -555,8 +601,55 @@ class Charter extends UIState {
|
||||
var length = FlxG.sound.music.getDefault(vocals).length;
|
||||
scrollBar.length = __endStep = Conductor.getStepForTime(length);
|
||||
|
||||
gridBackdrops.bottomLimitY = Conductor.getStepForTime(length) * 40;
|
||||
gridBackdrops.bottomLimitY = __endStep * 40;
|
||||
eventsBackdrop.bottomSeparator.y = gridBackdrops.bottomLimitY-2;
|
||||
|
||||
updateWaveforms();
|
||||
}
|
||||
|
||||
public function updateWaveforms() {
|
||||
var wavesToGenerate:Array<{name:String, sound:FlxSound}> = [
|
||||
{name: "Inst.ogg", sound: FlxG.sound.music},
|
||||
];
|
||||
if (PlayState.SONG.meta.needsVoices != false)
|
||||
wavesToGenerate.push({name: "Voices.ogg", sound: vocals});
|
||||
|
||||
for (strumLine in strumLines)
|
||||
if (strumLine.vocals != null && strumLine.strumLine.vocalsSuffix != null && strumLine.strumLine.vocalsSuffix != "")
|
||||
wavesToGenerate.push({
|
||||
name: 'Voices${strumLine.strumLine.vocalsSuffix}.ogg',
|
||||
sound: strumLine.vocals
|
||||
});
|
||||
|
||||
var oldWaveformList:Array<String> = waveformHandler.waveformList;
|
||||
var newWaveformList:Array<String> = [for (data in wavesToGenerate) data.name];
|
||||
|
||||
if (waveformHandler == null ? true : waveformHandler.ampsNeeded != __endStep*40) {
|
||||
waveformHandler.clearWaveforms();
|
||||
waveformHandler.ampsNeeded = __endStep * 40;
|
||||
|
||||
for (data in wavesToGenerate) {
|
||||
waveformHandler.generateShader(data.name, data.sound);
|
||||
waveformHandler.waveformList.push(data.name);
|
||||
}
|
||||
} else if (waveformHandler != null && waveformHandler.waveformList.length != newWaveformList.length) {
|
||||
for (name in oldWaveformList)
|
||||
if (!newWaveformList.contains(name))
|
||||
waveformHandler.clearWaveform(name);
|
||||
|
||||
for (data in wavesToGenerate)
|
||||
if (!oldWaveformList.contains(data.name))
|
||||
waveformHandler.generateShader(data.name, data.sound);
|
||||
|
||||
waveformHandler.waveformList = newWaveformList;
|
||||
}
|
||||
|
||||
for (strumLine in strumLines) {
|
||||
if (strumLine.selectedWaveform == -1) continue;
|
||||
|
||||
var oldName:String = oldWaveformList[strumLine.selectedWaveform];
|
||||
strumLine.selectedWaveform = waveformHandler.waveformList.indexOf(oldName);
|
||||
}
|
||||
}
|
||||
|
||||
public override function beatHit(curBeat:Int) {
|
||||
@@ -598,6 +691,36 @@ class Charter extends UIState {
|
||||
for(s in selection) s.selected = true;
|
||||
}
|
||||
|
||||
var __autoSaveLocation:String = null;
|
||||
public function updateAutoSaving(elapsed:Float) {
|
||||
if (!Options.charterAutoSaves) return;
|
||||
autoSaveTimer -= elapsed;
|
||||
|
||||
if (autoSaveTimer < Options.charterAutoSaveWarningTime && !autoSaveNotif.cancelled && !autoSaveNotif.showedAnimation) {
|
||||
if (Options.charterAutoSavesSeperateFolder)
|
||||
__autoSaveLocation = __diff.toLowerCase() + DateTools.format(Date.now(), "%m-%d_%H-%M");
|
||||
autoSaveNotif.startAutoSave(autoSaveTimer,
|
||||
!Options.charterAutoSavesSeperateFolder ? 'Saved chart at ${__diff.toLowerCase()}.json!' :
|
||||
'Saved chart at $__autoSaveLocation.json!'
|
||||
);
|
||||
}
|
||||
if (autoSaveTimer <= 0) {
|
||||
autoSaveTimer = Options.charterAutoSaveTime;
|
||||
if (!autoSaveNotif.cancelled) {
|
||||
buildChart();
|
||||
var songPath:String = '${Paths.getAssetsRoot()}/songs/${__song.toLowerCase()}';
|
||||
|
||||
if (Options.charterAutoSavesSeperateFolder)
|
||||
Chart.save(songPath, PlayState.SONG, __autoSaveLocation, {saveMetaInChart: false, folder: "autosaves", prettyPrint: Options.editorPrettyPrint});
|
||||
else
|
||||
Chart.save(songPath, PlayState.SONG, __diff.toLowerCase(), {saveMetaInChart: false, prettyPrint: Options.editorPrettyPrint});
|
||||
undos.save();
|
||||
}
|
||||
autoSaveNotif.cancelled = false;
|
||||
}
|
||||
}
|
||||
|
||||
var deletedNotes:Selection = new Selection();
|
||||
public function updateNoteLogic(elapsed:Float) {
|
||||
updateSelectionLogic();
|
||||
|
||||
@@ -669,11 +792,11 @@ class Charter extends UIState {
|
||||
for (s in selection) {
|
||||
if (s.draggable) {
|
||||
var changePoint:FlxPoint = FlxPoint.get(verticalChange, horizontalChange);
|
||||
if (!FlxG.keys.pressed.SHIFT)
|
||||
if (!FlxG.keys.pressed.SHIFT)
|
||||
changePoint.x -= ((s.step + verticalChange) - quantStepRounded(s.step+verticalChange, verticalChange > 0 ? 0.35 : 0.65));
|
||||
|
||||
var boundedChange:FlxPoint = changePoint.clone();
|
||||
|
||||
|
||||
// Some maths, so cool bro -lunar (i dont know why i quopte my self here)
|
||||
if (s.step + changePoint.x < 0) boundedChange.x += Math.abs(s.step + changePoint.x);
|
||||
if (s.step + changePoint.x > __endStep-1) boundedChange.x -= (s.step + changePoint.x) - (__endStep-1);
|
||||
@@ -702,7 +825,11 @@ class Charter extends UIState {
|
||||
}
|
||||
case NONE:
|
||||
if (FlxG.mouse.justPressed)
|
||||
FlxG.mouse.getWorldPosition(charterCamera, dragStartPos);
|
||||
FlxG.mouse.getWorldPosition(charterCamera, dragStartPos);
|
||||
else if (FlxG.mouse.justPressedRight) {
|
||||
closeCurrentContextMenu();
|
||||
gridActionType = DELETE_SELECTION;
|
||||
}
|
||||
|
||||
if (gridBackdropDummy.hovered) {
|
||||
// AUTO DETECT
|
||||
@@ -711,11 +838,11 @@ class Charter extends UIState {
|
||||
|
||||
var id = Math.floor(mousePos.x / 40);
|
||||
var mouseOnGrid = id >= 0 && id < 4 * gridBackdrops.strumlinesAmount && mousePos.y >= 0;
|
||||
|
||||
|
||||
if (FlxG.mouse.justReleased) {
|
||||
for (n in selection) n.selected = false;
|
||||
selection = [];
|
||||
|
||||
|
||||
if (mouseOnGrid && mousePos.y > 0 && mousePos.y < (__endStep)*40) {
|
||||
var note = new CharterNote();
|
||||
note.updatePos(
|
||||
@@ -745,13 +872,6 @@ class Charter extends UIState {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (FlxG.mouse.justReleasedRight) {
|
||||
var mousePos = FlxG.mouse.getScreenPosition(uiCamera);
|
||||
closeCurrentContextMenu();
|
||||
openContextMenu(topMenu[1].childs, null, mousePos.x, mousePos.y);
|
||||
mousePos.put();
|
||||
}
|
||||
case SUSTAIN_DRAG:
|
||||
selectionDragging = FlxG.mouse.pressed;
|
||||
if (selectionDragging) {
|
||||
@@ -760,7 +880,7 @@ class Charter extends UIState {
|
||||
var change:Float = Math.max((mousePos.y-(FlxG.keys.pressed.SHIFT ? dragStartPos.y : quantStep(dragStartPos.y))) / 40, -n.susLength);
|
||||
n.tempSusLength = change;
|
||||
|
||||
if (!FlxG.keys.pressed.SHIFT)
|
||||
if (!FlxG.keys.pressed.SHIFT)
|
||||
n.tempSusLength -= (n.susLength + change) - quantStepRounded(n.susLength + change, change > 0 ? 0.35 : 0.65);
|
||||
@:privateAccess n.__susInstaLerp = FlxG.keys.pressed.SHIFT;
|
||||
});
|
||||
@@ -777,15 +897,38 @@ class Charter extends UIState {
|
||||
undoChanges.push({before: oldSusLen, after: n.susLength, note: n});
|
||||
});
|
||||
undos.addToUndo(CEditSustains(undoChanges));
|
||||
|
||||
|
||||
gridActionType = NONE;
|
||||
currentCursor = ARROW;
|
||||
}
|
||||
case DELETE_SELECTION:
|
||||
notesGroup.forEach(function(n) {
|
||||
if (n.hovered || n.sustainDraggable) {
|
||||
deletedNotes.push(n);
|
||||
deleteSingleSelection(n, false);
|
||||
|
||||
if (selection.contains(n)) selection.remove(n);
|
||||
noteDeleteAnims.deleteNotes.push({
|
||||
note: n, time: noteDeleteAnims.deleteTime
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (FlxG.mouse.justReleasedRight) {
|
||||
if (deletedNotes.length > 0) undos.addToUndo(CDeleteSelection(deletedNotes.copy()));
|
||||
else if (noteDeleteAnims.garbageIcon.alpha <= .5) {
|
||||
var mousePos = FlxG.mouse.getScreenPosition(uiCamera);
|
||||
closeCurrentContextMenu();
|
||||
openContextMenu(topMenu[1].childs, null, mousePos.x, mousePos.y);
|
||||
mousePos.put();
|
||||
}
|
||||
gridActionType = NONE; deletedNotes = [];
|
||||
}
|
||||
}
|
||||
addEventSpr.selectable = !selectionBox.visible;
|
||||
|
||||
var inBoundsY:Bool = (mousePos.y > 0 && mousePos.y < (__endStep)*40);
|
||||
|
||||
|
||||
// Event Spr
|
||||
if (mousePos.x < 0 && mousePos.x > -addEventSpr.bWidth && gridActionType == NONE && inBoundsY) {
|
||||
addEventSpr.incorporeal = false;
|
||||
@@ -927,7 +1070,7 @@ class Charter extends UIState {
|
||||
var i = 0;
|
||||
var toBeDeleted:Selection = [];
|
||||
for (note in notesGroup.members)
|
||||
if (note.strumLineID == strumLineID) {
|
||||
if (note.strumLineID == strumLineID) {
|
||||
undoNotes.push(buildNote(note));
|
||||
toBeDeleted.push(note);
|
||||
}
|
||||
@@ -977,6 +1120,8 @@ class Charter extends UIState {
|
||||
strumLines.members[strID].updateInfo();
|
||||
|
||||
undos.addToUndo(CEditStrumLine(strID, oldData, _));
|
||||
|
||||
if (oldData.vocalsSuffix != _.vocalsSuffix) updateWaveforms();
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -997,6 +1142,7 @@ class Charter extends UIState {
|
||||
var __firstFrame:Bool = true;
|
||||
public override function update(elapsed:Float) {
|
||||
updateNoteLogic(elapsed);
|
||||
updateAutoSaving(elapsed);
|
||||
|
||||
if (FlxG.sound.music.playing || __firstFrame) {
|
||||
gridBackdrops.conductorSprY = curStepFloat * 40;
|
||||
@@ -1019,8 +1165,8 @@ class Charter extends UIState {
|
||||
|
||||
var buttonI:Int = 0;
|
||||
for (button in quantButtons) {
|
||||
button.visible = ((button.quant == quant) ||
|
||||
(button.quant == quants[FlxMath.wrap(quants.indexOf(quant)-1, 0, quants.length-1)]) ||
|
||||
button.visible = ((button.quant == quant) ||
|
||||
(button.quant == quants[FlxMath.wrap(quants.indexOf(quant)-1, 0, quants.length-1)]) ||
|
||||
(button.quant == quants[FlxMath.wrap(quants.indexOf(quant)+1, 0, quants.length-1)]));
|
||||
button.selectable = button.visible;
|
||||
if (!button.visible) continue;
|
||||
@@ -1039,7 +1185,7 @@ class Charter extends UIState {
|
||||
noteTypeText.y = Std.int((noteTopButton.bHeight - noteTypeText.height) / 2);
|
||||
}
|
||||
noteTypeText.text = '($noteType) ${noteTypes[noteType-1] == null ? "Default Note" : noteTypes[noteType-1]}';
|
||||
|
||||
|
||||
super.update(elapsed);
|
||||
|
||||
scrollBar.size = (FlxG.height / 40 / charterCamera.zoom);
|
||||
@@ -1141,7 +1287,7 @@ class Charter extends UIState {
|
||||
}
|
||||
|
||||
function _file_saveas(_) {
|
||||
openSubState(new SaveSubstate(Json.stringify(Chart.filterChartForSaving(PlayState.SONG, false)), {
|
||||
openSubState(new SaveSubstate(Json.stringify(Chart.filterChartForSaving(PlayState.SONG, false), null, Options.editorPrettyPrint ? "\t" : null), {
|
||||
defaultSaveFile: '${__diff.toLowerCase()}.json'
|
||||
}));
|
||||
undos.save();
|
||||
@@ -1157,7 +1303,7 @@ class Charter extends UIState {
|
||||
}
|
||||
|
||||
function _file_saveas_no_events(_) {
|
||||
openSubState(new SaveSubstate(Json.stringify(Chart.filterChartForSaving(PlayState.SONG, false, false)), {
|
||||
openSubState(new SaveSubstate(Json.stringify(Chart.filterChartForSaving(PlayState.SONG, false, false), null, Options.editorPrettyPrint ? "\t" : null), {
|
||||
defaultSaveFile: '${__diff.toLowerCase()}.json'
|
||||
}));
|
||||
undos.save();
|
||||
@@ -1165,13 +1311,13 @@ class Charter extends UIState {
|
||||
|
||||
function _file_meta_save(_) {
|
||||
#if sys
|
||||
sys.io.File.saveContent(
|
||||
CoolUtil.safeSaveFile(
|
||||
'${Paths.getAssetsRoot()}/songs/${__song.toLowerCase()}/meta.json',
|
||||
Json.stringify(PlayState.SONG.meta == null ? {} : PlayState.SONG.meta, null, "\t")
|
||||
);
|
||||
return;
|
||||
#end
|
||||
#else
|
||||
_file_meta_saveas(_);
|
||||
#end
|
||||
}
|
||||
|
||||
function _file_meta_saveas(_) {
|
||||
@@ -1180,20 +1326,32 @@ class Charter extends UIState {
|
||||
}));
|
||||
}
|
||||
|
||||
function _file_saveas_fnflegacy(_) {
|
||||
openSubState(new SaveSubstate(Json.stringify(FNFLegacyParser.encode(PlayState.SONG), null, Options.editorPrettyPrint ? "\t" : null), {
|
||||
defaultSaveFile: '${__song.toLowerCase().replace(" ", "-")}${__diff.toLowerCase() == "normal" ? "" : '-${__diff.toLowerCase()}'}.json',
|
||||
}));
|
||||
}
|
||||
|
||||
function _file_saveas_psych(_) {
|
||||
openSubState(new SaveSubstate(Json.stringify(PsychParser.encode(PlayState.SONG), null, Options.editorPrettyPrint ? "\t" : null), {
|
||||
defaultSaveFile: '${__song.toLowerCase().replace(" ", "-")}${__diff.toLowerCase() == "normal" ? "" : '-${__diff.toLowerCase()}'}.json',
|
||||
}));
|
||||
}
|
||||
|
||||
function _file_events_save(_) {
|
||||
#if sys
|
||||
sys.io.File.saveContent(
|
||||
CoolUtil.safeSaveFile(
|
||||
'${Paths.getAssetsRoot()}/songs/${__song.toLowerCase()}/events.json',
|
||||
Json.stringify({events: PlayState.SONG.events == null ? [] : PlayState.SONG.events})
|
||||
Json.stringify({events: PlayState.SONG.events == null ? [] : PlayState.SONG.events}, null, Options.editorPrettyPrint ? "\t" : null)
|
||||
);
|
||||
return;
|
||||
#end
|
||||
#else
|
||||
_file_events_saveas(_);
|
||||
#end
|
||||
}
|
||||
|
||||
function _file_events_saveas(_) {
|
||||
#if sys
|
||||
openSubState(new SaveSubstate(Json.stringify({events: PlayState.SONG.events == null ? [] : PlayState.SONG.events}), {
|
||||
openSubState(new SaveSubstate(Json.stringify({events: PlayState.SONG.events == null ? [] : PlayState.SONG.events}, null, Options.editorPrettyPrint ? "\t" : null), {
|
||||
defaultSaveFile: 'events.json'
|
||||
}));
|
||||
#end
|
||||
@@ -1202,7 +1360,7 @@ class Charter extends UIState {
|
||||
#if sys
|
||||
function saveTo(path:String, separateEvents:Bool = false) {
|
||||
buildChart();
|
||||
Chart.save(path, PlayState.SONG, __diff.toLowerCase(), {saveMetaInChart: false, saveEventsInChart: !separateEvents});
|
||||
Chart.save(path, PlayState.SONG, __diff.toLowerCase(), {saveMetaInChart: false, saveEventsInChart: !separateEvents, prettyPrint: Options.editorPrettyPrint});
|
||||
}
|
||||
#end
|
||||
|
||||
@@ -1245,7 +1403,7 @@ class Charter extends UIState {
|
||||
}
|
||||
selection = sObjects;
|
||||
_edit_copy(_); // to fix stupid bugs
|
||||
|
||||
|
||||
undos.addToUndo(CCreateSelection(sObjects.copy()));
|
||||
}
|
||||
|
||||
@@ -1258,12 +1416,15 @@ class Charter extends UIState {
|
||||
|
||||
function _edit_delete(_) {
|
||||
if (selection == null || selection.length == 0) return;
|
||||
selection = deleteSelection(selection);
|
||||
selection.loop((n:CharterNote) -> {
|
||||
noteDeleteAnims.deleteNotes.push({note: n, time: noteDeleteAnims.deleteTime});
|
||||
});
|
||||
selection = deleteSelection(selection, true);
|
||||
}
|
||||
|
||||
function _edit_undo(_) {
|
||||
if (strumLines.isDragging || selectionDragging || subState != null) return;
|
||||
|
||||
if (strumLines.isDragging || selectionDragging || (subState != null && !(subState is UIContextMenu))) return;
|
||||
|
||||
selection = [];
|
||||
var undo = undos.undo();
|
||||
switch(undo) {
|
||||
@@ -1286,7 +1447,7 @@ class Charter extends UIState {
|
||||
case CSelectionDrag(selectionDrags):
|
||||
for (s in selectionDrags)
|
||||
if (s.selectable.draggable) s.selectable.handleDrag(s.change * -1);
|
||||
|
||||
|
||||
selection = [for (s in selectionDrags) s.selectable];
|
||||
case CEditSustains(changes):
|
||||
for(n in changes)
|
||||
@@ -1308,7 +1469,7 @@ class Charter extends UIState {
|
||||
}
|
||||
|
||||
function _edit_redo(_) {
|
||||
if (strumLines.isDragging || selectionDragging || subState != null) return;
|
||||
if (strumLines.isDragging || selectionDragging || (subState != null && !(subState is UIContextMenu))) return;
|
||||
|
||||
selection = [];
|
||||
var redo = undos.redo();
|
||||
@@ -1367,7 +1528,7 @@ class Charter extends UIState {
|
||||
function chart_edit_data(_)
|
||||
FlxG.state.openSubState(new ChartDataScreen(PlayState.SONG));
|
||||
function chart_edit_metadata(_)
|
||||
FlxG.state.openSubState(new MetaDataScreen(PlayState.SONG.meta));
|
||||
FlxG.state.openSubState(new CharterMetaDataScreen(PlayState.SONG.meta));
|
||||
|
||||
function _playback_play(_) {
|
||||
if (Conductor.songPosition >= FlxG.sound.music.getDefault(vocals).length - Conductor.songOffset) return;
|
||||
@@ -1439,6 +1600,11 @@ class Charter extends UIState {
|
||||
t.icon = (Options.charterShowBeats = !Options.charterShowBeats) ? 1 : 0;
|
||||
eventsBackdrop.eventBeatSeparator.visible = gridBackdrops.beatsVisible = Options.charterShowBeats;
|
||||
}
|
||||
function _view_switchWaveformDetail(t) {
|
||||
t.icon = (Options.charterLowDetailWaveforms = !Options.charterLowDetailWaveforms) ? 1 : 0;
|
||||
for (shader in waveformHandler.waveShaders) shader.data.lowDetail.value = [Options.charterLowDetailWaveforms];
|
||||
}
|
||||
|
||||
inline function _snap_increasesnap(_) changequant(1);
|
||||
inline function _snap_decreasesnap(_) changequant(-1);
|
||||
inline function _snap_resetsnap(_) setquant(16);
|
||||
@@ -1466,7 +1632,7 @@ class Charter extends UIState {
|
||||
null
|
||||
];
|
||||
|
||||
for (_quant in quants)
|
||||
for (_quant in quants)
|
||||
newChilds.push({
|
||||
label: '${_quant}x Grid Snap',
|
||||
onSelect: (_) -> {setquant(_quant); buildSnapsUI();},
|
||||
@@ -1485,7 +1651,7 @@ class Charter extends UIState {
|
||||
|
||||
function _note_selectall(_) {
|
||||
selection = [for (note in notesGroup.members) note];
|
||||
}
|
||||
}
|
||||
|
||||
function _note_selectmeasure(_) {
|
||||
selection = [for (note in notesGroup.members)
|
||||
@@ -1614,7 +1780,7 @@ class Charter extends UIState {
|
||||
}
|
||||
notesGroup.sortNotes();
|
||||
for(n in notesGroup.members) {
|
||||
if (PlayState.SONG.strumLines[n.strumLineID] != null)
|
||||
if (PlayState.SONG.strumLines[n.strumLineID] != null)
|
||||
PlayState.SONG.strumLines[n.strumLineID].notes.push(buildNote(n));
|
||||
}
|
||||
buildEvents();
|
||||
@@ -1681,7 +1847,7 @@ class Charter extends UIState {
|
||||
newChanges[i] = CSelectionDrag([
|
||||
for (selectionDrag in selectionDrags)
|
||||
{
|
||||
selectable: __relinkSingleSelection(selectionDrag.selectable),
|
||||
selectable: __relinkSingleSelection(selectionDrag.selectable),
|
||||
change: selectionDrag.change
|
||||
}
|
||||
]);
|
||||
@@ -1714,10 +1880,13 @@ class Charter extends UIState {
|
||||
selection = new Selection();
|
||||
undos = new UndoList<CharterChange>();
|
||||
clipboard = []; playtestInfo = null;
|
||||
waveformHandler = new CharterWaveformHandler();
|
||||
autoSaveTimer = Options.charterAutoSaveTime;
|
||||
}
|
||||
|
||||
@:noCompletion public function __clearStatics() {
|
||||
selection = null; undos = null; clipboard = null; playtestInfo = null;
|
||||
selection = null; undos = null; clipboard = null; playtestInfo = null;
|
||||
waveformHandler.destroy(); Charter.waveformHandler = null; autoSaveTimer = 0;
|
||||
}
|
||||
|
||||
@:noCompletion public function __updatePlaytestInfo() {
|
||||
@@ -1725,10 +1894,11 @@ class Charter extends UIState {
|
||||
songPosition: Conductor.songPosition,
|
||||
playbackSpeed: playBackSlider.value,
|
||||
quantSelected: quant,
|
||||
noteTypeSelected: noteType,
|
||||
noteTypeSelected: noteType,
|
||||
strumlinesDraggable: strumLines.draggable,
|
||||
hitSounds: [for (strumLine in strumLines.members) strumLine.hitsounds],
|
||||
mutedVocals: [for (strumLine in strumLines.members) !(strumLine.vocals.volume > 0)],
|
||||
waveforms: [for (strumLine in strumLines.members) strumLine.selectedWaveform]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1745,6 +1915,8 @@ class Charter extends UIState {
|
||||
strumLine.hitsounds = playtestInfo.hitSounds[i];
|
||||
for (i => strumLine in strumLines.members)
|
||||
strumLine.vocals.volume = playtestInfo.mutedVocals[i] ? 0 : 1;
|
||||
for (i => strumLine in strumLines.members)
|
||||
strumLine.selectedWaveform = playtestInfo.waveforms[i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1814,6 +1986,7 @@ enum abstract CharterGridActionType(Int) {
|
||||
var NOTE_DRAG = 2;
|
||||
var INVALID_DRAG = 3;
|
||||
var SUSTAIN_DRAG = 4;
|
||||
var DELETE_SELECTION = 5;
|
||||
}
|
||||
|
||||
typedef PlaytestInfo = {
|
||||
@@ -1824,4 +1997,5 @@ typedef PlaytestInfo = {
|
||||
var strumlinesDraggable:Bool;
|
||||
var hitSounds:Array<Bool>;
|
||||
var mutedVocals:Array<Bool>;
|
||||
var waveforms:Array<Int>;
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package funkin.editors.charter;
|
||||
|
||||
import flixel.util.FlxTimer;
|
||||
import flixel.tweens.FlxTween;
|
||||
import flixel.math.FlxRect;
|
||||
|
||||
using flixel.util.FlxSpriteUtil;
|
||||
|
||||
class CharterAutoSaveUI extends UISliceSprite {
|
||||
public var icon:FlxSprite;
|
||||
public var autosavingText:UIText;
|
||||
public var progressBarBack:FlxSprite;
|
||||
public var progressBar:FlxSprite;
|
||||
|
||||
public var cancelButton:UIButton;
|
||||
public var cancelIcon:FlxSprite;
|
||||
|
||||
public var showedAnimation:Bool = false;
|
||||
public var cancelled:Bool = false;
|
||||
|
||||
public function new(x:Float, y:Float) {
|
||||
super(x, y, 300, 46, "editors/ui/inputbox");
|
||||
|
||||
icon = new FlxSprite(x+12, y+9).loadGraphic(Paths.image("editors/autosave-icons"), true, 10, 10);
|
||||
icon.animation.add("icon", [for(i in 0...3) i], 0, true);
|
||||
icon.animation.play("icon"); icon.animation.curAnim.curFrame = 0;
|
||||
members.push(icon);
|
||||
|
||||
members.push(autosavingText = new UIText(x+12+10+4, y+8, 0, "Autosaving in 10 seconds...", 12));
|
||||
|
||||
progressBarBack = new FlxSprite(x + 10, y + bHeight - 20).makeGraphic(Std.int(bWidth-20), 10, 0x00000000, true);
|
||||
progressBarBack.drawRoundRect(0, 0, progressBarBack.width, progressBarBack.height, 4, 6, 0xFF727272, null, {smoothing: false});
|
||||
progressBarBack.drawRoundRect(1, 1, progressBarBack.width-2, progressBarBack.height-2, 4, 6, 0xFF0D0D0D, null, {smoothing: false});
|
||||
members.push(progressBarBack); progressBarBack.antialiasing = false;
|
||||
|
||||
progressBar = new FlxSprite(x + 10, y + bHeight - 20).makeGraphic(Std.int(bWidth-20), 10, 0x00000000, true);
|
||||
progressBar.drawRoundRect(0, 0, progressBar.width, progressBar.height, 4, 6, 0xFF727272, null, {smoothing: false});
|
||||
progressBar.drawRoundRect(1, 1, progressBar.width-2, progressBar.height-2, 4, 6, 0xFFFFFFFF, null, {smoothing: false});
|
||||
progressBar.antialiasing = false; progressBar.clipRect = new FlxRect(0, 0, progressBar.width, progressBar.height);
|
||||
members.push(progressBar);
|
||||
|
||||
cancelButton = new UIButton(x-(10+16), y+8, "", () -> {
|
||||
if (cancelled || !showedAnimation) return;
|
||||
cancelled = true; __timer.cancel(); __tween.cancel();
|
||||
|
||||
icon.animation.curAnim.curFrame = 2;
|
||||
(new FlxTimer()).start(1, (_) -> {disappearAnimation(true);});
|
||||
autosavingText.text += " (Canceled)!"; cancelButton.visible = false;
|
||||
for (member in [this, autosavingText]) member.color = 0xFFE67F7F;
|
||||
for (member in [progressBar, progressBarBack]) member.color = 0xFFE67F7F;
|
||||
}, 24, 14);
|
||||
cancelButton.frames = Paths.getFrames("editors/ui/grayscale-button");
|
||||
cancelButton.color = 0xFFAC3D3D; cancelButton.alpha = 0.2;
|
||||
members.push(cancelButton); cancelButton.visible = false;
|
||||
|
||||
cancelIcon = new FlxSprite(x-(10+16), y+8).loadGraphic(Paths.image("editors/autosave-delete"));
|
||||
cancelIcon.color = 0xFFD60E0E;
|
||||
members.push(cancelIcon);
|
||||
|
||||
alpha = 0;
|
||||
}
|
||||
|
||||
var __timer:FlxTimer;
|
||||
var __tween:FlxTween;
|
||||
|
||||
public function startAutoSave(time:Float, sucessText:String) {
|
||||
appearAnimation();
|
||||
|
||||
__tween = FlxTween.num(0, 1, time, null, (v:Float) -> {
|
||||
if ((progress = v) < .95) {
|
||||
autosavingText.text = 'Autosaving in ${Math.min(Math.round(time), 1+Math.floor(Math.abs(time-(progress*time))))} seconds';
|
||||
autosavingText.text += [for (i in 0...(Math.floor((progress*time*3)%4))) "."].join("");
|
||||
}
|
||||
});
|
||||
__timer = new FlxTimer();
|
||||
__timer.start(time, (_) -> {
|
||||
autosavingText.text = sucessText; cancelButton.visible = false;
|
||||
|
||||
icon.animation.curAnim.curFrame = 1;
|
||||
for (member in [this, progressBar, progressBarBack, autosavingText]) member.color = 0xFFA3EC95;
|
||||
|
||||
(new FlxTimer()).start(1, (_) -> {disappearAnimation();});
|
||||
});
|
||||
}
|
||||
|
||||
public var progress:Float = 0;
|
||||
public override function update(elapsed:Float) {
|
||||
super.update(elapsed);
|
||||
|
||||
cancelButton.follow(this, bWidth-(10+24), 7);
|
||||
cancelButton.alpha = alpha * .7;
|
||||
|
||||
cancelIcon.follow(cancelButton, 3.5+1, 2);
|
||||
cancelIcon.alpha = alpha;
|
||||
|
||||
cancelIcon.visible = cancelButton.visible;
|
||||
|
||||
icon.follow(this, 12, 9);
|
||||
icon.alpha = alpha;
|
||||
|
||||
autosavingText.follow(this, 12+10+4, 8);
|
||||
autosavingText.alpha = alpha;
|
||||
|
||||
for (bar in [progressBar, progressBarBack]) {
|
||||
bar.follow(this, 10, bHeight-20);
|
||||
bar.alpha = alpha;
|
||||
}
|
||||
progressBar.clipRect = progressBar.clipRect.set(0, 0, progressBar.width*progress,progressBar.height);
|
||||
}
|
||||
|
||||
public function appearAnimation() {
|
||||
autosavingText.text = "Autosaving in seconds..."; progress = 0; icon.animation.curAnim.curFrame = 0;
|
||||
for (member in [this, autosavingText, progressBar, progressBarBack]) member.color = 0xFFFFFFFF;
|
||||
|
||||
x = -(320); alpha=0; FlxTween.cancelTweensOf(this); cancelled = false; cancelButton.visible = true;
|
||||
FlxTween.tween(this, {x: 20}, .4, {ease: FlxEase.circInOut});
|
||||
FlxTween.tween(this, {alpha: 1}, .3, {ease: FlxEase.sineOut, startDelay: .1});
|
||||
|
||||
showedAnimation = true;
|
||||
}
|
||||
|
||||
public function disappearAnimation(?canned:Bool = false) {
|
||||
x = 20; alpha = 1; FlxTween.cancelTweensOf(this);
|
||||
if (canned) FlxTween.tween(this, {x: -320}, .4, {ease: FlxEase.circInOut});
|
||||
FlxTween.tween(this, {alpha: 0}, .3, {ease: FlxEase.sineOut});
|
||||
|
||||
showedAnimation = false;
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,7 @@ class CharterBackdropGroup extends FlxTypedGroup<CharterBackdrop> {
|
||||
public override function update(elapsed:Float) {
|
||||
for (grid in members)
|
||||
grid.active = grid.visible = false;
|
||||
|
||||
|
||||
super.update(elapsed);
|
||||
|
||||
for (i => strumLine in strumLineGroup.members) {
|
||||
@@ -64,6 +64,8 @@ class CharterBackdropGroup extends FlxTypedGroup<CharterBackdrop> {
|
||||
grid.sectionSeparator.visible = sectionsVisible;
|
||||
grid.beatSeparator.visible = beatsVisible;
|
||||
|
||||
grid.waveformSprite.shader = strumLine.waveformShader;
|
||||
|
||||
grid.notesGroup.clear();
|
||||
notesGroup.forEach((n) -> {
|
||||
var onStr:Bool = (n.snappedToStrumline ? n.strumLineID : Std.int(FlxMath.bound((n.x+n.width)/(40*4), 0, strumLineGroup.members.length-1))) == i;
|
||||
@@ -74,7 +76,6 @@ class CharterBackdropGroup extends FlxTypedGroup<CharterBackdrop> {
|
||||
grid.active = grid.visible = true;
|
||||
grid.updateSprites();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public var draggingObj:CharterBackdrop = null;
|
||||
@@ -115,6 +116,8 @@ class CharterBackdrop extends FlxTypedGroup<Dynamic> {
|
||||
public var bottomLimit:FlxSprite;
|
||||
public var bottomSeparator:FlxSprite;
|
||||
|
||||
public var waveformSprite:FlxSprite;
|
||||
|
||||
public var conductorFollowerSpr:FlxSprite;
|
||||
public var beatSeparator:FlxBackdrop;
|
||||
public var sectionSeparator:FlxBackdrop;
|
||||
@@ -128,6 +131,11 @@ class CharterBackdrop extends FlxTypedGroup<Dynamic> {
|
||||
gridBackDrop = new FlxBackdrop(gridGraphic, Y, 0, 0);
|
||||
add(gridBackDrop);
|
||||
|
||||
waveformSprite = new FlxSprite().makeSolid(1, 1, 0xFF000000);
|
||||
waveformSprite.scale.set(160, 1);
|
||||
waveformSprite.updateHitbox();
|
||||
add(waveformSprite);
|
||||
|
||||
sectionSeparator = new FlxBackdrop(null, Y, 0, 0);
|
||||
sectionSeparator.y = -2;
|
||||
sectionSeparator.visible = Options.charterShowSections;
|
||||
@@ -135,7 +143,7 @@ class CharterBackdrop extends FlxTypedGroup<Dynamic> {
|
||||
beatSeparator = new FlxBackdrop(null, Y, 0, 0);
|
||||
beatSeparator.y = -1;
|
||||
beatSeparator.visible = Options.charterShowBeats;
|
||||
|
||||
|
||||
for(sep in [sectionSeparator, beatSeparator]) {
|
||||
sep.makeSolid(1, 1, -1);
|
||||
sep.alpha = 0.5;
|
||||
@@ -192,8 +200,9 @@ class CharterBackdrop extends FlxTypedGroup<Dynamic> {
|
||||
alpha = strumLine.strumLine.visible ? 0.9 : 0.4;
|
||||
} else alpha = 0.9;
|
||||
|
||||
for (spr in [gridBackDrop, sectionSeparator, beatSeparator, topLimit, bottomLimit, topSeparator, bottomSeparator, conductorFollowerSpr]) {
|
||||
spr.x = x; spr.alpha = alpha;
|
||||
for (spr in [gridBackDrop, sectionSeparator, beatSeparator, topLimit, bottomLimit,
|
||||
topSeparator, bottomSeparator, conductorFollowerSpr, waveformSprite]) {
|
||||
spr.x = x; if (spr != waveformSprite) spr.alpha = alpha;
|
||||
spr.cameras = this.cameras;
|
||||
}
|
||||
|
||||
@@ -206,6 +215,25 @@ class CharterBackdrop extends FlxTypedGroup<Dynamic> {
|
||||
|
||||
bottomLimit.scale.set(4 * 40, Math.ceil(FlxG.height / cameras[0].zoom));
|
||||
bottomLimit.updateHitbox();
|
||||
|
||||
waveformSprite.visible = waveformSprite.shader != null;
|
||||
if (waveformSprite.shader == null) return;
|
||||
|
||||
waveformSprite.scale.set(160, FlxG.height * (1/cameras[0].zoom));
|
||||
waveformSprite.updateHitbox();
|
||||
|
||||
waveformSprite.y = (cameras[0].scroll.y+FlxG.height/2)-(waveformSprite.height/2);
|
||||
|
||||
if (waveformSprite.y < 0) {waveformSprite.scale.y += waveformSprite.y; waveformSprite.y = 0;}
|
||||
if (waveformSprite.y + waveformSprite.height > bottomLimit.y) {
|
||||
waveformSprite.scale.y -= (waveformSprite.y + waveformSprite.height)-(bottomLimit.y);
|
||||
waveformSprite.y = (bottomLimit.y) - waveformSprite.scale.y;
|
||||
}
|
||||
waveformSprite.updateHitbox();
|
||||
|
||||
waveformSprite.shader.data.pixelOffset.value = [Math.max(conductorFollowerSpr.y - ((FlxG.height * (1/cameras[0].zoom)) * 0.5), 0)];
|
||||
waveformSprite.shader.data.textureRes.value = [waveformSprite.width, waveformSprite.height];
|
||||
waveformSprite.shader.data.playerPosition.value = [conductorFollowerSpr.y];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
package funkin.editors.charter;
|
||||
|
||||
class CharterDeleteAnim extends CharterNote {
|
||||
public var garbageIcon:FlxSprite;
|
||||
public var garbageCircle:FlxSprite;
|
||||
|
||||
public var deleteNotes:Array<{note:CharterNote, time:Float}> = [];
|
||||
public var deleteTime:Float = .4;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
|
||||
sustainSpr.color = 0xFF630000; color = 0xFF605A5A;
|
||||
snappedToStrumline = selectable = autoAlpha = false;
|
||||
@:privateAccess __animSpeed = 1.25;
|
||||
|
||||
garbageIcon = new FlxSprite().loadGraphic(Paths.image("editors/deleter"));
|
||||
garbageIcon.color = 0xFF880000;
|
||||
garbageIcon.cameras = [Charter.instance.uiCamera];
|
||||
|
||||
garbageCircle = new FlxSprite().loadGraphic(Paths.image("editors/deleter circle"));
|
||||
garbageCircle.color = 0xFF880000; garbageCircle.alpha = .6;
|
||||
garbageCircle.cameras = [Charter.instance.uiCamera];
|
||||
}
|
||||
|
||||
var __garbageAlpha:Float = 0;
|
||||
var __deletionTimer:Float = .1;
|
||||
@:noCompletion var __mousePos:FlxPoint = FlxPoint.get();
|
||||
public override function update(elapsed:Float) {
|
||||
for (deleteData in deleteNotes) {
|
||||
deleteData.time -= elapsed;
|
||||
if (deleteData.time < 0) deleteNotes.remove(deleteData);
|
||||
}
|
||||
|
||||
if (FlxG.mouse.justPressedRight) __deletionTimer = .1;
|
||||
__deletionTimer -= elapsed;
|
||||
|
||||
__garbageAlpha = FlxMath.lerp(__garbageAlpha, FlxG.mouse.pressedRight && __deletionTimer <= 0 ? 1 : 0, 1/10);
|
||||
|
||||
FlxG.mouse.getWorldPosition(Charter.instance.uiCamera, __mousePos);
|
||||
if (FlxG.mouse.pressedRight && __deletionTimer <= 0) {
|
||||
garbageIcon.setPosition(
|
||||
__mousePos.x + garbageIcon.width/2 + (.65*FlxG.random.float(-1, 1)) + 2,
|
||||
__mousePos.y - garbageIcon.height + (.65*FlxG.random.float(-1, 1)) - 8
|
||||
);
|
||||
|
||||
garbageCircle.setPosition(
|
||||
__mousePos.x - garbageCircle.width/2,
|
||||
(__mousePos.y - garbageCircle.height/2) + 2
|
||||
);
|
||||
}
|
||||
|
||||
garbageIcon.alpha = __garbageAlpha;
|
||||
garbageCircle.alpha = __garbageAlpha*.6;
|
||||
}
|
||||
|
||||
public override function draw() @:privateAccess {
|
||||
for (deleteData in deleteNotes) {
|
||||
y = deleteData.note.y + (deleteData.time>deleteTime*.5 ? (deleteData.time/deleteTime)*FlxG.random.float(-1.1, 1.1) : 0); // lunar when no shake :((
|
||||
x = deleteData.note.x + (deleteData.time>deleteTime*.5 ? (deleteData.time/deleteTime)*FlxG.random.float(-1.1, 1.1) : 0); // lunar when no shake :((
|
||||
angle = deleteData.note.angle; alpha = 1;
|
||||
animation.curAnim.curFrame = 3;
|
||||
|
||||
sustainSpr.scale.set(10, (40 * deleteData.note.susLength) + (height/2));
|
||||
sustainSpr.updateHitbox(); sustainSpr.follow(this, 15, 20);
|
||||
sustainSpr.exists = deleteData.note.susLength != 0; sustainSpr.alpha = .8;
|
||||
|
||||
typeText.text = Std.string(deleteData.note.type);
|
||||
typeText.exists = deleteData.note.type != 0; typeText.alpha = .4;
|
||||
typeText.follow(this, 20 - (typeText.frameWidth/2), 20 - (typeText.frameHeight/2));
|
||||
|
||||
for (member in [this, sustainSpr, typeText])
|
||||
member.alpha *= FlxEase.quadInOut(deleteData.time/deleteTime);
|
||||
|
||||
super.draw();
|
||||
}
|
||||
|
||||
if (garbageIcon.alpha > 0) garbageIcon.draw();
|
||||
if (garbageCircle.alpha > 0) garbageCircle.draw();
|
||||
}
|
||||
|
||||
public override function destroy() {
|
||||
super.destroy();
|
||||
__mousePos.put();
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,7 @@ class CharterEvent extends UISliceSprite implements ICharterSelectable {
|
||||
if (Assets.exists(Paths.pack('events/$name'))) {
|
||||
var packimg = Assets.getText(Paths.pack('events/$name')).split('________PACKSEP________')[3];
|
||||
if (isBase64 = (packimg != null))
|
||||
path = Assets.getText(Paths.pack('events/$name')).split('________PACKSEP________')[3];
|
||||
path = Assets.getText(Paths.pack('events/$name')).split('________PACKSEP________')[3];
|
||||
}
|
||||
var spr = new FlxSprite().loadGraphic(isBase64 ? openfl.display.BitmapData.fromBase64(path.trim(), 'UTF8') : path);
|
||||
return spr;
|
||||
|
||||
@@ -79,13 +79,13 @@ class CharterEventScreen extends UISubstateWindow {
|
||||
else {
|
||||
chartEvent.events = [for (i in eventsList.buttons.members) i.event];
|
||||
chartEvent.refreshEventIcons();
|
||||
Charter.instance.updateBPMEvents();
|
||||
|
||||
Charter.undos.addToUndo(CEditEvent(chartEvent, oldEvents, [for (event in events) Reflect.copy(event)]));
|
||||
}
|
||||
}
|
||||
|
||||
close();
|
||||
Charter.instance.updateBPMEvents();
|
||||
});
|
||||
saveButton.x -= saveButton.bWidth;
|
||||
add(saveButton);
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ import funkin.editors.extra.PropertyButton;
|
||||
|
||||
using StringTools;
|
||||
|
||||
class MetaDataScreen extends UISubstateWindow {
|
||||
class CharterMetaDataScreen extends UISubstateWindow {
|
||||
public var metadata:ChartMetaData;
|
||||
public var saveButton:UIButton;
|
||||
public var closeButton:UIButton;
|
||||
@@ -31,7 +31,7 @@ class CharterNote extends UISprite implements ICharterSelectable {
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
|
||||
|
||||
antialiasing = true; ID = -1;
|
||||
loadGraphic(Paths.image('editors/charter/note'), true, 157, 154);
|
||||
animation.add("note", [for(i in 0...frames.frames.length) i], 0, true);
|
||||
@@ -154,7 +154,7 @@ class CharterNote extends UISprite implements ICharterSelectable {
|
||||
|
||||
if (strumLine != null) {
|
||||
sustainSpr.alpha = alpha = !strumLine.strumLine.visible ? (__passed ? 0.2 : 0.4) : (__passed ? 0.6 : 1);
|
||||
typeText.alpha = !strumLine.strumLine.visible ? (__passed ? 0.4 : 0.6) : (__passed ? 0.8 : 1);
|
||||
typeText.alpha = !strumLine.strumLine.visible ? (__passed ? 0.4 : 0.6) : (__passed ? 0.8 : 1);
|
||||
}
|
||||
|
||||
colorTransform.redMultiplier = colorTransform.greenMultiplier = colorTransform.blueMultiplier = selected ? 0.75 : 1;
|
||||
|
||||
@@ -29,11 +29,11 @@ class CharterNoteGroup extends FlxTypedGroup<CharterNote> {
|
||||
|
||||
for(i in begin...end) {
|
||||
__loopSprite = members[i];
|
||||
if (!Charter.selection.contains(__loopSprite))
|
||||
if (__loopSprite != null && !Charter.selection.contains(__loopSprite))
|
||||
noteFunc(__loopSprite);
|
||||
}
|
||||
for(c in Charter.selection.copy())
|
||||
if (c is CharterNote) noteFunc(cast (c, CharterNote));
|
||||
if (c != null && c is CharterNote) noteFunc(cast (c, CharterNote));
|
||||
|
||||
__currentlyLooping = oldCur;
|
||||
}
|
||||
@@ -64,7 +64,7 @@ class CharterNoteGroup extends FlxTypedGroup<CharterNote> {
|
||||
|
||||
if (autoSort && members.length != __lastSort)
|
||||
sortNotes();
|
||||
|
||||
|
||||
forEach((n) -> {
|
||||
if(n.exists && n.active) {
|
||||
n.cameras = n.__lastDrawCameras = cameras;
|
||||
|
||||
@@ -44,18 +44,18 @@ class CharterNoteHoverer extends CharterNote {
|
||||
if (Charter.instance.gridActionType == NOTE_DRAG) {
|
||||
var verticalChange:Float = (__mousePos.y - Charter.instance.dragStartPos.y) / 40;
|
||||
var horizontalChange:Int = CoolUtil.floorInt((__mousePos.x - (Std.int(Charter.instance.dragStartPos.x / 40) * 40)) / 40);
|
||||
|
||||
|
||||
for (s in Charter.selection) {
|
||||
if (s != null && s.draggable && s is CharterNote) {
|
||||
var draggingNote:CharterNote = cast(s, CharterNote);
|
||||
y = (draggingNote.step + verticalChange);
|
||||
if (!FlxG.keys.pressed.SHIFT)
|
||||
if (!FlxG.keys.pressed.SHIFT)
|
||||
y -= ((draggingNote.step + verticalChange)
|
||||
- Charter.instance.quantStepRounded(draggingNote.step+verticalChange, verticalChange > 0 ? 0.35 : 0.65));
|
||||
y *= 40;
|
||||
var newID:Int = Std.int(FlxMath.bound(draggingNote.fullID + horizontalChange, 0, (Charter.instance.strumLines.members.length*4)-1));
|
||||
x = (id=newID) * 40; y = FlxMath.bound(y, 0, (Charter.instance.__endStep*40) - height);
|
||||
|
||||
|
||||
angle = switch(animation.curAnim.curFrame = (draggingNote.id % 4)) {
|
||||
case 0: -90;
|
||||
case 1: 180;
|
||||
|
||||
@@ -108,7 +108,7 @@ class NoteTypeButton extends UIButton {
|
||||
var path:String = 'game/notes/default';
|
||||
if (Assets.exists(Paths.image('game/notes/${notetype}')))
|
||||
path = 'game/notes/${notetype}';
|
||||
|
||||
|
||||
noteSpr.frames = Paths.getFrames(path);
|
||||
noteSpr.animation.addByPrefix('scroll', 'green0');
|
||||
noteSpr.animation.play("scroll");
|
||||
|
||||
@@ -29,7 +29,7 @@ class CharterSelection extends EditorTreeMenu {
|
||||
for(s in freeplayList.songs) new EditorIconOption(s.name, "Press ACCEPT to choose a difficulty to edit.", s.icon, function() {
|
||||
curSong = s;
|
||||
var list:Array<OptionType> = [
|
||||
for(d in s.difficulties) if (d != "")
|
||||
for(d in s.difficulties) if (d != "")
|
||||
new TextOption(d, "Press ACCEPT to edit the chart for the selected difficulty", function() {
|
||||
FlxG.switchState(new Charter(s.name, d));
|
||||
})
|
||||
@@ -46,6 +46,8 @@ class CharterSelection extends EditorTreeMenu {
|
||||
}));
|
||||
|
||||
main = new OptionsScreen("Chart Editor", "Select a song to modify the charts from.", list);
|
||||
|
||||
DiscordUtil.call("onEditorTreeLoaded", ["Chart Editor"]);
|
||||
}
|
||||
|
||||
override function createPost() {
|
||||
@@ -107,7 +109,7 @@ class CharterSelection extends EditorTreeMenu {
|
||||
sys.FileSystem.createDirectory('$songFolder/charts');
|
||||
|
||||
// Save Files
|
||||
sys.io.File.saveContent('$songFolder/meta.json', Json.stringify(creation.meta, "\t"));
|
||||
CoolUtil.safeSaveFile('$songFolder/meta.json', Json.stringify(creation.meta, "\t"));
|
||||
if (creation.instBytes != null) sys.io.File.saveBytes('$songFolder/song/Inst.${Paths.SOUND_EXT}', creation.instBytes);
|
||||
if (creation.voicesBytes != null) sys.io.File.saveBytes('$songFolder/song/Voices.${Paths.SOUND_EXT}', creation.voicesBytes);
|
||||
#end
|
||||
@@ -145,9 +147,7 @@ class CharterSelection extends EditorTreeMenu {
|
||||
var songFolder:String = '${Paths.getAssetsRoot()}/songs/${curSong.name}';
|
||||
|
||||
// Save Files
|
||||
#if sys
|
||||
sys.io.File.saveContent('$songFolder/charts/${name}.json', Json.stringify(data, "\t"));
|
||||
#end
|
||||
CoolUtil.safeSaveFile('$songFolder/charts/${name}.json', Json.stringify(data, "\t"));
|
||||
|
||||
// Add to List
|
||||
curSong.difficulties.push(name);
|
||||
@@ -160,7 +160,7 @@ class CharterSelection extends EditorTreeMenu {
|
||||
var meta = Json.parse(sys.io.File.getContent('$songFolder/meta.json'));
|
||||
if (meta.difficulties != null && !meta.difficulties.contains(name)) {
|
||||
meta.difficulties.push(name);
|
||||
sys.io.File.saveContent('$songFolder/meta.json', Json.stringify(meta));
|
||||
CoolUtil.safeSaveFile('$songFolder/meta.json', Json.stringify(meta));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,7 @@ class CharterStrumLineGroup extends FlxTypedGroup<CharterStrumline> {
|
||||
fixEvents();
|
||||
}
|
||||
|
||||
public inline function fixEvents() {
|
||||
public inline function fixEvents() {
|
||||
for (i in Charter.instance.eventsGroup.members) {
|
||||
for (j in i.events) {
|
||||
var paramTypes:Array<EventParamInfo> = EventsData.getEventParams(j.name);
|
||||
|
||||
@@ -5,6 +5,7 @@ import funkin.game.Character;
|
||||
import funkin.editors.ui.UITopMenu.UITopMenuButton;
|
||||
import funkin.game.HealthIcon;
|
||||
import funkin.backend.chart.ChartData.ChartStrumLine;
|
||||
import funkin.backend.shaders.CustomShader;
|
||||
import flixel.sound.FlxSound;
|
||||
|
||||
class CharterStrumline extends UISprite {
|
||||
@@ -22,6 +23,17 @@ class CharterStrumline extends UISprite {
|
||||
|
||||
public var vocals:FlxSound;
|
||||
|
||||
public var selectedWaveform(default, set):Int = -1;
|
||||
public function set_selectedWaveform(value:Int):Int {
|
||||
if (value == -1) waveformShader = null;
|
||||
else {
|
||||
var shaderName:String = Charter.waveformHandler.waveformList[value];
|
||||
waveformShader = Charter.waveformHandler.waveShaders.get(shaderName);
|
||||
}
|
||||
return selectedWaveform = value;
|
||||
}
|
||||
public var waveformShader:CustomShader;
|
||||
|
||||
public function new(strumLine:ChartStrumLine) {
|
||||
super();
|
||||
this.strumLine = strumLine;
|
||||
@@ -60,6 +72,8 @@ class CharterStrumline extends UISprite {
|
||||
|
||||
vocals = strumLine.vocalsSuffix.length > 0 ? FlxG.sound.load(Paths.voices(PlayState.SONG.meta.name, PlayState.difficulty, strumLine.vocalsSuffix)) : new FlxSound();
|
||||
vocals.group = FlxG.sound.defaultMusicGroup;
|
||||
|
||||
selectedWaveform = -1;
|
||||
}
|
||||
|
||||
private var __healthYOffset:Float = 0;
|
||||
@@ -154,6 +168,22 @@ class CharterStrumlineOptions extends UITopMenuButton {
|
||||
icon: 3
|
||||
}
|
||||
];
|
||||
|
||||
contextMenu.insert(0, {
|
||||
label: "No Waveform",
|
||||
onSelect: function(_) {strLine.selectedWaveform = -1;},
|
||||
icon: strLine.selectedWaveform == -1 ? 1 : 0
|
||||
});
|
||||
|
||||
for (i => name in Charter.waveformHandler.waveformList)
|
||||
contextMenu.insert(1+i, {
|
||||
label: name,
|
||||
onSelect: function(_) {strLine.selectedWaveform = i;},
|
||||
icon: strLine.selectedWaveform == i ? 6 : 5
|
||||
});
|
||||
|
||||
contextMenu.insert(1+Charter.waveformHandler.waveformList.length, null);
|
||||
|
||||
super.openContextMenu();
|
||||
}
|
||||
}
|
||||
@@ -59,10 +59,10 @@ class CharterStrumlineButton extends UISprite {
|
||||
super.update(elapsed);
|
||||
|
||||
UIState.state.updateSpriteRect(button);
|
||||
if(UIState.state.isOverlapping(button, button.__rect)) {
|
||||
if(UIState.state.curContextMenu == null && UIState.state.isOverlapping(button, button.__rect)) {
|
||||
buttonScale.set(0.95, 0.95);
|
||||
if (FlxG.mouse.justReleased && onClick != null) {
|
||||
onClick();
|
||||
if (FlxG.mouse.justPressed && onClick != null) {
|
||||
onClick();
|
||||
if (animationOnClick) pressAnimation();
|
||||
}
|
||||
}
|
||||
@@ -96,7 +96,7 @@ class CharterStrumlineButton extends UISprite {
|
||||
scaleTween = FlxTween.tween(buttonScaleOffset, {x: .015 * (extra ? 3 : 1), y: .02 * (extra ? 3 : 1)}, .12, {ease: FlxEase.circOut})
|
||||
.then(FlxTween.tween(buttonScaleOffset, {x: 0, y: 0}, .1 + FlxG.random.float(.1, .3), {ease: FlxEase.circIn}));
|
||||
|
||||
if (!extra) return;
|
||||
if (!extra) return;
|
||||
|
||||
if (angleTween != null) angleTween.cancel(); button.angle = 0;
|
||||
angleTween = FlxTween.tween(button, {angle: 360}, .5, {ease: FlxEase.circInOut});
|
||||
|
||||
@@ -63,7 +63,7 @@ class CharterStrumlineScreen extends UISubstateWindow {
|
||||
|
||||
var charFileList = Character.getList(true);
|
||||
if (charFileList.length == 0) charFileList = Character.getList(false);
|
||||
|
||||
|
||||
charactersList = new UIButtonList<CharacterButton>(15, title.y + title.height + 36, 250, 269, "", FlxPoint.get(250, 54), null, 0);
|
||||
charactersList.addButton.callback = () -> charactersList.add(new CharacterButton(0, 0, "New Char", charFileList, charactersList));
|
||||
charactersList.cameraSpacing = 0;
|
||||
@@ -112,7 +112,7 @@ class CharterStrumlineScreen extends UISubstateWindow {
|
||||
|
||||
var strOffset:Float = strumLine.strumLinePos == null ? (strumLine.type == 1 ? 0.75 : 0.25) : strumLine.strumLinePos;
|
||||
|
||||
var startingPos:FlxPoint = strumLine.strumLinePos == null ?
|
||||
var startingPos:FlxPoint = strumLine.strumPos == null ?
|
||||
FlxPoint.get(strOffset, 50) :
|
||||
FlxPoint.get(strOffset, strumLine.strumPos[1]);
|
||||
|
||||
@@ -142,7 +142,7 @@ class CharterStrumlineScreen extends UISubstateWindow {
|
||||
closeButton.color = 0xFFFF0000;
|
||||
|
||||
var suffixlist = ["NONE"];
|
||||
for (i in Paths.getFolderContent('songs/${Charter.__song.toLowerCase()}/song'))
|
||||
for (i in Paths.getFolderContent('songs/${Charter.__song.toLowerCase()}/song'))
|
||||
if (i.startsWith("Voices")) {
|
||||
i = haxe.io.Path.withoutExtension(i.substr("Voices".length));
|
||||
if (i == "") continue;
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
package funkin.editors.charter;
|
||||
|
||||
import flixel.util.FlxColor;
|
||||
import funkin.backend.system.Conductor;
|
||||
import flixel.sound.FlxSound;
|
||||
import funkin.backend.shaders.CustomShader;
|
||||
import openfl.display.BitmapData;
|
||||
|
||||
class CharterWaveformHandler extends FlxBasic {
|
||||
public var ampsNeeded:Float = 0;
|
||||
public var ampSqrt(get, never):Int;
|
||||
public function get_ampSqrt():Int {
|
||||
var sqrt:Float = Math.sqrt(Math.floor(ampsNeeded/3));
|
||||
var ampRet:Int = Math.floor(sqrt);
|
||||
if (sqrt % 1 > 0) ampRet += 1;
|
||||
return ampRet;
|
||||
}
|
||||
|
||||
public var waveDatas:Map<String, BitmapData> = [];
|
||||
public var waveShaders:Map<String, CustomShader> = [];
|
||||
|
||||
public var sounds:Map<String, FlxSound> = [];
|
||||
public var analyzers:Map<String, AudioAnalyzer> = [];
|
||||
|
||||
public var waveformList:Array<String> = [];
|
||||
|
||||
public function new() {super(); exists = false;}
|
||||
|
||||
public function generateData(name:String, sound:FlxSound):BitmapData {
|
||||
if (!sounds.exists(name)) sounds.set(name, sound);
|
||||
if (!analyzers.exists(name))
|
||||
analyzers.set(name, new AudioAnalyzer(sound));
|
||||
|
||||
var analyzer:AudioAnalyzer = analyzers.get(name);
|
||||
|
||||
var pixelsNeeded:Int = Math.floor(ampsNeeded/3);
|
||||
if ((ampsNeeded/3) % 1 > 0) pixelsNeeded += 1;
|
||||
|
||||
var waveData:BitmapData = new BitmapData(
|
||||
ampSqrt, 1+Math.floor(pixelsNeeded/ampSqrt), true, 0xFF000000
|
||||
);
|
||||
|
||||
for (y in 0...waveData.height)
|
||||
for (x in 0...waveData.width) {
|
||||
var amplitudes:Array<Float> = [0., 0., 0.];
|
||||
for (color in 0...3) {
|
||||
var gridY:Float = (y * (waveData.width * 3)) + (x * 3) + color;
|
||||
|
||||
var startTime:Float = Conductor.getTimeForStep(gridY/40);
|
||||
if (startTime > sound.length) if (color == 0) break; else continue;
|
||||
|
||||
var endTime:Float = Conductor.getTimeForStep((gridY+1)/40);
|
||||
if (endTime > sound.length) if (color == 0) break; else continue;
|
||||
|
||||
var amplitude:Float = analyzer.analyze(startTime, endTime);
|
||||
amplitudes[color] = amplitude;
|
||||
}
|
||||
waveData.setPixel(x, y, FlxColor.fromRGBFloat(amplitudes[0], amplitudes[1], amplitudes[2]));
|
||||
}
|
||||
|
||||
waveDatas.set(name, waveData);
|
||||
return waveData;
|
||||
}
|
||||
|
||||
public function generateShader(name:String, sound:FlxSound):CustomShader {
|
||||
if (!waveDatas.exists(name)) generateData(name, sound);
|
||||
|
||||
var waveData:BitmapData = waveDatas.get(name);
|
||||
|
||||
var waveShader:CustomShader = new CustomShader("engine/editorWaveforms");
|
||||
waveShader.data.waveformSize.value = [waveData.width, waveData.height];
|
||||
waveShader.data.waveformTexture.input = waveData;
|
||||
waveShader.data.textureRes.value = [0, 0];
|
||||
waveShader.data.pixelOffset.value = [0];
|
||||
waveShader.data.lowDetail.value = [Options.charterLowDetailWaveforms];
|
||||
|
||||
waveShaders.set(name, waveShader);
|
||||
return waveShader;
|
||||
}
|
||||
|
||||
public function clearWaveform(name:String) {
|
||||
waveDatas.get(name).dispose();
|
||||
waveDatas.remove(name);
|
||||
|
||||
waveShaders.set(name, null);
|
||||
waveShaders.remove(name);
|
||||
|
||||
analyzers.set(name, null);
|
||||
analyzers.remove(name);
|
||||
|
||||
sounds.remove(name);
|
||||
waveformList.remove(name);
|
||||
}
|
||||
|
||||
public function clearWaveforms() {
|
||||
for (data in waveDatas) data.dispose();
|
||||
for (shader in waveShaders) shader = null;
|
||||
for (analyzer in analyzers) analyzer = null;
|
||||
|
||||
waveDatas.clear(); waveShaders.clear();
|
||||
analyzers.clear(); sounds.clear();
|
||||
|
||||
waveformList = [];
|
||||
}
|
||||
|
||||
public override function destroy() {
|
||||
clearWaveforms();
|
||||
super.destroy();
|
||||
}
|
||||
}
|
||||
@@ -87,7 +87,7 @@ class UIAudioPlayer extends UIButton {
|
||||
playingSprite.animation.play(sound.playing ? "playing" : "paused");
|
||||
timeText.text = '${FlxStringUtil.formatTime(sound.time/1000, true)} / ${FlxStringUtil.formatTime(sound.length/1000)}';
|
||||
|
||||
if(timeBarPlayer.clipRect == null)
|
||||
if(timeBarPlayer.clipRect == null)
|
||||
timeBarPlayer.clipRect = new FlxRect(0, 0, timeBarPlayer.frameWidth, timeBarPlayer.frameHeight);
|
||||
|
||||
timeBarPlayer.clipRect.x = timeBarPlayer.frameWidth * (sound.time/sound.length);
|
||||
@@ -106,13 +106,13 @@ class UIAudioPlayer extends UIButton {
|
||||
|
||||
var spritePos:FlxPoint = sprite.getScreenPosition(FlxPoint.get(), __lastDrawCameras[0]);
|
||||
|
||||
if (((mousePos.x > (spritePos.x)) && (mousePos.x < (spritePos.x) + timeBar.barWidth))
|
||||
if (((mousePos.x > (spritePos.x)) && (mousePos.x < (spritePos.x) + timeBar.barWidth))
|
||||
&& ((mousePos.y > (spritePos.y)) && (mousePos.y < (spritePos.y) + timeBar.barHeight))) {
|
||||
if (FlxG.mouse.justPressed) {
|
||||
draggingObj = sprite;
|
||||
wasPlaying = draggingObj == timeBar ? sound.playing : false;
|
||||
}
|
||||
|
||||
|
||||
if (FlxG.mouse.pressed) {
|
||||
if (draggingObj == timeBar) {
|
||||
if (sound.playing) sound.pause();
|
||||
@@ -137,7 +137,7 @@ class UIAudioPlayer extends UIButton {
|
||||
super.destroy();
|
||||
|
||||
sound.stop();
|
||||
@:privateAccess sound.reset();
|
||||
@:privateAccess sound.reset();
|
||||
bytes = null;
|
||||
}
|
||||
}
|
||||
@@ -121,7 +121,6 @@ class UIButtonList<T:UIButton> extends UIWindow {
|
||||
if (dragCallback != null) dragCallback(cast button, button.ID, i);
|
||||
button.ID = i; // Ok back to normal :D
|
||||
}
|
||||
|
||||
}
|
||||
addButton.selectable = (hovered && !dragging);
|
||||
|
||||
|
||||
@@ -87,11 +87,11 @@ class UIColorwheel extends UISliceSprite {
|
||||
for (item in [colorPicker, colorPickerSelector, colorSlider, colorSliderSelector, colorHexTextBox, hexLabel, rgbLabel])
|
||||
members.push(item);
|
||||
|
||||
updateWheel();
|
||||
updateWheel(false);
|
||||
}
|
||||
|
||||
inline function updateColorPickerSelector()
|
||||
colorPickerSelector.selector.setPosition(colorPicker.x + (colorPicker.width *saturation) - 8, colorPicker.y + (colorPicker.height + (colorPicker.height * -brightness))- 8);
|
||||
colorPickerSelector.selector.setPosition(colorPicker.x + (colorPicker.width *saturation) - 8, colorPicker.y + (colorPicker.height + (colorPicker.height * -brightness))- 8);
|
||||
|
||||
inline function updateColorPickerMouse(mousePos:FlxPoint) {
|
||||
saturation = mousePos.x/colorPicker.width; brightness = 1 + -(mousePos.y/colorPicker.height);
|
||||
@@ -103,12 +103,13 @@ class UIColorwheel extends UISliceSprite {
|
||||
inline function updateColorSliderMouse(mousePos:FlxPoint)
|
||||
hue = (mousePos.y / colorSlider.height) * 360;
|
||||
|
||||
public function updateWheel() {
|
||||
public function updateWheel(checkChanged:Bool = true) {
|
||||
if(checkChanged) colorChanged = true;
|
||||
colorPickerShader.hset("hue", hue / 360);
|
||||
colorPickerSelector.curColor = color = curColor = FlxColor.fromHSB(hue, saturation, brightness); colorSliderSelector.curColor = FlxColor.fromHSB(hue, 1, 1);
|
||||
|
||||
updateColorPickerSelector(); updateColorSliderPickerSelector();
|
||||
colorHexTextBox.label.text = curColorString = curColor.toHexString(false).replace("0x", "#");
|
||||
colorHexTextBox.label.text = curColorString = curColor.toWebString();
|
||||
for (numStepper in rgbNumSteppers) {
|
||||
numStepper.label.text = Std.string(switch (numStepper.ID) {
|
||||
default: curColor.red;
|
||||
@@ -121,7 +122,7 @@ class UIColorwheel extends UISliceSprite {
|
||||
// For Character Editor
|
||||
public var colorChanged:Bool = false;
|
||||
|
||||
// Make the colorwhell feel better
|
||||
// Make the colorwheel feel better
|
||||
static inline var hitBoxExtenstion:Float = 8;
|
||||
|
||||
public override function update(elapsed:Float) {
|
||||
@@ -138,7 +139,6 @@ class UIColorwheel extends UISliceSprite {
|
||||
if (sprite == colorSlider) updateColorSliderMouse(mousePos);
|
||||
if (sprite == colorPicker) updateColorPickerMouse(mousePos);
|
||||
updateWheel();
|
||||
colorChanged = true;
|
||||
|
||||
spritePos.put();
|
||||
break;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user