Author SHA1 Message Date
Ralty dc61d682c0 Merge branch 'main' into internal-merge
# Conflicts:
#	source/funkin/backend/system/Flags.hx
2026-07-07 11:26:08 +07:00
HEIHUAaandGitHub d113fc40cb BloomEffect (#894)
* Create BloomEffect.hx

* Make the shader compatible with more devices.

* Default

* Update BloomEffect.hx

* no __applyFilter

* Update BloomEffect.hx

* Update BloomEffect.hx

* Performance improvement: 1.35x.

* quality

* Implemented low-resolution bloom, achieving a 10x performance boost!!!

* 1

* useLowQualityExtract

* brightness

* 更新 BloomEffect.hx

* blendMode

Fixed memory growth
Added blendMode

* 更新 BloomEffect.hx

* Wrap-up

* 更新 BloomEffect.hx

* 更新 BloomEffect.hx

* 更新 BloomEffect.hx

* no...

* Fix color banding issue in high brightness areas.

* 更新 BloomEffect.hx

* Fix frequent GC (Garbage Collection) issues.

* smoothness

* noCustomClass
2026-07-01 14:02:45 +07:00
sillyborjaandGitHub 45a2f28cf6 read description (#1016)
* read description

- rename tween to playTween
- use the recycle function for positioning in displayRatingNumbers
- add "tween" variable (which is an FlxTween instance, not to be confused with playTween)
- fix returns

* i think this will be confusing but ok

* Revert "i think this will be confusing but ok"

This reverts commit 5a8c834220.
2026-06-28 11:59:38 +07:00
CircuitellaandGitHub 45d47677ac Add a flag related to Icon Movement on the Healthbar (#1005)
* add flag

* Make The Flag be used in PlayState
2026-06-28 09:32:23 +07:00
pharaotisRealandGitHub a485080c27 Ratings event addition to the engine (#1015)
* Update PlayState.hx

Implemented RatingsShowEvent

* Add files via upload

* Update pixel.hx

Update because of ratings commits

* Update PlayState.hx

put the flxpoints after they're used, forgot to use event.tweenDuration in displayRatingNumbers

* Update PlayState.hx

oops

* Update PlayState.hx

I'm so not careful

* Update PlayState.hx

Commited NoteHitEvent checks for all display rating functions

* Update PlayState.hx

oops 2

* Update NoteHitEvent.hx

made the rating vars null class

* Update PlayState.hx

juust in case

* Update PlayState.hx

oops 3

* Update RatingsShowEvent.hx

Implemented a rating var which allows you to change the rating sprite.

* Update PlayState.hx

Implemented a rating var (In RatingsShowEvent) which allows you to change the rating sprite.

* Update PlayState.hx

now it should support displayRating/Combo being set from note hit event

* Update PlayState.hx

fixed a possibility where if the display bool was set to false or the event was cancelled, then it would still display the sprite as a haxeflixel logo
2026-06-28 09:31:59 +07:00
HeroandGitHub cb4ecc521f ZoomFactor in FunkinText, Early Implementation (#1011) 2026-06-20 21:59:22 +07:00
SrtHero278 0e269ddfc7 addressing https://github.com/CodenameCrew/CodenameEngine/issues/1004 2026-06-13 16:43:56 -07:00
SrtHero278 80ca43b46e shits break combo because read desc
this engine is spam and get away with it central like i struggled to hit a shit no joke

and i did get owner approval to do this
2026-05-11 19:44:59 -07:00
ADA_FunniandGitHub 8f0583958d Change the default value of "Multiplicative?" in the "Camera Zoom" event to be false. (#974) 2026-05-03 10:28:50 +07:00
Ralty bf3c45dbb7 Re-enable streamed music in this branch 2026-04-07 14:02:07 +07:00
Ralty 2591230927 Implement FlxTrail Backward Compatibility 2026-04-07 13:51:45 +07:00
Ralty d605eaea85 Use cne-hxvlc instead, rebuild lime in workflows 2026-04-07 13:37:58 +07:00
Ralty 4ad7b33bb2 Merge branch 'main' into internal-merge
# Conflicts:
#	.github/workflows/linux-selfhosted.yml
2026-04-07 10:44:48 +07:00
Ralty f82c8d7fb7 Remove linux-selfhosted, no longer needed. 2026-04-07 10:44:25 +07:00
Ralty 91c84cd9d0 Merge branch 'main' into internal-merge
# Conflicts:
#	.github/workflows/linux.yml
#	.github/workflows/macos.yml
#	.github/workflows/release.yml
#	.github/workflows/windows.yml
#	source/funkin/menus/FreeplayState.hx
#	source/openfl/utils/Assets.hx
2026-04-07 10:42:35 +07:00
Ralty 2a413071cd Disable Streamed Audio for now, better late than broken 2026-04-07 10:41:35 +07:00
Ralty 3fa3fbda14 Fix CoolUtil.playMenuSong volume 2026-04-07 10:41:34 +07:00
Nebula S. NovaandGitHub cd7c9f1afc Fix Commit Number in Main Menu (#950)
* Update checkout action to fetch full history

* Update linux.yml

* Update macos.yml

* Update release.yml

* Update windows.yml
2026-04-04 20:44:30 +07:00
rufiusandGitHub e458e868a4 Add ability to set custom default alternate animation suffix (#882)
The alt. animation toggle event currently does not support setting the
suffix directly,
but that's outside of the scope of adding this feature at the moment.
2026-04-04 13:32:24 +07:00
HEIHUAaandGitHub 6f8f43d3dc Optimize Note & Strum Rendering (#941)
* optimize

* Delete the unnecessary

* Delete __posPoint

* 更新 Note.hx

* @:dox(hide)

* 更新 Strum.hx

* Fix the bug
2026-04-03 21:35:27 +07:00
Ralty 621413682e Fix Backward Compatibility with Shader 2026-04-03 07:02:09 +07:00
BittoandGitHub a8a5ae7a89 Fix game crash and fix(?) == to != (#943) 2026-04-02 06:27:47 +07:00
Ralty 6502b8027f Don't use FAST_LINK with debug 2026-04-02 06:19:55 +07:00
Ralty b80c492afb FIx customizable fontName 2026-04-01 19:51:11 +07:00
Ralty ca0853615b Fix for long loading screen for a specific mod 2026-04-01 07:31:50 +07:00
Ralty 0530bd0732 Add back Modified StringTools.hx 2026-03-30 22:44:04 +07:00
Ralty 294b9f302a Merge branch 'main' into internal-merge 2026-03-30 06:58:21 +07:00
Ralty d7c9f2595a Fix Includes/Imports in Shader 2026-03-30 06:57:56 +07:00
BittoandGitHub e0b5369eb5 "Delete Stacked Notes" functionality for the chart editor (#935)
* Delete Stacked Notes

* unstack selection

* Attempts to translate to italian and polish

i do not know these languages so if they're wrong im sorry
2026-03-30 04:51:57 +07:00
BittoandGitHub d874ea0348 Fix an oversight with the alphabet getting the wrong width of an component (#937) 2026-03-30 04:49:11 +07:00
FrakitsandGitHub 2ec0500cd5 oops 2026-03-29 14:17:19 +03:00
FrakitsandGitHub 959aed576c fix action 2026-03-29 14:02:48 +03:00
Frakits 6272c3e98f selfhosted linux workflow because ubuntu stinks 2026-03-29 13:56:44 +03:00
FrakitsandGitHub d80b7b95cf selfhosted linux workflow because ubuntu stinks 2026-03-29 13:49:08 +03:00
Ralty 5ec57c5c39 i hate everything 2026-03-29 16:04:52 +07:00
Ralty a342783de4 Fix for Log.debug 2026-03-29 14:44:43 +07:00
Ralty eac0dac9b2 Add Flag DEFAULT_SOUND_TIME_SCALED_PITCH 2026-03-29 14:44:35 +07:00
Ralty d6488d37ad Merge remote-tracking branch 'origin/main' into internal-merge 2026-03-29 13:45:10 +07:00
Ralty 995a28e88a Corrected console color in Log.info 2026-03-29 13:41:56 +07:00
Ralty 6dd4058ac6 Deprecate CustomShader 2026-03-29 13:41:56 +07:00
b447031e2d Enable Mac OS Universal support, update hxvlc & actions dependencies, fix VIDEO_CUTSCENES (#931)
* Update hxvlc to 2.2.6

* Remove `arch -x86_64` as no longer needed

Since `cne-lime` got rebased with FunkinCrew's, which includes Apple Silicon (ARM64) support.

* Wtf

* Rename **Mac OS x64** to **Mac OS Universal** in the ReadME

Reason: **x64** is only powered by Intel/AMD, not ARM, so it will make the macOS users to think macOS builds still uses Intel.

* Enable videos for iOS

Since hxvlc 2.0.0 or newer, it fixed the video playback for iOS.

* Fixed the extension-androidtools import, when using extension-androidtools 2.2.X.

* Replace `start` with `wait` in `VideoCutscene.hx`

* Revert

* Nvm I think I found out why I guess

* Will this fix some actions deprecations?

* Oops

* F#CK

* I'm gonna lose it

* I forgot again

I'm going to scream into the pillow, If I keep forgetting to update those.

* Update macOS version to 26 in the macOS workflow

* Remove old hxvlc apis from the `VideoCutscene.hx` class, since hxvlc got updated to the latest

* Fix the f#cking conflicts

* Now it works

---------

Co-authored-by: Ralty <78720179+Raltyro@users.noreply.github.com>
2026-03-29 13:41:27 +07:00
270ed6b9b5 Note.noteAngle rewrite, fixes minus scrollSpeed (#857)
* fix 90% of issues with noteAngle and scrollSpeed of notes

cool  , sustains now dont look like ass when rotated and negative scroll speed doesnt mess tem up anymore

although the consequence of this is that noteAngle will go the other way around if on downscroll but i cant rlly get myself to fix that ;-;

* downscroll is done (hopefully

---------

Co-authored-by: Ralty <78720179+Raltyro@users.noreply.github.com>
2026-03-29 13:36:16 +07:00
Ralty 17bea45cd6 Redo FunkinShader once again 2026-03-29 09:06:22 +07:00
Ralty 8fc068e718 Libraries update 2026-03-29 09:06:15 +07:00
HEIHUAaandGitHub 39968efb19 (Charter) Add an ability to copy selected items by Alt-Dragging (#918) 2026-03-29 05:03:58 +07:00
HeroandGitHub 64ea9db1c1 EULER, smoothStep, inverseLerp, fract in MathUtil (#913) 2026-03-29 05:02:42 +07:00
ItsLJcoolandGitHub 5957a55b96 Add Text displaying if the user is running an Experimental Version of CodenameEngine (#933)
* cmon github actions, do something

* this will make it easier to know if a user is running an experimental version :trollface:
2026-03-29 04:18:46 +07:00
Ralty cf2c3689c5 Merge branch 'main' into internal-merge
# Conflicts:
#	building/libs.xml
#	source/openfl/utils/Assets.hx
2026-03-28 17:58:25 +07:00
Ralty 3266e22562 Correctly change the library rerefences 2026-03-28 17:41:53 +07:00
Ralty 491e5df430 Temporary commit 2026-03-28 17:39:06 +07:00
ItsLJcoolandGitHub a7b040152d Fixed / Refactored SysZip to actually work, and store compressed entries without uncompressing an entire zip (#761)
* well boys I fixed it. you can now have Zipped Mods!!!!!

* comment update

* quick fixes + optimizations

* fixed stream audio bug????

* found the issue ffs

* removing traces oops

* fixed videos from not being able to play. Inspired from VideoCutscene's fix for ZIP videos, and also removed that fix in favor for just fixing the issue entirely

* oop just in case no special characters that kill themself on other shit

* Implemented preloading every video (caching) when loading a ZipFolderLibrary.

Since videos have to be decompressed and be saved as a file anyways this reduces the time to do that, and what not.

* [UNTESTED] Allowed Zip Extensions for allowing any extension in the list to be passed as a `.zip`

* After some more testing loading Zip Addons works as well.

* Added the long awaited .cnemod file type!!!!! (it's just a folder with .cnemod with a .zip inside LMAO)

* Chalking up the Streamed Audio Bug to a mod issue, and also added capabilites to detect if a library is considered compressed

* Added warning to those who try to use the editor with compressed libraries

* ok instead of making it a .cnemod, the zip name will be `cnemod.zip` or what not.

* removing unnessesary traces oops

* clean Library accessor ig then

* fixed small issues and removed an idiot idea

* writing todos and fixing some context that left the room in comments

* Fixed an issue where if you had a file of 0 bytes (nothing) in a zipped library it would FUCKING CRASH the game

* Actually fixed the issue of decompressing 0 byte files

Also stopped saving the data for Folders in Zipped files, as they are 0 bytes anyways.

* Added the features that needed to exist, and removed a stupid line I saw in `ModsFolder` lol

For some reason animation offsets for characters are breaking and I can't tell if its my drive killing itself or cne so uh

* fix an issue that will force the game to crash if first ever mod being loaded is a ZipModLibrary
2026-03-15 14:24:47 +07:00
Ralty 0d9bf82b06 Fix Windows Compiling 2026-03-04 06:11:56 +07:00
Ralty 54eea79dec Disable Caching, several compiler flags 2026-03-04 05:00:38 +07:00
Ralty 4aaa3ba06b Modify openfl Assets in macro instead 2026-03-03 01:15:16 +07:00
Ralty 606e98c192 Merge branch 'main' into internal-merge
# Conflicts:
#	source/funkin/editors/ui/UITextBox.hx
2026-03-03 00:30:50 +07:00
Ralty d8964db5d9 Fix Shader Processing 2026-03-02 23:16:26 +07:00
Ralty 13e6b9a56f Fix UITextBox Text Input 2026-03-02 21:20:52 +07:00
sillyborjaandGitHub a951e38dbb add "onPostEvent" call (#914)
* add preventSustainClip

* add "onPostEvent" call

idk why this wasn't here before but i added it
2026-03-01 21:19:37 +07:00
TheZoroForce240andGitHub 4fe3ba76e3 Charter/Editor additions and fixes (#793)
* camera highlights again

* option to mute all hitsounds

* context menus inside context menus and wip sliders in context menu

* wip volume slider stuff

* strumline preview fix with resizable editors

* more slider stuff

* editor sfx option should now actually work for everything

* fixed strumline vocals volume, fixed note type option keybinds and moved bookmarks and note types into submenus

* fix for saving difficulty specific meta json

* some extra misc changes

fixed camera highlights not updating when zooming in/out, optimized some of the highlight draw code so it doesn't do a full loop, and added the note scale flag into the strumline preview

* fix compiling after merge
2026-03-01 21:13:33 +07:00
Ralty 2e7a8dcd21 can you work now 2026-03-01 20:42:04 +07:00
Ralty df386d7e68 Merge remote-tracking branch 'origin/main' into internal-merge 2026-03-01 20:21:53 +07:00
FrakitsandGitHub f44d0192af my first ever commit in 2026
Removed the noCustomClass metadata from CancellableEvent.
2026-03-01 15:21:32 +02:00
Ralty 5671b87e05 fix compiler flags, shader, music playing, etc 2026-03-01 20:21:21 +07:00
Ralty d922e6112f Compatibility with old glsl version shader issues 2026-03-01 18:23:26 +07:00
HEIHUAaandRalty 6fb716be07 Optimize HXCPP configuration compile options (#883) 2026-03-01 16:47:52 +07:00
Ralty b6d3333dfb Merge remote-tracking branch 'origin/main' into internal-merge 2026-03-01 16:26:44 +07:00
viviandGitHub f8a06bf94c Improved text handling and keyboard input functionality for UITextBox (#900)
* Refactor UITextBox for improved text handling and keyboard input functionality

* use cut paste copy sounds
2026-03-01 16:25:19 +07:00
HEIHUAaandGitHub ec2a39995b optimize __notePerStrum (#901)
* Update StrumLine.hx

* Update StrumLine.hx

* Update StrumLine.hx

* Update StrumLine.hx
2026-03-01 16:25:02 +07:00
Ralty c3b1900154 Remove freeplay preview music for now 2026-03-01 14:15:02 +07:00
Ralty c20c29250d Fix every internal_merge issues 2026-03-01 14:15:02 +07:00
Ralty 143cc447c8 Remove old library modification codes 2026-03-01 14:15:02 +07:00
Ralty 5a176e0ccc Clean libs.xml, project.xml 2026-03-01 14:15:01 +07:00
Ralty 3c15805c80 Switch to old library versions for this branch 2026-03-01 14:14:26 +07:00
Ralty 221d9dba1d Fork Flixel Animate to Fix frameOffsetAngle, layer 2026-03-01 14:06:24 +07:00
Mario HernandoandGitHub d87ac417f7 stress but cool (#911) 2026-02-28 09:44:24 +07:00
BittoandGitHub 3e084397a8 that was supposed to be an flxobject ok (#908)
* mouseOverlaps

* This makes more sense yeah

thinking of not even allowing disjointed overlap checks
keeping it for now

* oops forgot to define that var as flxcamera

* h
2026-02-20 20:15:53 +01:00
BittoandGitHub 370d5ede81 Better mouse overlapping function for CoolUtil (#813)
* mouseOverlaps

* This makes more sense yeah

thinking of not even allowing disjointed overlap checks
keeping it for now

* oops forgot to define that var as flxcamera
2026-02-20 19:10:05 +01:00
drfiffiandGitHub d7dbe5038d flixel-animate fix for cutscenes (#907)
* fixed flixel-animate name changes

* fixed guns

* fixed stress

still needs camera work
2026-02-20 16:19:39 +01:00
axelandGitHub 6c25431c75 Fix NaN check in RadioButton options, again (#899)
Comparing to NaN (even with itself) its always false, use Math.isNaN insted
2026-02-03 21:19:12 +07:00
💜 Rodney, An Imaginative Furball 💙andGitHub 37eb193e53 Fix Character uses one 'script' instead of multiple 'scripts' (#871) 2026-02-03 12:30:08 +07:00
ItsLJcoolandGitHub 0eeef88ac7 Re-implement onDraw functionality for FunkinSprite (#897)
As FlxAnimate didn't have the functionality before, so we have to do the check in FunkinSprite ourselves, as it itself stop's calling the `super.draw();` when it is a `isAnimate`
2026-02-03 12:28:11 +07:00
47a3526178 Allow string values for radio buttons in options menu (#896)
* Allow string values for radio buttons in options menu :D

NOT sure why this wasn't already a thing.... But it's here now

* Fix NaN check

---------

Co-authored-by: Ralty <78720179+Raltyro@users.noreply.github.com>
2026-02-03 12:21:09 +07:00
⍚~NexandGitHub bbb16f4c5c new shitty (thanks yosh :p) 2026-01-30 18:38:16 +01:00
axelandGitHub 5115067b49 Always use lastest FunkinModchart's release version (#895)
To avoid having to do PR every time I update FM, I suggest simply using the latest and most stable version (currently 1.2.5), which fixes many bugs, including a crash that occurred every single time you exited a song.
2026-01-30 17:30:40 +01:00
4d84e65cb5 flixel-animate implementation (#893)
* added flixel-animate to libs

* I BROKE THE OFFSETS FUCK

.

* yes it does blehtty wdym??

* Removed flxanimate entirely + Fixed transition + Fixed offsets

* Deleted caches (relaunching actions)

* frameOffset for atlases (need testing)

* useRenderTexture added to xml

* Fixed atlases for mods

* a simple redirect so old mods wont break that badly (#879)

* Update FunkinSprite.hx

* remove trace

* Fixed ghosts for atlases

* usable character editor (not entirely fixed)

* fixed zoomFactor + temp fix for atlas popping

* early structure for character editor atlas anim display

* zoomFactor for atlases

* Animate Atlas character editor previews

* FlxAnimateSettings specification

* fixed animation swapping on atlas characters

* OH YEA BABY NEW FLXANIMATE UPDATE THAT MADE CODE 50X SIMPLER **AGAIN** 💖 /pos

* Added label checkbox in Character Editor

* Fixed culling issues with FlxAnimate (fr this time)

* fixed some atlases

* HOW THE FUCK

* gf sad fix + AliasMacro (for backwards comp, manual impl for now)

* Fixed pop-ins

* Update Character.hx

* applyStageMatrix

* FlxAnimate pull request merge (empty commit)

* flixel-animate** i'm clumsy asf i meant the lib not the class name fuck

* Update libs.xml

* Merge changes from main (#892)

* repair ScriptableShader.shader = null (#877)

* optimize updateInput (#878)

* optimize updateInput

* resize optimize

* __notePerStrum optimize

* Update StrumLine.hx

* NoteGroup optimize (#881)

* NoteGroup optimize

* CoolUtil.bound faster

* makes commit with github desktop W FRAKITS

* Use fastSinCos for notes (#889)

* Update Strum.hx

* Update Strum.hx

---------

Co-authored-by: HEIHUAa <112499486+HEIHUAa@users.noreply.github.com>
Co-authored-by: Frakits <90983918+Frakits@users.noreply.github.com>

---------

Co-authored-by: Kolze <53307233+KolzeYT@users.noreply.github.com>
Co-authored-by: HEIHUAa <112499486+HEIHUAa@users.noreply.github.com>
Co-authored-by: Frakits <90983918+Frakits@users.noreply.github.com>
2026-01-28 20:29:32 +01:00
HEIHUAaandGitHub f8f9d6eb4a Use fastSinCos for notes (#889)
* Update Strum.hx

* Update Strum.hx
2026-01-25 12:18:18 +01:00
Frakits 6d3243b256 Merge branch 'main' of github.com:CodenameCrew/CodenameEngine 2026-01-22 18:54:33 +02:00
Frakits 0cfb3e52c5 makes commit with github desktop W FRAKITS 2026-01-22 18:54:14 +02:00
176 changed files with 28225 additions and 242650 deletions
+81 -81
View File
@@ -11,20 +11,21 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Pulling the new commit
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setting up Haxe
uses: krdlab/setup-haxe@v2
with:
haxe-version: 4.3.7
- name: Restore existing build cache for faster compilation
uses: actions/cache@v4.2.3
with:
# not caching the bin folder to prevent asset duplication and stuff like that
key: cache-build-linux
path: |
.haxelib/
export/release/linux/haxe/
export/release/linux/obj/
# - name: Restore existing build cache for faster compilation
# uses: actions/cache@v4.2.3
# with:
# # not caching the bin folder to prevent asset duplication and stuff like that
# key: cache-build-linux
# path: |
# .haxelib/
# export/release/linux/obj/
- run: |
echo "HXCPP_COMPILE_CACHE=~/.hxcpp" >> $GITHUB_ENV
- name: Installing LibVLC
@@ -35,47 +36,47 @@ jobs:
haxe -cp commandline -D analyzer-optimize --run Main setup -s
- name: Building the game
run: |
haxelib run lime build linux
haxelib run lime rebuild linux -nocolor -nocffi -release
haxelib run lime build linux -DCOMPILE_EXPERIMENTAL
# - name: Tar files
# run: tar -zcvf CodenameEngine.tar.gz -C export/release/linux/bin .
- name: Uploading artifact (executable)
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: Codename Engine (Executable Only)
path: export/release/linux/bin/CodenameEngine
- name: Uploading artifact (entire build)
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: Codename Engine
path: export/release/linux/bin/
- name: Clearing already existing cache
uses: actions/github-script@v6
with:
script: |
const caches = await github.rest.actions.getActionsCacheList({
owner: context.repo.owner,
repo: context.repo.repo,
})
for (const cache of caches.data.actions_caches) {
if (cache.key == "cache-build-linux") {
console.log('Clearing ' + cache.key + '...')
await github.rest.actions.deleteActionsCacheById({
owner: context.repo.owner,
repo: context.repo.repo,
cache_id: cache.id,
})
console.log("Cache cleared.")
}
}
- name: Uploading new cache
uses: actions/cache@v4.2.3
with:
# caching again since for some reason it doesnt work with the first post cache shit
key: cache-build-linux
path: |
.haxelib/
export/release/linux/haxe/
export/release/linux/obj/
# - name: Clearing already existing cache
# uses: actions/github-script@v6
# with:
# script: |
# const caches = await github.rest.actions.getActionsCacheList({
# owner: context.repo.owner,
# repo: context.repo.repo,
# })
# for (const cache of caches.data.actions_caches) {
# if (cache.key == "cache-build-linux") {
# console.log('Clearing ' + cache.key + '...')
# await github.rest.actions.deleteActionsCacheById({
# owner: context.repo.owner,
# repo: context.repo.repo,
# cache_id: cache.id,
# })
# console.log("Cache cleared.")
# }
# }
# - name: Uploading new cache
# uses: actions/cache@v4.2.3
# with:
# # caching again since for some reason it doesnt work with the first post cache shit
# key: cache-build-linux
# path: |
# .haxelib/
# export/release/linux/obj/
# didnt compile debug in the same job or github would have said that job wasn't completed until debug was done too (debug uploads are not essential)
debug_build:
@@ -85,20 +86,19 @@ jobs:
needs: build # since its low priority, it'll run after, so actions will concentrate first on normal builds
steps:
- name: Pulling the new commit
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Setting up Haxe
uses: krdlab/setup-haxe@v2
with:
haxe-version: 4.3.7
- name: Restore existing build cache for faster compilation
uses: actions/cache@v4.2.3
with:
# not caching the bin folder to prevent asset duplication and stuff like that
key: cache-build-linux-debug
path: |
.haxelib/
export/debug/linux/haxe/
export/debug/linux/obj/
# - name: Restore existing build cache for faster compilation
# uses: actions/cache@v4.2.3
# with:
# # not caching the bin folder to prevent asset duplication and stuff like that
# key: cache-build-linux-debug
# path: |
# .haxelib/
# export/debug/linux/obj/
- run: |
echo "HXCPP_COMPILE_CACHE=~/.hxcpp" >> $GITHUB_ENV
- name: Installing LibVLC
@@ -109,39 +109,39 @@ jobs:
haxe -cp commandline -D analyzer-optimize --run Main setup -s
- name: Building the game
run: |
haxelib run lime build linux -debug
haxelib run lime rebuild linux -nocolor -nocffi -debug
haxelib run lime build linux -debug -DCOMPILE_EXPERIMENTAL
# - name: Tar files
# run: tar -zcvf CodenameEngine.tar.gz -C export/debug/linux/bin .
- name: Uploading artifact (entire build)
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: Codename Engine Debug
path: export/debug/linux/bin/
- name: Clearing already existing cache
uses: actions/github-script@v6
with:
script: |
const caches = await github.rest.actions.getActionsCacheList({
owner: context.repo.owner,
repo: context.repo.repo,
})
for (const cache of caches.data.actions_caches) {
if (cache.key == "cache-build-linux-debug") {
console.log('Clearing ' + cache.key + '...')
await github.rest.actions.deleteActionsCacheById({
owner: context.repo.owner,
repo: context.repo.repo,
cache_id: cache.id,
})
console.log("Cache cleared.")
}
}
- name: Uploading new cache
uses: actions/cache@v4.2.3
with:
# caching again since for some reason it doesnt work with the first post cache shit
key: cache-build-linux-debug
path: |
.haxelib/
export/debug/linux/haxe/
export/debug/linux/obj/
# - name: Clearing already existing cache
# uses: actions/github-script@v6
# with:
# script: |
# const caches = await github.rest.actions.getActionsCacheList({
# owner: context.repo.owner,
# repo: context.repo.repo,
# })
# for (const cache of caches.data.actions_caches) {
# if (cache.key == "cache-build-linux-debug") {
# console.log('Clearing ' + cache.key + '...')
# await github.rest.actions.deleteActionsCacheById({
# owner: context.repo.owner,
# repo: context.repo.repo,
# cache_id: cache.id,
# })
# console.log("Cache cleared.")
# }
# }
# - name: Uploading new cache
# uses: actions/cache@v4.2.3
# with:
# # caching again since for some reason it doesnt work with the first post cache shit
# key: cache-build-linux-debug
# path: |
# .haxelib/
# export/debug/linux/obj/
+83 -83
View File
@@ -8,23 +8,24 @@ jobs:
build:
name: Mac OS Build
permissions: write-all
runs-on: macos-14
runs-on: macos-26
steps:
- name: Pulling the new commit
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setting up Haxe
uses: krdlab/setup-haxe@v2
with:
haxe-version: 4.3.7
- name: Restore existing build cache for faster compilation
uses: actions/cache@v4.2.3
with:
# not caching the bin folder to prevent asset duplication and stuff like that
key: cache-build-mac
path: |
.haxelib/
export/release/macos/haxe/
export/release/macos/obj/
# - name: Restore existing build cache for faster compilation
# uses: actions/cache@v4.2.3
# with:
# # not caching the bin folder to prevent asset duplication and stuff like that
# key: cache-build-mac
# path: |
# .haxelib/
# export/release/macos/obj/
- run: |
echo "HXCPP_COMPILE_CACHE=~/.hxcpp" >> $GITHUB_ENV
- name: Installing/Updating libraries
@@ -32,70 +33,69 @@ jobs:
haxe -cp commandline -D analyzer-optimize --run Main setup -s
- name: Building the game
run: |
arch -x86_64 haxelib run lime build mac
haxelib run lime rebuild mac -nocolor -nocffi -release
haxelib run lime build mac -DCOMPILE_EXPERIMENTAL
- name: Tar files
run: tar -zcvf CodenameEngine.tar.gz -C export/release/macos/bin .
- name: Uploading artifact (executable)
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: Codename Engine (Executable Only)
path: export/release/macos/bin/CodenameEngine.app/Contents/MacOS/CodenameEngine
- name: Uploading artifact (entire build)
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: Codename Engine
path: CodenameEngine.tar.gz
- name: Clearing already existing cache
uses: actions/github-script@v6
with:
script: |
const caches = await github.rest.actions.getActionsCacheList({
owner: context.repo.owner,
repo: context.repo.repo,
})
for (const cache of caches.data.actions_caches) {
if (cache.key == "cache-build-mac") {
console.log('Clearing ' + cache.key + '...')
await github.rest.actions.deleteActionsCacheById({
owner: context.repo.owner,
repo: context.repo.repo,
cache_id: cache.id,
})
console.log("Cache cleared.")
}
}
- name: Uploading new cache
uses: actions/cache@v4.2.3
with:
# caching again since for some reason it doesnt work with the first post cache shit
key: cache-build-mac
path: |
.haxelib/
export/release/macos/haxe/
export/release/macos/obj/
# - name: Clearing already existing cache
# uses: actions/github-script@v6
# with:
# script: |
# const caches = await github.rest.actions.getActionsCacheList({
# owner: context.repo.owner,
# repo: context.repo.repo,
# })
# for (const cache of caches.data.actions_caches) {
# if (cache.key == "cache-build-mac") {
# console.log('Clearing ' + cache.key + '...')
# await github.rest.actions.deleteActionsCacheById({
# owner: context.repo.owner,
# repo: context.repo.repo,
# cache_id: cache.id,
# })
# console.log("Cache cleared.")
# }
# }
# - name: Uploading new cache
# uses: actions/cache@v4.2.3
# with:
# # caching again since for some reason it doesnt work with the first post cache shit
# key: cache-build-mac
# path: |
# .haxelib/
# export/release/macos/obj/
# didnt compile debug in the same job or github would have said that job wasn't completed until debug was done too (debug uploads are not essential)
debug_build:
name: Mac OS Debug Build
permissions: write-all
runs-on: macos-14
runs-on: macos-26
needs: build # since its low priority, it'll run after, so actions will concentrate first on normal builds
steps:
- name: Pulling the new commit
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Setting up Haxe
uses: krdlab/setup-haxe@v2
with:
haxe-version: 4.3.7
- name: Restore existing build cache for faster compilation
uses: actions/cache@v4.2.3
with:
# not caching the bin folder to prevent asset duplication and stuff like that
key: cache-build-mac-debug
path: |
.haxelib/
export/debug/macos/haxe/
export/debug/macos/obj/
# - name: Restore existing build cache for faster compilation
# uses: actions/cache@v4.2.3
# with:
# # not caching the bin folder to prevent asset duplication and stuff like that
# key: cache-build-mac-debug
# path: |
# .haxelib/
# export/debug/macos/obj/
- run: |
echo "HXCPP_COMPILE_CACHE=~/.hxcpp" >> $GITHUB_ENV
- name: Installing/Updating libraries
@@ -103,39 +103,39 @@ jobs:
haxe -cp commandline -D analyzer-optimize --run Main setup -s
- name: Building the game
run: |
arch -x86_64 haxelib run lime build mac -debug
haxelib run lime rebuild mac -nocolor -nocffi -debug
haxelib run lime build mac -debug -DCOMPILE_EXPERIMENTAL
- name: Tar files
run: tar -zcvf CodenameEngine.tar.gz -C export/debug/macos/bin .
- name: Uploading artifact (entire build)
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: Codename Engine Debug
path: CodenameEngine.tar.gz
- name: Clearing already existing cache
uses: actions/github-script@v6
with:
script: |
const caches = await github.rest.actions.getActionsCacheList({
owner: context.repo.owner,
repo: context.repo.repo,
})
for (const cache of caches.data.actions_caches) {
if (cache.key == "cache-build-mac-debug") {
console.log('Clearing ' + cache.key + '...')
await github.rest.actions.deleteActionsCacheById({
owner: context.repo.owner,
repo: context.repo.repo,
cache_id: cache.id,
})
console.log("Cache cleared.")
}
}
- name: Uploading new cache
uses: actions/cache@v4.2.3
with:
# caching again since for some reason it doesnt work with the first post cache shit
key: cache-build-mac-debug
path: |
.haxelib/
export/debug/macos/haxe/
export/debug/macos/obj/
# - name: Clearing already existing cache
# uses: actions/github-script@v6
# with:
# script: |
# const caches = await github.rest.actions.getActionsCacheList({
# owner: context.repo.owner,
# repo: context.repo.repo,
# })
# for (const cache of caches.data.actions_caches) {
# if (cache.key == "cache-build-mac-debug") {
# console.log('Clearing ' + cache.key + '...')
# await github.rest.actions.deleteActionsCacheById({
# owner: context.repo.owner,
# repo: context.repo.repo,
# cache_id: cache.id,
# })
# console.log("Cache cleared.")
# }
# }
# - name: Uploading new cache
# uses: actions/cache@v4.2.3
# with:
# # caching again since for some reason it doesnt work with the first post cache shit
# key: cache-build-mac-debug
# path: |
# .haxelib/
# export/debug/macos/obj/
+9 -7
View File
@@ -21,10 +21,12 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Download Windows Full Build
uses: dawidd6/action-download-artifact@v6
uses: dawidd6/action-download-artifact@v8
with:
workflow: windows.yml
name: Codename Engine
@@ -32,7 +34,7 @@ jobs:
allow_forks: false
- name: Download Windows Executable
uses: dawidd6/action-download-artifact@v6
uses: dawidd6/action-download-artifact@v8
with:
workflow: windows.yml
name: Codename Engine (Executable Only)
@@ -40,7 +42,7 @@ jobs:
allow_forks: false
- name: Download Mac OS Full Build
uses: dawidd6/action-download-artifact@v6
uses: dawidd6/action-download-artifact@v8
with:
workflow: macos.yml
name: Codename Engine
@@ -48,7 +50,7 @@ jobs:
allow_forks: false
- name: Download Mac OS Executable
uses: dawidd6/action-download-artifact@v6
uses: dawidd6/action-download-artifact@v8
with:
workflow: macos.yml
name: Codename Engine (Executable Only)
@@ -56,7 +58,7 @@ jobs:
allow_forks: false
- name: Download Linux Full Build
uses: dawidd6/action-download-artifact@v6
uses: dawidd6/action-download-artifact@v8
with:
workflow: linux.yml
name: Codename Engine
@@ -64,7 +66,7 @@ jobs:
allow_forks: false
- name: Download Linux Executable
uses: dawidd6/action-download-artifact@v6
uses: dawidd6/action-download-artifact@v8
with:
workflow: linux.yml
name: Codename Engine (Executable Only)
+84 -81
View File
@@ -11,20 +11,21 @@ jobs:
runs-on: windows-latest
steps:
- name: Pulling the new commit
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setting up Haxe
uses: krdlab/setup-haxe@v2
with:
haxe-version: 4.3.7
- name: Restore existing build cache for faster compilation
uses: actions/cache@v4.2.3
with:
# not caching the bin folder to prevent asset duplication and stuff like that
key: cache-build-windows
path: |
.haxelib/
export/release/windows/haxe/
export/release/windows/obj/
# - name: Restore existing build cache for faster compilation
# uses: actions/cache@v4.2.3
# with:
# # not caching the bin folder to prevent asset duplication and stuff like that
# key: cache-build-windows
# path: |
# .haxelib/
# export/release/windows/obj/
- run: |
echo "HXCPP_COMPILE_CACHE=~/.hxcpp" >> $GITHUB_ENV
- name: Installing/Updating libraries
@@ -32,45 +33,47 @@ jobs:
haxe -cp commandline -D analyzer-optimize --run Main setup -s --no-vscheck
- name: Building the game
run: |
haxelib run lime build windows
haxelib run lime rebuild windows -nocolor -nocffi -release
haxelib run lime build windows -DCOMPILE_EXPERIMENTAL
- name: Uploading artifact (executable)
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: Codename Engine (Executable Only)
path: export/release/windows/bin/CodenameEngine.exe
path: |
export/release/windows/bin/CodenameEngine.exe
export/release/windows/bin/lime.ndll
- name: Uploading artifact (entire build)
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: Codename Engine
path: export/release/windows/bin
- name: Clearing already existing cache
uses: actions/github-script@v6
with:
script: |
const caches = await github.rest.actions.getActionsCacheList({
owner: context.repo.owner,
repo: context.repo.repo,
})
for (const cache of caches.data.actions_caches) {
if (cache.key == "cache-build-windows") {
console.log('Clearing ' + cache.key + '...')
await github.rest.actions.deleteActionsCacheById({
owner: context.repo.owner,
repo: context.repo.repo,
cache_id: cache.id,
})
console.log("Cache cleared.")
}
}
- name: Uploading new cache
uses: actions/cache@v4.2.3
with:
# caching again since for some reason it doesnt work with the first post cache shit
key: cache-build-windows
path: |
.haxelib/
export/release/windows/haxe/
export/release/windows/obj/
# - name: Clearing already existing cache
# uses: actions/github-script@v6
# with:
# script: |
# const caches = await github.rest.actions.getActionsCacheList({
# owner: context.repo.owner,
# repo: context.repo.repo,
# })
# for (const cache of caches.data.actions_caches) {
# if (cache.key == "cache-build-windows") {
# console.log('Clearing ' + cache.key + '...')
# await github.rest.actions.deleteActionsCacheById({
# owner: context.repo.owner,
# repo: context.repo.repo,
# cache_id: cache.id,
# })
# console.log("Cache cleared.")
# }
# }
# - name: Uploading new cache
# uses: actions/cache@v4.2.3
# with:
# # caching again since for some reason it doesnt work with the first post cache shit
# key: cache-build-windows
# path: |
# .haxelib/
# export/release/windows/obj/
# didnt compile debug in the same job or github would have said that job wasn't completed until debug was done too (debug uploads are not essential)
debug_build:
@@ -80,20 +83,20 @@ jobs:
needs: build # since its low priority, it'll run after, so actions will concentrate first on normal builds
steps:
- name: Pulling the new commit
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Setting up Haxe
uses: krdlab/setup-haxe@v2
with:
haxe-version: 4.3.7
- name: Restore existing build cache for faster compilation
uses: actions/cache@v4.2.3
with:
# not caching the bin folder to prevent asset duplication and stuff like that
key: cache-build-windows-debug
path: |
.haxelib/
export/debug/windows/haxe/
export/debug/windows/obj/
# - name: Restore existing build cache for faster compilation
# uses: actions/cache@v4.2.3
# with:
# # not caching the bin folder to prevent asset duplication and stuff like that
# key: cache-build-windows-debug
# path: |
# .haxelib/
# export/debug/windows/haxe/
# export/debug/windows/obj/
- run: |
echo "HXCPP_COMPILE_CACHE=~/.hxcpp" >> $GITHUB_ENV
- name: Installing/Updating libraries
@@ -101,37 +104,37 @@ jobs:
haxe -cp commandline -D analyzer-optimize --run Main setup -s --no-vscheck
- name: Building the game
run: |
haxelib run lime rebuild windows -nocolor -nocffi -debug
haxelib run lime build windows -debug
- name: Uploading artifact (entire build)
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: Codename Engine Debug
path: export/debug/windows/bin
- name: Clearing already existing cache
uses: actions/github-script@v6
with:
script: |
const caches = await github.rest.actions.getActionsCacheList({
owner: context.repo.owner,
repo: context.repo.repo,
})
for (const cache of caches.data.actions_caches) {
if (cache.key == "cache-build-windows-debug") {
console.log('Clearing ' + cache.key + '...')
await github.rest.actions.deleteActionsCacheById({
owner: context.repo.owner,
repo: context.repo.repo,
cache_id: cache.id,
})
console.log("Cache cleared.")
}
}
- name: Uploading new cache
uses: actions/cache@v4.2.3
with:
# caching again since for some reason it doesnt work with the first post cache shit
key: cache-build-windows-debug
path: |
.haxelib/
export/debug/windows/haxe/
export/debug/windows/obj/
# - name: Clearing already existing cache
# uses: actions/github-script@v6
# with:
# script: |
# const caches = await github.rest.actions.getActionsCacheList({
# owner: context.repo.owner,
# repo: context.repo.repo,
# })
# for (const cache of caches.data.actions_caches) {
# if (cache.key == "cache-build-windows-debug") {
# console.log('Clearing ' + cache.key + '...')
# await github.rest.actions.deleteActionsCacheById({
# owner: context.repo.owner,
# repo: context.repo.repo,
# cache_id: cache.id,
# })
# console.log("Cache cleared.")
# }
# }
# - name: Uploading new cache
# uses: actions/cache@v4.2.3
# with:
# # caching again since for some reason it doesnt work with the first post cache shit
# key: cache-build-windows-debug
# path: |
# .haxelib/
# export/debug/windows/obj/
+3 -3
View File
@@ -71,11 +71,11 @@ _**QOL = Quality of Life**_
- Characters are located in `data/weeks/characters`.
- 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
- Editors for Charts and Characters (Stage coming soon)
- Undos/Redos supported
- Warning on closing unsaved work
- Warning on closing unsaved work.
- Clean UI (for ocd freaks)
- Mature Chart editor
- Mature Chart editor (Character editor rework soon)
- Features not found in other editors!
- Every single state & substate can be modified via HScript (`data/states/StateName.hx`)
- **Instances launched via `lime test windows` will automatically use assets from source.**
+1 -1
View File
@@ -47,7 +47,7 @@ The engine uses [HaxeFlixel](https://haxeflixel.com/) and it mainly features:
---
> [!NOTE]
> Codename Engine as for now supports **Windows x64**, **Mac OS x64** and **Linux x64**.<br>
> Codename Engine as for now supports **Windows x64**, **Mac OS Universal** and **Linux x64**.<br>
> More platforms will soon come, stay tuned!<br>
> - [ ] **Web (HTML5) Support**
> - [ ] **Mobile Support**
-7
View File
@@ -2,13 +2,6 @@
<character x="115" y="325" sprite="gf-christmas" icon="gf" color="#A5004D">
<anim name="danceLeft" anim="GF Dancing Beat" x="0" y="-9" fps="24" loop="false" indices="0..14"/>
<anim name="danceRight" anim="GF Dancing Beat" x="0" y="-9" fps="24" loop="false" indices="15..30"/>
<anim name="singUP" anim="GF Up Note" x="0" y="-9" fps="24" loop="false"/>
<anim name="singDOWN" anim="GF Down Note" x="0" y="-9" fps="24" loop="false"/>
<anim name="singLEFT" anim="GF left note" x="0" y="-9" fps="24" loop="false"/>
<anim name="singRIGHT" anim="GF Right Note" x="0" y="-9" fps="24" loop="false"/>
<anim name="scared" anim="GF FEAR" x="0" y="-9" fps="24" loop="true"/>
<anim name="hairBlow" anim="GF Dancing Beat Hair blowing" x="0" y="-9" fps="24" loop="false" indices="0..3"/>
<anim name="hairFall" anim="GF Dancing Beat Hair Landing" x="0" y="-9" fps="24" loop="false" indices="0..11"/>
<anim name="cheer" anim="GF Cheer" x="0" y="-9" fps="24" loop="false"/>
<anim name="sad" anim="gf sad" x="-51" y="306" fps="24" loop="true" indices="0..12"/>
</character>
+12 -12
View File
@@ -1,14 +1,14 @@
<!DOCTYPE codename-engine-character>
<character x="100" y="275" sprite="gf" icon="gf" color="#A5004D">
<anim name="cheer" anim="GF Cheer" x="0" y="0" fps="24" loop="false"/>
<anim name="singUP" anim="GF Up Note" x="0" y="0" fps="24" loop="false"/>
<anim name="singLEFT" anim="GF left note" x="0" y="0" fps="24" loop="false"/>
<anim name="singRIGHT" anim="GF Right Note" x="0" y="0" fps="24" loop="false"/>
<anim name="singDOWN" anim="GF Down Note" x="0" y="0" fps="24" loop="false"/>
<anim name="danceLeft" anim="GF Dancing Beat" x="0" y="0" fps="24" loop="false" indices="0..14"/>
<anim name="danceRight" anim="GF Dancing Beat" x="0" y="0" fps="24" loop="false" indices="15..30"/>
<anim name="hairBlow" anim="GF Dancing Beat Hair blowing" x="0" y="0" fps="24" loop="true" indices="0,1,2,3"/>
<anim name="hairFall" anim="GF Dancing Beat Hair Landing" x="0" y="0" fps="24" loop="false" indices="0..11"/>
<anim name="scared" anim="GF FEAR" x="0" y="0" fps="24" loop="true"/>
<anim name="sad" anim="gf sad" x="0" y="0" fps="24" loop="true" indices="0..12"/>
<character x="100" y="275" color="#A5004D">
<anim name="cheer" anim="GF Cheer"/>
<anim name="singUP" anim="GF Up Note"/>
<anim name="singLEFT" anim="GF left note"/>
<anim name="singRIGHT" anim="GF Right Note"/>
<anim name="singDOWN" anim="GF Down Note"/>
<anim name="danceLeft" anim="GF Dancing Beat" indices="0..14"/>
<anim name="danceRight" anim="GF Dancing Beat" indices="15..30"/>
<anim name="hairBlow" anim="GF Dancing Beat Hair blowing" loop="true" indices="0..3"/>
<anim name="hairFall" anim="GF Dancing Beat Hair Landing" indices="0..11"/>
<anim name="scared" anim="GF FEAR " loop="true"/>
<anim name="sad" anim="gf sad" x="-51" y="315" loop="true" indices="0..12"/>
</character>
-3
View File
@@ -1,6 +1,3 @@
# THIS FILE ISN'T NECESSARY,
# BUT YOU CAN USE IT TO SORT AND WHITELIST FREEPLAY SONGS
test
tutorial
-8
View File
@@ -1,8 +0,0 @@
# THIS FILE ISN'T NECESSARY,
# BUT YOU CAN USE IT TO SORT AND WHITELIST GAME MODES
solo
opponent
coop
coop-switched
botplay
-4
View File
@@ -1,4 +0,0 @@
{
"displayName": "Botplay Mode",
"modeID": "codename.botplay"
}
-2
View File
@@ -1,2 +0,0 @@
<!DOCTYPE codename-engine-game-mode>
<mode name="Botplay Mode" id="codename.botplay"/>
-5
View File
@@ -1,5 +0,0 @@
{
"displayName": "Co-Op Mode (Switched)",
"modeID": "codename.coop-opponent",
"scripts": ["opponent", "coop"]
}
-11
View File
@@ -1,11 +0,0 @@
<!DOCTYPE codename-engine-game-mode>
<mode name="Co-Op Mode (Switched)" id="codename.coop-opponent">
<script>coop</script>
<script>opponent</script>
<!--
just a small example of what you could do with fields!!
<field name="switchStrums" type="bool" val="true"/>
<field name="strumSize" type="float" val="0.6"/>
-->
</mode>
-4
View File
@@ -1,4 +0,0 @@
{
"displayName": "Co-Op Mode",
"modeID": "codename.coop"
}
-2
View File
@@ -1,2 +0,0 @@
<!DOCTYPE codename-engine-game-mode>
<mode name="Co-Op Mode" id="codename.coop"/>
-5
View File
@@ -1,5 +0,0 @@
solo
opponent
coop
coop-switched
botplay
-4
View File
@@ -1,4 +0,0 @@
{
"displayName": "Opponent Mode",
"modeID": "codename.opponent"
}
-2
View File
@@ -1,2 +0,0 @@
<!DOCTYPE codename-engine-game-mode>
<mode name="Opponent Mode" id="codename.opponent"/>
-4
View File
@@ -1,4 +0,0 @@
{
"displayName": "Solo Mode",
"modeID": "codename.solo"
}
-2
View File
@@ -1,2 +0,0 @@
<!DOCTYPE codename-engine-game-mode>
<mode name="Solo Mode" id="codename.solo"/>
+1 -1
View File
@@ -75,7 +75,7 @@ function onCountdown(event) {
};
}
function onPlayerHit(event:NoteHitEvent) {
function onRatingsShown(event:RatingsShowEvent) {
if (!enablePixelUI) return;
event.ratingPrefix = "stages/school/ui/";
event.ratingScale = daPixelZoom * 0.7;
+1 -1
View File
@@ -11,7 +11,7 @@
<sprite name="fgSnow" x="-600" y="680" sprite="fgSnow"/>
<girlfriend x="540" y="110"/>
<girlfriend x="440" y="110"/>
<dad/>
<boyfriend x="1030" camyoffset="-150" camxoffset="-150"/>
@@ -1,5 +1,5 @@
# THIS FILE ISN'T NECESSARY,
# BUT YOU CAN USE IT TO SORT AND WHITELIST WEEKS
# BUT YOU CAN USE IT TO SORT WEEKS
tutorial
week1
File diff suppressed because it is too large Load Diff
+27 -27
View File
@@ -1,28 +1,28 @@
{"ATLAS": {"SPRITES":[
{"SPRITE" : {"name": "0000","x":1636,"y":275,"w":183,"h":115,"rotated": false}},
{"SPRITE" : {"name": "0001","x":215,"y":360,"w":84,"h":140,"rotated": false}},
{"SPRITE" : {"name": "0002","x":419,"y":358,"w":251,"h":121,"rotated": false}},
{"SPRITE" : {"name": "0003","x":1636,"y":394,"w":120,"h":65,"rotated": false}},
{"SPRITE" : {"name": "0004","x":4,"y":360,"w":108,"h":126,"rotated": false}},
{"SPRITE" : {"name": "0005","x":674,"y":358,"w":102,"h":147,"rotated": false}},
{"SPRITE" : {"name": "0006","x":116,"y":360,"w":95,"h":130,"rotated": false}},
{"SPRITE" : {"name": "0007","x":2038,"y":4,"w":1,"h":4,"rotated": false}},
{"SPRITE" : {"name": "0008","x":4,"y":4,"w":411,"h":352,"rotated": false}},
{"SPRITE" : {"name": "0009","x":419,"y":4,"w":398,"h":350,"rotated": false}},
{"SPRITE" : {"name": "0010","x":1303,"y":275,"w":329,"h":162,"rotated": false}},
{"SPRITE" : {"name": "0011","x":303,"y":360,"w":90,"h":103,"rotated": false}},
{"SPRITE" : {"name": "0012","x":1823,"y":4,"w":211,"h":236,"rotated": false}},
{"SPRITE" : {"name": "0013","x":1823,"y":244,"w":208,"h":235,"rotated": false}},
{"SPRITE" : {"name": "0014","x":821,"y":258,"w":478,"h":262,"rotated": false}},
{"SPRITE" : {"name": "0015","x":821,"y":4,"w":521,"h":250,"rotated": false}},
{"SPRITE" : {"name": "0016","x":1346,"y":4,"w":473,"h":267,"rotated": false}}
]},
"meta": {
"app": "Adobe Animate",
"version": "22.0.5.191",
"image": "spritemap1.png",
"format": "RGBA8888",
"size": {"w":2043,"h":524},
"resolution": "1"
}
{"ATLAS":{"SPRITES":[
{"SPRITE":{"name":"0","x":1662,"y":282,"w":194,"h":117,"rotated":false}},
{"SPRITE":{"name":"1","x":1790,"y":417,"w":92,"h":136,"rotated":false}},
{"SPRITE":{"name":"2","x":1193,"y":539,"w":259,"h":123,"rotated":false}},
{"SPRITE":{"name":"3","x":483,"y":553,"w":125,"h":68,"rotated":false}},
{"SPRITE":{"name":"4","x":1662,"y":417,"w":110,"h":127,"rotated":false}},
{"SPRITE":{"name":"5","x":1886,"y":0,"w":105,"h":149,"rotated":false}},
{"SPRITE":{"name":"6","x":1886,"y":167,"w":97,"h":130,"rotated":false}},
{"SPRITE":{"name":"7","x":1398,"y":0,"w":470,"h":264,"rotated":false}},
{"SPRITE":{"name":"8","x":867,"y":0,"w":513,"h":254,"rotated":false}},
{"SPRITE":{"name":"9","x":0,"y":372,"w":465,"h":270,"rotated":false}},
{"SPRITE":{"name":"10","x":1900,"y":315,"w":101,"h":118,"rotated":false}},
{"SPRITE":{"name":"11","x":867,"y":272,"w":308,"h":367,"rotated":false}},
{"SPRITE":{"name":"12","x":483,"y":371,"w":338,"h":164,"rotated":false}},
{"SPRITE":{"name":"13","x":0,"y":0,"w":422,"h":354,"rotated":false}},
{"SPRITE":{"name":"14","x":440,"y":0,"w":409,"h":353,"rotated":false}},
{"SPRITE":{"name":"15","x":1900,"y":451,"w":92,"h":103,"rotated":false}},
{"SPRITE":{"name":"16","x":1193,"y":282,"w":218,"h":239,"rotated":false}},
{"SPRITE":{"name":"17","x":1429,"y":282,"w":215,"h":237,"rotated":false}}]},
"meta":{
"app":"Adobe Animate (Better TA Extension)",
"version":"24.0.2.12",
"image":"spritemap1.png",
"format":"RGBA8888",
"size":{"w":2031,"h":662},
"resolution":"1"
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 134 KiB

File diff suppressed because it is too large Load Diff
@@ -1,58 +1,40 @@
{"ATLAS": {"SPRITES":[
{"SPRITE" : {"name": "0000","x":994,"y":1029,"w":187,"h":118,"rotated": false}},
{"SPRITE" : {"name": "0001","x":1953,"y":524,"w":84,"h":140,"rotated": false}},
{"SPRITE" : {"name": "0002","x":471,"y":430,"w":258,"h":137,"rotated": false}},
{"SPRITE" : {"name": "0003","x":1300,"y":641,"w":122,"h":66,"rotated": false}},
{"SPRITE" : {"name": "0004","x":1825,"y":1078,"w":108,"h":126,"rotated": false}},
{"SPRITE" : {"name": "0005","x":360,"y":695,"w":103,"h":149,"rotated": false}},
{"SPRITE" : {"name": "0006","x":1945,"y":867,"w":95,"h":130,"rotated": false}},
{"SPRITE" : {"name": "0007","x":2034,"y":4,"w":1,"h":4,"rotated": false}},
{"SPRITE" : {"name": "0008","x":943,"y":650,"w":309,"h":375,"rotated": false}},
{"SPRITE" : {"name": "0009","x":4,"y":4,"w":778,"h":422,"rotated": false}},
{"SPRITE" : {"name": "0010","x":786,"y":4,"w":761,"h":393,"rotated": false}},
{"SPRITE" : {"name": "0011","x":1551,"y":4,"w":411,"h":352,"rotated": false}},
{"SPRITE" : {"name": "0012","x":1551,"y":360,"w":398,"h":350,"rotated": false}},
{"SPRITE" : {"name": "0013","x":4,"y":1028,"w":329,"h":162,"rotated": false}},
{"SPRITE" : {"name": "0014","x":1945,"y":1001,"w":90,"h":103,"rotated": false}},
{"SPRITE" : {"name": "0015","x":1300,"y":401,"w":211,"h":236,"rotated": false}},
{"SPRITE" : {"name": "0016","x":782,"y":1029,"w":208,"h":235,"rotated": false}},
{"SPRITE" : {"name": "0017","x":782,"y":910,"w":117,"h":83,"rotated": false}},
{"SPRITE" : {"name": "0018","x":994,"y":1151,"w":117,"h":83,"rotated": false}},
{"SPRITE" : {"name": "0019","x":1937,"y":1108,"w":103,"h":83,"rotated": false}},
{"SPRITE" : {"name": "0020","x":1115,"y":1151,"w":117,"h":83,"rotated": false}},
{"SPRITE" : {"name": "0021","x":1654,"y":714,"w":287,"h":360,"rotated": false}},
{"SPRITE" : {"name": "0022","x":471,"y":571,"w":179,"h":67,"rotated": false}},
{"SPRITE" : {"name": "0023","x":654,"y":571,"w":118,"h":75,"rotated": false}},
{"SPRITE" : {"name": "0024","x":1966,"y":223,"w":55,"h":112,"rotated": false}},
{"SPRITE" : {"name": "0025","x":1966,"y":4,"w":64,"h":106,"rotated": false}},
{"SPRITE" : {"name": "0026","x":1185,"y":1029,"w":67,"h":70,"rotated": false}},
{"SPRITE" : {"name": "0027","x":337,"y":1182,"w":122,"h":62,"rotated": false}},
{"SPRITE" : {"name": "0028","x":1647,"y":1078,"w":174,"h":97,"rotated": false}},
{"SPRITE" : {"name": "0029","x":360,"y":870,"w":82,"h":14,"rotated": false}},
{"SPRITE" : {"name": "0030","x":1647,"y":1179,"w":128,"h":61,"rotated": false}},
{"SPRITE" : {"name": "0031","x":463,"y":1182,"w":124,"h":58,"rotated": false}},
{"SPRITE" : {"name": "0032","x":1966,"y":114,"w":59,"h":105,"rotated": false}},
{"SPRITE" : {"name": "0033","x":1953,"y":360,"w":87,"h":160,"rotated": false}},
{"SPRITE" : {"name": "0034","x":1945,"y":714,"w":92,"h":149,"rotated": false}},
{"SPRITE" : {"name": "0035","x":1426,"y":641,"w":104,"h":42,"rotated": false}},
{"SPRITE" : {"name": "0036","x":1953,"y":692,"w":73,"h":18,"rotated": false}},
{"SPRITE" : {"name": "0037","x":1426,"y":687,"w":72,"h":19,"rotated": false}},
{"SPRITE" : {"name": "0038","x":360,"y":848,"w":72,"h":18,"rotated": false}},
{"SPRITE" : {"name": "0039","x":1953,"y":668,"w":73,"h":20,"rotated": false}},
{"SPRITE" : {"name": "0040","x":471,"y":650,"w":468,"h":256,"rotated": false}},
{"SPRITE" : {"name": "0041","x":786,"y":401,"w":510,"h":245,"rotated": false}},
{"SPRITE" : {"name": "0042","x":4,"y":430,"w":463,"h":261,"rotated": false}},
{"SPRITE" : {"name": "0043","x":360,"y":910,"w":418,"h":268,"rotated": false}},
{"SPRITE" : {"name": "0044","x":1256,"y":1008,"w":387,"h":271,"rotated": false}},
{"SPRITE" : {"name": "0045","x":1256,"y":714,"w":394,"h":290,"rotated": false}},
{"SPRITE" : {"name": "0046","x":4,"y":695,"w":352,"h":329,"rotated": false}}
]},
"meta": {
"app": "Adobe Animate",
"version": "22.0.5.191",
"image": "spritemap1.png",
"format": "RGBA8888",
"size": {"w":2044,"h":1283},
"resolution": "1"
}
{"ATLAS":{"SPRITES":[
{"SPRITE":{"name":"0","x":349,"y":867,"w":254,"h":136,"rotated":false}},
{"SPRITE":{"name":"1","x":1648,"y":328,"w":287,"h":363,"rotated":false}},
{"SPRITE":{"name":"2","x":1571,"y":709,"w":185,"h":117,"rotated":false}},
{"SPRITE":{"name":"3","x":1686,"y":855,"w":86,"h":136,"rotated":false}},
{"SPRITE":{"name":"4","x":349,"y":1021,"w":122,"h":68,"rotated":false}},
{"SPRITE":{"name":"5","x":1774,"y":709,"w":110,"h":128,"rotated":false}},
{"SPRITE":{"name":"6","x":621,"y":867,"w":105,"h":148,"rotated":false}},
{"SPRITE":{"name":"7","x":1571,"y":844,"w":97,"h":131,"rotated":false}},
{"SPRITE":{"name":"8","x":800,"y":1,"w":543,"h":308,"rotated":false}},
{"SPRITE":{"name":"9","x":800,"y":1,"w":543,"h":308,"rotated":false}},
{"SPRITE":{"name":"10","x":800,"y":1,"w":543,"h":308,"rotated":false}},
{"SPRITE":{"name":"11","x":800,"y":1,"w":543,"h":308,"rotated":false}},
{"SPRITE":{"name":"12","x":800,"y":1,"w":543,"h":308,"rotated":false}},
{"SPRITE":{"name":"13","x":800,"y":1,"w":543,"h":308,"rotated":false}},
{"SPRITE":{"name":"14","x":800,"y":1,"w":543,"h":308,"rotated":false}},
{"SPRITE":{"name":"15","x":800,"y":1,"w":543,"h":308,"rotated":false}},
{"SPRITE":{"name":"16","x":1363,"y":1,"w":543,"h":308,"rotated":false}},
{"SPRITE":{"name":"17","x":1,"y":444,"w":771,"h":404,"rotated":false}},
{"SPRITE":{"name":"18","x":791,"y":700,"w":302,"h":369,"rotated":false}},
{"SPRITE":{"name":"19","x":1111,"y":957,"w":120,"h":86,"rotated":false}},
{"SPRITE":{"name":"20","x":1790,"y":855,"w":120,"h":86,"rotated":false}},
{"SPRITE":{"name":"21","x":1790,"y":959,"w":106,"h":86,"rotated":false}},
{"SPRITE":{"name":"22","x":1249,"y":957,"w":120,"h":86,"rotated":false}},
{"SPRITE":{"name":"23","x":0,"y":0,"w":781,"h":425,"rotated":false}},
{"SPRITE":{"name":"24","x":0,"y":867,"w":331,"h":164,"rotated":false}},
{"SPRITE":{"name":"25","x":799,"y":328,"w":413,"h":354,"rotated":false}},
{"SPRITE":{"name":"26","x":1230,"y":328,"w":400,"h":353,"rotated":false}},
{"SPRITE":{"name":"27","x":1387,"y":954,"w":90,"h":103,"rotated":false}},
{"SPRITE":{"name":"28","x":1111,"y":700,"w":213,"h":239,"rotated":false}},
{"SPRITE":{"name":"29","x":1342,"y":699,"w":211,"h":237,"rotated":false}}]},
"meta":{
"app":"Adobe Animate (Better TA Extension)",
"version":"24.0.2.12",
"image":"spritemap1.png",
"format":"RGBA8888",
"size":{"w":1965,"h":1089},
"resolution":"1"
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 228 KiB

After

Width:  |  Height:  |  Size: 453 KiB

File diff suppressed because it is too large Load Diff
+54 -56
View File
@@ -1,57 +1,55 @@
{"ATLAS": {"SPRITES":[
{"SPRITE" : {"name": "0000","x":1623,"y":602,"w":287,"h":360,"rotated": false}},
{"SPRITE" : {"name": "0001","x":1310,"y":269,"w":309,"h":375,"rotated": false}},
{"SPRITE" : {"name": "0002","x":4,"y":4,"w":420,"h":359,"rotated": false}},
{"SPRITE" : {"name": "0003","x":428,"y":4,"w":406,"h":358,"rotated": false}},
{"SPRITE" : {"name": "0004","x":4,"y":639,"w":336,"h":165,"rotated": false}},
{"SPRITE" : {"name": "0005","x":125,"y":808,"w":90,"h":103,"rotated": false}},
{"SPRITE" : {"name": "0006","x":1819,"y":4,"w":215,"h":242,"rotated": false}},
{"SPRITE" : {"name": "0007","x":1217,"y":648,"w":213,"h":240,"rotated": false}},
{"SPRITE" : {"name": "0008","x":606,"y":660,"w":191,"h":120,"rotated": false}},
{"SPRITE" : {"name": "0009","x":606,"y":784,"w":90,"h":151,"rotated": false}},
{"SPRITE" : {"name": "0010","x":344,"y":660,"w":258,"h":124,"rotated": false}},
{"SPRITE" : {"name": "0011","x":448,"y":859,"w":122,"h":67,"rotated": false}},
{"SPRITE" : {"name": "0012","x":1914,"y":755,"w":108,"h":126,"rotated": false}},
{"SPRITE" : {"name": "0013","x":1914,"y":602,"w":103,"h":149,"rotated": false}},
{"SPRITE" : {"name": "0014","x":700,"y":784,"w":95,"h":130,"rotated": false}},
{"SPRITE" : {"name": "0015","x":2038,"y":4,"w":1,"h":4,"rotated": false}},
{"SPRITE" : {"name": "0016","x":838,"y":253,"w":468,"h":256,"rotated": false}},
{"SPRITE" : {"name": "0017","x":838,"y":4,"w":510,"h":245,"rotated": false}},
{"SPRITE" : {"name": "0018","x":1352,"y":4,"w":463,"h":261,"rotated": false}},
{"SPRITE" : {"name": "0019","x":4,"y":367,"w":418,"h":268,"rotated": false}},
{"SPRITE" : {"name": "0020","x":826,"y":513,"w":387,"h":271,"rotated": false}},
{"SPRITE" : {"name": "0021","x":428,"y":366,"w":394,"h":290,"rotated": false}},
{"SPRITE" : {"name": "0022","x":1623,"y":269,"w":352,"h":329,"rotated": false}},
{"SPRITE" : {"name": "0023","x":1143,"y":788,"w":67,"h":70,"rotated": false}},
{"SPRITE" : {"name": "0024","x":1033,"y":875,"w":122,"h":62,"rotated": false}},
{"SPRITE" : {"name": "0025","x":1217,"y":513,"w":64,"h":106,"rotated": false}},
{"SPRITE" : {"name": "0026","x":1979,"y":359,"w":55,"h":112,"rotated": false}},
{"SPRITE" : {"name": "0027","x":799,"y":788,"w":98,"h":118,"rotated": false}},
{"SPRITE" : {"name": "0028","x":1979,"y":250,"w":59,"h":105,"rotated": false}},
{"SPRITE" : {"name": "0029","x":1434,"y":749,"w":87,"h":160,"rotated": false}},
{"SPRITE" : {"name": "0030","x":1525,"y":749,"w":92,"h":149,"rotated": false}},
{"SPRITE" : {"name": "0031","x":219,"y":887,"w":104,"h":42,"rotated": false}},
{"SPRITE" : {"name": "0032","x":527,"y":811,"w":73,"h":18,"rotated": false}},
{"SPRITE" : {"name": "0033","x":527,"y":788,"w":72,"h":19,"rotated": false}},
{"SPRITE" : {"name": "0034","x":527,"y":833,"w":72,"h":18,"rotated": false}},
{"SPRITE" : {"name": "0035","x":1217,"y":623,"w":73,"h":20,"rotated": false}},
{"SPRITE" : {"name": "0036","x":344,"y":788,"w":179,"h":67,"rotated": false}},
{"SPRITE" : {"name": "0037","x":219,"y":808,"w":118,"h":75,"rotated": false}},
{"SPRITE" : {"name": "0038","x":901,"y":875,"w":128,"h":61,"rotated": false}},
{"SPRITE" : {"name": "0039","x":1914,"y":885,"w":124,"h":58,"rotated": false}},
{"SPRITE" : {"name": "0040","x":901,"y":788,"w":117,"h":83,"rotated": false}},
{"SPRITE" : {"name": "0041","x":1022,"y":788,"w":117,"h":83,"rotated": false}},
{"SPRITE" : {"name": "0042","x":341,"y":859,"w":103,"h":83,"rotated": false}},
{"SPRITE" : {"name": "0043","x":4,"y":808,"w":117,"h":83,"rotated": false}},
{"SPRITE" : {"name": "0044","x":1434,"y":648,"w":174,"h":97,"rotated": false}},
{"SPRITE" : {"name": "0045","x":1819,"y":250,"w":82,"h":14,"rotated": false}}
]},
"meta": {
"app": "Adobe Animate",
"version": "21.0.1.37179",
"image": "spritemap1.png",
"format": "RGBA8888",
"size": {"w":2043,"h":966},
"resolution": "1"
}
{"ATLAS":{"SPRITES":[
{"SPRITE":{"name":"0","x":1129,"y":977,"w":86,"h":17,"rotated":false}},
{"SPRITE":{"name":"1","x":1690,"y":1012,"w":86,"h":17,"rotated":false}},
{"SPRITE":{"name":"2","x":1656,"y":852,"w":126,"h":64,"rotated":false}},
{"SPRITE":{"name":"3","x":1915,"y":841,"w":121,"h":77,"rotated":false}},
{"SPRITE":{"name":"4","x":1382,"y":980,"w":131,"h":64,"rotated":false}},
{"SPRITE":{"name":"5","x":1132,"y":283,"w":420,"h":270,"rotated":false}},
{"SPRITE":{"name":"6","x":1570,"y":277,"w":389,"h":273,"rotated":false}},
{"SPRITE":{"name":"7","x":0,"y":743,"w":397,"h":292,"rotated":false}},
{"SPRITE":{"name":"8","x":431,"y":267,"w":354,"h":332,"rotated":false}},
{"SPRITE":{"name":"9","x":1592,"y":568,"w":190,"h":117,"rotated":false}},
{"SPRITE":{"name":"10","x":1444,"y":826,"w":86,"h":136,"rotated":false}},
{"SPRITE":{"name":"11","x":723,"y":852,"w":260,"h":123,"rotated":false}},
{"SPRITE":{"name":"12","x":1548,"y":947,"w":124,"h":68,"rotated":false}},
{"SPRITE":{"name":"13","x":1001,"y":852,"w":110,"h":128,"rotated":false}},
{"SPRITE":{"name":"14","x":1933,"y":0,"w":106,"h":148,"rotated":false}},
{"SPRITE":{"name":"15","x":1129,"y":828,"w":97,"h":131,"rotated":false}},
{"SPRITE":{"name":"16","x":803,"y":283,"w":311,"h":369,"rotated":false}},
{"SPRITE":{"name":"17","x":1592,"y":703,"w":167,"h":101,"rotated":false}},
{"SPRITE":{"name":"18","x":1835,"y":852,"w":57,"h":105,"rotated":false}},
{"SPRITE":{"name":"19","x":1977,"y":270,"w":66,"h":104,"rotated":false}},
{"SPRITE":{"name":"20","x":1910,"y":936,"w":70,"h":73,"rotated":false}},
{"SPRITE":{"name":"21","x":1244,"y":828,"w":182,"h":69,"rotated":false}},
{"SPRITE":{"name":"22","x":1690,"y":934,"w":127,"h":60,"rotated":false}},
{"SPRITE":{"name":"23","x":418,"y":617,"w":287,"h":363,"rotated":false}},
{"SPRITE":{"name":"24","x":1244,"y":915,"w":120,"h":86,"rotated":false}},
{"SPRITE":{"name":"25","x":1777,"y":748,"w":120,"h":86,"rotated":false}},
{"SPRITE":{"name":"26","x":1933,"y":166,"w":106,"h":86,"rotated":false}},
{"SPRITE":{"name":"27","x":1915,"y":737,"w":120,"h":86,"rotated":false}},
{"SPRITE":{"name":"28","x":1800,"y":568,"w":89,"h":162,"rotated":false}},
{"SPRITE":{"name":"29","x":1907,"y":568,"w":95,"h":151,"rotated":false}},
{"SPRITE":{"name":"30","x":1977,"y":392,"w":61,"h":107,"rotated":false}},
{"SPRITE":{"name":"31","x":415,"y":998,"w":107,"h":45,"rotated":false}},
{"SPRITE":{"name":"32","x":727,"y":993,"w":77,"h":22,"rotated":false}},
{"SPRITE":{"name":"33","x":634,"y":998,"w":75,"h":23,"rotated":false}},
{"SPRITE":{"name":"34","x":822,"y":993,"w":75,"h":22,"rotated":false}},
{"SPRITE":{"name":"35","x":540,"y":998,"w":76,"h":24,"rotated":false}},
{"SPRITE":{"name":"36","x":1445,"y":0,"w":470,"h":259,"rotated":false}},
{"SPRITE":{"name":"37","x":431,"y":0,"w":513,"h":249,"rotated":false}},
{"SPRITE":{"name":"38","x":962,"y":0,"w":465,"h":265,"rotated":false}},
{"SPRITE":{"name":"39","x":723,"y":670,"w":331,"h":164,"rotated":false}},
{"SPRITE":{"name":"40","x":0,"y":0,"w":413,"h":354,"rotated":false}},
{"SPRITE":{"name":"41","x":0,"y":372,"w":400,"h":353,"rotated":false}},
{"SPRITE":{"name":"42","x":1548,"y":826,"w":90,"h":103,"rotated":false}},
{"SPRITE":{"name":"43","x":1132,"y":571,"w":213,"h":239,"rotated":false}},
{"SPRITE":{"name":"44","x":1363,"y":571,"w":211,"h":237,"rotated":false}}]},
"meta":{
"app":"Adobe Animate (Better TA Extension)",
"version":"24.0.2.12",
"image":"spritemap1.png",
"format":"RGBA8888",
"size":{"w":2064,"h":1065},
"resolution":"1"
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 165 KiB

After

Width:  |  Height:  |  Size: 265 KiB

File diff suppressed because it is too large Load Diff
@@ -1,60 +1,60 @@
{"ATLAS": {"SPRITES":[
{"SPRITE" : {"name": "0000","x":4076,"y":2,"w":9,"h":12,"rotated": false}},
{"SPRITE" : {"name": "0001","x":1957,"y":2,"w":524,"h":501,"rotated": false}},
{"SPRITE" : {"name": "0002","x":716,"y":2,"w":721,"h":621,"rotated": false}},
{"SPRITE" : {"name": "0003","x":2331,"y":505,"w":139,"h":109,"rotated": false}},
{"SPRITE" : {"name": "0004","x":3244,"y":725,"w":303,"h":170,"rotated": false}},
{"SPRITE" : {"name": "0005","x":1691,"y":516,"w":248,"h":277,"rotated": false}},
{"SPRITE" : {"name": "0006","x":2495,"y":843,"w":173,"h":229,"rotated": false}},
{"SPRITE" : {"name": "0007","x":2,"y":642,"w":262,"h":221,"rotated": false}},
{"SPRITE" : {"name": "0008","x":2331,"y":616,"w":118,"h":117,"rotated": false}},
{"SPRITE" : {"name": "0009","x":3549,"y":865,"w":261,"h":139,"rotated": false}},
{"SPRITE" : {"name": "0010","x":3209,"y":897,"w":202,"h":122,"rotated": false}},
{"SPRITE" : {"name": "0011","x":580,"y":913,"w":202,"h":122,"rotated": false}},
{"SPRITE" : {"name": "0012","x":2831,"y":304,"w":45,"h":42,"rotated": false}},
{"SPRITE" : {"name": "0013","x":1957,"y":505,"w":372,"h":311,"rotated": false}},
{"SPRITE" : {"name": "0014","x":1439,"y":516,"w":250,"h":325,"rotated": false}},
{"SPRITE" : {"name": "0015","x":716,"y":625,"w":235,"h":286,"rotated": false}},
{"SPRITE" : {"name": "0016","x":953,"y":625,"w":245,"h":249,"rotated": false}},
{"SPRITE" : {"name": "0017","x":3644,"y":373,"w":136,"h":133,"rotated": false}},
{"SPRITE" : {"name": "0018","x":2331,"y":735,"w":150,"h":91,"rotated": false}},
{"SPRITE" : {"name": "0019","x":3644,"y":508,"w":151,"h":95,"rotated": false}},
{"SPRITE" : {"name": "0020","x":784,"y":913,"w":140,"h":90,"rotated": false}},
{"SPRITE" : {"name": "0021","x":3644,"y":605,"w":149,"h":92,"rotated": false}},
{"SPRITE" : {"name": "0022","x":2670,"y":932,"w":144,"h":87,"rotated": false}},
{"SPRITE" : {"name": "0023","x":2670,"y":843,"w":152,"h":87,"rotated": false}},
{"SPRITE" : {"name": "0024","x":4087,"y":2,"w":1,"h":4,"rotated": false}},
{"SPRITE" : {"name": "0025","x":2831,"y":373,"w":411,"h":352,"rotated": false}},
{"SPRITE" : {"name": "0026","x":3244,"y":373,"w":398,"h":350,"rotated": false}},
{"SPRITE" : {"name": "0027","x":266,"y":642,"w":329,"h":162,"rotated": false}},
{"SPRITE" : {"name": "0028","x":597,"y":642,"w":90,"h":103,"rotated": false}},
{"SPRITE" : {"name": "0029","x":1200,"y":625,"w":211,"h":236,"rotated": false}},
{"SPRITE" : {"name": "0030","x":2831,"y":727,"w":208,"h":235,"rotated": false}},
{"SPRITE" : {"name": "0031","x":2483,"y":2,"w":738,"h":300,"rotated": false}},
{"SPRITE" : {"name": "0032","x":2483,"y":304,"w":346,"h":537,"rotated": false}},
{"SPRITE" : {"name": "0033","x":2,"y":865,"w":235,"h":158,"rotated": false}},
{"SPRITE" : {"name": "0034","x":3812,"y":865,"w":216,"h":141,"rotated": false}},
{"SPRITE" : {"name": "0035","x":2000,"y":818,"w":299,"h":155,"rotated": false}},
{"SPRITE" : {"name": "0036","x":1200,"y":863,"w":179,"h":208,"rotated": false}},
{"SPRITE" : {"name": "0037","x":1691,"y":818,"w":307,"h":154,"rotated": false}},
{"SPRITE" : {"name": "0038","x":3644,"y":702,"w":320,"h":161,"rotated": false}},
{"SPRITE" : {"name": "0039","x":266,"y":806,"w":312,"h":155,"rotated": false}},
{"SPRITE" : {"name": "0040","x":239,"y":963,"w":224,"h":108,"rotated": false}},
{"SPRITE" : {"name": "0041","x":3223,"y":2,"w":580,"h":369,"rotated": false}},
{"SPRITE" : {"name": "0042","x":3805,"y":2,"w":269,"h":698,"rotated": false}},
{"SPRITE" : {"name": "0043","x":1413,"y":843,"w":205,"h":222,"rotated": false}},
{"SPRITE" : {"name": "0044","x":3041,"y":727,"w":166,"h":292,"rotated": false}},
{"SPRITE" : {"name": "0045","x":953,"y":876,"w":203,"h":137,"rotated": false}},
{"SPRITE" : {"name": "0046","x":1439,"y":2,"w":516,"h":512,"rotated": false}},
{"SPRITE" : {"name": "0047","x":2,"y":2,"w":712,"h":638,"rotated": false}},
{"SPRITE" : {"name": "0048","x":2301,"y":843,"w":192,"h":227,"rotated": false}}
]},
"meta": {
"app": "Adobe Animate",
"version": "21.0.1.37179",
"image": "spritemap1.png",
"format": "RGBA8888",
"size": {"w":4090,"h":1074},
"resolution": "1"
}
{"ATLAS":{"SPRITES":[
{"SPRITE":{"name":"0","x":2834,"y":332,"w":12,"h":15,"rotated":false}},
{"SPRITE":{"name":"1","x":1476,"y":532,"w":527,"h":503,"rotated":false}},
{"SPRITE":{"name":"2","x":733,"y":0,"w":725,"h":623,"rotated":false}},
{"SPRITE":{"name":"3","x":0,"y":659,"w":741,"h":304,"rotated":false}},
{"SPRITE":{"name":"4","x":2311,"y":0,"w":349,"h":540,"rotated":false}},
{"SPRITE":{"name":"5","x":759,"y":641,"w":583,"h":373,"rotated":false}},
{"SPRITE":{"name":"6","x":2021,"y":0,"w":272,"h":702,"rotated":false}},
{"SPRITE":{"name":"7","x":1476,"y":0,"w":518,"h":514,"rotated":false}},
{"SPRITE":{"name":"8","x":0,"y":0,"w":715,"h":641,"rotated":false}},
{"SPRITE":{"name":"9","x":619,"y":1032,"w":205,"h":122,"rotated":false}},
{"SPRITE":{"name":"10","x":842,"y":1032,"w":205,"h":122,"rotated":false}},
{"SPRITE":{"name":"11","x":2311,"y":558,"w":115,"h":112,"rotated":false}},
{"SPRITE":{"name":"12","x":2801,"y":947,"w":305,"h":172,"rotated":false}},
{"SPRITE":{"name":"13","x":2678,"y":0,"w":375,"h":314,"rotated":false}},
{"SPRITE":{"name":"14","x":2870,"y":332,"w":252,"h":328,"rotated":false}},
{"SPRITE":{"name":"15","x":3071,"y":0,"w":239,"h":290,"rotated":false}},
{"SPRITE":{"name":"16","x":3135,"y":678,"w":220,"h":246,"rotated":false}},
{"SPRITE":{"name":"17","x":3597,"y":248,"w":173,"h":231,"rotated":false}},
{"SPRITE":{"name":"18","x":3769,"y":0,"w":225,"h":190,"rotated":false}},
{"SPRITE":{"name":"19","x":1290,"y":1053,"w":131,"h":81,"rotated":false}},
{"SPRITE":{"name":"20","x":3905,"y":814,"w":132,"h":85,"rotated":false}},
{"SPRITE":{"name":"21","x":1733,"y":1053,"w":122,"h":80,"rotated":false}},
{"SPRITE":{"name":"22","x":3905,"y":917,"w":129,"h":82,"rotated":false}},
{"SPRITE":{"name":"23","x":1589,"y":1053,"w":126,"h":78,"rotated":false}},
{"SPRITE":{"name":"24","x":1439,"y":1053,"w":132,"h":77,"rotated":false}},
{"SPRITE":{"name":"25","x":3778,"y":814,"w":109,"h":107,"rotated":false}},
{"SPRITE":{"name":"26","x":3124,"y":1123,"w":3,"h":7,"rotated":false}},
{"SPRITE":{"name":"27","x":3145,"y":1123,"w":3,"h":7,"rotated":false}},
{"SPRITE":{"name":"28","x":3673,"y":497,"w":260,"h":141,"rotated":false}},
{"SPRITE":{"name":"29","x":3788,"y":208,"w":237,"h":161,"rotated":false}},
{"SPRITE":{"name":"30","x":3542,"y":660,"w":218,"h":144,"rotated":false}},
{"SPRITE":{"name":"31","x":3124,"y":947,"w":301,"h":158,"rotated":false}},
{"SPRITE":{"name":"32","x":3371,"y":498,"w":284,"h":144,"rotated":false}},
{"SPRITE":{"name":"33","x":0,"y":981,"w":295,"h":150,"rotated":false}},
{"SPRITE":{"name":"34","x":313,"y":981,"w":288,"h":145,"rotated":false}},
{"SPRITE":{"name":"35","x":3443,"y":942,"w":182,"h":212,"rotated":false}},
{"SPRITE":{"name":"36","x":3371,"y":255,"w":208,"h":225,"rotated":false}},
{"SPRITE":{"name":"37","x":3373,"y":660,"w":151,"h":264,"rotated":false}},
{"SPRITE":{"name":"38","x":3778,"y":656,"w":206,"h":140,"rotated":false}},
{"SPRITE":{"name":"39","x":3557,"y":0,"w":194,"h":230,"rotated":false}},
{"SPRITE":{"name":"40","x":2678,"y":485,"w":47,"h":44,"rotated":false}},
{"SPRITE":{"name":"41","x":2870,"y":678,"w":247,"h":251,"rotated":false}},
{"SPRITE":{"name":"42","x":2678,"y":332,"w":138,"h":135,"rotated":false}},
{"SPRITE":{"name":"43","x":1065,"y":1053,"w":207,"h":101,"rotated":false}},
{"SPRITE":{"name":"44","x":2452,"y":947,"w":331,"h":164,"rotated":false}},
{"SPRITE":{"name":"45","x":2021,"y":720,"w":413,"h":354,"rotated":false}},
{"SPRITE":{"name":"46","x":2452,"y":558,"w":400,"h":353,"rotated":false}},
{"SPRITE":{"name":"47","x":3951,"y":387,"w":90,"h":103,"rotated":false}},
{"SPRITE":{"name":"48","x":3140,"y":308,"w":213,"h":239,"rotated":false}},
{"SPRITE":{"name":"49","x":3328,"y":0,"w":211,"h":237,"rotated":false}}]},
"meta":{
"app":"Adobe Animate (Better TA Extension)",
"version":"24.0.2.12",
"image":"spritemap1.png",
"format":"RGBA8888",
"size":{"w":4061,"h":1154},
"resolution":"1"
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 344 KiB

After

Width:  |  Height:  |  Size: 535 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 804 B

After

Width:  |  Height:  |  Size: 1.0 KiB

File diff suppressed because it is too large Load Diff
@@ -1,145 +1,241 @@
{"ATLAS": {"SPRITES":[
{"SPRITE" : {"name": "0000","x":2847,"y":969,"w":327,"h":397,"rotated": false}},
{"SPRITE" : {"name": "0001","x":2441,"y":894,"w":110,"h":159,"rotated": false}},
{"SPRITE" : {"name": "0002","x":1709,"y":1631,"w":197,"h":185,"rotated": false}},
{"SPRITE" : {"name": "0003","x":408,"y":1773,"w":92,"h":155,"rotated": false}},
{"SPRITE" : {"name": "0004","x":236,"y":1639,"w":274,"h":132,"rotated": false}},
{"SPRITE" : {"name": "0005","x":3427,"y":1495,"w":133,"h":74,"rotated": false}},
{"SPRITE" : {"name": "0006","x":3270,"y":540,"w":121,"h":162,"rotated": false}},
{"SPRITE" : {"name": "0007","x":359,"y":649,"w":518,"h":294,"rotated": false}},
{"SPRITE" : {"name": "0008","x":1957,"y":2,"w":775,"h":483,"rotated": false}},
{"SPRITE" : {"name": "0009","x":1014,"y":2,"w":941,"h":607,"rotated": false}},
{"SPRITE" : {"name": "0010","x":2,"y":2,"w":1010,"h":645,"rotated": false}},
{"SPRITE" : {"name": "0011","x":4059,"y":2,"w":20,"h":142,"rotated": false}},
{"SPRITE" : {"name": "0012","x":4035,"y":616,"w":40,"h":83,"rotated": false}},
{"SPRITE" : {"name": "0013","x":2755,"y":1508,"w":64,"h":57,"rotated": false}},
{"SPRITE" : {"name": "0014","x":3176,"y":1171,"w":91,"h":48,"rotated": false}},
{"SPRITE" : {"name": "0015","x":3245,"y":1737,"w":88,"h":41,"rotated": false}},
{"SPRITE" : {"name": "0016","x":3064,"y":1368,"w":109,"h":93,"rotated": false}},
{"SPRITE" : {"name": "0017","x":3402,"y":2,"w":655,"h":434,"rotated": false}},
{"SPRITE" : {"name": "0018","x":1957,"y":487,"w":626,"h":405,"rotated": false}},
{"SPRITE" : {"name": "0019","x":3402,"y":438,"w":631,"h":438,"rotated": false}},
{"SPRITE" : {"name": "0020","x":1170,"y":1211,"w":393,"h":287,"rotated": false}},
{"SPRITE" : {"name": "0021","x":2847,"y":540,"w":421,"h":427,"rotated": false}},
{"SPRITE" : {"name": "0022","x":2734,"y":2,"w":666,"h":536,"rotated": false}},
{"SPRITE" : {"name": "0023","x":542,"y":1480,"w":224,"h":221,"rotated": false}},
{"SPRITE" : {"name": "0024","x":3657,"y":1736,"w":186,"h":175,"rotated": false}},
{"SPRITE" : {"name": "0025","x":4035,"y":764,"w":56,"h":52,"rotated": false}},
{"SPRITE" : {"name": "0026","x":502,"y":1876,"w":126,"h":104,"rotated": false}},
{"SPRITE" : {"name": "0027","x":1709,"y":1818,"w":135,"h":104,"rotated": false}},
{"SPRITE" : {"name": "0028","x":2,"y":1440,"w":232,"h":236,"rotated": false}},
{"SPRITE" : {"name": "0029","x":3938,"y":1437,"w":139,"h":109,"rotated": false}},
{"SPRITE" : {"name": "0030","x":2755,"y":1627,"w":235,"h":158,"rotated": false}},
{"SPRITE" : {"name": "0031","x":1147,"y":1500,"w":198,"h":233,"rotated": false}},
{"SPRITE" : {"name": "0032","x":2,"y":1860,"w":118,"h":117,"rotated": false}},
{"SPRITE" : {"name": "0033","x":1565,"y":1398,"w":262,"h":221,"rotated": false}},
{"SPRITE" : {"name": "0034","x":3845,"y":1736,"w":222,"h":145,"rotated": false}},
{"SPRITE" : {"name": "0035","x":979,"y":1480,"w":166,"h":292,"rotated": false}},
{"SPRITE" : {"name": "0036","x":3657,"y":1592,"w":276,"h":142,"rotated": false}},
{"SPRITE" : {"name": "0037","x":925,"y":1774,"w":203,"h":138,"rotated": false}},
{"SPRITE" : {"name": "0038","x":236,"y":1467,"w":304,"h":170,"rotated": false}},
{"SPRITE" : {"name": "0039","x":4081,"y":2,"w":1,"h":4,"rotated": false}},
{"SPRITE" : {"name": "0040","x":2441,"y":1055,"w":135,"h":127,"rotated": false}},
{"SPRITE" : {"name": "0041","x":2,"y":1678,"w":195,"h":180,"rotated": false}},
{"SPRITE" : {"name": "0042","x":2751,"y":1787,"w":160,"h":144,"rotated": false}},
{"SPRITE" : {"name": "0043","x":713,"y":945,"w":243,"h":261,"rotated": false}},
{"SPRITE" : {"name": "0044","x":2375,"y":1508,"w":378,"h":121,"rotated": false}},
{"SPRITE" : {"name": "0045","x":3064,"y":1495,"w":361,"h":128,"rotated": false}},
{"SPRITE" : {"name": "0046","x":713,"y":1211,"w":455,"h":267,"rotated": false}},
{"SPRITE" : {"name": "0047","x":2,"y":1112,"w":272,"h":326,"rotated": false}},
{"SPRITE" : {"name": "0048","x":3710,"y":878,"w":249,"h":557,"rotated": false}},
{"SPRITE" : {"name": "0049","x":2585,"y":540,"w":260,"h":701,"rotated": false}},
{"SPRITE" : {"name": "0050","x":1014,"y":611,"w":291,"h":598,"rotated": false}},
{"SPRITE" : {"name": "0051","x":1307,"y":611,"w":315,"h":540,"rotated": false}},
{"SPRITE" : {"name": "0052","x":2,"y":649,"w":355,"h":461,"rotated": false}},
{"SPRITE" : {"name": "0053","x":359,"y":945,"w":352,"h":373,"rotated": false}},
{"SPRITE" : {"name": "0054","x":3064,"y":1625,"w":347,"h":110,"rotated": false}},
{"SPRITE" : {"name": "0055","x":2039,"y":1248,"w":379,"h":216,"rotated": false}},
{"SPRITE" : {"name": "0056","x":2827,"y":1368,"w":235,"h":257,"rotated": false}},
{"SPRITE" : {"name": "0057","x":2100,"y":1879,"w":140,"h":92,"rotated": false}},
{"SPRITE" : {"name": "0058","x":776,"y":1886,"w":119,"h":79,"rotated": false}},
{"SPRITE" : {"name": "0059","x":1565,"y":1249,"w":434,"h":147,"rotated": false}},
{"SPRITE" : {"name": "0060","x":276,"y":1320,"w":433,"h":145,"rotated": false}},
{"SPRITE" : {"name": "0061","x":3270,"y":878,"w":438,"h":342,"rotated": false}},
{"SPRITE" : {"name": "0062","x":3176,"y":1222,"w":385,"h":271,"rotated": false}},
{"SPRITE" : {"name": "0063","x":3563,"y":1437,"w":373,"h":153,"rotated": false}},
{"SPRITE" : {"name": "0064","x":3245,"y":1786,"w":202,"h":122,"rotated": false}},
{"SPRITE" : {"name": "0065","x":3449,"y":1786,"w":202,"h":122,"rotated": false}},
{"SPRITE" : {"name": "0066","x":3064,"y":1861,"w":150,"h":91,"rotated": false}},
{"SPRITE" : {"name": "0067","x":3938,"y":1548,"w":151,"h":95,"rotated": false}},
{"SPRITE" : {"name": "0068","x":3845,"y":1883,"w":140,"h":90,"rotated": false}},
{"SPRITE" : {"name": "0069","x":2913,"y":1861,"w":149,"h":92,"rotated": false}},
{"SPRITE" : {"name": "0070","x":630,"y":1886,"w":144,"h":87,"rotated": false}},
{"SPRITE" : {"name": "0071","x":3935,"y":1645,"w":152,"h":87,"rotated": false}},
{"SPRITE" : {"name": "0072","x":2441,"y":1243,"w":384,"h":263,"rotated": false}},
{"SPRITE" : {"name": "0073","x":1624,"y":611,"w":248,"h":277,"rotated": false}},
{"SPRITE" : {"name": "0074","x":1624,"y":894,"w":413,"h":353,"rotated": false}},
{"SPRITE" : {"name": "0075","x":2039,"y":894,"w":400,"h":352,"rotated": false}},
{"SPRITE" : {"name": "0076","x":1829,"y":1466,"w":330,"h":163,"rotated": false}},
{"SPRITE" : {"name": "0077","x":3987,"y":1883,"w":90,"h":103,"rotated": false}},
{"SPRITE" : {"name": "0078","x":2161,"y":1466,"w":212,"h":238,"rotated": false}},
{"SPRITE" : {"name": "0079","x":768,"y":1480,"w":209,"h":236,"rotated": false}},
{"SPRITE" : {"name": "0080","x":2242,"y":1879,"w":86,"h":84,"rotated": false}},
{"SPRITE" : {"name": "0081","x":879,"y":649,"w":126,"h":148,"rotated": false}},
{"SPRITE" : {"name": "0082","x":1908,"y":1631,"w":216,"h":168,"rotated": false}},
{"SPRITE" : {"name": "0083","x":2575,"y":1631,"w":174,"h":192,"rotated": false}},
{"SPRITE" : {"name": "0084","x":1130,"y":1901,"w":106,"h":75,"rotated": false}},
{"SPRITE" : {"name": "0085","x":3961,"y":1367,"w":129,"h":63,"rotated": false}},
{"SPRITE" : {"name": "0086","x":1829,"y":1398,"w":158,"h":60,"rotated": false}},
{"SPRITE" : {"name": "0087","x":3270,"y":704,"w":123,"h":148,"rotated": false}},
{"SPRITE" : {"name": "0088","x":3961,"y":878,"w":123,"h":148,"rotated": false}},
{"SPRITE" : {"name": "0089","x":199,"y":1773,"w":207,"h":142,"rotated": false}},
{"SPRITE" : {"name": "0090","x":1238,"y":1901,"w":91,"h":53,"rotated": false}},
{"SPRITE" : {"name": "0091","x":276,"y":1112,"w":65,"h":96,"rotated": false}},
{"SPRITE" : {"name": "0092","x":276,"y":1210,"w":65,"h":96,"rotated": false}},
{"SPRITE" : {"name": "0093","x":2518,"y":1825,"w":136,"h":102,"rotated": false}},
{"SPRITE" : {"name": "0094","x":1537,"y":1857,"w":136,"h":102,"rotated": false}},
{"SPRITE" : {"name": "0095","x":3427,"y":1592,"w":228,"h":192,"rotated": false}},
{"SPRITE" : {"name": "0096","x":1541,"y":1621,"w":166,"h":234,"rotated": false}},
{"SPRITE" : {"name": "0097","x":512,"y":1703,"w":205,"h":171,"rotated": false}},
{"SPRITE" : {"name": "0098","x":2126,"y":1706,"w":205,"h":171,"rotated": false}},
{"SPRITE" : {"name": "0099","x":719,"y":1718,"w":204,"h":166,"rotated": false}},
{"SPRITE" : {"name": "0100","x":1147,"y":1735,"w":206,"h":164,"rotated": false}},
{"SPRITE" : {"name": "0101","x":1874,"y":611,"w":79,"h":185,"rotated": false}},
{"SPRITE" : {"name": "0102","x":3176,"y":969,"w":83,"h":200,"rotated": false}},
{"SPRITE" : {"name": "0103","x":3563,"y":1222,"w":86,"h":180,"rotated": false}},
{"SPRITE" : {"name": "0104","x":3961,"y":1028,"w":89,"h":186,"rotated": false}},
{"SPRITE" : {"name": "0105","x":2375,"y":1631,"w":198,"h":183,"rotated": false}},
{"SPRITE" : {"name": "0106","x":1908,"y":1801,"w":190,"h":120,"rotated": false}},
{"SPRITE" : {"name": "0107","x":2656,"y":1825,"w":86,"h":145,"rotated": false}},
{"SPRITE" : {"name": "0108","x":1355,"y":1724,"w":180,"h":170,"rotated": false}},
{"SPRITE" : {"name": "0109","x":3961,"y":1216,"w":111,"h":149,"rotated": false}},
{"SPRITE" : {"name": "0110","x":4035,"y":516,"w":39,"h":98,"rotated": false}},
{"SPRITE" : {"name": "0111","x":1307,"y":1153,"w":118,"h":47,"rotated": false}},
{"SPRITE" : {"name": "0112","x":1427,"y":1153,"w":120,"h":43,"rotated": false}},
{"SPRITE" : {"name": "0113","x":2441,"y":1184,"w":120,"h":41,"rotated": false}},
{"SPRITE" : {"name": "0114","x":3216,"y":1910,"w":95,"h":33,"rotated": false}},
{"SPRITE" : {"name": "0115","x":3563,"y":1404,"w":95,"h":31,"rotated": false}},
{"SPRITE" : {"name": "0116","x":3563,"y":1404,"w":95,"h":31,"rotated": false}},
{"SPRITE" : {"name": "0117","x":2330,"y":1906,"w":95,"h":34,"rotated": false}},
{"SPRITE" : {"name": "0118","x":2585,"y":487,"w":131,"h":47,"rotated": false}},
{"SPRITE" : {"name": "0119","x":4059,"y":258,"w":31,"h":18,"rotated": false}},
{"SPRITE" : {"name": "0120","x":1355,"y":1896,"w":122,"h":66,"rotated": false}},
{"SPRITE" : {"name": "0121","x":2992,"y":1737,"w":251,"h":122,"rotated": false}},
{"SPRITE" : {"name": "0122","x":879,"y":799,"w":114,"h":133,"rotated": false}},
{"SPRITE" : {"name": "0123","x":1347,"y":1500,"w":192,"h":222,"rotated": false}},
{"SPRITE" : {"name": "0124","x":4035,"y":818,"w":39,"h":34,"rotated": false}},
{"SPRITE" : {"name": "0125","x":4035,"y":701,"w":50,"h":61,"rotated": false}},
{"SPRITE" : {"name": "0126","x":1874,"y":798,"w":64,"h":78,"rotated": false}},
{"SPRITE" : {"name": "0127","x":4035,"y":438,"w":52,"h":76,"rotated": false}},
{"SPRITE" : {"name": "0128","x":958,"y":934,"w":46,"h":63,"rotated": false}},
{"SPRITE" : {"name": "0129","x":4059,"y":146,"w":30,"h":41,"rotated": false}},
{"SPRITE" : {"name": "0130","x":4059,"y":189,"w":23,"h":35,"rotated": false}},
{"SPRITE" : {"name": "0131","x":4059,"y":226,"w":20,"h":30,"rotated": false}},
{"SPRITE" : {"name": "0132","x":4059,"y":278,"w":17,"h":22,"rotated": false}},
{"SPRITE" : {"name": "0133","x":2333,"y":1816,"w":183,"h":88,"rotated": false}}
]},
"meta": {
"app": "Adobe Animate",
"version": "21.0.1.37179",
"image": "spritemap1.png",
"format": "RGBA8888",
"size": {"w":4093,"h":1988},
"resolution": "1"
}
{"ATLAS":{"SPRITES":[
{"SPRITE":{"name":"0","x":2564,"y":2,"w":23,"h":144,"rotated":false}},
{"SPRITE":{"name":"1","x":3024,"y":522,"w":42,"h":85,"rotated":false}},
{"SPRITE":{"name":"2","x":2598,"y":1211,"w":67,"h":60,"rotated":false}},
{"SPRITE":{"name":"3","x":3964,"y":932,"w":93,"h":51,"rotated":false}},
{"SPRITE":{"name":"4","x":3691,"y":1016,"w":91,"h":43,"rotated":false}},
{"SPRITE":{"name":"5","x":3877,"y":270,"w":111,"h":95,"rotated":false}},
{"SPRITE":{"name":"6","x":3449,"y":1124,"w":113,"h":127,"rotated":false}},
{"SPRITE":{"name":"7","x":367,"y":1129,"w":382,"h":123,"rotated":false}},
{"SPRITE":{"name":"8","x":2,"y":1122,"w":364,"h":131,"rotated":false}},
{"SPRITE":{"name":"9","x":2,"y":1122,"w":364,"h":131,"rotated":false}},
{"SPRITE":{"name":"10","x":2437,"y":1136,"w":31,"h":31,"rotated":false}},
{"SPRITE":{"name":"11","x":1599,"y":1133,"w":350,"h":113,"rotated":false}},
{"SPRITE":{"name":"12","x":1599,"y":1133,"w":350,"h":113,"rotated":false}},
{"SPRITE":{"name":"13","x":2670,"y":1175,"w":142,"h":94,"rotated":false}},
{"SPRITE":{"name":"14","x":3877,"y":366,"w":122,"h":82,"rotated":false}},
{"SPRITE":{"name":"15","x":1162,"y":1112,"w":436,"h":151,"rotated":false}},
{"SPRITE":{"name":"16","x":1599,"y":985,"w":435,"h":147,"rotated":false}},
{"SPRITE":{"name":"17","x":1599,"y":985,"w":435,"h":147,"rotated":false}},
{"SPRITE":{"name":"18","x":779,"y":692,"w":440,"h":344,"rotated":false}},
{"SPRITE":{"name":"19","x":1550,"y":711,"w":388,"h":273,"rotated":false}},
{"SPRITE":{"name":"20","x":2106,"y":2,"w":376,"h":155,"rotated":false}},
{"SPRITE":{"name":"21","x":2,"y":2,"w":932,"h":689,"rotated":false}},
{"SPRITE":{"name":"22","x":3907,"y":1171,"w":48,"h":36,"rotated":false}},
{"SPRITE":{"name":"23","x":3907,"y":1171,"w":48,"h":36,"rotated":false}},
{"SPRITE":{"name":"24","x":3858,"y":1206,"w":48,"h":40,"rotated":false}},
{"SPRITE":{"name":"25","x":3762,"y":1093,"w":48,"h":64,"rotated":false}},
{"SPRITE":{"name":"26","x":3713,"y":1060,"w":48,"h":66,"rotated":false}},
{"SPRITE":{"name":"27","x":3885,"y":1095,"w":48,"h":67,"rotated":false}},
{"SPRITE":{"name":"28","x":2106,"y":158,"w":48,"h":69,"rotated":false}},
{"SPRITE":{"name":"29","x":2481,"y":498,"w":48,"h":71,"rotated":false}},
{"SPRITE":{"name":"30","x":1162,"y":1037,"w":48,"h":73,"rotated":false}},
{"SPRITE":{"name":"31","x":4018,"y":188,"w":48,"h":76,"rotated":false}},
{"SPRITE":{"name":"32","x":3455,"y":856,"w":48,"h":78,"rotated":false}},
{"SPRITE":{"name":"33","x":3785,"y":1011,"w":48,"h":81,"rotated":false}},
{"SPRITE":{"name":"34","x":4002,"y":1164,"w":48,"h":82,"rotated":false}},
{"SPRITE":{"name":"35","x":3953,"y":1083,"w":48,"h":87,"rotated":false}},
{"SPRITE":{"name":"36","x":3904,"y":1004,"w":48,"h":90,"rotated":false}},
{"SPRITE":{"name":"37","x":4013,"y":1070,"w":48,"h":93,"rotated":false}},
{"SPRITE":{"name":"38","x":3964,"y":984,"w":48,"h":98,"rotated":false}},
{"SPRITE":{"name":"39","x":1550,"y":985,"w":48,"h":103,"rotated":false}},
{"SPRITE":{"name":"40","x":3848,"y":894,"w":50,"h":109,"rotated":false}},
{"SPRITE":{"name":"41","x":3797,"y":894,"w":50,"h":116,"rotated":false}},
{"SPRITE":{"name":"42","x":2777,"y":452,"w":50,"h":121,"rotated":false}},
{"SPRITE":{"name":"43","x":4002,"y":585,"w":50,"h":119,"rotated":false}},
{"SPRITE":{"name":"44","x":3913,"y":886,"w":50,"h":117,"rotated":false}},
{"SPRITE":{"name":"45","x":3059,"y":2,"w":52,"h":129,"rotated":false}},
{"SPRITE":{"name":"46","x":3964,"y":886,"w":123,"h":45,"rotated":false}},
{"SPRITE":{"name":"47","x":1770,"y":228,"w":123,"h":43,"rotated":false}},
{"SPRITE":{"name":"48","x":3424,"y":486,"w":99,"h":35,"rotated":false}},
{"SPRITE":{"name":"49","x":2979,"y":1141,"w":99,"h":34,"rotated":false}},
{"SPRITE":{"name":"50","x":2979,"y":1141,"w":99,"h":34,"rotated":false}},
{"SPRITE":{"name":"51","x":2590,"y":360,"w":99,"h":36,"rotated":false}},
{"SPRITE":{"name":"52","x":3709,"y":783,"w":35,"h":21,"rotated":false}},
{"SPRITE":{"name":"53","x":1220,"y":711,"w":329,"h":400,"rotated":false}},
{"SPRITE":{"name":"54","x":3042,"y":979,"w":112,"h":161,"rotated":false}},
{"SPRITE":{"name":"55","x":2929,"y":163,"w":199,"h":188,"rotated":false}},
{"SPRITE":{"name":"56","x":2175,"y":574,"w":96,"h":158,"rotated":false}},
{"SPRITE":{"name":"57","x":1623,"y":570,"w":277,"h":134,"rotated":false}},
{"SPRITE":{"name":"58","x":1550,"y":1089,"w":38,"h":22,"rotated":false}},
{"SPRITE":{"name":"59","x":3666,"y":152,"w":124,"h":165,"rotated":false}},
{"SPRITE":{"name":"60","x":1623,"y":272,"w":309,"h":297,"rotated":false}},
{"SPRITE":{"name":"61","x":3801,"y":2,"w":121,"h":91,"rotated":false}},
{"SPRITE":{"name":"62","x":3281,"y":522,"w":320,"h":77,"rotated":false}},
{"SPRITE":{"name":"63","x":3921,"y":755,"w":17,"h":22,"rotated":false}},
{"SPRITE":{"name":"64","x":1351,"y":272,"w":162,"h":74,"rotated":false}},
{"SPRITE":{"name":"65","x":3801,"y":94,"w":69,"h":50,"rotated":false}},
{"SPRITE":{"name":"66","x":2273,"y":574,"w":277,"h":174,"rotated":false}},
{"SPRITE":{"name":"67","x":2261,"y":1136,"w":175,"h":123,"rotated":false}},
{"SPRITE":{"name":"68","x":4058,"y":932,"w":32,"h":49,"rotated":false}},
{"SPRITE":{"name":"69","x":3791,"y":270,"w":66,"h":38,"rotated":false}},
{"SPRITE":{"name":"70","x":3079,"y":1141,"w":71,"h":40,"rotated":false}},
{"SPRITE":{"name":"71","x":2690,"y":360,"w":82,"h":29,"rotated":false}},
{"SPRITE":{"name":"72","x":3602,"y":516,"w":88,"h":69,"rotated":false}},
{"SPRITE":{"name":"73","x":4022,"y":806,"w":69,"h":27,"rotated":false}},
{"SPRITE":{"name":"74","x":1894,"y":228,"w":30,"h":40,"rotated":false}},
{"SPRITE":{"name":"75","x":3987,"y":654,"w":10,"h":13,"rotated":false}},
{"SPRITE":{"name":"76","x":3896,"y":1084,"w":7,"h":7,"rotated":false}},
{"SPRITE":{"name":"77","x":3834,"y":1074,"w":9,"h":9,"rotated":false}},
{"SPRITE":{"name":"78","x":3885,"y":1084,"w":10,"h":10,"rotated":false}},
{"SPRITE":{"name":"79","x":3441,"y":736,"w":12,"h":12,"rotated":false}},
{"SPRITE":{"name":"80","x":3811,"y":1128,"w":19,"h":17,"rotated":false}},
{"SPRITE":{"name":"81","x":3971,"y":654,"w":15,"h":14,"rotated":false}},
{"SPRITE":{"name":"82","x":3858,"y":1150,"w":7,"h":7,"rotated":false}},
{"SPRITE":{"name":"83","x":3794,"y":452,"w":5,"h":5,"rotated":false}},
{"SPRITE":{"name":"84","x":3326,"y":751,"w":32,"h":57,"rotated":false}},
{"SPRITE":{"name":"85","x":2583,"y":147,"w":6,"h":7,"rotated":false}},
{"SPRITE":{"name":"86","x":935,"y":617,"w":198,"h":66,"rotated":false}},
{"SPRITE":{"name":"87","x":426,"y":692,"w":352,"h":436,"rotated":false}},
{"SPRITE":{"name":"88","x":3814,"y":452,"w":156,"h":69,"rotated":false}},
{"SPRITE":{"name":"89","x":2829,"y":452,"w":194,"h":197,"rotated":false}},
{"SPRITE":{"name":"90","x":2670,"y":733,"w":181,"h":216,"rotated":false}},
{"SPRITE":{"name":"91","x":3791,"y":150,"w":93,"h":119,"rotated":false}},
{"SPRITE":{"name":"92","x":4000,"y":372,"w":86,"h":75,"rotated":false}},
{"SPRITE":{"name":"93","x":3587,"y":320,"w":113,"h":195,"rotated":false}},
{"SPRITE":{"name":"94","x":2483,"y":2,"w":80,"h":151,"rotated":false}},
{"SPRITE":{"name":"95","x":3493,"y":2,"w":177,"h":149,"rotated":false}},
{"SPRITE":{"name":"96","x":3327,"y":183,"w":9,"h":8,"rotated":false}},
{"SPRITE":{"name":"97","x":3787,"y":452,"w":6,"h":6,"rotated":false}},
{"SPRITE":{"name":"98","x":4002,"y":705,"w":57,"h":48,"rotated":false}},
{"SPRITE":{"name":"99","x":2574,"y":147,"w":8,"h":8,"rotated":false}},
{"SPRITE":{"name":"100","x":3814,"y":605,"w":8,"h":12,"rotated":false}},
{"SPRITE":{"name":"101","x":1589,"y":1089,"w":9,"h":10,"rotated":false}},
{"SPRITE":{"name":"102","x":3701,"y":318,"w":85,"h":140,"rotated":false}},
{"SPRITE":{"name":"103","x":2,"y":692,"w":423,"h":429,"rotated":false}},
{"SPRITE":{"name":"104","x":3533,"y":152,"w":132,"h":167,"rotated":false}},
{"SPRITE":{"name":"105","x":3249,"y":961,"w":66,"h":16,"rotated":false}},
{"SPRITE":{"name":"106","x":3576,"y":808,"w":52,"h":43,"rotated":false}},
{"SPRITE":{"name":"107","x":3858,"y":1163,"w":46,"h":42,"rotated":false}},
{"SPRITE":{"name":"108","x":3834,"y":1011,"w":13,"h":62,"rotated":false}},
{"SPRITE":{"name":"109","x":3654,"y":1025,"w":34,"h":29,"rotated":false}},
{"SPRITE":{"name":"110","x":3811,"y":1150,"w":46,"h":65,"rotated":false}},
{"SPRITE":{"name":"111","x":3701,"y":459,"w":112,"h":46,"rotated":false}},
{"SPRITE":{"name":"112","x":2035,"y":898,"w":226,"h":223,"rotated":false}},
{"SPRITE":{"name":"113","x":3233,"y":351,"w":190,"h":170,"rotated":false}},
{"SPRITE":{"name":"114","x":3654,"y":1060,"w":58,"h":55,"rotated":false}},
{"SPRITE":{"name":"115","x":3885,"y":94,"w":112,"h":94,"rotated":false}},
{"SPRITE":{"name":"116","x":3576,"y":706,"w":132,"h":101,"rotated":false}},
{"SPRITE":{"name":"117","x":1939,"y":493,"w":235,"h":239,"rotated":false}},
{"SPRITE":{"name":"118","x":3242,"y":1150,"w":141,"h":111,"rotated":false}},
{"SPRITE":{"name":"119","x":2822,"y":2,"w":236,"h":160,"rotated":false}},
{"SPRITE":{"name":"120","x":2475,"y":749,"w":194,"h":236,"rotated":false}},
{"SPRITE":{"name":"121","x":3455,"y":736,"w":120,"h":119,"rotated":false}},
{"SPRITE":{"name":"122","x":2551,"y":398,"w":225,"h":189,"rotated":false}},
{"SPRITE":{"name":"123","x":3923,"y":2,"w":130,"h":81,"rotated":false}},
{"SPRITE":{"name":"124","x":3691,"y":621,"w":132,"h":83,"rotated":false}},
{"SPRITE":{"name":"125","x":3531,"y":1025,"w":122,"h":80,"rotated":false}},
{"SPRITE":{"name":"126","x":3814,"y":522,"w":129,"h":82,"rotated":false}},
{"SPRITE":{"name":"127","x":3709,"y":705,"w":125,"h":77,"rotated":false}},
{"SPRITE":{"name":"128","x":3885,"y":189,"w":132,"h":76,"rotated":false}},
{"SPRITE":{"name":"129","x":2035,"y":1122,"w":225,"h":142,"rotated":false}},
{"SPRITE":{"name":"130","x":2777,"y":187,"w":151,"h":264,"rotated":false}},
{"SPRITE":{"name":"131","x":2551,"y":588,"w":277,"h":144,"rotated":false}},
{"SPRITE":{"name":"132","x":3327,"y":197,"w":205,"h":140,"rotated":false}},
{"SPRITE":{"name":"133","x":2175,"y":401,"w":305,"h":172,"rotated":false}},
{"SPRITE":{"name":"134","x":2841,"y":1136,"w":137,"h":129,"rotated":false}},
{"SPRITE":{"name":"135","x":3129,"y":172,"w":197,"h":178,"rotated":false}},
{"SPRITE":{"name":"136","x":2,"y":1122,"w":364,"h":131,"rotated":false}},
{"SPRITE":{"name":"137","x":3424,"y":338,"w":162,"h":147,"rotated":false}},
{"SPRITE":{"name":"138","x":1933,"y":228,"w":223,"h":264,"rotated":false}},
{"SPRITE":{"name":"139","x":1351,"y":2,"w":418,"h":269,"rotated":false}},
{"SPRITE":{"name":"140","x":1599,"y":1133,"w":350,"h":113,"rotated":false}},
{"SPRITE":{"name":"141","x":1599,"y":985,"w":435,"h":147,"rotated":false}},
{"SPRITE":{"name":"142","x":3921,"y":670,"w":80,"h":84,"rotated":false}},
{"SPRITE":{"name":"143","x":2564,"y":147,"w":9,"h":8,"rotated":false}},
{"SPRITE":{"name":"144","x":2437,"y":1168,"w":31,"h":27,"rotated":false}},
{"SPRITE":{"name":"145","x":3664,"y":808,"w":110,"h":88,"rotated":false}},
{"SPRITE":{"name":"146","x":3024,"y":608,"w":43,"h":39,"rotated":false}},
{"SPRITE":{"name":"147","x":3563,"y":1106,"w":55,"h":58,"rotated":false}},
{"SPRITE":{"name":"148","x":3971,"y":619,"w":19,"h":34,"rotated":false}},
{"SPRITE":{"name":"149","x":3416,"y":1250,"w":30,"h":23,"rotated":false}},
{"SPRITE":{"name":"150","x":1939,"y":898,"w":82,"h":85,"rotated":false}},
{"SPRITE":{"name":"151","x":4054,"y":39,"w":34,"h":41,"rotated":false}},
{"SPRITE":{"name":"152","x":3691,"y":516,"w":122,"h":104,"rotated":false}},
{"SPRITE":{"name":"153","x":3762,"y":1060,"w":17,"h":32,"rotated":false}},
{"SPRITE":{"name":"154","x":3745,"y":783,"w":28,"h":20,"rotated":false}},
{"SPRITE":{"name":"155","x":3524,"y":486,"w":45,"h":35,"rotated":false}},
{"SPRITE":{"name":"156","x":4000,"y":266,"w":74,"h":105,"rotated":false}},
{"SPRITE":{"name":"157","x":3775,"y":836,"w":137,"h":57,"rotated":false}},
{"SPRITE":{"name":"158","x":3384,"y":1250,"w":31,"h":23,"rotated":false}},
{"SPRITE":{"name":"159","x":3504,"y":908,"w":24,"h":24,"rotated":false}},
{"SPRITE":{"name":"160","x":4013,"y":984,"w":55,"h":85,"rotated":false}},
{"SPRITE":{"name":"161","x":4054,"y":2,"w":40,"h":36,"rotated":false}},
{"SPRITE":{"name":"162","x":3775,"y":783,"w":163,"h":52,"rotated":false}},
{"SPRITE":{"name":"163","x":1950,"y":1133,"w":73,"h":115,"rotated":false}},
{"SPRITE":{"name":"164","x":3531,"y":962,"w":159,"h":62,"rotated":false}},
{"SPRITE":{"name":"165","x":3811,"y":1093,"w":20,"h":34,"rotated":false}},
{"SPRITE":{"name":"166","x":4067,"y":230,"w":27,"h":32,"rotated":false}},
{"SPRITE":{"name":"167","x":4067,"y":188,"w":24,"h":41,"rotated":false}},
{"SPRITE":{"name":"168","x":3504,"y":856,"w":26,"h":51,"rotated":false}},
{"SPRITE":{"name":"169","x":2929,"y":352,"w":86,"h":98,"rotated":false}},
{"SPRITE":{"name":"170","x":3824,"y":605,"w":146,"h":64,"rotated":false}},
{"SPRITE":{"name":"171","x":1589,"y":1100,"w":9,"h":10,"rotated":false}},
{"SPRITE":{"name":"172","x":3327,"y":172,"w":8,"h":10,"rotated":false}},
{"SPRITE":{"name":"173","x":3939,"y":806,"w":82,"h":27,"rotated":false}},
{"SPRITE":{"name":"174","x":3944,"y":522,"w":141,"h":62,"rotated":false}},
{"SPRITE":{"name":"175","x":3024,"y":352,"w":208,"h":169,"rotated":false}},
{"SPRITE":{"name":"176","x":3129,"y":2,"w":208,"h":169,"rotated":false}},
{"SPRITE":{"name":"177","x":3042,"y":814,"w":206,"h":164,"rotated":false}},
{"SPRITE":{"name":"178","x":3072,"y":522,"w":208,"h":161,"rotated":false}},
{"SPRITE":{"name":"179","x":779,"y":1037,"w":382,"h":218,"rotated":false}},
{"SPRITE":{"name":"180","x":935,"y":357,"w":237,"h":259,"rotated":false}},
{"SPRITE":{"name":"181","x":3155,"y":979,"w":86,"h":203,"rotated":false}},
{"SPRITE":{"name":"182","x":3364,"y":751,"w":90,"h":183,"rotated":false}},
{"SPRITE":{"name":"183","x":3357,"y":961,"w":91,"h":188,"rotated":false}},
{"SPRITE":{"name":"184","x":2852,"y":814,"w":185,"h":122,"rotated":false}},
{"SPRITE":{"name":"185","x":3787,"y":318,"w":89,"h":133,"rotated":false}},
{"SPRITE":{"name":"186","x":2590,"y":187,"w":183,"h":172,"rotated":false}},
{"SPRITE":{"name":"187","x":3242,"y":979,"w":114,"h":151,"rotated":false}},
{"SPRITE":{"name":"188","x":4047,"y":834,"w":42,"h":36,"rotated":false}},
{"SPRITE":{"name":"189","x":1134,"y":617,"w":53,"h":63,"rotated":false}},
{"SPRITE":{"name":"190","x":3166,"y":1183,"w":67,"h":80,"rotated":false}},
{"SPRITE":{"name":"191","x":3848,"y":1004,"w":55,"h":79,"rotated":false}},
{"SPRITE":{"name":"192","x":3834,"y":1084,"w":50,"h":65,"rotated":false}},
{"SPRITE":{"name":"193","x":3629,"y":808,"w":33,"h":43,"rotated":false}},
{"SPRITE":{"name":"194","x":3493,"y":152,"w":26,"h":38,"rotated":false}},
{"SPRITE":{"name":"195","x":3971,"y":585,"w":23,"h":33,"rotated":false}},
{"SPRITE":{"name":"196","x":2530,"y":498,"w":20,"h":24,"rotated":false}},
{"SPRITE":{"name":"197","x":3939,"y":755,"w":121,"h":50,"rotated":false}},
{"SPRITE":{"name":"198","x":3913,"y":836,"w":133,"h":49,"rotated":false}},
{"SPRITE":{"name":"199","x":3971,"y":449,"w":119,"h":69,"rotated":false}},
{"SPRITE":{"name":"200","x":3072,"y":684,"w":253,"h":125,"rotated":false}},
{"SPRITE":{"name":"201","x":3441,"y":600,"w":116,"h":135,"rotated":false}},
{"SPRITE":{"name":"202","x":2475,"y":986,"w":194,"h":224,"rotated":false}},
{"SPRITE":{"name":"203","x":1770,"y":2,"w":335,"h":225,"rotated":false}},
{"SPRITE":{"name":"204","x":2157,"y":158,"w":217,"h":242,"rotated":false}},
{"SPRITE":{"name":"205","x":3249,"y":810,"w":114,"h":150,"rotated":false}},
{"SPRITE":{"name":"206","x":3326,"y":600,"w":114,"h":150,"rotated":false}},
{"SPRITE":{"name":"207","x":3835,"y":670,"w":85,"h":87,"rotated":false}},
{"SPRITE":{"name":"208","x":3671,"y":2,"w":129,"h":147,"rotated":false}},
{"SPRITE":{"name":"209","x":2852,"y":650,"w":219,"h":163,"rotated":false}},
{"SPRITE":{"name":"210","x":3338,"y":2,"w":154,"h":194,"rotated":false}},
{"SPRITE":{"name":"211","x":1514,"y":272,"w":108,"h":68,"rotated":false}},
{"SPRITE":{"name":"212","x":3664,"y":897,"w":132,"h":64,"rotated":false}},
{"SPRITE":{"name":"213","x":2437,"y":1211,"w":160,"h":62,"rotated":false}},
{"SPRITE":{"name":"214","x":3449,"y":935,"w":81,"h":188,"rotated":false}},
{"SPRITE":{"name":"215","x":2841,"y":950,"w":200,"h":185,"rotated":false}},
{"SPRITE":{"name":"216","x":3384,"y":1150,"w":63,"h":99,"rotated":false}},
{"SPRITE":{"name":"217","x":2481,"y":398,"w":63,"h":99,"rotated":false}},
{"SPRITE":{"name":"218","x":3558,"y":600,"w":132,"h":105,"rotated":false}},
{"SPRITE":{"name":"219","x":3531,"y":856,"w":132,"h":105,"rotated":false}},
{"SPRITE":{"name":"220","x":2590,"y":2,"w":231,"h":184,"rotated":false}},
{"SPRITE":{"name":"221","x":2670,"y":950,"w":170,"h":224,"rotated":false}},
{"SPRITE":{"name":"222","x":2273,"y":749,"w":198,"h":144,"rotated":false}},
{"SPRITE":{"name":"223","x":3691,"y":962,"w":93,"h":53,"rotated":false}},
{"SPRITE":{"name":"224","x":2979,"y":1183,"w":186,"h":91,"rotated":false}},
{"SPRITE":{"name":"225","x":1939,"y":733,"w":333,"h":164,"rotated":false}},
{"SPRITE":{"name":"226","x":935,"y":2,"w":415,"h":354,"rotated":false}},
{"SPRITE":{"name":"227","x":1220,"y":357,"w":402,"h":353,"rotated":false}},
{"SPRITE":{"name":"228","x":3998,"y":84,"w":90,"h":103,"rotated":false}},
{"SPRITE":{"name":"229","x":2375,"y":158,"w":214,"h":239,"rotated":false}},
{"SPRITE":{"name":"230","x":2262,"y":898,"w":212,"h":237,"rotated":false}}]},
"meta":{
"app":"Adobe Animate (Better TA Extension)",
"version":"22.0.3.179",
"image":"spritemap1.png",
"format":"RGBA8888",
"size":{"w":4096,"h":1280},
"resolution":"1"
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 642 KiB

After

Width:  |  Height:  |  Size: 1.2 MiB

+11 -3
View File
@@ -203,6 +203,7 @@
<str id="paste">Paste</str>
<str id="cut">Cut</str>
<str id="delete">Delete</str>
<str id="deletestacked">Delete Stacked Notes</str>
</group>
<str id="topBar.chart">Chart</str>
@@ -223,6 +224,7 @@
<str id="resetZoom">Reset Zoom</str>
<str id="showSectionsSeparator">Show Sections Separator</str>
<str id="showBeatsSeparator">Show Beats Separator</str>
<str id="showCameraHighlights">Show Camera Highlights</str>
<str id="rainbowWaveforms">Rainbow Waveforms</str>
<str id="lowDetailWaveforms">Low Detail Waveforms</str>
<str id="scrollLeft">Scroll Left</str>
@@ -236,8 +238,9 @@
<str id="goEnd">Go forward to the end</str> <!-- used to be "Go to the end" -->
<str id="addOpponentCamera">Add camera on Opponent</str>
<str id="addPlayerCamera">Add camera on Player</str>
<str id="muteInst">Mute instrumental</str>
<str id="muteVoices">Mute voices</str>
<str id="inst">Instrumental</str>
<str id="voices">Voices</str>
<str id="hitsounds">Hitsounds</str>
</group>
<group name="BookmarkMenu" prefix="bookmarks.">
@@ -250,6 +253,7 @@
<str id="editBookmarkListTitle">Bookmark List</str>
<str id="editBookmarksTitle">Edit Bookmarks</str>
<str id="newBookmarkName">New Bookmark</str>
<str id="bookmarkList">Bookmark List</str>
</group>
<str id="topBar.note">Note</str>
@@ -258,6 +262,7 @@
<str id="subtractSustainLength">Subtract sustain length</str>
<str id="selectAll">Select all</str>
<str id="selectMeasure">Select measure</str>
<str id="noteTypesList">Note Types List</str>
<str id="editNoteTypesList">Edit Note Types List</str>
</group>
<str id="topBar.snap">Snap</str>
@@ -308,8 +313,9 @@
<group name="StrumlineOptions" prefix="strumLine.">
<str id="button-name">Options ↓</str>
<str id="waveforms">Waveforms</str>
<str id="hitsounds">Hitsounds</str>
<str id="muteVocals">Mute Vocals</str>
<str id="vocals">Vocals</str>
<str id="edit">Edit</str>
<str id="delete">Delete</str>
@@ -433,6 +439,8 @@
<str id="position">Position (X, Y)</str>
<str id="fps">FPS</str>
<str id="indices">Indices (Frames)</str>
<str id="looping">Looping?</str>
<str id="label">Label</str>
</group>
<group name="CharacterSpriteScreen" prefix="characterSpriteScreen.">
+2 -1
View File
@@ -16,7 +16,7 @@
<str id="animation">Animación</str>
<str id="atlas">Atlas</str>
<str id="spritemap">Mapa de sprites</str>
<str id="directory">Ubicación ({0}/)</str>
<str id="found">{0} {1} Encontrado</str>
<str id="foundplural">{0} {1} Encontrados</str>
@@ -188,6 +188,7 @@
<str id="paste">Pegar</str>
<str id="cut">Cortar</str>
<str id="delete">Eliminar</str>
<str id="deletestacked">Eliminar Notas Apiladas</str>
</group>
<str id="topBar.chart">Chart</str>
+1
View File
@@ -194,6 +194,7 @@
<str id="paste">Incolla</str>
<str id="cut">Taglia</str>
<str id="delete">Elimina</str>
<str id="deletestacked">Elimina Note Impilate</str>
</group>
<str id="topBar.chart">Chart</str>
+4 -3
View File
@@ -18,7 +18,7 @@
<str id="animation">Animacja</str>
<str id="atlas">Atlas</str>
<str id="spritemap">Mapa sprite'ów</str>
<str id="directory">Folder ({0}/)</str>
<str id="found">{0} {1} Znaleziono</str>
<str id="foundplural">{0} {1} Znaleziono</str>
@@ -87,7 +87,7 @@
<group name="CharterEventScreen" prefix="charterEventScreen.">
<str id="title-creating">Stwórz Grupę Wydarzeń</str>
<str id="title-editing">Edytuj Grupę Wydarzeń</str>
<str id="noEvent">Brak Wydarzenia</str>
<str id="strumLine.format">Struma #{0} ({1})</str>
@@ -197,6 +197,7 @@
<str id="paste">Wklej</str>
<str id="cut">Wytnij</str>
<str id="delete">Usuń</str>
<str id="deletestacked">Usuń Notatki Ułożone w Stos</str>
</group>
<str id="topBar.chart">Mapa</str>
@@ -223,7 +224,7 @@
<str id="scrollRight">Przewiń w Prawo</str>
<str id="scrollReset">Resetuj Przewinięcie</str>
</group>
<str id="topBar.song">Ścieżka</str>
<group name="SongMenu" prefix="song.">
<str id="goStart">Wróć do początku</str>
+1
View File
@@ -203,6 +203,7 @@
<str id="paste">Colar</str>
<str id="cut">Cortar</str>
<str id="delete">Apagar</str>
<str id="deletestacked">Apagar Notas Empilhadas</str>
</group>
<str id="topBar.chart">Mapa</str>
+16 -2
View File
@@ -1,6 +1,5 @@
#pragma header
// Used in charter by waveforms
#version 120 // this shader doesnt require expensive calculations
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);
@@ -18,6 +17,21 @@ uniform vec2 waveformSize;
uniform bool lowDetail;
float catmullRom(
float p0, float p1, float p2, float p3,
float t
) {
float t2 = t * t;
float t3 = t2 * t;
return 0.5 * (
(2.0 * p1) +
(-p0 + p2) * t +
(2.0*p0 - 5.0*p1 + 4.0*p2 - p3) * t2 +
(-p0 + 3.0*p1 - 3.0*p2 + p3) * t3
);
}
float getAmplitude(vec2 pixel) {
float pixelID = floor((pixel.y+pixelOffset)/3.0);
+2 -2
View File
@@ -12,7 +12,7 @@ function create() {
tankman = new FunkinSprite(game.dad.x + game.dad.globalOffset.x + 520, game.dad.y + game.dad.globalOffset.y + 225);
tankman.antialiasing = true;
tankman.loadSprite(Paths.image('game/cutscenes/tank/guns-tankman'));
tankman.animateAtlas.anim.addBySymbol('tank', 'TANK TALK 2', 0, false);
tankman.addAnim('tank', 'TANK TALK 2', 0, false);
game.insert(game.members.indexOf(game.dad), tankman);
game.dad.visible = false;
@@ -65,4 +65,4 @@ function destroy() {
for(thing in [tankman, tankTalk]) thing.destroy();
if(destroyDistorto) distorto.destroy();
FlxTween.tween(FlxG.camera, {zoom: game.defaultCamZoom}, 0.7, {ease: FlxEase.quadInOut, startDelay: 0});
}
}
+13 -9
View File
@@ -33,20 +33,20 @@ function create() {
tankman = new FunkinSprite(game.dad.x + game.dad.globalOffset.x + 520, game.dad.y + game.dad.globalOffset.y + 225);
tankman.antialiasing = true;
tankman.loadSprite(Paths.image('game/cutscenes/tank/stress-tankman'));
tankman.animateAtlas.anim.addBySymbol('p1', 'TANK TALK 3 P1 UNCUT', 0, false);
tankman.animateAtlas.anim.addBySymbol('p2', 'TANK TALK 3 P2 UNCUT', 0, false);
tankman.addAnim('p1', 'TANK TALK 3 P1 UNCUT', 0, false);
tankman.addAnim('p2', 'TANK TALK 3 P2 UNCUT', 0, false);
tankman.playAnim('p1');
pico = new FunkinSprite(game.gf.x + game.gf.globalOffset.x + 150, game.gf.y + game.gf.globalOffset.y + 395);
pico = new FunkinSprite(game.gf.x + game.gf.globalOffset.x - 615, game.gf.y + game.gf.globalOffset.y - 130);
pico.antialiasing = true;
pico.loadSprite(Paths.image('game/cutscenes/tank/stress-pico'));
pico.animateAtlas.anim.addBySymbol('die', 'GF Time to Die sequence', 24, false);
pico.animateAtlas.anim.addBySymbol('saves', 'Pico Saves them sequence', 24, false);
pico.animateAtlas.anim.addBySymbol('idle', 'Pico Dual Wield on Speaker idle', 24, true);
pico.addAnim('die', 'die', 24, false, null, null, 0, 0, null, true);
pico.addAnim('saves', 'saves', 24, false, null, null, 0, 0, null, true);
pico.addAnim('idle', 'idle', 24, true, null, null, 0, 0, null, true);
pico.scrollFactor.set(0.95, 0.95);
pico.playAnim("idle");
pico.visible = false;
game.insert(game.members.indexOf(game.gf) + 1, pico);
game.insert(game.members.indexOf(game.gf) + 2, pico);
game.insert(game.members.indexOf(game.dad) + 1, tankman);
game.dad.visible = false;
@@ -59,7 +59,11 @@ function update(elapsed) {
lipSync(tankman, 0, 16750);
if (stressCutscene.time > 15100) {
step = 1;
focusOn(game.gf);
//focusOn(game.gf);
game.camFollow.x += 350;
game.camFollow.y -= 200;
pico.visible = true;
pico.playAnim('die', true);
@@ -118,7 +122,7 @@ function update(elapsed) {
}
function lipSync(char:FunkinSprite, begin:Float, end:Float) {
char.animateAtlas.anim.curFrame = Std.int(FlxMath.remapToRange(stressCutscene.time, begin, end, 0, char.animateAtlas.anim.length-1));
char.anim.curAnim.curFrame = Std.int(FlxMath.remapToRange(stressCutscene.time, begin, end, 0, char.anim.curAnim.numFrames - 1));
}
function focusOn(char, snap:Bool = false) {
+3 -3
View File
@@ -12,8 +12,8 @@ function create() {
tankman = new FunkinSprite(game.dad.x + game.dad.globalOffset.x + 520, game.dad.y + game.dad.globalOffset.y + 225);
tankman.antialiasing = true;
tankman.loadSprite(Paths.image('game/cutscenes/tank/ugh-tankman'));
tankman.animateAtlas.anim.addBySymbol('1', 'TANK TALK 1 P1', 0, false);
tankman.animateAtlas.anim.addBySymbol('2', 'TANK TALK 1 P2', 0, false);
tankman.addAnim('1', 'TANK TALK 1 P1', 0, false);
tankman.addAnim('2', 'TANK TALK 1 P2', 0, false);
game.insert(game.members.indexOf(game.dad), tankman);
game.dad.visible = false;
@@ -77,4 +77,4 @@ function destroy() {
for(timer in timers) timer.cancel();
for(thing in [tankTalk1, tankTalk2, bfBeep, tankman]) thing.destroy();
if(destroyDistorto) distorto.destroy();
}
}
-17
View File
@@ -1,17 +0,0 @@
[General]
sample-type=float32
stereo-mode=speakers
hrtf=false
cf_level=0
output-limiter=false
front-stabilizer=false
volume-adjust=0
period_size=441
sources=512
sends=64
dither=false
[decoder]
hq-mode=true
distance-comp=true
nfc=false
+26 -29
View File
@@ -3,36 +3,32 @@
<if cond="update || all">
<print pretty="true">Preparing installation...</print>
<!-- OpenFL & Lime (Required for Flixel) -->
<git name="openfl" url="https://github.com/CodenameCrew/cne-openfl" />
<lib name="lime" version="8.1.2" />
<!-- <git name="lime" url="https://github.com/CodenameCrew/cne-lime" /> disabled for now until fixed -->
<!-- Hxcpp & OpenFL & Lime (Required for Flixel) -->
<git name="hxcpp" url="https://github.com/CodenameCrew/cne-hxcpp"/>
<git name="openfl" url="https://github.com/CodenameCrew/cne-openfl" ref="cne" skipDeps="true"/>
<git name="lime" url="https://github.com/CodenameCrew/cne-lime" ref="cne" skipDeps="true"/>
<!-- Flixel -->
<git name="flixel" url="https://github.com/CodenameCrew/cne-flixel" />
<git name="flixel-addons" url="https://github.com/CodenameCrew/cne-flixel-addons" />
<git name="flixel" url="https://github.com/CodenameCrew/cne-flixel" ref="cne" skipDeps="true"/>
<git name="flixel-addons" url="https://github.com/CodenameCrew/cne-flixel-addons" ref="dev" skipDeps="true"/>
<!-- CNE Core Libraries -->
<git name="flixel-animate" url="https://github.com/CodenameCrew/cne-flixel-animate" skipDeps="true"/>
<git name="hscript-improved" url="https://github.com/CodenameCrew/hscript-improved" ref="codename-dev"/>
<git name="away3d" url="https://github.com/CodenameCrew/away3d" skipDeps="true"/>
<!-- Other Libraries -->
<git name="hscript-improved" url="https://github.com/CodenameCrew/hscript-improved" ref="codename-dev" />
<git name="flxanimate" url="https://github.com/CodenameCrew/cne-flxanimate" />
<git name="hxdiscord_rpc" url="https://github.com/CodenameCrew/cne-hxdiscord_rpc" skipDeps="true" />
<lib name="funkin-modchart" version="1.2.4" skipDeps="true" />
<lib name="hxvlc" version="1.9.3" skipDeps="true" />
<git name="bin-serializer" url="https://github.com/CodenameCrew/bin-serializer" />
<!-- Documentation and other features -->
<git name="away3d" url="https://github.com/CodenameCrew/away3d" />
<!-- <lib name="dox" /> -->
<lib name="markdown" />
<lib name="hxcpp-debug-server" />
<lib name="nape-haxe4" />
<git name="hxdiscord_rpc" url="https://github.com/CodenameCrew/cne-hxdiscord_rpc" skipDeps="true"/>
<git name="hxvlc" url="https://github.com/CodenameCrew/cne-hxvlc" skipDeps="true"/>
<lib name="funkin-modchart" skipDeps="true"/>
<lib name="hxcpp-debug-server"/>
<lib name="format"/>
<lib name="markdown"/>
<lib name="nape-haxe4"/>
<!-- For building lime -->
<lib global="true" name="hxp" /> <lib name="hxp" />
<lib global="true" name="format" /> <lib name="format" />
<git name="hxcpp" url="https://github.com/CodenameCrew/cne-hxcpp" />
<!-- <lib global="true" name="hxp"/> <lib name="hxp"/> -->
<!-- <lib global="true" name="format"/> <lib name="format"/> -->
</if>
<!-- Hxcpp Building -->
@@ -41,15 +37,16 @@
<!-- Build hxcpp -->
<cmd inLib="hxcpp" dir="tools/hxcpp" cmd="haxe compile.hxml" />
<cmd inLib="lime" cmd="haxelib run lime rebuild hxcpp"/>
</if>
<!-- Lime Building -->
<!-- <if cond="build-lime || all">
<if cond="build-lime">
<print pretty="true">Rebuilding Lime...</print>
<!- - Build lime - ->
<cmd inLib="lime" cmd="haxelib run lime rebuild . $PLATFORM -release -clean" />
<cmd inLib="lime" dir="tools" cmd="haxe tools.hxml" />
</if> -->
<!-- Build lime -->
<cmd inLib="lime" dir="tools" cmd="haxe tools.hxml"/>
<cmd inLib="lime" cmd="haxelib run lime rebuild $PLATFORM -nocolor -nocffi -release"/>
</if>
</libraries>
+150 -149
View File
@@ -1,78 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<project>
<!-- _________________________ Application Settings _________________________ -->
<app
title="Friday Night Funkin' - Codename Engine" main="funkin.backend.system.Main"
file="CodenameEngine" packageName="com.codenamecrew.codenameengine"
package="com.codenamecrew.codenameengine"
version="1.0.1" company="CodenameCrew" />
<!--
CHANGE THE SAVE PATH & NAME FOR YOUR HARDCODED MOD HERE!
-->
<haxedef name="SAVE_PATH" value="CodenameCrew/CodenameEngine"/>
<haxedef name="SAVE_NAME" value="save-default"/>
<!--Switch Export with Unique ApplicationID and Icon-->
<set name="APP_ID" value="0x0100f6c013bbc000" />
<!-- DO NOT REMOVE!! ALLOWS ME TO DO REGIONS LIKE IN C# AND KEEP CODE ORGANIZED. REMOVING IT WOULD BREAK THE ENGINE -->
<haxedef name="REGION" />
<!--The flixel preloader is not accurate in Chrome. You can use it regularly if you embed the swf into a html file
or you can set the actual size of your file manually at "FlxPreloaderBase-onUpdate-bytesTotal"-->
<app preloader="flixel.system.FlxPreloader" />
<!--Minimum without FLX_NO_GAMEPAD: 11.8, without FLX_NO_NATIVE_CURSOR: 11.2-->
<set name="SWF_VERSION" value="11.8" />
<project xmlns="http://lime.software/project/1.0.4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://lime.software/project/1.0.4 http://lime.software/xsd/project-1.0.4.xsd">
<!-- ____________________________ Window Settings ___________________________ -->
<!--These window settings apply to all targets-->
<window width="1280" height="720" background="#000000" hardware="true" vsync="false" />
<!-- CHANGE THE SAVE PATH & NAME FOR YOUR MOD HERE! -->
<haxedef name="SAVE_PATH" value="CodenameEngine"/>
<haxedef name="SAVE_NAME" value="save-default"/>
<!--HTML5-specific-->
<window if="html5" resizable="true" />
<haxedef name="SAVE_OPTIONS_PATH" value="CodenameEngine"/>
<haxedef name="SAVE_OPTIONS_NAME" value="options"/>
<!--Desktop-specific-->
<window if="desktop" orientation="landscape" fullscreen="false" resizable="true" vsync="false"/>
<window if="mac" allow-high-dpi="true" />
<!-- Comment this out to disable commit number on FPS -->
<define name="SHOW_BUILD_ON_FPS"/>
<!--Mobile-specific-->
<window if="mobile" orientation="landscape" fullscreen="true" width="0" height="0" resizable="false"/>
<!-- Comment this out to disable dark mode windows -->
<define name="DARK_MODE_WINDOW"/>
<!--Switch-specific-->
<window if="switch" orientation="landscape" fullscreen="true" width="0" height="0" resizable="true" />
<!-- Should it checks for updates? -->
<define name="UPDATE_CHECKING" if="desktop" unless="hl || debug"/>
<!-- _________________________________ Engine Settings _______________________________ -->
<!-- Comment this out to disable updates !-->
<define name="UPDATE_CHECKING" unless="web || hl || neko || debug"/>
<!-- Comment this out to disable Discord RPC !-->
<section if="cpp">
<define name="DISCORD_RPC" if="desktop"/>
<!-- Compile With Discord Rich Presence -->
<!-- TODO: Update Discord RPC Library & Rewrite DiscordUtil -->
<!-- <define name="DISCORD_RPC" if="desktop"/> -->
<!-- Compile with video support (hxvlc) -->
<define name="VIDEO_CUTSCENES" if="desktop || mobile"/>
</section>
<!-- Uncomment this to achive faster compile times, will strip extraneous and commonly unused features. -->
<!-- <define name="STRIPPED_COMPILE" unless="debug"/> -->
<!-- Comment this out to disable modcharting features -->
<define name="MODCHARTING_FEATURES" unless="STRIPPED_COMPILE" />
<!-- Compile with _theo0p's modcharting tools -->
<define name="MODCHARTING_FEATURES" unless="STRIPPED_COMPILE"/>
<!-- Comment this out to disable GitHub API integration !-->
<define name="GITHUB_API" unless="web || hl"/>
<!-- Comment this out to prevent unused classes from being compiled.
Reduces compilation time at the cost of limited HScript flexibility. !-->
<define name="COMPILE_ALL_CLASSES" unless="STRIPPED_COMPILE" />
<define name="COMPILE_ALL_CLASSES" unless="STRIPPED_COMPILE"/>
<!-- Comment this out to prevent extending classes in hscript.
Reduces compilation time at the cost of limited HScript flexibility. !-->
<define name="CUSTOM_CLASSES" unless="STRIPPED_COMPILE" />
<define name="CUSTOM_CLASSES" unless="STRIPPED_COMPILE"/>
<!-- Comment this out to disable abstract support in hscript. !-->
<haxedef name="HSCRIPT_ABSTRACT_SUPPORT" unless="STRIPPED_COMPILE" />
<!-- Comment this out to disable multithreading !-->
<haxedef name="ALLOW_MULTITHREADING" unless="web || flash" />
<haxedef name="ALLOW_MULTITHREADING" if="cpp"/>
<!-- Comment this out to disable mods folder !-->
<haxedef name="MOD_SUPPORT" unless="web"/>
@@ -81,36 +57,60 @@
<haxedef name="TRANSLATIONS_SUPPORT"/>
<!-- Comment this out to disable global scripts !-->
<haxedef name="GLOBAL_SCRIPT" />
<haxedef name="GLOBAL_SCRIPT"/>
<!-- Comment this out to disable softcoded states and state scripting !-->
<haxedef name="SOFTCODED_STATES" />
<haxedef name="SOFTCODED_STATES"/>
<!-- Comment this out to disable support for custom ndlls. !-->
<haxedef name="NDLLS_SUPPORTED" unless="web || iphonesim || hl" />
<haxedef name="NDLLS_SUPPORTED" unless="web || iphonesim || hl"/>
<!-- Comment this out to use the default OpenFL assets system for the assets/ folder. !-->
<define name="USE_ADAPTED_ASSETS" unless="web" />
<define name="USE_ADAPTED_ASSETS" unless="web"/>
<!-- Comment this out to disable support for Away3D Flixel Integration (reduces compile times) !-->
<define name="THREE_D_SUPPORT" unless="STRIPPED_COMPILE" />
<define name="THREE_D_SUPPORT" unless="STRIPPED_COMPILE"/>
<!-- Comment this out to disable support for Nape integration (flixel.addons.nape) (reduces compile times) !-->
<define name="NAPE_ENABLED" unless="STRIPPED_COMPILE" />
<!-- Comment this out to disable video cutscene support, in case of compilation errors. !-->
<section if="cpp">
<define name="VIDEO_CUTSCENES" if="desktop || android" />
</section>
<!-- Comment this out to disable commit number on FPS -->
<define name="SHOW_BUILD_ON_FPS" />
<!-- Comment this out to disable dark mode windows -->
<define name="DARK_MODE_WINDOW"/>
<define name="NAPE_ENABLED" unless="STRIPPED_COMPILE"/>
<!-- Disable a optimization, to allow reflection to use more functions -->
<define name="FLX_NO_GENERIC" />
<define name="FLX_NO_GENERIC"/>
<!-- _________________________ Application Settings _________________________ -->
<app
title="Friday Night Funkin' - Codename Engine"
file="CodenameEngine" packageName="com.yoshman29.codenameengine"
package="com.yoshman29.codenameengine"
version="1.0.2" company="Yoshman29"/>
<!--Switch Export with Unique ApplicationID and Icon-->
<set name="APP_ID" value="0x0100f6c013bbc000"/>
<!--<set name="SWF_VERSION" value="11.8"/>-->
<!--Place custom nodes like icons here (higher priority to override the HaxeFlixel icon)-->
<icon path="art/icon16.png" size='16'/>
<icon path="art/icon32.png" size='24'/>
<icon path="art/icon32.png" size='32'/>
<icon path="art/icon64.png" size='40'/>
<icon path="art/icon64.png" size='48'/>
<icon path="art/icon64.png" size='64'/>
<icon path="art/iconOG.png" size='96'/>
<icon path="art/iconOG.png" size='128'/>
<icon path="art/iconOG.png" size='196'/>
<icon path="art/iconOG.png" size='256'/>
<icon path="art/iconOG.png" size='512'/>
<icon path="art/iconOG.png" size='768'/>
<icon path="art/iconOG.png" size='1024'/>
<!-- ____________________________ Window Settings ___________________________ -->
<window hardware="true" colorDepth="32" background="" fps="0" orientation="landscape"/>
<window unless="desktop" width="0" height="0" vsync="true" fullscreen="true"/>
<window if="desktop" type="opengl" width="1280" height="720" fullscreen="false" resizable="true" vsync="false" allowHighDPI="true"/>
<window if="mobile" resizable="false"/>
<window if="html5 || switch" resizable="true"/>
<!-- _______________________________ Libraries ______________________________ -->
@@ -118,33 +118,46 @@
<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" />
<haxelib name="flixel-addons" />
<haxelib name="flixel-addons"/>
<haxelib name="flixel-animate"/>
<haxelib name="hxvlc" if="VIDEO_CUTSCENES" />
<haxelib name="away3d" if="THREE_D_SUPPORT" />
<haxelib name="format" />
<haxelib name="flxanimate" />
<haxelib name="bin-serializer" />
<haxelib name="hscript-improved"/>
<haxelib name="format" unless="STRIPPED_COMPILE"/>
<haxelib name="markdown" unless="STRIPPED_COMPILE"/>
<haxelib name="hxvlc" if="VIDEO_CUTSCENES"/>
<haxelib name="hxdiscord_rpc" if="DISCORD_RPC"/>
<haxelib name="away3d" if="THREE_D_SUPPORT"/>
<haxelib name="nape-haxe4" if="NAPE_ENABLED"/>
<haxelib name="hscript-improved" />
<haxelib name="hxdiscord_rpc" if="DISCORD_RPC"/>
<haxelib name="markdown" />
<haxelib name="hxcpp-debug-server" if="TEST_BUILD debug" />
<haxelib name="hxcpp-debug-server" if="debug"/>
<!-- _____________________________ Path Settings ____________________________ -->
<!-- ____________________________ Source Settings ___________________________ -->
<set name="BUILD_DIR" value="export/debug" if="debug" />
<set name="BUILD_DIR" value="export/release" unless="debug" />
<set name="BUILD_DIR" value="export/debug-32bit" if="debug 32bit" />
<set name="BUILD_DIR" value="export/release-32bit" if="32bit" unless="debug" />
<set name="BUILD_DIR" value="latest/" if="beta" />
<!-- DO NO REMOVE THIS -->
<haxedef name="REGION"/>
<source name="source" />
<set name="BUILD_DIR" value="export/debug" if="debug"/>
<set name="BUILD_DIR" value="export/release" unless="debug"/>
<set name="BUILD_DIR" value="export/debug-32bit" if="debug 32bit"/>
<set name="BUILD_DIR" value="export/release-32bit" if="32bit" unless="debug"/>
<set name="BUILD_DIR" value="latest/" if="beta"/>
<app main="funkin.backend.system.Main" preloader="flixel.system.FlxPreloader"/>
<source name="source"/>
<section if="MODCHARTING_FEATURES">
<haxedef name="FM_ENGINE" value="CODENAME"/>
<haxedef name="FM_ENGINE_VERSION" value="1.0"/>
<haxelib name="funkin-modchart" />
<haxeflag name="--macro" value="modchart.backend.macros.Macro.includeFiles()"/>
</section>
<!-- ____________________________ Assets Settings ___________________________ -->
<define name="PRELOAD_ALL" unless="web" />
<define name="NO_PRELOAD_ALL" unless="PRELOAD_ALL"/>
@@ -160,81 +173,69 @@
<assets path='mods' rename='mods' embed='false' />
</section>
<assets path='art/readme.txt' rename='do NOT readme.txt' />
<!-- OpenAL config -->
<section if="desktop">
<assets path="building/alsoft.txt" rename="plugins/alsoft.ini" type="text" if="windows"/>
<assets path="building/alsoft.txt" rename="plugins/alsoft.conf" type="text" unless="windows"/>
</section>
<!-- <assets path='art/readme.txt' rename='do NOT readme.txt' /> -->
<!-- ______________________________ Haxedefines _____________________________ -->
<haxeflag name="--macro" value="funkin.backend.system.macros.BuildInfo.printBuildInfo()" />
<haxeflag name="--macro" value="funkin.backend.system.macros.Macros.initMacros()"/>
<haxedef name="FLX_NO_FOCUS_LOST_SCREEN" />
<haxedef name="VIDEO_CUTSCENES" if="VIDEO_CUTSCENES"/>
<haxedef name="UPDATE_CHECKING" if="UPDATE_CHECKING"/>
<haxedef name="DISCORD_RPC" if="DISCORD_RPC"/>
<haxedef name="SHOW_BUILD_ON_FPS" if="SHOW_BUILD_ON_FPS"/>
<haxedef name="SOFTCODED_CLASSES" if="SOFTCODED_CLASSES"/>
<haxedef name="USE_ADAPTED_ASSETS" if="USE_ADAPTED_ASSETS"/>
<!--Disable the Flixel core debugger. Automatically gets set whenever you compile in release mode!-->
<haxedef name="FLX_NO_DEBUG" unless="debug" />
<!-- Backward Compatibilities -->
<haxedef name="FLX_HEALTH" />
<haxedef name="analyzer-optimize" unless="debug" />
<haxedef name="FLX_NO_FOCUS_LOST_SCREEN"/>
<haxedef name="FLX_NO_DEBUG" unless="debug"/>
<haxedef name="VIDEO_CUTSCENES" if="VIDEO_CUTSCENES" />
<haxedef name="UPDATE_CHECKING" if="UPDATE_CHECKING" />
<haxedef name="DISCORD_RPC" if="DISCORD_RPC" />
<haxedef name="SHOW_BUILD_ON_FPS" if="SHOW_BUILD_ON_FPS" />
<haxedef name="SOFTCODED_CLASSES" if="SOFTCODED_CLASSES" />
<haxedef name="USE_ADAPTED_ASSETS" if="USE_ADAPTED_ASSETS" />
<haxedef name="openfl_dpi_aware" if="openfl_dpi_aware" />
<haxedef name="DISCORD_DISABLE_IO_THREAD" if="DISCORD_RPC"/>
<!-- Disable it for more concise compilation errors. -->
<haxedef name="message.reporting" value="pretty" />
<!-- _________________________________ Custom _______________________________ -->
<!--Place custom nodes like icons here (higher priority to override the HaxeFlixel icon)-->
<icon path="art/icon16.png" size='16'/>
<icon path="art/icon32.png" size='24'/>
<icon path="art/icon32.png" size='32'/>
<icon path="art/icon64.png" size='40'/>
<icon path="art/icon64.png" size='48'/>
<icon path="art/icon64.png" size='64'/>
<icon path="art/iconOG.png" size='96' />
<icon path="art/iconOG.png" size='128' />
<icon path="art/iconOG.png" size='196' />
<icon path="art/iconOG.png" size='256' />
<icon path="art/iconOG.png" size='512' />
<icon path="art/iconOG.png" size='768' />
<icon path="art/iconOG.png" size='1024' />
<!-- _________________________________ Additional stuff _______________________________ -->
<section if="MODCHARTING_FEATURES">
<haxedef name="FM_ENGINE" value="CODENAME"/>
<haxedef name="FM_ENGINE_VERSION" value="1.0"/>
<haxelib name="funkin-modchart" />
<haxeflag name="--macro" value="modchart.backend.macros.Macro.includeFiles()"/>
</section>
<section if="COMPILE_ALL_CLASSES">
<haxeflag name="-dce" value="no" />
<haxeflag name="--macro" value="funkin.backend.system.macros.Macros.addAdditionalClasses()" />
</section>
<haxeflag name="--macro" value="funkin.backend.system.macros.Macros.initMacros()" />
<!-- <haxedef name="no-deprecation-warnings"/> -->
<!-- Fix compiling issues -->
<setenv name="HAXEPATH" value="./"/>
<haxedef name="HXCPP_M32" if="32bit" />
<haxedef name="HXCPP_DEBUG_LINK" if="debug" />
<haxedef name="HXCPP_CHECK_POINTER" />
<haxedef name="HXCPP_STACK_LINE" />
<haxedef name="HXCPP_CATCH_SEGV" />
<!-- Haxe 4.3.0+: Enable pretty syntax errors and stuff. -->
<haxedef name="message.reporting" value="pretty"/>
<haxedef name="hscriptPos" /> <!-- for logging -->
<!-- for logging -->
<haxedef name="hscriptPos"/>
<section if="COMPILE_ALL_CLASSES">
<haxeflag name="-dce" value="no"/>
<haxeflag name="--macro" value="funkin.backend.system.macros.Macros.addAdditionalClasses()"/>
</section>
<haxeflag name="--macro" value="funkin.backend.system.macros.BuildInfo.printBuildInfo()"/>
<!-- EXPERMENTAL FEATURES -->
<haxedef name="EXPERIMENTAL_FLXGRAPHIC_DESTROY_FIX" />
<haxedef name="openfl_dpi_aware"/>
<haxedef name="openfl_pool_events"/>
<haxedef name="openfl-enable-handle-error"/>
<haxedef name="openfl_no_custom_render_event"/>
<haxedef name="HXCPP_M32" if="32bit"/>
<haxedef name="HXCPP_DEBUG_LINK" if="debug"/>
<!--C++20 seems doesn't seem to do anything but causes compile warnings-->
<!--<haxedef name="HXCPP_CPP20"/>-->
<!--<haxedef name="HXCPP_CLANG"/>-->
<!--<haxedef name="HXCPP_MSVC"/>-->
<!-- This seems to causes more harm, but to be fair, its mostly because of text rendering -->
<!-- This is really important to fix honestly, try to get cairo text rendering not memory leak in the future -->
<!--<haxedef name="HXCPP_GC_BIG_BLOCKS"/>-->
<!--<haxedef name="HXCPP_GC_GENERATIONAL"/>-->
<!--<haxedef name="HXCPP_GC_DYNAMIC_SIZE"/>-->
<haxedef name="HXCPP_CHECK_POINTER"/>
<haxedef name="HXCPP_STACK_LINE"/>
<haxedef name="HXCPP_STACK_TRACE"/>
<!--<haxedef name="HXCPP_CATCH_SEGV"/>-->
<haxedef name="HXCPP_FAST_LINK" unless="debug"/>
<!--<haxedef name="HXCPP_ALIGN_ALLOC"/>--> <!--hxcpp.h(71): warning C4005: 'HXCPP_ALIGN_ALLOC': macro redefinition-->
<haxedef name="analyzer-optimize" unless="debug"/>
</project>
-960
View File
@@ -1,960 +0,0 @@
package flixel.sound;
import lime.media.AudioBuffer;
import lime.media.AudioSource;
import lime.media.AudioManager;
import openfl.Assets;
import openfl.events.IEventDispatcher;
import openfl.events.Event;
import openfl.media.Sound;
import openfl.media.SoundChannel;
import openfl.media.SoundTransform;
import openfl.media.SoundMixer;
import openfl.net.URLRequest;
import openfl.utils.AssetType;
#if flash11
import openfl.utils.ByteArray;
#end
import flixel.math.FlxMath;
import flixel.math.FlxPoint;
import flixel.system.FlxAssets.FlxSoundAsset;
import flixel.tweens.FlxTween;
import flixel.util.FlxDestroyUtil;
import flixel.util.FlxSignal;
import flixel.util.FlxStringUtil;
import flixel.FlxBasic;
import flixel.FlxObject;
import flixel.FlxG;
@:access(flixel.FlxGame)
class FlxSound extends FlxBasic {
/**
* The x position of this sound in world coordinates.
* Only really matters if you are doing proximity/panning stuff.
*/
public var x:Float;
/**
* The y position of this sound in world coordinates.
* Only really matters if you are doing proximity/panning stuff.
*/
public var y:Float;
/**
* Whether or not this sound should be automatically destroyed when you switch states.
*/
public var persist:Bool;
/**
* Whether or not the sound is currently playing.
*/
public var playing(get, never):Bool;
/**
* Set volume to a value between 0 and 1* to change how this sound is.
*/
public var volume(get, set):Float;
/**
* Whether to make this sound muted or not.
*/
public var muted(default, set):Bool;
#if FLX_PITCH
/**
* Set pitch, which also alters the playback speed. Default is 1.
* @since 5.0.0
*/
public var pitch(get, set):Float;
/**
* Alters the pitch of the sound depends on the current FlxG.timeScale. Default is true.
* @since raltyMod
*/
public var timeScaleBased:Bool;
#end
/**
* Pan amount. -1 = full left, 1 = full right. Proximity based panning overrides this.
*/
public var pan(get, set):Float;
/**
* The position in runtime of the music playback in milliseconds.
* If set while paused, changes only come into effect after a `resume()` call.
*/
public var time(get, set):Float;
/**
* The offset for this FlxSound.
* Useful for just generally offsetting this sound without affecting time.
* @since raltyMod
*/
public var offset(get, set):Float;
/**
* The length of the sound in milliseconds.
* @since 4.2.0
*/
public var length(get, never):Float;
/**
* The latency of the sound in milliseconds.
* @since raltyMod
*/
//public var latency(get, never):Float;
/**
* Whether or not this sound should loop.
*/
public var looped(default, set):Bool;
/**
* In case of looping, the point (in milliseconds) from where to restart the sound when it loops back
* @since 4.1.0
*/
public var loopTime(default, set):Float;
/**
* At which point to stop playing the sound, in milliseconds.
* If not set / `null`, the sound completes normally.
* @since 4.2.0
*/
public var endTime(default, set):Null<Float>;
/**
* The sound's "target" (for proximity and panning).
* @since raltyMod
*/
public var target:Null<FlxObject>;
/**
* The maximum effective radius of this sound (for proximity and panning).
* @since raltyMod
*/
public var radius:Float;
/**
* Whether the proximity alters the pan or not.
* @since raltyMod
*/
public var proximityPan:Bool;
/**
* Controls how much this object is affected by camera scrolling. `0` = no movement (e.g. a static sound),
* This is only useful if used with proximity (Initialized once proximity is used).
* @since raltyMod
*/
public var scrollFactor(default, null):FlxPoint;
/**
* Stores for how much channels are in the loaded sound.
* @since raltyMod
*/
public var channels(get, never):Int;
/**
* Whether or not this sound is stereo instead of mono.
* @since raltyMod
*/
public var stereo(get, never):Bool;
/**
* Whether or not this sound is loaded yet.
* @since raltyMod
*/
public var loaded(get, never):Bool;
/**
* Whether or not this sound is streamed, only vorbis though.
* @since raltyMod
*/
public var streamed(get, never):Bool;
/**
* Stores the average wave amplitude of both stereo channels.
* @since raltyMod
*/
public var amplitude(get, never):Float;
/**
* Just the amplitude of the left stereo channel
* @since raltyMod
*/
public var amplitudeLeft(get, never):Float;
/**
* Just the amplitude of the right stereo channel
* @since raltyMod
*/
public var amplitudeRight(get, never):Float;
/**
* The ID3 song name. Defaults to null. Currently only works for MP3 streamed sounds.
*/
public var name(default, null):String;
/**
* The ID3 artist name. Defaults to null. Currently only works for MP3 streamed sounds.
*/
public var artist(default, null):String;
/**
* Whether to call `destroy()` when the sound has finished playing.
*/
public var autoDestroy:Bool;
/**
* Signal that is dispatched on sound complete.
* Seperates the looping from onComplete.
*/
public final onFinish:FlxSignal;
/**
* Tracker for sound complete callback. If assigned, will be called
* each time when sound reaches its end.
*/
//@:deprecated("`FlxSound.onComplete` is deprecated! Use `FlxSound.onFinish` instead.")
public var onComplete:Void->Void;
/**
* The sound group this sound belongs to
*/
public var group(default, set):FlxSoundGroup;
/**
* Stores the sound lime AudioBuffer if exists.
* @since raltyMod
*/
public var buffer(get, never):AudioBuffer;
/**
* The tween used to fade this sound's volume in and out (set via `fadeIn()` and `fadeOut()`)
* @since 4.1.0
*/
public var fadeTween:FlxTween;
@:allow(flixel.system.frontEnds.SoundFrontEnd.load) var _sound:Sound;
var _transform:SoundTransform;
var _channel:SoundChannel;
var _source:AudioSource;
var _paused:Bool;
var _volume:Float;
var _volumeAdjust:Float;
var _pan:Float;
var _panAdjust:Float;
var _time:Float;
var _offset:Float;
var _timeInterpolation:Float;
var _lastTime:Null<Float>; // FlxG.game.getTicks(), in MS
var _length:Float;
#if FLX_PITCH
var _pitch:Float;
var _timeScaleAdjust:Float;
var _realPitch:Float;
#end
var _amplitudeLeft:Float;
var _amplitudeRight:Float;
var _amplitudeUpdate:Bool;
var _alreadyPaused:Null<Bool>;
public function new() {
super();
onFinish = new FlxSignal();
revive();
}
/**
* Resets this FlxSound properties.
*
* @param clean Whether if this FlxSound also needs to be cleaned up too.
*/
public function reset():Void {
if (_source != null) stop();
onFinish.removeAll();
x = y = 0;
@:bypassAccessor muted = false;
@:bypassAccessor looped = false;
@:bypassAccessor loopTime = 0;
@:bypassAccessor endTime = null;
autoDestroy = false;
visible = false;
target = null;
radius = 0;
proximityPan = true;
onComplete = null;
timeScaleBased = true;
_alreadyPaused = null;
_cameras = null;
_lastTime = null;
_paused = false;
_offset = _length = _time = 0;
_volume = _volumeAdjust = 1;
_amplitudeLeft = _amplitudeRight = 0;
_amplitudeUpdate = true;
#if FLX_PITCH _pitch = _realPitch = _timeScaleAdjust = 1; #end
if (_transform == null) _transform = new SoundTransform();
}
/**
* Internal cleanup function for cleaning up this FlxSound.
* @since raltyMod
*/
function cleanup(destroySound:Bool, resetPosition:Bool = true) @:privateAccess {
active = false;
_lastTime = null;
if (destroySound) {
scrollFactor = FlxDestroyUtil.put(scrollFactor);
if (group != null) group.remove(this);
if (_channel != null) {
_channel.stop();
_channel = null;
}
if (_source != null) {
_source.onComplete.remove(stopped);
_source.onLoop.remove(source_looped);
_source.dispose();
}
_source = null;
_sound = null;
if (autoDestroy) persist = false;
reset();
}
else if (_channel != null && _channel.__isValid) {
if (resetPosition) {
_source.stop();
_time = 0;
_paused = false;
}
else if (!_paused) {
get_time();
_source.pause();
}
}
}
/**
* Handles fade out, fade in, panning, proximity, and amplitude operations each frame.
*/
override function update(elapsed:Float):Void {
if (!playing) return;
var timeScaleTarget = timeScaleBased ? FlxG.timeScale : 1.0;
if (_timeScaleAdjust != timeScaleTarget) {
_timeScaleAdjust = timeScaleTarget;
pitch = _pitch;
if (_channel == null) return;
}
_amplitudeUpdate = true;
// Distance-based volume control
if (target != null) {
var targetPosition = target.getPosition(), position = getPosition();
var camera = camera;
if (camera != null) {
targetPosition.subtract(camera.scroll.x * target.scrollFactor.x, camera.scroll.y * target.scrollFactor.y);
if (scrollFactor != null) position.subtract(camera.scroll.x * scrollFactor.x, camera.scroll.y * scrollFactor.y);
else position.subtract(camera.scroll.x, camera.scroll.y);
}
var radialMultiplier = targetPosition.distanceTo(position) / radius;
// Make it so it affects the 3d position of the source and not just the panning?
_volumeAdjust = 1 - FlxMath.bound(radialMultiplier, 0, 1);
if (proximityPan) _panAdjust = (position.x - targetPosition.x) / radius;
targetPosition.put();
position.put();
}
else
_volumeAdjust = 1.0;
updateTransform();
}
override function revive() {
reset();
super.revive();
}
override function kill() {
super.kill();
reset();
}
override function destroy() {
super.destroy();
cleanup(true);
}
/**
* One of the main setup functions for sounds, this function loads a sound from an embedded MP3.
*
* @param embeddedSound An embedded Class object representing an MP3 file.
* @param looped Whether or not this sound should loop endlessly.
* @param autoDestroy Whether or not this FlxSound instance should be destroyed when the sound finishes playing.
* Default value is false, but `FlxG.sound.play()` and `FlxG.sound.stream()` will set it to true by default.
* @param onComplete Called when the sound finished playing
* @return This FlxSound instance (nice for chaining stuff together, if you're into that).
*/
public function loadEmbedded(embeddedSound:FlxSoundAsset, looped = false, autoDestroy = false, ?onComplete:Void->Void):FlxSound {
if (!exists || embeddedSound == null) return this;
cleanup(true);
if ((embeddedSound is Sound)) _sound = embeddedSound;
else if ((embeddedSound is Class)) _sound = Type.createInstance(embeddedSound, []);
else if ((embeddedSound is String)) {
if (Assets.exists(embeddedSound, AssetType.MUSIC) && this == FlxG.sound.music)
_sound = Assets.getMusic(embeddedSound);
else if (Assets.exists(embeddedSound, AssetType.SOUND))
_sound = Assets.getSound(embeddedSound);
else
FlxG.log.error('Could not find a Sound asset with an ID of \'$embeddedSound\'.');
}
return init(looped, autoDestroy, onComplete);
}
/**
* One of the main setup functions for sounds, this function loads a sound from a URL.
*
* @param soundURL A string representing the URL of the MP3 file you want to play.
* @param looped Whether or not this sound should loop endlessly.
* @param autoDestroy Whether or not this FlxSound instance should be destroyed when the sound finishes playing.
* Default value is false, but `FlxG.sound.play()` and `FlxG.sound.stream()` will set it to true by default.
* @param onComplete Called when the sound finished playing
* @param onLoad Called when the sound finished loading.
* @return This FlxSound instance (nice for chaining stuff together, if you're into that).
*/
public function loadStream(soundURL:String, looped = false, autoDestroy = false, ?onComplete:Void->Void, ?onLoad:Void->Void):FlxSound {
if (!exists) return this;
cleanup(true);
_sound = new Sound();
_sound.addEventListener(Event.ID3, gotID3);
var loadCallback:Event->Void = null;
loadCallback = function(e:Event)
{
(e.target : IEventDispatcher).removeEventListener(e.type, loadCallback);
// Check if the sound was destroyed before calling. Weak ref doesn't guarantee GC.
if (_sound == e.target)
{
_length = _sound.length;
if (onLoad != null)
onLoad();
}
}
// Use a weak reference so this can be garbage collected if destroyed before loading.
_sound.addEventListener(Event.COMPLETE, loadCallback, false, 0, true);
_sound.load(new URLRequest(soundURL));
return init(looped, autoDestroy, onComplete);
}
#if flash11
/**
* One of the main setup functions for sounds, this function loads a sound from a ByteArray.
*
* @param bytes A ByteArray object.
* @param looped Whether or not this sound should loop endlessly.
* @param autoDestroy Whether or not this FlxSound instance should be destroyed when the sound finishes playing.
* Default value is false, but `FlxG.sound.play()` and `FlxG.sound.stream()` will set it to true by default.
* @return This FlxSound instance (nice for chaining stuff together, if you're into that).
*/
public function loadByteArray(bytes:ByteArray, looped = false, autoDestroy = false, ?onComplete:Void->Void):FlxSound {
if (!exists) return this;
cleanup(true);
_sound = new Sound();
_sound.addEventListener(Event.ID3, gotID3);
_sound.loadCompressedDataFromByteArray(bytes, bytes.length);
return init(looped, autoDestroy, onComplete);
}
#end
function init(?looped:Null<Bool>, ?autoDestroy:Null<Bool>, ?onComplete:Null<Void->Void>):FlxSound {
if (looped != null) this.looped = looped;
if (autoDestroy != null) this.autoDestroy = autoDestroy;
if (onComplete != null) this.onComplete = onComplete;
if (_sound != null) makeChannel();
else _length = 0;
endTime = null;
return this;
}
/**
* Call inbetween init function if a sound asset does exists.
* @since raltyMod
*/
function makeChannel() @:privateAccess {
if (_sound.__buffer == null) return;
if (_source != null) _source.dispose();
if (_channel == null) (_source = (_channel = new SoundChannel(null)).__source = new AudioSource(_sound.__buffer)).gain = 0;
else {
(_source = new AudioSource(_sound.__buffer)).gain = 0;
_channel.__dispose();
_channel.__source = _source;
SoundMixer.__registerSoundChannel(_channel);
}
_length = _source.length;
_source.onComplete.add(stopped);
_source.onLoop.add(source_looped);
_channel.__soundTransform = _transform;
_channel.__isValid = true;
}
/**
* Call after adjusting the volume to update the sound channel's settings.
*/
@:allow(flixel.sound.FlxSoundGroup)
function updateTransform() {
_transform.volume = calcTransformVolume();
_transform.pan = _pan + _panAdjust;
if (_channel != null) _channel.soundTransform = _transform;
}
public function calcTransformVolume():Float {
if (muted) return 0.0;
#if FLX_SOUND_SYSTEM
if (FlxG.sound.muted) return 0.0;
// TODO: when flixel-cne is updated, enable this
//return FlxG.sound.applySoundCurve(FlxG.sound.volume * volume);
return FlxG.sound.volume * getActualVolume();
#else
return getActualVolume();
#end
}
/**
* Call this function if you want this sound's volume to change
* based on distance from a particular FlxObject.
*
* @param X The X position of the sound.
* @param Y The Y position of the sound.
* @param TargetObject The object you want to track.
* @param Radius The maximum distance this sound can travel.
* @param Pan Whether panning should be used in addition to the volume changes.
* @return This FlxSound instance (nice for chaining stuff together, if you're into that).
*/
public function proximity(x = 0.0, y = 0.0, ?targetObject:FlxObject, ?radius:Float, pan = true, ?scrollFactor:FlxPoint):FlxSound {
setPosition(x, y);
if (targetObject != null) this.target = targetObject;
if (radius != null) this.radius = radius;
proximityPan = pan;
if (this.scrollFactor == null) this.scrollFactor = FlxPoint.get(1, 1);
if (scrollFactor != null) this.scrollFactor.copyFrom(scrollFactor);
return this;
}
/**
* Helper function to set the coordinates of this object.
* Sound positioning is used in conjunction with proximity/panning.
*
* @param x The new x position
* @param y The new y position
*/
public function setPosition(x = 0.0, y = 0.0):Void {
this.x = x;
this.y = y;
}
/**
* Returns the world position of this object.
*
* @param result Optional arg for the returning point.
* @return The world position of this object.
* @since raltyMod
*/
public function getPosition(?result:FlxPoint):FlxPoint {
if (result == null)
result = FlxPoint.get();
return result.set(x, y);
}
/**
* Call this function to play the sound - also works on paused sounds.
*
* @param forceRestart Whether to start the sound over or not.
* Default value is false, meaning if the sound is already playing or was
* paused when you call play(), it will continue playing from its current
* position, NOT start again from the beginning.
* @param startTime At which point to start playing the sound, in milliseconds.
* @param endTime At which point to stop playing the sound, in milliseconds.
* If not set / `null`, the sound completes normally.
*/
public function play(forceRestart = false, startTime = 0.0, ?endTime:Null<Float>):FlxSound {
if (!exists) return this;
if (forceRestart) cleanup(false, true);
else if (playing) return this;
if (endTime != null) this.endTime = endTime;
if (_paused) resume();
else startSound(startTime);
return this;
}
/**
* Unpause a sound. Only works on sounds that have been paused.
* @return This FlxSound instance (nice for chaining stuff together, if you're into that).
*/
public function resume():FlxSound {
if (_paused) startSound(_time);
return this;
}
/**
* Call this function to pause this sound.
* @return This FlxSound instance (nice for chaining stuff together, if you're into that).
*/
public function pause():FlxSound {
if (!playing) return this;
cleanup(false, false);
_paused = true;
return this;
}
/**
* Call this function to stop this sound.
* @return This FlxSound instance (nice for chaining stuff together, if you're into that).
*/
public function stop():FlxSound {
cleanup(autoDestroy, true);
return this;
}
/**
* Helper function that tweens this sound's volume.
*
* @param duration The amount of time the fade-out operation should take.
* @param to The volume to tween to, 0 by default.
* @return This FlxSound instance (nice for chaining stuff together, if you're into that).
*/
public function fadeOut(duration = 1.0, to = 0.0, ?onComplete:FlxTween->Void):FlxSound {
if (fadeTween != null) fadeTween.cancel();
fadeTween = FlxTween.num(volume, to, duration, {onComplete: onComplete}, volumeTween);
return this;
}
/**
* Helper function that tweens this sound's volume.
* If the sound wasn't playing at all, it'll play before the tween starts.
*
* @param duration The amount of time the fade-in operation should take.
* @param from The volume to tween from, 0 by default.
* @param to The volume to tween to, 1 by default.
* @return This FlxSound instance (nice for chaining stuff together, if you're into that).
*/
public function fadeIn(duration = 1.0, from = 0.0, to = 1.0, ?onComplete:FlxTween->Void):FlxSound {
if (!playing) play();
if (fadeTween != null) fadeTween.cancel();
fadeTween = FlxTween.num(from, to, duration, {onComplete: onComplete}, volumeTween);
return this;
}
function volumeTween(f:Float) volume = f;
/**
* Returns the currently selected "real" volume of the sound (takes fades and proximity into account).
*
* @return The adjusted volume of the sound.
*/
public inline function getActualVolume():Float
return (group != null ? group.getVolume() : 1.0) * _volume * _volumeAdjust;
#if FLX_PITCH
/**
* Returns the currently selected "real" pitch of the sound.
*
* @return The adjusted pitch of the sound.
*/
public inline function getActualPitch():Float
return _realPitch;
#end
/**
* Returns the actual time coming from the internal, can be used for detecting sync error.
*
* @return The actual time of the sound.
*/
public inline function getActualTime():Float {
get_time();
return _time;
}
/**
* An internal helper function used to attempt to start playing
* the sound and populate the _channel variable.
*/
function startSound(startTime:Float) @:privateAccess {
if (_sound == null) return;
_paused = false;
_time = startTime;
_lastTime = FlxG.game.getTicks();
if (_channel == null || !_channel.__isValid || _source == null #if lime_cffi || _source.__backend.disposed #end)
makeChannel();
if (_channel != null) {
#if FLX_PITCH
_timeScaleAdjust = timeScaleBased ? FlxG.timeScale : 1.0;
pitch = _pitch;
#end
updateTransform();
_channel.__lastPeakTime = -10;
_channel.__leftPeak = 0;
_channel.__rightPeak = 0;
#if lime_cffi _source.__backend.playing = true; #end
_source.offset = 0;
_source.currentTime = startTime + _offset;
#if !lime_cffi _source.play(); #end
looped = looped;
loopTime = loopTime;
endTime = endTime;
active = true;
}
else {
exists = false;
active = false;
}
}
function stopped() {
onFinish.dispatch();
if (onComplete != null) onComplete();
if (looped) {
cleanup(false);
play(false, loopTime, endTime);
}
else cleanup(autoDestroy);
}
function source_looped() {
if (onComplete != null) onComplete();
if (!looped) {
cleanup(autoDestroy);
_lastTime = FlxG.game.getTicks();
_time = loopTime;
}
else if (_source != null)
_source.loops = 999;
}
/**
* Internal event handler for ID3 info (i.e. fetching the song name).
*/
function gotID3(_) {
name = _sound.id3.songName;
artist = _sound.id3.artist;
_sound.removeEventListener(Event.ID3, gotID3);
}
#if FLX_SOUND_SYSTEM
@:allow(flixel.system.frontEnds.SoundFrontEnd)
function onFocus() if (!_alreadyPaused) {
resume();
_alreadyPaused = null;
}
@:allow(flixel.system.frontEnds.SoundFrontEnd)
function onFocusLost() if (_alreadyPaused == null && !(_alreadyPaused = _paused)) pause();
#end
function set_group(value:FlxSoundGroup):FlxSoundGroup {
if (value != null) value.add(this);
else group.remove(this);
return group;
}
inline function get_playing():Bool @:privateAccess
return _source != null && _source.playing;
inline function get_volume():Float
return _volume;
inline function set_volume(v:Float):Float {
_volume = FlxMath.bound(v, 0, 10);
updateTransform();
return _volume;
}
inline function set_muted(v:Bool):Bool {
muted = v;
updateTransform();
return muted;
}
inline function get_pan():Float return _pan;
inline function set_pan(v:Float):Float {
_pan = FlxMath.bound(v, -1, 1);
updateTransform();
return _pan;
}
inline function get_loaded():Bool
return buffer != null;
inline function get_streamed():Bool
@:privateAccess return #if lime_vorbis _sound != null && _sound.__buffer.__srcVorbisFile != null #else false #end;
inline function get_buffer():AudioBuffer
@:privateAccess return _sound != null ? _sound.__buffer : null;
inline function update_amplitude():Void @:privateAccess {
if (_channel != null && _channel.__updatePeaks(get_time()) && _amplitudeUpdate) {
_amplitudeUpdate = false;
_amplitudeLeft = _channel.__leftPeak;
_amplitudeRight = _channel.__rightPeak;
}
}
inline function get_amplitudeLeft():Float {
update_amplitude();
return _amplitudeLeft;
}
inline function get_amplitudeRight():Float {
update_amplitude();
return _amplitudeRight;
}
inline function get_amplitude():Float {
update_amplitude();
return Math.max(_amplitudeLeft, _amplitudeRight);//if (stereo) (_amplitudeLeft + _amplitudeRight) * 0.5; else _amplitudeLeft;
}
inline function get_channels():Int
@:privateAccess return (buffer != null) ? buffer.channels : 0;
inline function get_stereo():Bool
return channels > 1;
#if FLX_PITCH
inline function get_pitch():Float
return _pitch;
inline function set_pitch(v:Float):Float {
_realPitch = (_pitch = v) * _timeScaleAdjust;
if (_source != null) _source.pitch = _realPitch;
return _pitch;
}
#end
function set_looped(v:Bool):Bool {
if (playing) _source.loops = v ? 999 : 0;
return looped = v;
}
function set_loopTime(v:Float):Float {
if (playing) _source.loopTime = v;
return loopTime = v;
}
function set_endTime(v:Null<Float>):Null<Float> {
if (playing) {
if (v != null && v > 0 && v < _length) _source.length = v;
else _source.length = null;
}
return endTime = v;
}
inline function getFakeTime():Float {
if (_source.playing && _realPitch > 0 && _lastTime != null)
return _time + (FlxG.game.getTicks() - _lastTime) * _realPitch * _timeInterpolation;
else
return _time;
}
function get_time():Float {
if (_source == null || /*AudioManager.context == null*/funkin.backend.system.Main.audioDisconnected) return _time;
final sourceTime = _source.currentTime - _source.offset - _offset;
if (!_source.playing || _realPitch <= 0) {
_lastTime = null;
return _time = sourceTime;
}
final fakeTime = getFakeTime();
if (sourceTime != _time) {
_lastTime = FlxG.game.getTicks();
if ((_timeInterpolation = 1 - Math.min(fakeTime - sourceTime, 1000) * 0.001) < 1 && _timeInterpolation > .9)
return _time = fakeTime;
else {
_timeInterpolation = 1;
return _time = sourceTime;
}
}
else
return fakeTime;
}
function set_time(time:Float):Float @:privateAccess {
time = FlxMath.bound(time, _offset, length - 1);
if (_channel != null && _realPitch > 0) {
if (!_channel.__isValid) {
cleanup(false, true);
startSound(time);
}
else {
_source.offset = 0;
_source.currentTime = time + _offset;
}
}
_lastTime = null;
return _time = time;
}
function get_offset():Float return _offset;
function set_offset(offset:Float):Float {
if (_offset == (_offset = offset)) return offset;
//time = time + _offset;
return offset;
}
function get_length():Float return _length - _offset;
//function get_latency():Float return _source != null ? _source.latency : 0;
override function toString():String {
return FlxStringUtil.getDebugString([
LabelValuePair.weak("playing", playing),
LabelValuePair.weak("time", time),
LabelValuePair.weak("length", length),
LabelValuePair.weak("volume", volume),
LabelValuePair.weak("pitch", pitch)
]);
}
}
-120
View File
@@ -1,120 +0,0 @@
package flixel.sound;
/**
* A way of grouping sounds for things such as collective volume control
*/
class FlxSoundGroup
{
/**
* The sounds in this group
*/
public var sounds:Array<FlxSound> = [];
/**
* The volume of this group
*/
public var volume(default, set):Float;
/**
* Whether or not this group is muted
*/
public var muted(default, set):Bool;
/**
* Create a new sound group
* @param volume The initial volume of this group
*/
public function new(volume:Float = 1)
{
this.volume = volume;
}
/**
* Add a sound to this group, will remove the sound from any group it is currently in
* @param sound The sound to add to this group
* @return True if sound was successfully added, false otherwise
*/
public function add(sound:FlxSound):Bool
{
if (!sounds.contains(sound))
{
// remove from prev group
if (sound.group != null)
sound.group.sounds.remove(sound);
sounds.push(sound);
@:bypassAccessor
sound.group = this;
sound.updateTransform();
return true;
}
return false;
}
/**
* Remove a sound from this group
* @param sound The sound to remove
* @return True if sound was successfully removed, false otherwise
*/
public function remove(sound:FlxSound):Bool
{
if (sounds.contains(sound))
{
@:bypassAccessor
sound.group = null;
sounds.remove(sound);
sound.updateTransform();
return true;
}
return false;
}
/**
* Call this function to pause all sounds in this group.
* @since 4.3.0
*/
public function pause():Void
{
for (sound in sounds)
sound.pause();
}
/**
* Unpauses all sounds in this group. Only works on sounds that have been paused.
* @since 4.3.0
*/
public function resume():Void
{
for (sound in sounds)
sound.resume();
}
/**
* Returns the volume of this group, taking `muted` in account.
* @return The volume of the group or 0 if the group is muted.
*/
public function getVolume():Float
{
return muted ? 0.0 : volume;
}
function set_volume(volume:Float):Float
{
this.volume = volume;
for (sound in sounds)
{
sound.updateTransform();
}
return volume;
}
function set_muted(value:Bool):Bool
{
muted = value;
for (sound in sounds)
{
sound.updateTransform();
}
return muted;
}
}
-92
View File
@@ -1,92 +0,0 @@
package funkin.backend;
import flixel.graphics.frames.FlxFrame;
import flixel.math.FlxAngle;
import flixel.math.FlxMatrix;
import openfl.display.BlendMode;
import openfl.geom.ColorTransform;
class FlxAnimate extends flxanimate.FlxAnimate {
static var rMatrix = new FlxMatrix();
override function drawLimb(limb:FlxFrame, _rMatrix:FlxMatrix, ?colorTransform:ColorTransform, ?blendMode:BlendMode)
{
if (alpha == 0 || colorTransform != null && (colorTransform.alphaMultiplier == 0 || colorTransform.alphaOffset == -255) || limb == null || limb.type == EMPTY)
return;
if (blendMode == null)
blendMode = BlendMode.NORMAL;
for (camera in cameras)
{
rMatrix.identity();
limb.prepareMatrix(rMatrix, FlxFrameAngle.ANGLE_0, _checkFlipX() != camera.flipX, _checkFlipY() != camera.flipY);
rMatrix.concat(_rMatrix);
if (!camera.visible || !camera.exists || !limbOnScreen(limb, _rMatrix, camera))
return;
getScreenPosition(_point, camera).subtractPoint(offset);
rMatrix.translate(-origin.x, -origin.y);
if (limb != _pivot) {
if (frameOffsetAngle != null && frameOffsetAngle != angle)
{
var angleOff = (frameOffsetAngle - angle) * FlxAngle.TO_RAD;
var cos = Math.cos(angleOff);
var sin = Math.sin(angleOff);
// cos doesn't need to be negated
rMatrix.rotateWithTrig(cos, -sin);
rMatrix.translate(-frameOffset.x, -frameOffset.y);
rMatrix.rotateWithTrig(cos, sin);
}
else
{
rMatrix.translate(-frameOffset.x, -frameOffset.y);
}
rMatrix.scale(scale.x, scale.y);
if (!matrixExposed && bakedRotationAngle <= 0)
{
updateTrig();
if (angle != 0)
rMatrix.rotateWithTrig(_cosAngle, _sinAngle);
}
}
else
rMatrix.a = rMatrix.d = 0.7 / camera.zoom;
if (matrixExposed)
{
rMatrix.concat(transformMatrix);
}
else
{
rMatrix.concat(@:privateAccess flxanimate.FlxAnimate._skewMatrix);
}
_point.addPoint(origin);
if (isPixelPerfectRender(camera))
{
_point.floor();
}
rMatrix.translate(_point.x, _point.y);
camera.drawPixels(limb, null, rMatrix, colorTransform, blendMode, antialiasing, shaderEnabled ? shader : null);
#if FLX_DEBUG
FlxBasic.visibleCount++;
#end
}
// doesn't work, needs to be remade
// #if FLX_DEBUG
// if (FlxG.debugger.drawDebug)
// drawDebug();
// #end
}
override function limbOnScreen(limb:FlxFrame, m:FlxMatrix, ?Camera:FlxCamera)
{
// TODO: ACTUAL OPTIMIZATION
return true;
}
}
+76 -144
View File
@@ -1,5 +1,7 @@
package funkin.backend;
import animate.FlxAnimate;
import animate.FlxAnimateController.FlxAnimateAnimation;
import flixel.addons.effects.FlxSkewedSprite;
import flixel.animation.FlxAnimation;
import flixel.math.FlxMatrix;
@@ -7,7 +9,6 @@ import flixel.math.FlxPoint;
import flixel.math.FlxRect;
import flixel.system.FlxAssets.FlxGraphicAsset;
import flixel.util.typeLimit.OneOfTwo;
import flxanimate.animate.FlxAnim.FlxSymbolAnimation;
import funkin.backend.scripting.events.sprite.PlayAnimContext;
import funkin.backend.system.interfaces.IBeatReceiver;
import funkin.backend.system.interfaces.IOffsetCompatible;
@@ -15,6 +16,10 @@ import funkin.backend.utils.XMLUtil.AnimData;
import funkin.backend.utils.XMLUtil.BeatAnim;
import funkin.backend.utils.XMLUtil.IXMLEvents;
import haxe.io.Path;
import flixel.graphics.frames.FlxFrame;
import flixel.math.FlxAngle;
import animate.internal.RenderTexture;
import animate.FlxAnimateFrames;
enum abstract XMLAnimType(Int)
{
@@ -43,7 +48,7 @@ enum abstract XMLAnimType(Int)
}
}
class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements IOffsetCompatible implements IXMLEvents
class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffsetCompatible implements IXMLEvents
{
public var extra:Map<String, Dynamic> = [];
@@ -56,6 +61,9 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
public var animEnabled:Bool = true;
public var zoomFactorEnabled:Bool = true;
//Backwards compatibility
public var animateAtlas(get, never):FunkinSprite;
public var globalCurFrame(get, set):Int;
/**
@@ -66,9 +74,7 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
public var beatOffset:Int = 0;
public var skipNegativeBeats:Bool = false;
public var animateAtlas:FlxAnimate;
@:noCompletion public var atlasPlayingAnim:String;
@:noCompletion public var atlasPath:String;
public var animateSettings:FlxAnimateSettings = {};
var _rect2:FlxRect;
@@ -85,6 +91,7 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
}
moves = false;
applyStageMatrix = true;
}
/**
@@ -100,8 +107,6 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
@:privateAccess {
spr.setPosition(source.x, source.y);
spr.frames = source.frames;
if (casted != null && casted.animateAtlas != null && casted.atlasPath != null)
spr.loadSprite(casted.atlasPath);
spr.animation.copyFrom(source.animation);
spr.visible = source.visible;
spr.alpha = source.alpha;
@@ -111,8 +116,6 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
if (casted != null) {
spr.skew.set(casted.skew.x, casted.skew.y);
spr.transformMatrix = casted.transformMatrix;
spr.matrixExposed = casted.matrixExposed;
spr.animOffsets = casted.animOffsets.copy();
spr.zoomFactor = casted.zoomFactor;
}
@@ -123,8 +126,6 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
public override function update(elapsed:Float)
{
super.update(elapsed);
if (animateAtlas != null)
animateAtlas.update(elapsed);
// hate how it looks like but hey at least its optimized and fast - Nex
if (!debugMode && isAnimFinished()) {
@@ -142,15 +143,7 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
public function loadSprite(path:String, Unique:Bool = false, Key:String = null)
{
var noExt = Path.withoutExtension(path);
if (Assets.exists('$noExt/Animation.json'))
{
atlasPath = noExt;
animateAtlas = new FlxAnimate(x, y, noExt);
}
else
{
frames = Paths.getFrames(path, true);
}
frames = Paths.getFrames(path, true, null, null, animateSettings);
return this;
}
@@ -180,50 +173,22 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
{
}
// ANIMATE ATLAS DRAWING
#if REGION
public override function draw()
{
if (animateAtlas != null)
{
copyAtlasValues();
animateAtlas.draw();
}
else
{
super.draw();
}
public override function draw() {
// re-implementing the `onDraw` functionality from `FlxSprite` since `FlxAnimate` didn't have this, so we have to add it back in ourselves
if (this.isAnimate && this.__drawOverrided) {
this.__drawOverrided = false;
this.onDraw(this);
this.__drawOverrided = true;
return;
}
super.draw();
}
public function copyAtlasValues()
{
@:privateAccess {
animateAtlas.cameras = cameras; // investigate if we can use _cameras
animateAtlas.scrollFactor = scrollFactor;
animateAtlas.scale = scale;
animateAtlas.offset = offset;
animateAtlas.frameOffset = frameOffset;
animateAtlas.x = x;
animateAtlas.y = y;
animateAtlas.angle = angle;
animateAtlas.alpha = alpha;
animateAtlas.visible = visible;
animateAtlas.flipX = flipX;
animateAtlas.flipY = flipY;
animateAtlas.shader = shader;
animateAtlas.shaderEnabled = shaderEnabled;
animateAtlas.antialiasing = antialiasing;
animateAtlas.skew = skew;
animateAtlas.transformMatrix = transformMatrix;
animateAtlas.matrixExposed = matrixExposed;
animateAtlas.colorTransform = colorTransform;
}
}
// ANIMATE ATLAS DRAWING
#if REGION
public override function destroy()
{
animateAtlas = FlxDestroyUtil.destroy(animateAtlas);
if (animOffsets != null) {
for (key in animOffsets.keys()) {
final point = animOffsets[key];
@@ -260,25 +225,6 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
);
}
public override function getScreenBounds(?newRect:FlxRect, ?camera:FlxCamera):FlxRect
{
if (camera == null)
camera = FlxG.camera;
newRect = super.getScreenBounds(newRect, camera);
if(__shouldDoZoomFactor()) {
__prepareZoomFactor(_rect2, camera);
newRect.set(
(newRect.x - _rect2.x) * _rect2.width + _rect2.x,
(newRect.y - _rect2.y) * _rect2.height + _rect2.y,
newRect.width * _rect2.width,
newRect.height * _rect2.height,
);
}
return newRect;
}
override public function isOnScreen(?camera:FlxCamera):Bool
{
if (forceIsOnScreen)
@@ -293,22 +239,6 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
return camera.containsRect(bounds);
}
// ZOOM FACTOR RENDERING
public override function doAdditionalMatrixStuff(matrix:FlxMatrix, camera:FlxCamera)
{
// no need to...
//super.doAdditionalMatrixStuff(matrix, camera);
if(__shouldDoZoomFactor()) {
__prepareZoomFactor(_rect, camera);
matrix.setTo(
matrix.a * _rect.width, matrix.b * _rect.height,
matrix.c * _rect.width, matrix.d * _rect.height,
(matrix.tx - _rect.x) * _rect.width + _rect.x,
(matrix.ty - _rect.y) * _rect.height + _rect.y,
);
}
}
// OFFSETTING
#if REGION
public var animOffsets:Map<String, FlxPoint> = new Map<String, FlxPoint>();
@@ -340,13 +270,7 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
Force = anim != null && anim.forced;
}
if (animateAtlas != null)
{
@:privateAccess
animateAtlas.anim.play(AnimName, Force, Reversed, Frame);
atlasPlayingAnim = AnimName;
}
else animation.play(AnimName, Force, Reversed, Frame);
animation.play(AnimName, Force, Reversed, Frame);
var daOffset = getAnimOffset(AnimName);
frameOffset.set(daOffset.x, daOffset.y);
@@ -355,7 +279,7 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
lastAnimContext = Context;
}
public inline function addAnim(name:String, prefix:String, frameRate:Float = 24, ?looped:Bool, ?forced:Bool, ?indices:Array<Int>, x:Float = 0, y:Float = 0, animType:XMLAnimType = NONE)
public inline function addAnim(name:String, prefix:String, frameRate:Float = 24, ?looped:Bool, ?forced:Bool, ?indices:Array<Int>, x:Float = 0, y:Float = 0, animType:XMLAnimType = NONE, animateAtlasLabel:Bool = false)
{
return XMLUtil.addAnimToSprite(this, {
name: name,
@@ -366,22 +290,16 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
x: x,
y: y,
indices: indices,
forced: forced
forced: forced,
label: animateAtlasLabel
});
}
public inline function removeAnim(name:String)
{
if (animateAtlas != null)
@:privateAccess animateAtlas.anim.animsMap.remove(name);
else
animation.remove(name);
public inline function removeAnim(name:String) {
animation.remove(name);
}
public function getAnim(name:String):OneOfTwo<FlxAnimation, FlxSymbolAnimation>
{
if(animateAtlas != null)
return animateAtlas.anim.getByName(name);
public function getAnim(name:String):OneOfTwo<FlxAnimation, FlxAnimateAnimation> {
return animation.getByName(name);
}
@@ -392,40 +310,26 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
return FlxPoint.weak(0, 0);
}
public inline function hasAnim(AnimName:String):Bool @:privateAccess
return animateAtlas != null ? (animateAtlas.anim.animsMap.exists(AnimName)
|| animateAtlas.anim.symbolDictionary.exists(AnimName)) : animation.exists(AnimName);
public inline function hasAnim(AnimName:String):Bool
return animation.exists(AnimName);
public inline function getAnimName() {
return (animateAtlas != null) ? atlasPlayingAnim : animation.name;
}
public inline function getAnimName()
return animation.name;
public inline function isAnimReversed():Bool {
return animateAtlas != null ? animateAtlas.anim.reversed : animation.curAnim != null ? animation.curAnim.reversed : false;
}
public inline function isAnimReversed():Bool
return animation.curAnim?.reversed ?? false;
public inline function getNameList():Array<String> {
if (animateAtlas != null)
return [for (name in @:privateAccess animateAtlas.anim.animsMap.keys()) name];
else
return animation.getNameList();
}
public inline function getNameList():Array<String>
return animation.getNameList();
public inline function stopAnim()
{
if (animateAtlas != null)
animateAtlas.anim.pause();
else
animation.stop();
}
animation.stop();
public inline function isAnimFinished() {
return animateAtlas != null ? animateAtlas.anim.finished : (animation.curAnim != null ? animation.curAnim.finished : true);
}
public inline function isAnimFinished()
return animation.curAnim?.finished ?? true;
public inline function isAnimAtEnd() {
return animateAtlas != null ? animateAtlas.anim.isAtEnd : (animation.curAnim != null ? animation.curAnim.isAtEnd : false);
}
public inline function isAnimAtEnd()
return animation.curAnim?.isAtEnd ?? false;
override function updateAnimation(elapsed:Float) {
if (animEnabled)
@@ -447,10 +351,38 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
return beatInterval = v;
}
@:noCompletion private inline function get_globalCurFrame() {
return animateAtlas != null ? (animateAtlas.anim.curFrame) : (animation.curAnim != null ? animation.curAnim.curFrame : 0);
}
@:noCompletion
@:deprecated("`FunkinSprite.animateAtlas` is deprecated, just use `FunkinSprite` instead")
public function get_animateAtlas():FunkinSprite
return isAnimate ? this : null;
@:noCompletion private inline function get_globalCurFrame()
return animation.curAnim?.curFrame ?? 0;
@:noCompletion private inline function set_globalCurFrame(val:Int) {
return animateAtlas != null ? (animateAtlas.anim.curFrame = val) : (animation.curAnim != null ? animation.curAnim.curFrame = val : val);
if (animation.curAnim != null)
animation.curAnim.curFrame = val;
return val;
}
override function prepareDrawMatrix(matrix:FlxMatrix, camera:FlxCamera):Void {
super.prepareDrawMatrix(matrix, camera);
if (__shouldDoZoomFactor()) {
__prepareZoomFactor(_rect2, camera);
matrix.setTo(
matrix.a * _rect2.width, matrix.b * _rect2.height,
matrix.c * _rect2.width, matrix.d * _rect2.height,
(matrix.tx - _rect2.x) * _rect2.width + _rect2.x,
(matrix.ty - _rect2.y) * _rect2.height + _rect2.y,
);
}
}
override function checkFlipX() {
return super.checkFlipX() != camera.flipX;
}
override function checkFlipY() {
return super.checkFlipY() != camera.flipY;
}
}
+83 -4
View File
@@ -1,19 +1,98 @@
package funkin.backend;
import flixel.FlxCamera;
import flixel.FlxG;
import flixel.math.FlxMath;
import flixel.text.FlxText;
import flixel.util.FlxColor;
import funkin.backend.system.Flags;
class FunkinText extends FlxText {
public function new(X:Float = 0, Y:Float = 0, FieldWidth:Float = 0, ?Text:String, ?Size:Int, Border:Bool = true) {
if (Size == null) Size = Flags.DEFAULT_FONT_SIZE;
class FunkinText extends FlxText
{
public var zoomFactor:Float = 1;
public var zoomFactorEnabled:Bool = true;
public function new(X:Float = 0, Y:Float = 0, FieldWidth:Float = 0, ?Text:String, ?Size:Int, Border:Bool = true)
{
if (Size == null)
Size = Flags.DEFAULT_FONT_SIZE;
super(X, Y, FieldWidth, Text, Size);
setFormat(Paths.font(Flags.DEFAULT_FONT), Size, FlxColor.WHITE);
if (Border) {
if (Border)
{
borderStyle = OUTLINE;
borderSize = 1;
borderColor = 0xFF000000;
}
}
private inline function __shouldDoZoomFactor():Bool
{
return zoomFactorEnabled && zoomFactor != 1;
}
private inline function __getZoomScaleX(camera:FlxCamera):Float
{
return (camera.scaleX > 0 ? Math.max : Math.min)(0, FlxMath.lerp(1 / camera.scaleX, 1, zoomFactor));
}
private inline function __getZoomScaleY(camera:FlxCamera):Float
{
return (camera.scaleY > 0 ? Math.max : Math.min)(0, FlxMath.lerp(1 / camera.scaleY, 1, zoomFactor));
}
private inline function __getZoomAnchorX(camera:FlxCamera):Float
{
if (Flags.USE_LEGACY_ZOOM_FACTOR)
return camera.width * 0.5;
return camera.width * 0.5 + camera.scroll.x * scrollFactor.x;
}
private inline function __getZoomAnchorY(camera:FlxCamera):Float
{
if (Flags.USE_LEGACY_ZOOM_FACTOR)
return camera.height * 0.5;
return camera.height * 0.5 + camera.scroll.y * scrollFactor.y;
}
override public function draw():Void
{
if (!__shouldDoZoomFactor())
{
super.draw();
return;
}
var camera:FlxCamera = this.camera;
if (camera == null)
camera = FlxG.camera;
var oldX:Float = x;
var oldY:Float = y;
var oldScaleX:Float = scale.x;
var oldScaleY:Float = scale.y;
var zoomScaleX:Float = __getZoomScaleX(camera);
var zoomScaleY:Float = __getZoomScaleY(camera);
var anchorX:Float = __getZoomAnchorX(camera);
var anchorY:Float = __getZoomAnchorY(camera);
x = (x - anchorX) * zoomScaleX + anchorX;
y = (y - anchorY) * zoomScaleY + anchorY;
scale.set(scale.x * zoomScaleX, scale.y * zoomScaleY);
super.draw();
x = oldX;
y = oldY;
scale.set(oldScaleX, oldScaleY);
}
}
+2 -6
View File
@@ -114,12 +114,8 @@ class MusicBeatTransition extends MusicBeatSubstate {
}
if (transitionSprite != null) {
if (transitionSprite.animateAtlas == null) {
transitionSprite.setGraphicSize(transitionCamera.width, transitionCamera.height);
transitionSprite.updateHitbox();
} else {
transitionSprite.screenCenter();
}
transitionSprite.setGraphicSize(transitionCamera.width, transitionCamera.height);
transitionSprite.updateHitbox();
}
}
@@ -5,9 +5,21 @@ import funkin.backend.assets.TranslatedAssetLibrary;
#end
import funkin.backend.assets.IModsAssetLibrary;
import lime.utils.AssetLibrary;
import haxe.ds.Map;
class AssetsLibraryList extends AssetLibrary {
public var libraries:Array<AssetLibrary> = [];
public var cleanLibraries(get, never):Array<AssetLibrary>;
function get_cleanLibraries():Array<AssetLibrary> {
return [for (l in libraries) getCleanLibrary(l)];
}
// is true if any library in `libraries` contains some kind of compressed library.
public var hasCompressedLibrary(get, never):Bool;
function get_hasCompressedLibrary():Bool {
for (l in libraries) if (getCleanLibrary(l).isCompressed) return true;
return false;
}
@:allow(funkin.backend.system.Main)
@:allow(funkin.backend.system.MainState)
@@ -18,6 +30,9 @@ class AssetsLibraryList extends AssetLibrary {
public var transLib:TranslatedAssetLibrary;
#end
private var cachePaths:Map<String, AssetLibrary> = [];
private var cacheNonExistentPaths:Map<String, Int> = [];
public function removeLibrary(lib:AssetLibrary) {
if (lib != null) {
libraries.remove(lib);
@@ -41,12 +56,29 @@ class AssetsLibraryList extends AssetLibrary {
public function existsSpecific(id:String, type:String, source:AssetSource = BOTH) {
if (!id.startsWith("assets/") && existsSpecific('assets/$id', type, source))
return true;
// There's a mod that heavily relies on addons and that can causes lags just to get a path.
final sec = Date.now().getSeconds();
if (cacheNonExistentPaths.exists(id) && sec - 10 < cacheNonExistentPaths.get(id)) {
return false;
}
else if (cachePaths.exists(id)) {
if (cachePaths.get(id).exists(id, type)) return true;
else cachePaths.remove(id);
}
for(k=>l in libraries) {
if (shouldSkipLib(l, source)) continue;
if (l.exists(id, type)) {
//trace("EXISTS", id, type, source);
cachePaths.set(id, l);
return true;
}
}
//trace("DOESNT EXISTS", id, type, source);
cacheNonExistentPaths.set(id, sec);
return false;
}
public override inline function exists(id:String, type:String):Bool
@@ -141,6 +173,16 @@ class AssetsLibraryList extends AssetLibrary {
public override inline function getAsset(id:String, type:String):Dynamic
return getSpecificAsset(id, type, BOTH);
public override function list(type:String):Array<String> {
// idk if there's a more efficient way tbh, correct if u find better
var files:Map<String, Bool> = [];
for(k=>l in libraries) {
for(f in l.list(type))
files.set(f, false);
}
return [for(k=>e in files) k];
}
public override function isLocal(id:String, type:String) {
return true;
}
@@ -175,6 +217,7 @@ class AssetsLibraryList extends AssetLibrary {
public function reset() {
unloadLibraries();
cachePaths.clear();
libraries = [];
// adds default libraries in again
+13 -21
View File
@@ -83,10 +83,11 @@ class ModsFolder {
*/
public static function loadModLib(path:String, force:Bool = false, ?modName:String) {
#if MOD_SUPPORT
if (FileSystem.exists('$path.zip'))
return loadLibraryFromZip('$path'.toLowerCase(), '$path.zip', force, modName);
else
return loadLibraryFromFolder('$path'.toLowerCase(), '$path', force, modName);
for (ext in Flags.ALLOWED_ZIP_EXTENSIONS) {
if (!FileSystem.exists('$path.$ext')) continue;
return loadLibraryFromZip('$path'.toLowerCase(), '$path.$ext', force, modName);
}
return loadLibraryFromFolder('$path'.toLowerCase(), '$path', force, modName);
#else
return null;
@@ -96,27 +97,16 @@ class ModsFolder {
public static function getModsList():Array<String> {
var mods:Array<String> = [];
#if MOD_SUPPORT
if (!FileSystem.exists(modsPath)) {
// Mods directory does not exist yet, create it
FileSystem.createDirectory(modsPath);
}
// Mods directory does not exist yet, create it
if (!FileSystem.exists(modsPath)) FileSystem.createDirectory(modsPath);
final modsList:Array<String> = FileSystem.readDirectory(modsPath);
if (modsList == null || modsList.length <= 0)
return mods;
if (modsList == null || modsList.length <= 0) return mods;
for (modFolder in modsList) {
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));
}
}
if (FileSystem.isDirectory(modsPath + modFolder)) mods.push(modFolder);
else if (Flags.ALLOWED_ZIP_EXTENSIONS.contains(Path.extension(modFolder))) mods.push(Path.withoutExtension(modFolder));
}
#end
return mods;
@@ -128,7 +118,9 @@ class ModsFolder {
#if TRANSLATIONS_SUPPORT
if(skipTranslated && (l is TranslatedAssetLibrary)) continue;
#end
if (l is ScriptedAssetLibrary || l is IModsAssetLibrary) libs.push(cast(l, IModsAssetLibrary));
// No need to check for it being a `ScriptedAssetLibrary`, if `ScriptedAssetLibrary` extends ModsFolderLibrary, which implements `IModsAssetLibrary`
// If you have to revert this change then uhhhhh wasn't me, trust 🙏
if (/*l is ScriptedAssetLibrary ||*/ l is IModsAssetLibrary) libs.push(cast(l, IModsAssetLibrary));
}
return libs;
}
@@ -149,6 +149,22 @@ class ModsFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
}
return true;
}
public override function list(type:String):Array<String> {
var result = [];
__listAppend(result, '');
return result;
}
function __listAppend(arr:Array<String>, folder:String) {
for(file in FileSystem.readDirectory('$basePath/$folder')) {
var fullPath = '$basePath/$folder/$file';
if (FileSystem.isDirectory(fullPath))
__listAppend(arr, '$folder$file/');
else
arr.push('$prefix$folder$file');
}
}
#end
// Backwards compat
@@ -47,7 +47,7 @@ class MultiFramesCollection extends FlxFramesCollection
public function addFrames(collection:FlxFramesCollection) {
if (collection == null || collection.frames == null) return;
collection.parent.useCount++;
collection.parent.incrementUseCount();
parentedFrames.push(collection);
for(f in collection.frames) {
@@ -63,7 +63,7 @@ class MultiFramesCollection extends FlxFramesCollection
if(parentedFrames != null) {
for(collection in parentedFrames) {
if(collection != null)
collection.parent.useCount--;
collection.parent.decrementUseCount();
}
parentedFrames = null;
}
+10 -4
View File
@@ -8,6 +8,7 @@ import funkin.backend.scripting.Script;
import haxe.io.Path;
import lime.utils.AssetLibrary;
import openfl.utils.Assets as OpenFlAssets;
import animate.FlxAnimateFrames;
using StringTools;
@@ -174,6 +175,9 @@ class Paths
inline static public function getSparrowAtlas(key:String, ?library:String, ?ext:String)
return FlxAtlasFrames.fromSparrow(image(key, library, ext), file('images/$key.xml', library));
inline static public function getAnimateAtlasAlt(key:String, ?settings:FlxAnimateSettings)
return FlxAnimateFrames.fromAnimate(key, null, null, null, false, settings);
inline static public function getSparrowAtlasAlt(key:String, ?ext:String)
return FlxAtlasFrames.fromSparrow('$key.${ext != null ? ext : Flags.IMAGE_EXT}', '$key.xml');
@@ -190,14 +194,14 @@ class Paths
return FlxAtlasFrames.fromAseprite('$key.${ext != null ? ext : Flags.IMAGE_EXT}', '$key.json');
inline static public function getAssetsRoot():String
return ModsFolder.currentModFolder != null ? '${ModsFolder.modsPath}${ModsFolder.currentModFolder}' : #if (sys && TEST_BUILD) './${Main.pathBack}assets/' #else './assets' #end;
return ModsFolder.currentModFolder != null ? '${ModsFolder.modsPath}${ModsFolder.currentModFolder}' : #if (sys && TEST_BUILD) './${Main.pathBack}assets/' #else './assets' #end;
/**
* Gets frames at specified path.
* @param key Path to the frames
* @param library (Additional) library to load the frames from.
*/
public static function getFrames(key:String, assetsPath:Bool = false, ?library:String, ?ext:String = null) {
public static function getFrames(key:String, assetsPath:Bool = false, ?library:String, ?ext:String = null, ?animateSettings:FlxAnimateSettings) {
if (tempFramesCache.exists(key)) {
var frames = tempFramesCache[key];
if (frames != null && frames.parent != null && frames.parent.bitmap != null && frames.parent.bitmap.readable)
@@ -205,7 +209,7 @@ class Paths
else
tempFramesCache.remove(key);
}
return tempFramesCache[key] = loadFrames(assetsPath ? key : Paths.image(key, library, true, ext), false, null, false, ext);
return tempFramesCache[key] = loadFrames(assetsPath ? key : Paths.image(key, library, true, ext), false, null, false, ext, animateSettings);
}
/**
@@ -242,7 +246,7 @@ class Paths
* @param Ext Extension of the image.
* @return FlxFramesCollection Frames
*/
static function loadFrames(path:String, Unique:Bool = false, Key:String = null, SkipAtlasCheck:Bool = false, SkipMultiCheck:Bool = false, ?Ext:String = null):FlxFramesCollection {
static function loadFrames(path:String, Unique:Bool = false, Key:String = null, SkipAtlasCheck:Bool = false, SkipMultiCheck:Bool = false, ?Ext:String = null, ?animateSettings:FlxAnimateSettings):FlxFramesCollection {
var noExt = Path.withoutExtension(path);
var ext = Ext != null ? Ext : Flags.IMAGE_EXT;
@@ -263,6 +267,8 @@ class Paths
cur++;
}
return finalFrames;
} else if (Assets.exists('$noExt/Animation.json')) {
return Paths.getAnimateAtlasAlt(noExt, animateSettings);
} else if (Assets.exists('$noExt.xml')) {
return Paths.getSparrowAtlasAlt(noExt, ext);
} else if (Assets.exists('$noExt.txt')) {
@@ -108,6 +108,8 @@ class TranslatedAssetLibrary extends AssetLibrary implements IModsAssetLibrary {
return null;
}
// TODO: list support for TranslatedAssetLibrary (idk how it works)
#if MOD_SUPPORT
public var _parsedAsset:String = null; // Theres no need to actually make this work - Nex
@@ -1,11 +1,14 @@
package funkin.backend.assets;
import funkin.backend.system.Flags;
import haxe.io.Path;
import lime.graphics.Image;
import lime.media.AudioBuffer;
import lime.text.Font;
import lime.utils.Bytes;
import openfl.utils.AssetLibrary;
import sys.io.File;
#if MOD_SUPPORT
import funkin.backend.utils.SysZip.SysZipEntry;
@@ -15,15 +18,16 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
public var basePath:String;
public var modName:String;
public var libName:String;
public var useImageCache:Bool = false;
public var prefix = 'assets/';
public var zip:SysZip;
public var assets:Map<String, SysZipEntry> = [];
public var lowerCaseAssets:Map<String, SysZipEntry> = [];
public var nameMap:Map<String, String> = [];
public function new(basePath:String, libName:String, ?modName:String) {
public var PRELOAD_VIDEOS:Bool = true;
public function new(basePath:String, libName:String, ?modName:String, ?preloadVideos:Bool = true) {
this.libName = libName;
this.basePath = basePath;
@@ -31,21 +35,59 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
this.modName = (modName == null) ? libName : modName;
zip = SysZip.openFromFile(basePath);
zip.read();
for(entry in zip.entries) {
lowerCaseAssets[entry.fileName.toLowerCase()] = assets[entry.fileName.toLowerCase()] = assets[entry.fileName] = entry;
nameMap.set(entry.fileName.toLowerCase(), entry.fileName);
if (entry.fileName.length < 0 || entry.fileName.endsWith("/")) continue;
var name:String = entry.fileName.toLowerCase(); // calling .toLowerCase a million times is never the solution
lowerCaseAssets[name] = assets[name] = assets[entry.fileName] = entry;
nameMap.set(name, entry.fileName);
}
super();
isCompressed = true;
// don't override default value of true if the file exists.
// by default `PRELOAD_VIDEOS` is true so you will never need to add this file, but in the case of it being false this is a backup method.
PRELOAD_VIDEOS = (!PRELOAD_VIDEOS) ? exists("assets/data/PRECACHE_VIDEOS", "TEXT") : PRELOAD_VIDEOS;
// if (PRELOAD_VIDEOS) precacheVideos(); // we do this in `MainState` now to handle for `Flags.VIDEO_EXT` :)
}
public function precacheVideos() {
_videoExtensions = [Flags.VIDEO_EXT];
videoCacheRemap = [];
for (entry in zip.entries) {
var name = entry.fileName.toLowerCase();
if (_videoExtensions.contains(Path.extension(name))) getPath(prefix+name);
}
var count:Int = 0;
for (_ in videoCacheRemap.keys()) count++;
if (count <= 0) return;
trace('Precached $count video${(count == 1) ? "" : "s"}');
}
// Now we have supports for videos in ZIP!!
public var _videoExtensions:Array<String> = [Flags.VIDEO_EXT];
public var videoCacheRemap:Map<String, String> = [];
public function getVideoRemap(originalPath:String):String {
if (!_videoExtensions.contains(Path.extension(_parsedAsset))) return originalPath;
if (videoCacheRemap.exists(originalPath)) return videoCacheRemap.get(originalPath);
// We adding the length of the string to counteract folder in folder naming duplicates.
var newPath = './.temp/${_parsedAsset.length}-zipvideo-${_parsedAsset.split("/").pop()}';
File.saveBytes(newPath, unzip(assets[_parsedAsset]));
videoCacheRemap.set(originalPath, newPath);
return newPath;
}
function toString():String {
return '(ZipFolderLibrary: $libName/$modName)';
return '(ZipFolderLibrary: $libName/$modName | ${zip.entries.length} entries | Detected Video Extensions: ${_videoExtensions.join(", ")})';
}
public var _parsedAsset:String;
public override function getAudioBuffer(id:String):AudioBuffer {
__parseAsset(id);
return AudioBuffer.fromBytes(unzip(assets[_parsedAsset]));
@@ -68,15 +110,12 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
return getAssetPath();
}
public inline function unzip(f:SysZipEntry)
return f == null ? null : zip.unzipEntry(f);
public inline function unzip(f:SysZipEntry) return (f == null) ? null : zip.unzipEntry(f);
public function __parseAsset(asset:String):Bool {
if (!asset.startsWith(prefix)) return false;
_parsedAsset = asset.substr(prefix.length);
if(ModsFolder.useLibFile) {
if (ModsFolder.useLibFile) {
var file = new haxe.io.Path(_parsedAsset);
if(file.file.startsWith("LIB_")) {
var library = file.file.substr(4);
@@ -87,8 +126,7 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
}
_parsedAsset = _parsedAsset.toLowerCase();
if(nameMap.exists(_parsedAsset))
_parsedAsset = nameMap.get(_parsedAsset);
if (nameMap.exists(_parsedAsset)) _parsedAsset = nameMap.get(_parsedAsset);
return true;
}
@@ -103,9 +141,8 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
return assets[_parsedAsset] != null;
}
private function getAssetPath() {
trace('[ZIP]$basePath/$_parsedAsset');
return '[ZIP]$basePath/$_parsedAsset';
private inline function getAssetPath() {
return getVideoRemap('$basePath/$_parsedAsset');
}
// TODO: rewrite this to 1 function, like ModsFolderLibrary
@@ -154,14 +191,6 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
return content;
}
// Backwards compat
@:noCompletion public var zipPath(get, set):String;
@:noCompletion private inline function get_zipPath():String {
return basePath;
}
@:noCompletion private inline function set_zipPath(value:String):String {
return basePath = value;
}
public override function list(type:String):Array<String> { return [for(k=>e in nameMap) '$prefix$e']; }
}
#end
+7 -38
View File
@@ -97,41 +97,6 @@ class Chart {
data.setFieldDefault("vocalsSuffix", "");
data.setFieldDefault("needsVoices", true);
data.setFieldDefault("difficulties", []);
var songNameLower = songName.toLowerCase();
var metaPath = Paths.file('songs/${songNameLower}/meta.json');
var metaDiffPath = Paths.file('songs/${songNameLower}/meta-${difficulty.toLowerCase()}.json');
var blacklist:Array<String> = [];
var data:ChartMetaData = null;
var fromMods:Bool = fromMods;
for (path in [metaDiffPath, metaPath]) {
if (Assets.exists(path)) {
fromMods = Paths.assetsTree.existsSpecific(path, "TEXT", MODS);
try {
var temp = CoolUtil.parseJson(path);
// Backwards compatibility (they both can be null so != true) - Nex
var coopExlc = false;
if (Reflect.hasField(temp, "coopAllowed") && Reflect.field(temp, "coopAllowed") != true) {
blacklist = blacklist.concat(["codename.coop", "codename.coop-opponent"]);
Reflect.deleteField(temp, "coopAllowed");
coopExlc = true;
}
if (Reflect.hasField(temp, "opponentModeAllowed") && Reflect.field(temp, "opponentModeAllowed") != true) {
if (!coopExlc) blacklist.push("codename.coop-opponent");
blacklist.push("codename.opponent");
Reflect.deleteField(temp, "opponentModeAllowed");
}
data = temp;
} catch(e) {
Logs.trace('Failed to load song metadata for ${songName} ($path): ${Std.string(e)}', ERROR);
}
if (data != null) break;
}
}
data.setFieldDefault("excludedGameModes", blacklist);
data.setFieldDefault("variants", []);
data.setFieldDefault("metas", []);
@@ -313,9 +278,13 @@ class Chart {
var filteredChart = filterChartForSaving(chart, saveSettings.saveMetaInChart, saveSettings.saveLocalEvents, saveSettings.saveGlobalEvents && saveSettings.seperateGlobalEvents != true);
#if sys
var songPath = saveSettings.songFolder == null ? 'songs/${chart.meta.name}' : saveSettings.songFolder, variantSuffix = variant != null && variant != "" ? '-$variant' : "";
var metaPath = 'meta$variantSuffix.json', prettyPrint = saveSettings.prettyPrint == true ? Flags.JSON_PRETTY_PRINT : null, temp:String;
if ((temp = Paths.assetsTree.getPath('assets/$songPath/$metaPath')) != null) {
var songPath = saveSettings.songFolder == null ? 'songs/${chart.meta.name}' : saveSettings.songFolder, variantSuffix = variant != null && variant != "" ? '-$variant' : "", difficultySuffix = difficulty != null && difficulty != "" ? '-$difficulty' : "";
var metaPath = 'meta$variantSuffix.json', altMetaPath = 'meta${variantSuffix}${difficultySuffix}.json', prettyPrint = saveSettings.prettyPrint == true ? Flags.JSON_PRETTY_PRINT : null, temp:String;
if ((temp = Paths.assetsTree.getPath('assets/$songPath/$altMetaPath')) != null) { //check for difficulty specific
songPath = temp.substr(0, temp.length - altMetaPath.length - 1);
metaPath = temp;
}
else if ((temp = Paths.assetsTree.getPath('assets/$songPath/$metaPath')) != null) {
songPath = temp.substr(0, temp.length - metaPath.length - 1);
metaPath = temp;
}
+2 -1
View File
@@ -32,7 +32,8 @@ typedef ChartMetaData = {
public var ?icon:String;
public var ?color:FlxColor;
public var ?excludedGameModes:Array<String>;
public var ?coopAllowed:Bool;
public var ?opponentModeAllowed:Bool;
public var ?metas:Map<String, ChartMetaData>;
public var ?instSuffix:String;
+1 -1
View File
@@ -75,7 +75,7 @@ class EventsData {
defValue: "In"
},
{name: "Mode", type: TDropDown(['direct', 'stage']), defValue: "direct"},
{name: "Multiplicative?", type: TBool, defValue: true}
{name: "Multiplicative?", type: TBool, defValue: false}
],
"Camera Modulo Change" => [
{name: "Modulo Interval", type: TInt(1, 9999999, 1), defValue: 4},
@@ -106,12 +106,15 @@ class GlobalScript {
public static function onModSwitch(newMod:String) {
destroy();
scripts = new ScriptPack("GlobalScript");
for (i in funkin.backend.assets.ModsFolder.getLoadedMods()) {
var path = Paths.script('data/global/LIB_$i');
for (lib in funkin.backend.assets.ModsFolder.getLoadedModsLibs()) {
var modName = lib.modName;
var path = Paths.script('data/global/LIB_$modName');
var script = Script.create(path);
if (script is DummyScript)
continue;
script.remappedNames.set(script.fileName, '$i:${script.fileName}');
if (script is DummyScript) continue;
script.remappedNames.set(script.fileName, '$modName:${script.fileName}');
// so you can get the current mod's library in GloablScript :)
// you should not make this a static variable then all scripts will try to reference the 1 static variable, which will be overwritten :yoikes:
script.set("MOD_LIBRARY", lib);
scripts.add(script);
script.load();
}
+3 -3
View File
@@ -89,9 +89,9 @@ class Script extends FlxBasic implements IFlxDestroyable {
"Paths" => funkin.backend.assets.Paths,
"Conductor" => funkin.backend.system.Conductor,
"FunkinShader" => funkin.backend.shaders.FunkinShader,
"CustomShader" => funkin.backend.shaders.CustomShader,
"CustomShader" => funkin.backend.shaders.CustomShader, // deprecated
"FunkinText" => funkin.backend.FunkinText,
"FlxAnimate" => funkin.backend.FlxAnimate,
"FlxAnimate" => animate.FlxAnimate,
"FunkinSprite" => funkin.backend.FunkinSprite,
"Alphabet" => funkin.menus.ui.Alphabet,
"Flags" => funkin.backend.system.Flags,
@@ -402,4 +402,4 @@ class Script extends FlxBasic implements IFlxDestroyable {
* Called when the script is loaded.
*/
public function onLoad() {}
}
}
@@ -4,7 +4,6 @@ import flixel.util.FlxDestroyUtil.IFlxDestroyable;
@:allow(funkin.backend.scripting.ScriptPack)
@:autoBuild(funkin.backend.system.macros.EventMacro.build())
@:noCustomClass
class CancellableEvent implements IFlxDestroyable {
@:dox(hide) public var cancelled:Bool = false;
@:dox(hide) private var __continueCalls:Bool = true;
@@ -54,4 +53,4 @@ class CancellableEvent implements IFlxDestroyable {
public function destroy() {
data = null;
}
}
}
@@ -0,0 +1,96 @@
package funkin.backend.scripting.events.gameplay;
import flixel.math.FlxPoint;
import flixel.tweens.FlxTween;
final class RatingsShowEvent extends CancellableEvent
{
/**
* Rating sprite (may be null)
*/
public var ratingSprite:Null<FlxSprite>;
/**
* Number sprite (may be null)
*/
public var numberSprite:Null<FlxSprite>;
/**
* Combo sprite (may be null)
*/
public var comboSprite:Null<FlxSprite>;
/**
* Scale of combo numbers. (may be null)
*/
public var numScale:Null<Float> = 0.5;
/**
* Whenever antialiasing should be enabled on combo numbers. (may be null)
*/
public var numAntialiasing:Null<Bool> = true;
/**
* Scale of the rating sprites. (may be null)
*/
public var ratingScale:Null<Float> = 0.7;
/**
* Whenever antialiasing should be enabled on ratings. (may be null)
*/
public var ratingAntialiasing:Null<Bool> = true;
/**
* Prefix of the rating sprite path. Defaults to "game/score/"
*/
public var ratingPrefix:String;
/**
* Suffix of the rating sprite path.
*/
public var ratingSuffix:String;
/**
* The sprite's acceleration.
*/
public var acceleration:Float;
/**
* A FlxPoint which x or y properties preposition the sprites current velocity.
*/
public var velocity:FlxPoint;
/**
* The duration of the sprite's alpha tween.
*/
public var tweenDuration:Float;
/**
* The start delay of the sprite's alpha tween.
*/
public var startDelay:Float;
/**
* Whenever the Rating sprites should be shown or not.
*/
public var displayRating:Bool;
/**
* Whenever the Rating sprites should be shown or not.
*/
public var displayNumbers:Bool;
/**
* Whenever the Combo sprite should be shown or not (like old Week 7 patches).
*/
public var displayCombo:Bool;
/**
* Whether the sprite should be tweened or not.
*/
public var playTween:Bool;
/**
* The amount of spacing for the combo numbers. (may be null)
*/
public var numSpacing:Null<Float>;
/**
* The position of the sprite.
*/
public var position:FlxPoint;
/**
* Whether to reset the sprite or not.
*/
public var resetSprite:Bool;
/**
* The rating name of the rating sprite. (may be null)
*/
public var rating:Null<String>;
/**
* The FlxTween instance. (null before "onPostRatingsShown")
*/
public var tween:Null<FlxTween>;
}
@@ -1,7 +1,5 @@
package funkin.backend.scripting.events.menu.freeplay;
import funkin.menus.FreeplayState.FreeplayGameMode;
final class FreeplaySongSelectEvent extends CancellableEvent {
/**
* Song name that is about to be played
@@ -16,26 +14,11 @@ final class FreeplaySongSelectEvent extends CancellableEvent {
*/
public var variant:String;
/**
* Used game mode's data.
* Whenever opponent mode is enabled or not.
*/
public var gameMode:FreeplayGameMode;
// Backwards compat
@:noCompletion public var opponentMode(get, set):Bool;
@:noCompletion private function get_opponentMode() return gameMode.modeID == "codename.opponent" || gameMode.modeID == "codename.coop-opponent";
@:noCompletion private function set_opponentMode(val:Bool) {
gameMode = coopMode ?
(val ? new FreeplayGameMode("Co-Op Mode (Switched)", "codename.coop-opponent", ["coop-switched", "opponent", "coop"]) : new FreeplayGameMode("Opponent Mode", "codename.opponent", ["opponent"])) :
(val ? new FreeplayGameMode("Opponent Mode", "codename.opponent", ["opponent"]) : null);
return val;
}
@:noCompletion public var coopMode(get, set):Bool;
@:noCompletion private function get_coopMode() return gameMode.modeID == "codename.coop" || gameMode.modeID == "codename.coop-opponent";
@:noCompletion private function set_coopMode(val:Bool) {
gameMode = opponentMode ?
(val ? new FreeplayGameMode("Co-Op Mode (Switched)", "codename.coop-opponent", ["coop-switched", "opponent", "coop"]) : new FreeplayGameMode("Co-Op Mode", "codename.coop", ["coop"])) :
(val ? new FreeplayGameMode("Co-Op Mode", "codename.coop", ["coop"]) : null);
return val;
}
public var opponentMode:Bool;
/**
* Whenever coop mode is enabled.
*/
public var coopMode:Bool;
}
@@ -34,11 +34,11 @@ final class NoteHitEvent extends CancellableEvent {
/**
* Whenever the Rating sprites should be shown or not.
*/
public var displayRating:Bool;
public var displayRating:Null<Bool>;
/**
* Whenever the Combo sprite should be shown or not (like old Week 7 patches).
*/
public var displayCombo:Bool;
public var displayCombo:Null<Bool>;
/**
* Note that has been pressed
*/
@@ -66,11 +66,11 @@ final class NoteHitEvent extends CancellableEvent {
/**
* Prefix of the rating sprite path. Defaults to "game/score/"
*/
public var ratingPrefix:String;
public var ratingPrefix:Null<String>;
/**
* Suffix of the rating sprite path.
*/
public var ratingSuffix:String;
public var ratingSuffix:Null<String>;
/**
* Direction of the press (0 = Left, 1 = Down, 2 = Up, 3 = Right)
*/
@@ -98,19 +98,19 @@ final class NoteHitEvent extends CancellableEvent {
/**
* Scale of combo numbers.
*/
public var numScale:Float = 0.5;
public var numScale:Null<Float>;
/**
* Whenever antialiasing should be enabled on combo number.
*/
public var numAntialiasing:Bool = true;
public var numAntialiasing:Null<Bool>;
/**
* Scale of ratings.
*/
public var ratingScale:Float = 0.7;
public var ratingScale:Null<Float>;
/**
* Whenever antialiasing should be enabled on ratings.
*/
public var ratingAntialiasing:Bool = true;
public var ratingAntialiasing:Null<Bool>;
/**
* Whenever the animation should be forced to play (if it's null it will be forced based on the sprite's data xml, if it has one).
*/
@@ -1,36 +0,0 @@
package funkin.backend.shaders;
import flixel.util.FlxColor;
import openfl.display.ShaderParameter;
@:dox(hide)
typedef BlendModeShader =
{
var uBlendColor:ShaderParameter<Float>;
}
@:dox(hide)
class BlendModeEffect
{
public var shader(default, null):BlendModeShader;
@:isVar
public var color(default, set):FlxColor;
public function new(shader:BlendModeShader, color:FlxColor):Void
{
shader.uBlendColor.value = [];
this.shader = shader;
this.color = color;
}
function set_color(color:FlxColor):FlxColor
{
shader.uBlendColor.value[0] = color.redFloat;
shader.uBlendColor.value[1] = color.greenFloat;
shader.uBlendColor.value[2] = color.blueFloat;
shader.uBlendColor.value[3] = color.alphaFloat;
return this.color = color;
}
}
@@ -0,0 +1,766 @@
package funkin.backend.shaders;
import haxe.Timer;
import openfl.filters.BitmapFilter;
import openfl.filters.BitmapFilterShader;
import openfl.display.BitmapData;
import openfl.display.DisplayObjectRenderer;
import openfl.display.BlendMode;
import openfl.display.Shader;
import openfl.geom.Point;
import openfl.geom.Rectangle;
/**
This BloomEffect was modified by heihua based on openfl.filters.BlurFilter.
The BloomEffect class applies a bloom/glow visual effect to display objects.
A bloom effect extracts bright areas from an image, blurs them, and combines
them back to create a glowing halo around bright objects. This effect is
commonly used to simulate intense light, emissive materials, or to add a
dreamy, atmospheric quality to scenes.
The effect consists of three stages:
1. Extraction - Bright pixels above a threshold are extracted
2. Blurring - The extracted bright areas are blurred horizontally and vertically
3. Combination - The blurred result is blended back with the original image
**/
@:noCustomClass
class BloomEffect extends BitmapFilter
{
@:noCompletion private static var __blurShader:BlurShader;
@:noCompletion private static var __combineShader:CombineShader;
@:noCompletion private static var __extractShader:ExtractShader;
@:noCompletion private static var __extractLowShader:ExtractLowShader;
/**
Values that are a power of 2 (such as 2, 4, 8, 16 and 32) are optimized to render
more quickly than other values.
**/
public var blurX(get, set):Float;
/**
Values that are a power of 2 (such as 2, 4, 8, 16 and 32) are optimized to render
more quickly than other values.
**/
public var blurY(get, set):Float;
/**
The downscaling factor for bloom rendering. Higher values significantly reduce
GPU performance cost, but setting values too high may cause noticeable flickering.
Recommended range is 8-24.
**/
public var quality(get, set):Float;
/**
The intensity of the bloom effect. Higher values produce more pronounced bloom.
**/
public var strength(get, set):Float;
/**
The brightness threshold for bloom extraction. Pixels brighter than this value
will contribute to the bloom effect. Value range is 0.0 to 1.0.
**/
public var threshold(get, set):Float;
/**
The smoothness of the threshold transition in blur shader.
Higher values create a smoother transition for brightness correction.
Value range is 0.0 to 1.0. Default is 0.1.
**/
public var smoothness(get, set):Float;
/**
Enables extended rendering area to avoid edge artifacts. Enabling this option
will increase performance cost. Generally not required when rendering to camera.
**/
public var extension(get, set):Bool;
/**
Low-quality pixel sampling mode. Disabling it significantly reduces screen flickering,
with minimal performance impact on desktop platforms but a higher
performance cost on non-desktop platforms.
**/
public var useLowQualityExtract(get, set):Bool;
/**
The weights for calculating brightness (RGB to grayscale).
Order: [Red, Green, Blue]. Default is [0.2126, 0.7152, 0.0722].
**/
public var weights(get, set):Array<Float>;
/**
The blend mode used when combining the bloom with the original image.
BlendMode currently supports: (BlendMode.ADD, BlendMode.ALPHA, BlendMode.HARDLIGHT,
BlendMode.LIGHTEN, BlendMode.MULTIPLY, BlendMode.OVERLAY, BlendMode.SCREEN,
BlendMode.COLORDODGE, BlendMode.SOFTLIGHT).
Default is BlendMode.ADD.
**/
public var blendMode(get, set):BlendMode;
@:noCompletion private var __blurX:Float;
@:noCompletion private var __blurY:Float;
@:noCompletion private var __horizontalPasses:Int;
@:noCompletion private var __quality:Float;
@:noCompletion private var __verticalPasses:Int;
@:noCompletion private var __strength:Float;
@:noCompletion private var __threshold:Float;
@:noCompletion private var __smoothness:Float;
@:noCompletion private var __extension:Bool;
@:noCompletion private var __useLowQualityExtract:Bool;
@:noCompletion private var __weights:Array<Float>;
@:noCompletion private var __blendMode:BlendMode;
#if openfljs
@:noCompletion private static function __init__()
{
untyped Object.defineProperties(BloomEffect.prototype, {
"blurX": {
get: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function () { return this.get_blurX (); }"),
set: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function (v) { return this.set_blurX (v); }")
},
"blurY": {
get: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function () { return this.get_blurY (); }"),
set: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function (v) { return this.set_blurY (v); }")
},
"quality": {
get: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function () { return this.get_quality (); }"),
set: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function (v) { return this.set_quality (v); }")
},
"strength": {
get: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function () { return this.get_strength (); }"),
set: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function (v) { return this.set_strength (v); }")
},
"threshold": {
get: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function () { return this.get_threshold (); }"),
set: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function (v) { return this.set_threshold (v); }")
},
"useLowQualityExtract": {
get: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function () { return this.get_useLowQualityExtract (); }"),
set: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function (v) { return this.set_useLowQualityExtract (v); }")
},
"weights": {
get: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function () { return this.get_weights (); }"),
set: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function (v) { return this.set_weights (v); }")
},
"blendMode": {
get: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function () { return this.get_blendMode (); }"),
set: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function (v) { return this.set_blendMode (v); }")
},
});
}
#end
/**
Initializes the bloom filter with the specified parameters.
@param blurX The amount to blur horizontally.
@param blurY The amount to blur vertically.
@param quality The downscaling factor for bloom rendering (higher values reduce
GPU cost but may cause flickering if too high).
@param strength The intensity of the bloom effect.
@param threshold The brightness threshold for bloom extraction (0.0 to 1.0).
@param smoothness The smoothness of threshold transition in blur (0.0 to 1.0).
@param useLowQualityExtract Enables performance-optimized extraction with
potentially more flickering.
**/
public function new(blurX:Float = 50, blurY:Float = 50, quality:Float = 8, strength:Float = 0.6, threshold:Float = 0.6, smoothness:Float = 0.1, useLowQualityExtract:Bool = true)
{
super();
if (__blurShader == null) __blurShader = new BlurShader();
if (__combineShader == null) __combineShader = new CombineShader();
if (__extractShader == null) __extractShader = new ExtractShader();
if (__extractLowShader == null) __extractLowShader = new ExtractLowShader();
this.blurX = blurX;
this.blurY = blurY;
this.quality = quality;
this.strength = strength;
this.threshold = threshold;
this.smoothness = smoothness;
this.extension = false;
this.useLowQualityExtract = useLowQualityExtract;
this.weights = [0.2126, 0.7152, 0.0722];
this.blendMode = BlendMode.ADD;
__needSecondBitmapData = true;
__preserveObject = true;
__renderDirty = true;
}
public override function clone():BitmapFilter
{
var cloned = new BloomEffect(__blurX, __blurY, __quality, __strength, __threshold, __smoothness, __useLowQualityExtract);
cloned.weights = __weights != null ? __weights.copy() : [0.2126, 0.7152, 0.0722];
cloned.blendMode = __blendMode;
return cloned;
}
@:noCompletion private override function __applyFilter(bitmapData:BitmapData, sourceBitmapData:BitmapData, sourceRect:Rectangle, destPoint:Point):BitmapData
{
trace("Due to technical limitations, I'm unable to implement the bitmapData rendering method. If you know how to implement it, you're welcome to contribute this feature.");
return sourceBitmapData;
}
@:noCompletion private override function __initShader(renderer:DisplayObjectRenderer, pass:Int, sourceBitmapData:BitmapData):Shader
{
final numBlurPasses = __horizontalPasses + __verticalPasses;
switch pass
{
case 0:
if (__useLowQualityExtract)
{
__extractLowShader.uThreshold.value[0] = __threshold;
__extractLowShader.uSmoothness.value[0] = __smoothness;
__extractLowShader.uQuality.value[0] = __quality;
__extractLowShader.uWeights.value = __weights;
return __extractLowShader;
}
else
{
__extractShader.uThreshold.value[0] = __threshold;
__extractShader.uSmoothness.value[0] = __smoothness;
__extractShader.uQuality.value[0] = __quality;
__extractShader.uWeights.value = __weights;
return __extractShader;
}
case _ if (pass <= numBlurPasses):
final blurPass = pass - 1;
final isHorizontal = blurPass < __horizontalPasses;
final scalePass = isHorizontal ? blurPass : blurPass - __horizontalPasses;
final scale = Math.pow(0.5, scalePass >> 1);
final blurRadius = isHorizontal ? blurX * scale : blurY * scale;
if (isHorizontal)
{
__blurShader.uRadius.value[0] = blurRadius / __quality;
__blurShader.uRadius.value[1] = 0.0;
}
else
{
__blurShader.uRadius.value[0] = 0.0;
__blurShader.uRadius.value[1] = blurRadius / __quality;
}
__blurShader.uQuality.value[0] = __quality;
__blurShader.uStrength.value[0] = Math.pow(__strength, 1.0 / numBlurPasses);
return __blurShader;
default:
__combineShader.sourceBitmap.input = sourceBitmapData;
__combineShader.uThreshold.value[0] = __threshold;
__combineShader.uQuality.value[0] = __quality;
__combineShader.uBlendMode.value[0] = cast __blendMode;
return __combineShader;
}
}
// Get & Set Methods
@:noCompletion private function get_blurX():Float
{
return __blurX;
}
@:noCompletion private function set_blurX(value:Float):Float
{
if (value != __blurX)
{
__blurX = value;
__renderDirty = true;
if (!__extension)
{
// Setting it to 1 prevents bloom flickering at the screen edges
__leftExtension = 1;
__rightExtension = 1;
}
else
{
__leftExtension = (value > 0 ? Math.ceil(value) : 0);
__rightExtension = __leftExtension;
}
__horizontalPasses = (value <= 0) ? 0 : Math.ceil(value * 0.0625 / quality) + 1;
__numShaderPasses = __horizontalPasses + __verticalPasses + 2;
}
return value;
}
@:noCompletion private function get_blurY():Float
{
return __blurY;
}
@:noCompletion private function set_blurY(value:Float):Float
{
if (value != __blurY)
{
__blurY = value;
__renderDirty = true;
if (!__extension)
{
// Setting it to 1 prevents bloom flickering at the screen edges
__topExtension = 1;
__bottomExtension = 1;
}
else
{
__topExtension = (value > 0 ? Math.ceil(value) : 0);
__bottomExtension = __topExtension;
}
__verticalPasses = (value <= 0) ? 0 : Math.ceil(value * 0.0625 / quality) + 1;
__numShaderPasses = __horizontalPasses + __verticalPasses + 2;
}
return value;
}
@:noCompletion private function get_quality():Float
{
return __quality;
}
@:noCompletion private function set_quality(value:Float):Float
{
__horizontalPasses = (__blurX <= 0) ? 0 : Math.round(__blurX * 0.125 / value) + 1;
__verticalPasses = (__blurY <= 0) ? 0 : Math.round(__blurY * 0.125 / value) + 1;
__numShaderPasses = __horizontalPasses + __verticalPasses + 2;
if (value != __quality)
__renderDirty = true;
return __quality = value;
}
@:noCompletion private function get_strength():Float
{
return __strength;
}
@:noCompletion private function set_strength(value:Float):Float
{
if (value != __strength)
{
__strength = value;
__renderDirty = true;
}
return value;
}
@:noCompletion private function get_threshold():Float
{
return __threshold;
}
@:noCompletion private function set_threshold(value:Float):Float
{
if (value != __threshold)
{
__threshold = value;
__renderDirty = true;
}
return value;
}
@:noCompletion private function get_smoothness():Float
{
return __smoothness;
}
@:noCompletion private function set_smoothness(value:Float):Float
{
if (value != __smoothness)
{
__smoothness = value;
__renderDirty = true;
}
return value;
}
@:noCompletion private function get_extension():Bool
{
return __extension;
}
@:noCompletion private function set_extension(value:Bool):Bool
{
if (value != __extension)
{
__extension = value;
if (!value)
__leftExtension = __rightExtension = __topExtension = __bottomExtension = 0;
else
{
__leftExtension = __rightExtension = (__blurX > 0 ? Math.ceil(__blurX) : 0);
__topExtension = __bottomExtension = (__blurY > 0 ? Math.ceil(__blurY) : 0);
}
__renderDirty = true;
}
return value;
}
@:noCompletion private function get_useLowQualityExtract():Bool
{
return __useLowQualityExtract;
}
@:noCompletion private function set_useLowQualityExtract(value:Bool):Bool
{
if (value != __useLowQualityExtract)
{
__useLowQualityExtract = value;
__renderDirty = true;
}
return value;
}
@:noCompletion private function get_weights():Array<Float>
{
return __weights;
}
@:noCompletion private function set_weights(value:Array<Float>):Array<Float>
{
if (value != __weights)
{
__weights = value;
__renderDirty = true;
}
return value;
}
@:noCompletion private function get_blendMode():BlendMode
{
return __blendMode;
}
@:noCompletion private function set_blendMode(value:BlendMode):BlendMode
{
if (value != __blendMode)
{
__blendMode = value;
__renderDirty = true;
}
return value;
}
}
private class BlurShader extends BitmapFilterShader
{
@:glFragmentSource("
uniform sampler2D openfl_Texture;
uniform float uStrength;
varying mat2 vBlurCoord0;
varying mat2 vBlurCoord1;
varying vec2 vBlurCoord2;
varying mat2 vBlurCoord3;
varying mat2 vBlurCoord4;
varying float invQuality;
void main(void) {
if ((all(greaterThanEqual(vBlurCoord2, vec2(0.0))) && all(lessThanEqual(vBlurCoord2, vec2(1.0)))) == false) return;
vec4 sum = texture2D(openfl_Texture, clamp(vBlurCoord0[0], 0.0, invQuality)) * 0.028532;
sum += texture2D(openfl_Texture, clamp(vBlurCoord0[1], 0.0, invQuality)) * 0.067234;
sum += texture2D(openfl_Texture, clamp(vBlurCoord1[0], 0.0, invQuality)) * 0.124009;
sum += texture2D(openfl_Texture, clamp(vBlurCoord1[1], 0.0, invQuality)) * 0.179044;
sum += texture2D(openfl_Texture, clamp(vBlurCoord2, 0.0, invQuality)) * 0.202360;
sum += texture2D(openfl_Texture, clamp(vBlurCoord3[0], 0.0, invQuality)) * 0.179044;
sum += texture2D(openfl_Texture, clamp(vBlurCoord3[1], 0.0, invQuality)) * 0.124009;
sum += texture2D(openfl_Texture, clamp(vBlurCoord4[0], 0.0, invQuality)) * 0.067234;
sum += texture2D(openfl_Texture, clamp(vBlurCoord4[1], 0.0, invQuality)) * 0.028532;
gl_FragColor = sum * uStrength;
}
")
@:glVertexSource("
attribute vec4 openfl_Position;
attribute vec2 openfl_TextureCoord;
uniform mat4 openfl_Matrix;
uniform vec2 uRadius;
uniform vec2 uTextureSize;
uniform float uQuality;
varying mat2 vBlurCoord0;
varying mat2 vBlurCoord1;
varying vec2 vBlurCoord2;
varying mat2 vBlurCoord3;
varying mat2 vBlurCoord4;
varying float invQuality;
void main(void) {
vec4 pos = openfl_Position;
invQuality = 1.0 / uQuality;
pos.xy *= invQuality;
gl_Position = openfl_Matrix * pos;
vec2 r = uRadius / uTextureSize;
vec2 coord = openfl_TextureCoord * invQuality;
vBlurCoord0[0] = coord - r;
vBlurCoord0[1] = coord - r * 0.25;
vBlurCoord1[0] = coord - r * 0.5;
vBlurCoord1[1] = coord - r * 0.75;
vBlurCoord2 = coord;
vBlurCoord3[0] = coord + r * 0.25;
vBlurCoord3[1] = coord + r * 0.5;
vBlurCoord4[0] = coord + r * 0.75;
vBlurCoord4[1] = coord + r;
}
")
public function new()
{
super();
uStrength.value = [1.0];
uRadius.value = [0, 0];
uQuality.value = [8];
uTextureSize.value = [1, 1];
}
@:noCompletion private override function __update():Void
{
#if !macro
uTextureSize.value[0] = __texture.input.width;
uTextureSize.value[1] = __texture.input.height;
#end
super.__update();
}
}
private class ExtractLowShader extends BitmapFilterShader
{
@:glFragmentSource("
uniform sampler2D openfl_Texture;
uniform float uThreshold;
uniform float uSmoothness;
uniform vec3 uWeights;
varying vec2 vTexCoord;
void main(void) {
if ((all(greaterThanEqual(vTexCoord, vec2(0.0))) && all(lessThanEqual(vTexCoord, vec2(1.0)))) == false) return;
vec4 texel = texture2D(openfl_Texture, vTexCoord);
float brightness = min(dot(texel.rgb, uWeights), 1.0);
float mask = smoothstep(uThreshold, uThreshold + uSmoothness, brightness);
gl_FragColor = texel * mask;
}
")
@:glVertexSource("
attribute vec4 openfl_Position;
attribute vec2 openfl_TextureCoord;
uniform mat4 openfl_Matrix;
uniform vec2 openfl_TextureSize;
uniform float uQuality;
varying vec2 vTexCoord;
void main(void) {
vec4 pos = openfl_Position;
pos.xy /= uQuality;
gl_Position = openfl_Matrix * pos;
vTexCoord = openfl_TextureCoord;
}
")
public function new()
{
super();
uThreshold.value = [0.6];
uSmoothness.value = [0.1];
uQuality.value = [8];
uWeights.value = [0.2126, 0.7152, 0.0722];
}
}
private class ExtractShader extends BitmapFilterShader
{
@:glFragmentSource("
uniform sampler2D openfl_Texture;
uniform vec2 openfl_TextureSize;
uniform float uThreshold;
uniform float uSmoothness;
uniform float uQuality;
uniform vec3 uWeights;
varying vec2 vTexCoord;
varying vec4 border;
void main(void) {
if ((all(greaterThanEqual(vTexCoord, border.xy)) && all(lessThanEqual(vTexCoord, border.zw))) == false) return;
float quality = floor(uQuality) / 2.0;
vec2 texelSize = 1.0 / openfl_TextureSize;
vec4 accumulated = vec4(0.0);
int sampleCount = 0;
for (float dx = -quality; dx <= quality; dx += 2.0) {
for (float dy = -quality; dy <= quality; dy += 2.0) {
vec2 sampleCoord = vTexCoord + vec2(dx, dy) * texelSize;
vec4 texel = texture2D(openfl_Texture, sampleCoord);
float brightness = min(dot(texel.rgb, uWeights), 1.0);
float mask = smoothstep(uThreshold, uThreshold + uSmoothness, brightness);
accumulated += texel * mask;
sampleCount++;
}
}
gl_FragColor = accumulated / float(sampleCount);
}
")
@:glVertexSource("
attribute vec4 openfl_Position;
attribute vec2 openfl_TextureCoord;
uniform mat4 openfl_Matrix;
uniform vec2 openfl_TextureSize;
uniform float uQuality;
varying vec2 vTexCoord;
varying vec4 border;
void main(void) {
vec4 pos = openfl_Position;
pos.xy /= uQuality;
vec2 size = 1.0 / openfl_TextureSize * uQuality;
border = vec4(size, vec2(1.0) - size);
gl_Position = openfl_Matrix * pos;
vTexCoord = openfl_TextureCoord;
}
")
public function new()
{
super();
uThreshold.value = [0.6];
uSmoothness.value = [0.1];
uQuality.value = [8];
uWeights.value = [0.2126, 0.7152, 0.0722];
}
}
private class CombineShader extends BitmapFilterShader
{
@:glFragmentSource("
uniform sampler2D openfl_Texture;
uniform sampler2D sourceBitmap;
uniform float uThreshold;
uniform int uBlendMode;
varying vec4 textureCoords;
vec4 blendScreen(vec4 src, vec4 bloom) {
return vec4(1.0) - (vec4(1.0) - src) * (vec4(1.0) - bloom);
}
vec4 blendMultiply(vec4 src, vec4 bloom) {
return src * bloom;
}
vec4 blendLighten(vec4 src, vec4 bloom) {
return max(src, bloom);
}
vec4 blendOverlay(vec4 src, vec4 bloom) {
vec4 result = vec4(0.0);
for (int i = 0; i < 4; i++) {
if (src[i] < 0.5) {
result[i] = 2.0 * src[i] * bloom[i];
} else {
result[i] = 1.0 - 2.0 * (1.0 - src[i]) * (1.0 - bloom[i]);
}
}
return result;
}
vec4 blendColorDodge(vec4 src, vec4 bloom) {
vec4 result = vec4(0.0);
for (int i = 0; i < 4; i++) {
if (bloom[i] < 1.0) {
result[i] = min(1.0, src[i] / (1.0 - bloom[i]));
} else {
result[i] = 1.0;
}
}
return result;
}
vec4 blendSoftLight(vec4 src, vec4 bloom) {
vec4 result = vec4(0.0);
for (int i = 0; i < 4; i++) {
if (bloom[i] < 0.5) {
result[i] = src[i] - (1.0 - 2.0 * bloom[i]) * src[i] * (1.0 - src[i]);
} else {
float d = (src[i] <= 0.25) ? ((16.0 * src[i] - 12.0) * src[i] + 4.0) * src[i] : sqrt(src[i]);
result[i] = src[i] + (2.0 * bloom[i] - 1.0) * (d - src[i]);
}
}
return result;
}
vec4 blendAlpha(vec4 src, vec4 bloom) {
return src + bloom * (1.0 - src.a);
}
void main(void) {
vec4 src = texture2D(sourceBitmap, textureCoords.xy);
vec4 bloom = texture2D(openfl_Texture, textureCoords.zw);
vec4 result;
if(uBlendMode == 0)
result = src + bloom;
else if(uBlendMode == 1)
result = blendAlpha(src, bloom);
else if(uBlendMode == 5)
result = blendOverlay(src, bloom);
else if(uBlendMode == 8)
result = blendLighten(src, bloom);
else if(uBlendMode == 9)
result = blendMultiply(src, bloom);
else if(uBlendMode == 11)
result = blendOverlay(src, bloom);
else if(uBlendMode == 12)
result = blendScreen(src, bloom);
else if(uBlendMode == 15)
result = blendColorDodge(src, bloom);
else if(uBlendMode == 17)
result = blendSoftLight(src, bloom);
else
result = src + bloom;
gl_FragColor = result;
}
")
@:glVertexSource("
attribute vec4 openfl_Position;
attribute vec2 openfl_TextureCoord;
uniform mat4 openfl_Matrix;
uniform vec2 openfl_TextureSize;
uniform float uQuality;
varying vec4 textureCoords;
void main(void) {
gl_Position = openfl_Matrix * openfl_Position;
textureCoords = vec4(openfl_TextureCoord, openfl_TextureCoord / uQuality);
}
")
public function new()
{
super();
uQuality.value = [8];
uThreshold.value = [0.6];
uBlendMode.value = [0];
}
}
+8 -32
View File
@@ -2,39 +2,15 @@ package funkin.backend.shaders;
import openfl.Assets;
/**
* Class for custom shaders.
*
* To create one, create a `shaders` folder in your assets/mod folder, then add a file named `my-shader.frag` or/and `my-shader.vert`.
*
* Non-existent shaders will only load the default one, and throw a warning in the console.
*
* To access the shader's uniform variables, use `shader.variable`
*/
@:deprecated("Use funkin.backend.shaders.FunkinShader.fromFile instead.")
class CustomShader extends FunkinShader {
public var path:String = "";
@:isVar
public var path(get, set):String;
inline function get_path():String return path != null ? path : _fragmentFilePath + _vertexFilePath;
inline function set_path(v:Null<String>):String return path = cast v;
/**
* Creates a new custom shader
* @param name Name of the frag and vert files.
* @param glslVersion GLSL version to use. Defaults to `120`.
*/
public function new(name:String, glslVersion:String = null) {
if (glslVersion == null) glslVersion = Flags.DEFAULT_GLSL_VERSION;
var fragShaderPath = Paths.fragShader(name);
var vertShaderPath = Paths.vertShader(name);
var fragCode = Assets.exists(fragShaderPath) ? Assets.getText(fragShaderPath) : null;
var vertCode = Assets.exists(vertShaderPath) ? Assets.getText(vertShaderPath) : null;
fileName = name;
fragFileName = fragShaderPath;
vertFileName = vertShaderPath;
path = fragShaderPath+vertShaderPath;
if (fragCode == null && vertCode == null)
Logs.error('Shader "$name" couldn\'t be found.');
super(fragCode, vertCode, glslVersion);
public function new(name:String, ?glslVersion:String) {
super();
loadShaderFile(Paths.fragShader(name), Paths.vertShader(name), glslVersion);
}
}
+260 -609
View File
@@ -1,533 +1,65 @@
package funkin.backend.shaders;
import flixel.graphics.FlxGraphic;
import flixel.system.FlxAssets.FlxShader;
import flixel.util.FlxSignal.FlxTypedSignal;
import haxe.io.Path;
import haxe.Exception;
import hscript.IHScriptCustomBehaviour;
import lime.utils.Float32Array;
import openfl.display.BitmapData;
import openfl.display.ShaderInput;
import openfl.display.Shader;
import openfl.display.ShaderParameter;
import openfl.display.ShaderParameterType;
import openfl.display.ShaderPrecision;
import openfl.display.ShaderInput;
import openfl.display3D._internal.GLProgram;
import openfl.display3D._internal.GLShader;
import openfl.display3D.Program3D;
import openfl.utils._internal.Log;
import openfl.utils.GLSLSourceAssembler;
import flixel.addons.display.FlxRuntimeShader;
import flixel.graphics.FlxGraphic;
import flixel.util.FlxSignal.FlxTypedSignal;
import flixel.util.FlxStringUtil;
using StringTools;
@:access(openfl.display3D.Context3D)
@:access(openfl.display3D.Program3D)
@:access(openfl.display.ShaderInput)
@:access(openfl.display.ShaderParameter)
class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
private static var __instanceFields = Type.getInstanceFields(FunkinShader);
private static var FRAGMENT_SHADER = 0;
private static var VERTEX_SHADER = 1;
class FunkinShader extends FlxRuntimeShader implements IHScriptCustomBehaviour {
public var onGLUpdate:FlxTypedSignal<Void->Void> = new FlxTypedSignal<Void->Void>();
public var onProcessGLData:FlxTypedSignal<(String, String)->Void> = new FlxTypedSignal<(String, String)->Void>();
public var glslVer:String = Flags.DEFAULT_GLSL_VERSION;
public var fileName:String = "FunkinShader";
public var fragFileName:String = "FunkinShader";
public var vertFileName:String = "FunkinShader";
public var shaderPrefix:String = "";
public var fragmentPrefix:String = "";
public var vertexPrefix:String = "";
/**
* Creates a new shader from the specified fragment and vertex source.
* Accepts `#pragma header`.
* @param frag Fragment source (pass `null` to use default)
* @param vert Vertex source (pass `null` to use default)
* @param glslVer Version of GLSL to use (defaults to 120)
*/
public override function new(frag:String, vert:String, glslVer:String = null) {
if (glslVer == null) glslVer = Flags.DEFAULT_GLSL_VERSION;
if (frag == null) frag = ShaderTemplates.defaultFragmentSource;
if (vert == null) vert = ShaderTemplates.defaultVertexSource;
this.glFragmentSource = frag;
this.glVertexSource = vert;
this.glslVer = glslVer;
super();
public function new(?fragmentSource:String, ?vertexSource:String, ?version:String) {
super(fragmentSource, vertexSource, version ?? (fragmentSource != null || vertexSource != null ? Flags.DEFAULT_GLSL_VERSION : null));
}
static var IMPORT_REGEX = ~/#import\s+<(.*)>/;
private function processImports(value:String, type:Int):String
{
while(IMPORT_REGEX.match(value))
{
var importPath = IMPORT_REGEX.matched(1);
var importSource = Assets.getText("assets/shaders/" + importPath);
if(importSource == null) {
var fileName = type == FRAGMENT_SHADER ? fragFileName : vertFileName;
Logs.traceColored([
Logs.logText('[Shader] ', RED),
Logs.logText('Failed to import shader ${importPath} in ${fileName}', RED),
]);
} else {
value = value.replace(IMPORT_REGEX.matched(0), importSource);
}
}
return value;
public static function fromFile(fragmentPath:String, ?vertexPath:String, ?version:String):FunkinShader {
return new FunkinShader().loadShaderFile(fragmentPath, vertexPath, version);
}
static var ERROR_POS_REGEX = ~/(\d+):(\d+): (.*)/g;
static var ERROR_REGEX = ~/ERROR: (\d+):(\d+): (.*)/g;
static var ERROR_REGEX_2 = ~/(\d+)\((\d+)\) : error ([^:]+): (.*)/g;
@:noCompletion private override function __createGLShader(source:String, type:Int):GLShader
{
var gl = __context.gl;
var shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
var shaderInfoLog = gl.getShaderInfoLog(shader);
var hasInfoLog = shaderInfoLog != null && StringTools.trim(shaderInfoLog) != "";
var compileStatus = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (hasInfoLog || compileStatus == 0)
{
var isVertexShader = type == gl.VERTEX_SHADER;
var messageBuf = new StringBuf();
messageBuf.add((compileStatus == 0) ? "Error" : "Info");
if(isVertexShader) {
messageBuf.add(" compiling vertex shader");
if(vertFileName != null && vertFileName.length > 0) {
messageBuf.add(" (" + vertFileName + ")");
}
} else {
messageBuf.add(" compiling fragment shader");
if(fragFileName != null && fragFileName.length > 0) {
messageBuf.add(" (" + fragFileName + ")");
}
}
messageBuf.add("\n");
var errorPositions = [];
var regex = null;
var tmp = shaderInfoLog;
if(shaderInfoLog.contains(" : error ")) {
regex = ERROR_REGEX_2;
while(regex.match(tmp)) {
errorPositions.push(new ShaderErrorPosition(regex.matched(2), regex.matched(1), regex.matched(4)));
tmp = regex.matchedRight();
}
} else if(shaderInfoLog.contains("ERROR: ")) {
regex = ERROR_REGEX;
while(regex.match(tmp)) {
errorPositions.push(new ShaderErrorPosition(regex.matched(2), regex.matched(1), regex.matched(3)));
tmp = regex.matchedRight();
}
} else {
regex = ERROR_POS_REGEX;
while(regex.match(tmp)) {
errorPositions.push(new ShaderErrorPosition(regex.matched(2), regex.matched(1), regex.matched(3)));
tmp = regex.matchedRight();
}
}
var splitSource = source.split("\n");
for(error in errorPositions) {
messageBuf.add("ERROR: Line: " + error.line);
if(error.column > 0) {
messageBuf.add(", Column: " + error.column);
}
messageBuf.add(", " + error.message);
if(error.line < splitSource.length) {
messageBuf.add("\nLine: ");
messageBuf.add(splitSource[error.line-1].trim());
}
messageBuf.add("\n\n");
}
var hasErrorPosition = errorPositions.length > 0;
if(hasErrorPosition) {
messageBuf.add("Raw shader info log:\n");
}
messageBuf.add(shaderInfoLog);
messageBuf.add("\n");
messageBuf.add(source);
var message = messageBuf.toString();
if (compileStatus == 0) Log.error(message);
else if (hasInfoLog) Log.debug(message);
public function loadShaderFile(fragmentPath:String, ?vertexPath:String, ?version:String):FunkinShader {
if (vertexPath == null) {
final idx = fragmentPath.lastIndexOf(".");
if (idx == -1) vertexPath = fragmentPath;
else vertexPath = fragmentPath.substr(0, idx);
}
return shader;
}
fragmentPath = FlxRuntimeShader._getPath(fragmentPath, false);
vertexPath = FlxRuntimeShader._getPath(vertexPath, true);
_fromFile(fragmentPath, vertexPath, version ?? (fragmentPath != null || vertexPath != null ? Flags.DEFAULT_GLSL_VERSION : null));
@:noCompletion private override function __createGLProgram(vertexSource:String, fragmentSource:String):GLProgram
{
var program:GLProgram = null;
try
{
var gl = __context.gl;
var vertexShader = __createGLShader(vertexSource, gl.VERTEX_SHADER);
var fragmentShader = __createGLShader(fragmentSource, gl.FRAGMENT_SHADER);
program = gl.createProgram();
// Fix support for drivers that don't draw if attribute 0 is disabled
for (param in __paramFloat)
{
if (param.name.indexOf("Position") > -1 && StringTools.startsWith(param.name, "openfl_"))
{
gl.bindAttribLocation(program, 0, param.name);
break;
}
}
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (gl.getProgramParameter(program, gl.LINK_STATUS) == 0)
{
var messageBuf = new StringBuf();
messageBuf.add("Unable to initialize the shader program");
messageBuf.add("\n");
messageBuf.add(gl.getProgramInfoLog(program));
var message = messageBuf.toString();
Log.error(message);
}
}
catch (error:Dynamic)
{
Logs.traceColored([
Logs.logText('[Shader] ', BLUE),
Logs.logText('Failed to compile shader ${fileName}: ', RED),
Logs.logText(Std.string(error))
], TRACE);
}
return program;
return program;
}
var glRawFragmentSource:String;
var glRawVertexSource:String;
@:noCompletion override private function set_glFragmentSource(value:String):String
{
if(value == null)
value = ShaderTemplates.defaultFragmentSource;
glRawFragmentSource = value;
value = processImports(value, FRAGMENT_SHADER);
value = value.replace("#pragma header", ShaderTemplates.fragHeader).replace("#pragma body", ShaderTemplates.fragBody);
if (value != __glFragmentSource)
{
__glSourceDirty = true;
}
return __glFragmentSource = value;
}
@:noCompletion override private function set_glVertexSource(value:String):String
{
if(value == null)
value = ShaderTemplates.defaultVertexSource;
glRawVertexSource = value;
value = processImports(value, VERTEX_SHADER);
var useBackCompat:Bool = true;
for (regex in ShaderTemplates.vertBackCompatVarList) if (!regex.match(value)) {
useBackCompat = false;
break;
}
var header = useBackCompat ? ShaderTemplates.vertHeaderBackCompat : ShaderTemplates.vertHeader;
var body = useBackCompat ? ShaderTemplates.vertBodyBackCompat : ShaderTemplates.vertBody;
value = value.replace("#pragma header", header).replace("#pragma body", body);
if (value != __glVertexSource)
{
__glSourceDirty = true;
}
return __glVertexSource = value;
}
override function __updateGL():Void {
onGLUpdate.dispatch();
super.__updateGL();
}
@:noCompletion private override function __initGL():Void
{
if (__glSourceDirty || __paramBool == null)
{
__glSourceDirty = false;
program = null;
__inputBitmapData = new Array();
__paramBool = new Array();
__paramFloat = new Array();
__paramInt = new Array();
__processGLData(glVertexSource, "attribute");
__processGLData(glVertexSource, "uniform");
__processGLData(glFragmentSource, "uniform");
}
if (__context != null && program == null)
{
var prefixBuf = new StringBuf();
prefixBuf.add('#version ${glslVer}\n');
prefixBuf.add(shaderPrefix);
var gl = __context.gl;
prefixBuf.add("#ifdef GL_ES\n");
if (precisionHint == FULL) {
prefixBuf.add("#ifdef GL_FRAGMENT_PRECISION_HIGH\n");
prefixBuf.add("precision highp float;\n");
prefixBuf.add("#else\n");
prefixBuf.add("precision mediump float;\n");
prefixBuf.add("#endif\n");
} else {
prefixBuf.add("precision lowp float;\n");
}
prefixBuf.add("#endif\n");
var prefix = prefixBuf.toString();
var vertex = prefix + vertexPrefix + glVertexSource;
var fragment = prefix + fragmentPrefix + glFragmentSource;
var id = vertex + fragment;
if (__context.__programs.exists(id))
{
program = __context.__programs.get(id);
}
else
{
program = __context.createProgram(GLSL);
program.__glProgram = __createGLProgram(vertex, fragment);
__context.__programs.set(id, program);
}
if (program != null)
{
glProgram = program.__glProgram;
for (input in __inputBitmapData) {
if (input.__isUniform) {
input.index = gl.getUniformLocation(glProgram, input.name);
} else {
input.index = gl.getAttribLocation(glProgram, input.name);
}
}
for (parameter in __paramBool) {
if (parameter.__isUniform) {
parameter.index = gl.getUniformLocation(glProgram, parameter.name);
} else {
parameter.index = gl.getAttribLocation(glProgram, parameter.name);
}
}
for (parameter in __paramFloat) {
if (parameter.__isUniform) {
parameter.index = gl.getUniformLocation(glProgram, parameter.name);
} else {
parameter.index = gl.getAttribLocation(glProgram, parameter.name);
}
}
for (parameter in __paramInt) {
if (parameter.__isUniform) {
parameter.index = gl.getUniformLocation(glProgram, parameter.name);
} else {
parameter.index = gl.getAttribLocation(glProgram, parameter.name);
}
}
}
// initInstance(vertex, fragment); // btw make sure to disable the prefixes for ._isInstance
}
}
var __cancelNextProcessGLData:Bool = false;
@:noCompletion private override function __processGLData(source:String, storageType:String):Void
{
onProcessGLData.dispatch(source, storageType);
if (__cancelNextProcessGLData != (__cancelNextProcessGLData = false))
return;
var lastMatch = 0, position, regex, name, type;
if (storageType == "uniform")
{
regex = ~/uniform ([A-Za-z0-9]+) ([A-Za-z0-9_]+)/;
}
else
{
regex = ~/attribute ([A-Za-z0-9]+) ([A-Za-z0-9_]+)/;
}
while (regex.matchSub(source, lastMatch))
{
type = regex.matched(1);
name = regex.matched(2);
if (StringTools.startsWith(name, "gl_"))
{
continue;
}
var isUniform = (storageType == "uniform");
registerParameter(name, type, isUniform);
position = regex.matchedPos();
lastMatch = position.pos + position.len;
}
}
function registerParameter(name:String, type:String, isUniform:Bool):Void
{
if (StringTools.startsWith(type, "sampler"))
{
var input = new ShaderInput<BitmapData>();
input.name = name;
input.__isUniform = isUniform;
__inputBitmapData.push(input);
switch (name)
{
case "openfl_Texture":
__texture = input;
case "bitmap":
__bitmap = input;
default:
}
Reflect.setField(__data, name, input);
try{Reflect.setField(this, name, input);} catch(e) {}
}
else if (!Reflect.hasField(__data, name) || Reflect.field(__data, name) == null)
{
var parameterType:ShaderParameterType = switch (type)
{
case "bool": BOOL;
case "double", "float": FLOAT;
case "int", "uint": INT;
case "bvec2": BOOL2;
case "bvec3": BOOL3;
case "bvec4": BOOL4;
case "ivec2", "uvec2": INT2;
case "ivec3", "uvec3": INT3;
case "ivec4", "uvec4": INT4;
case "vec2", "dvec2": FLOAT2;
case "vec3", "dvec3": FLOAT3;
case "vec4", "dvec4": FLOAT4;
case "mat2", "mat2x2": MATRIX2X2;
case "mat2x3": MATRIX2X3;
case "mat2x4": MATRIX2X4;
case "mat3x2": MATRIX3X2;
case "mat3", "mat3x3": MATRIX3X3;
case "mat3x4": MATRIX3X4;
case "mat4x2": MATRIX4X2;
case "mat4x3": MATRIX4X3;
case "mat4", "mat4x4": MATRIX4X4;
default: null;
}
var length = switch (parameterType)
{
case BOOL2, INT2, FLOAT2: 2;
case BOOL3, INT3, FLOAT3: 3;
case BOOL4, INT4, FLOAT4, MATRIX2X2: 4;
case MATRIX3X3: 9;
case MATRIX4X4: 16;
default: 1;
}
var arrayLength = switch (parameterType)
{
case MATRIX2X2: 2;
case MATRIX3X3: 3;
case MATRIX4X4: 4;
default: 1;
}
switch (parameterType)
{
case BOOL, BOOL2, BOOL3, BOOL4:
var parameter = new ShaderParameter<Bool>();
parameter.name = name;
parameter.type = parameterType;
parameter.__arrayLength = arrayLength;
parameter.__isBool = true;
parameter.__isUniform = isUniform;
parameter.__length = length;
__paramBool.push(parameter);
if (name == "openfl_HasColorTransform")
{
__hasColorTransform = parameter;
}
Reflect.setField(__data, name, parameter);
try{Reflect.setField(this, name, parameter);} catch(e) {}
case INT, INT2, INT3, INT4:
var parameter = new ShaderParameter<Int>();
parameter.name = name;
parameter.type = parameterType;
parameter.__arrayLength = arrayLength;
parameter.__isInt = true;
parameter.__isUniform = isUniform;
parameter.__length = length;
__paramInt.push(parameter);
Reflect.setField(__data, name, parameter);
try{Reflect.setField(this, name, parameter);} catch(e) {}
default:
var parameter = new ShaderParameter<Float>();
parameter.name = name;
parameter.type = parameterType;
parameter.__arrayLength = arrayLength;
#if lime
if (arrayLength > 0) parameter.__uniformMatrix = new Float32Array(arrayLength * arrayLength);
#end
parameter.__isFloat = true;
parameter.__isUniform = isUniform;
parameter.__length = length;
__paramFloat.push(parameter);
if (StringTools.startsWith(name, "openfl_"))
{
switch (name)
{
case "openfl_Alpha": __alpha = parameter;
case "openfl_ColorMultiplier": __colorMultiplier = parameter;
case "openfl_ColorOffset": __colorOffset = parameter;
case "openfl_Matrix": __matrix = parameter;
case "openfl_Position": __position = parameter;
case "openfl_TextureCoord": __textureCoord = parameter;
case "openfl_TextureSize": __textureSize = parameter;
default:
}
}
Reflect.setField(__data, name, parameter);
try{Reflect.setField(this, name, parameter);} catch(e) {}
}
}
return this;
}
#if REGION /* IHScriptCustomBehaviour */
public function hget(name:String):Dynamic {
if (__instanceFields.contains(name) || __instanceFields.contains('get_${name}'))
return Reflect.getProperty(this, name);
if (!Reflect.hasField(data, name))
return null;
var field:Dynamic = Reflect.field(data, name);
if (__glSourceDirty) __init();
if (__thisHasField(name) || __thisHasField('get_${name}')) return Reflect.getProperty(this, name);
else if (!Reflect.hasField(__data, name)) return null;
final field:Dynamic = Reflect.field(__data, name);
var cl:String = Type.getClassName(Type.getClass(field));
// little problem we are facing boys...
@@ -546,17 +78,19 @@ class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
}
public function hset(name:String, val:Dynamic):Dynamic {
if (__instanceFields.contains(name) || __instanceFields.contains('set_${name}')) {
if (__glSourceDirty) __init();
if (__thisHasField(name) || __thisHasField('set_${name}')) {
Reflect.setProperty(this, name, val);
return val;
}
if (!Reflect.hasField(data, name)) {
Reflect.setField(data, name, val);
else if (!Reflect.hasField(__data, name)) {
// ??? huh
Reflect.setField(__data, name, val);
return val;
}
var field = Reflect.field(data, name);
var field = Reflect.field(__data, name);
var cl = Type.getClassName(Type.getClass(field));
var isNotNull = val != null;
// cant do "field is ShaderInput" for some reason
@@ -598,67 +132,142 @@ class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
return val;
}
#end
override function __updateGL():Void {
onGLUpdate.dispatch();
super.__updateGL();
}
override function __createAssembler():Void {
__glSourceAssembler = new FunkinShaderSourceAssembler(this);
}
override function toString():String {
return __cacheProgramId != null ? 'FunkinShader(${__cacheProgramId})' : 'FunkinShader';
}
#if REGION /* Deprecated */
public var shaderPrefix:String = "";
public var fragmentPrefix:String = "";
public var vertexPrefix:String = "";
#end
#if REGION /* Backward Compatibility */
private static var __instanceFields = Type.getInstanceFields(FunkinShader);
private static var FRAGMENT_SHADER = 0;
private static var VERTEX_SHADER = 1;
public var fileName(get, set):String;
inline function get_fileName():String return _fragmentFilePath ?? _vertexFilePath ?? "FunkinShader";
inline function set_fileName(v:String):String return _fragmentFilePath = _vertexFilePath = v;
public var fragFileName(get, set):String;
inline function get_fragFileName():String return _fragmentFilePath ?? "FunkinShader";
inline function set_fragFileName(v:String):String return _fragmentFilePath = v;
public var vertFileName(get, set):String;
inline function get_vertFileName():String return _vertexFilePath ?? "FunkinShader";
inline function set_vertFileName(v:String):String return _vertexFilePath = v;
public var glslVer(get, set):String;
inline function get_glslVer():String return glVersion;
inline function set_glslVer(v:String):String return glVersion = v;
public var glRawFragmentSource(get, set):String;
inline function get_glRawFragmentSource():String return __glFragmentSourceRaw;
inline function set_glRawFragmentSource(v:String):String return __glFragmentSourceRaw = v;
public var glRawVertexSource(get, set):String;
inline function get_glRawVertexSource():String return __glVertexSourceRaw;
inline function set_glRawVertexSource(v:String):String return __glVertexSourceRaw = v;
function thisHasField(v:String):Bool return __thisHasField(v);
function registerParameter(name:String, type:String, isUniform:Bool) {
__registerParameter(name, Shader.getParameterTypeFromGLSL(type, false), StringTools.startsWith(type, "sampler"), 1, null, isUniform, null);
}
// Unused... cne-openfl uses a different system
var __cancelNextProcessGLData:Bool = false;
public var onProcessGLData:FlxTypedSignal<(String, String)->Void> = new FlxTypedSignal<(String, String)->Void>();
#end
}
class FunkinShaderSourceAssembler extends FlxRuntimeShader.FlxShaderSourceAssembler {
final funkinParent:FunkinShader;
public function new(parent:FunkinShader) {
super(funkinParent = parent);
}
override function __appendIncludes(source:String, isVertex:Bool, ?includedKeys:Map<String, Bool>):String
{
if (includedKeys == null) includedKeys = [];
source = GLSLSourceAssembler.__getIncludeFinder().map(source, (regex:EReg) ->
{
var key = regex.matched(1);
if (includedKeys.get(key)) return '/*Recursive include $key*/\n';
var include = __getIncludeSource(key, isVertex);
if (include == null) return '/*Unknown include $key*/\n';
includedKeys.set(key, true);
return '/*include $key*/\n' + __appendIncludes(include, isVertex, includedKeys);
});
return __getImportCompatibilityFinder().map(source, (regex:EReg) ->
{
var key = regex.matched(1);
if (includedKeys.get(key)) return '/*Recursive import $key*/\n';
var include = __getIncludeSource(key, isVertex);
if (include == null) return '/*Unknown import $key*/\n';
includedKeys.set(key, true);
return '/*import $key*/\n' + __appendIncludes(include, isVertex, includedKeys);
});
}
override function __getIncludeSource(include:String, fromVertex:Bool):Null<String> {
final path = Paths.getPath('shaders/' + include);
if (Assets.exists(path)) return Assets.getText(path);
final fallback = __getIncludeSource(include, fromVertex);
if (fallback != null) return fallback;
Logs.traceColored([
Logs.logText('[Shader] ', RED),
Logs.logText('Failed to import shader $include', RED),
]);
return null;
}
override function __appendPrefix(source:String, versionNumber:Int, versionProfile:String, extensions:Map<String, String>, isVertex:Bool,
precisionHint:Null<ShaderPrecision>):String
{
var result = super.__appendPrefix(null, versionNumber, versionProfile, extensions, isVertex, precisionHint) + "\n";
result += funkinParent.shaderPrefix + "\n" + (isVertex ? funkinParent.vertexPrefix : funkinParent.fragmentPrefix) + "\n";
if (source != null) {
if (!isVertex && versionNumber >= 300 && versionProfile != "compatibility" && !StringTools.contains(source, "out vec4")) {
result += "out vec4 openfl_FragColor;\n";
}
result += source;
}
return result;
}
private static inline function __getImportCompatibilityFinder():EReg {
return ~/#import\s+(?|"([^"]+)"|'([^']+)'|<(.*)>|([^\s]+))/g;
}
}
#if REGION /* Backward Compatibility */
class ShaderTemplates {
public static final fragHeader:String = "varying float openfl_Alphav;
varying vec4 openfl_ColorMultiplierv;
varying vec4 openfl_ColorOffsetv;
varying vec2 openfl_TextureCoordv;
uniform bool openfl_HasColorTransform;
uniform vec2 openfl_TextureSize;
uniform sampler2D bitmap;
uniform bool hasTransform;
uniform bool hasColorTransform;
vec4 applyFlixelEffects(vec4 color) {
if(!hasTransform) {
return color;
}
if(color.a == 0.0) {
return vec4(0.0, 0.0, 0.0, 0.0);
}
if(!hasColorTransform) {
return color * openfl_Alphav;
}
color.rgb = color.rgb / color.a;
color = clamp(openfl_ColorOffsetv + (color * openfl_ColorMultiplierv), 0.0, 1.0);
if(color.a > 0.0) {
return vec4(color.rgb * color.a * openfl_Alphav, color.a * openfl_Alphav);
}
return vec4(0.0, 0.0, 0.0, 0.0);
}
vec4 flixel_texture2D(sampler2D bitmap, vec2 coord) {
vec4 color = texture2D(bitmap, coord);
return applyFlixelEffects(color);
}
uniform vec4 _camSize;
float map(float value, float min1, float max1, float min2, float max2) {
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
}
vec2 getCamPos(vec2 pos) {
vec4 size = _camSize / vec4(openfl_TextureSize, openfl_TextureSize);
return vec2(map(pos.x, size.x, size.x + size.z, 0.0, 1.0), map(pos.y, size.y, size.y + size.w, 0.0, 1.0));
}
vec2 camToOg(vec2 pos) {
vec4 size = _camSize / vec4(openfl_TextureSize, openfl_TextureSize);
return vec2(map(pos.x, 0.0, 1.0, size.x, size.x + size.z), map(pos.y, 0.0, 1.0, size.y, size.y + size.w));
}
vec4 textureCam(sampler2D bitmap, vec2 pos) {
return flixel_texture2D(bitmap, camToOg(pos));
}";
public static final fragBody:String = "gl_FragColor = flixel_texture2D(bitmap, openfl_TextureCoordv);";
public static final vertHeader:String = "attribute float openfl_Alpha;
attribute vec4 openfl_ColorMultiplier;
attribute vec4 openfl_ColorOffset;
@@ -679,32 +288,97 @@ attribute vec4 colorMultiplier;
attribute vec4 colorOffset;
uniform bool hasColorTransform;";
public static final vertBody:String = "openfl_Alphav = openfl_Alpha;
openfl_TextureCoordv = openfl_TextureCoord;
public static final vertBody:String = "openfl_TextureCoordv = openfl_TextureCoord;
if(openfl_HasColorTransform) {
openfl_ColorMultiplierv = openfl_ColorMultiplier;
openfl_ColorOffsetv = openfl_ColorOffset / 255.0;
if (hasColorTransform)
{
openfl_Alphav = openfl_Alpha * colorMultiplier.a;
if (openfl_HasColorTransform)
{
openfl_ColorOffsetv = (openfl_ColorOffset / 255.0 * colorMultiplier) + (colorOffset / 255.0);
openfl_ColorMultiplierv = openfl_ColorMultiplier * vec4(colorMultiplier.rgb, 1.0);
}
else
{
openfl_ColorOffsetv = colorOffset / 255.0;
openfl_ColorMultiplierv = vec4(colorMultiplier.rgb, 1.0);
}
}
else
{
openfl_Alphav = openfl_Alpha * alpha;
if (openfl_HasColorTransform)
{
openfl_ColorOffsetv = (openfl_ColorOffset + colorOffset) / 255.0;
openfl_ColorMultiplierv = openfl_ColorMultiplier;
}
else
{
openfl_ColorOffsetv = colorOffset / 255.0;
openfl_ColorMultiplierv = vec4(1.0);
}
}";
public static final fragHeader:String = "varying float openfl_Alphav;
varying vec4 openfl_ColorMultiplierv;
varying vec4 openfl_ColorOffsetv;
varying vec2 openfl_TextureCoordv;
uniform bool openfl_HasColorTransform;
uniform vec2 openfl_TextureSize;
uniform sampler2D bitmap;
uniform bool hasTransform;
uniform bool hasColorTransform;
uniform bool premultiplyAlpha;
vec4 apply_flixel_transform(vec4 color)
{
if (!hasTransform) return color;
else if (color.a <= 0.0 || openfl_Alphav == 0.0) return vec4(0.0);
// this is just solely for ASTC compressed textures.
// ...also in flixel_texture2D, it also converts to linear alpha anyway.
if (!premultiplyAlpha) color.rgb /= color.a;
color = clamp(openfl_ColorOffsetv + (color * openfl_ColorMultiplierv), 0.0, 1.0);
return vec4(color.rgb * color.a * openfl_Alphav, color.a * openfl_Alphav);
}
#define applyFlixelEffects(color) apply_flixel_transform(color)
vec4 flixel_texture2D(sampler2D bitmap, vec2 coord)
{
return apply_flixel_transform(texture2D(bitmap, coord));
}
openfl_Alphav = openfl_Alpha * alpha;
uniform vec4 _camSize;
if(hasColorTransform) {
openfl_ColorOffsetv = colorOffset / 255.0;
openfl_ColorMultiplierv = colorMultiplier;
float map(float value, float min1, float max1, float min2, float max2) {
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
}
gl_Position = openfl_Matrix * openfl_Position;";
vec2 getCamPos(vec2 pos) {
vec4 size = _camSize / vec4(openfl_TextureSize, openfl_TextureSize);
return vec2(map(pos.x, size.x, size.x + size.z, 0.0, 1.0), map(pos.y, size.y, size.y + size.w, 0.0, 1.0));
}
vec2 camToOg(vec2 pos) {
vec4 size = _camSize / vec4(openfl_TextureSize, openfl_TextureSize);
return vec2(map(pos.x, 0.0, 1.0, size.x, size.x + size.z), map(pos.y, 0.0, 1.0, size.y, size.y + size.w));
}
vec4 textureCam(sampler2D bitmap, vec2 pos) {
return flixel_texture2D(bitmap, camToOg(pos));
}";
// TODO: make this ignore comments
public static final vertBackCompatVarList:Array<EReg> = [
~/attribute float alpha/,
~/attribute vec4 colorMultiplier/,
~/attribute vec4 colorOffset/,
~/uniform bool hasColorTransform/
];
public static final fragBody:String = "gl_FragColor = flixel_texture2D(bitmap, openfl_TextureCoordv);
if (gl_FragColor.a == 0.0) discard;";
public static final vertHeaderBackCompat:String = "attribute float openfl_Alpha;
public static final vertBackCompatVarList:Array<EReg> = [
~/attribute float alpha/,
~/attribute vec4 colorMultiplier/,
~/attribute vec4 colorOffset/,
~/uniform bool hasColorTransform/
];
public static final vertHeaderBackCompat:String = "attribute float openfl_Alpha;
attribute vec4 openfl_ColorMultiplier;
attribute vec4 openfl_ColorOffset;
attribute vec4 openfl_Position;
@@ -719,7 +393,7 @@ uniform mat4 openfl_Matrix;
uniform bool openfl_HasColorTransform;
uniform vec2 openfl_TextureSize;";
public static final vertBodyBackCompat:String = "openfl_Alphav = openfl_Alpha;
public static final vertBodyBackCompat:String = "openfl_Alphav = openfl_Alpha;
openfl_TextureCoordv = openfl_TextureCoord;
if(openfl_HasColorTransform) {
@@ -728,19 +402,8 @@ if(openfl_HasColorTransform) {
}
gl_Position = openfl_Matrix * openfl_Position;";
public static final defaultVertexSource:String = "#pragma header
void main(void) {
#pragma body
}";
public static final defaultFragmentSource:String = "#pragma header
void main(void) {
#pragma body
}";
}
#end
class ShaderTypeException extends Exception {
var has:Class<Dynamic>;
@@ -753,16 +416,4 @@ class ShaderTypeException extends Exception {
this.name = name;
super('ShaderTypeException - Tried to set the shader uniform "${name}" as a ${Type.getClassName(has)}, but the shader uniform is a ${Std.string(want)}.');
}
}
class ShaderErrorPosition {
public var column:Int;
public var line:Int;
public var message:String;
public function new(line:String, column:String, message:String) {
this.line = Std.parseInt(line);
this.column = Std.parseInt(column);
this.message = message;
}
}
@@ -0,0 +1,471 @@
package funkin.backend.shaders;
import haxe.Exception;
import haxe.io.Path;
import flixel.graphics.FlxGraphic;
import flixel.system.FlxAssets.FlxShader;
import flixel.util.FlxSignal.FlxTypedSignal;
import flixel.util.FlxStringUtil;
import hscript.IHScriptCustomBehaviour;
import openfl.display.BitmapData;
import openfl.display.ShaderInput;
import openfl.display.ShaderParameter;
import openfl.display.ShaderParameterType;
import openfl.display.Shader;
import openfl.display3D._internal.GLProgram;
import openfl.display3D._internal.GLShader;
import openfl.display3D.Program3D;
import openfl.utils._internal.Log;
using StringTools;
@:access(openfl.display3D.Context3D)
@:access(openfl.display3D.Program3D)
@:access(openfl.display.ShaderInput)
@:access(openfl.display.ShaderParameter)
class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
#if REGION /* Backward Compatibility */
private static var __instanceFields = Type.getInstanceFields(FunkinShader);
private static var FRAGMENT_SHADER = 0;
private static var VERTEX_SHADER = 1;
public var glslVer(get, set):String;
inline function get_glslVer():String return glVersion;
inline function set_glslVer(v:String):String return glVersion = v;
public var glRawFragmentSource(get, set):String;
inline function get_glRawFragmentSource():String return __glFragmentSourceRaw;
inline function set_glRawFragmentSource(v:String):String return __glFragmentSourceRaw = v;
public var glRawVertexSource(get, set):String;
inline function get_glRawVertexSource():String return __glVertexSourceRaw;
inline function set_glRawVertexSource(v:String):String return __glVertexSourceRaw = v;
// Unused... cne-openfl uses a different system
var __cancelNextProcessGLData:Bool = false;
public var onProcessGLData:FlxTypedSignal<(String, String)->Void> = new FlxTypedSignal<(String, String)->Void>();
#end
public static function getShaderCode(key:String, isFragment = true):Null<String> {
var path = "shaders/" + key;
key = Path.withoutExtension(key);
final ext = Path.extension(path);
if (ext == "") path = path + (isFragment ? ".frag" : ".vert");
else isFragment = ext != "vert";
path = Paths.getPath(path);
return Assets.exists(path) ? Assets.getText(path) : null;
}
private static function processGLSLText(source:String, glVersion:String, isFragment:Bool, ?pragmas:Map<String, String>):String
return Shader.processGLSLText(_processGLSLText(source, glVersion, isFragment, pragmas), glVersion, isFragment);
private static function _processGLSLText(source:String, glVersion:String, isFragment:Bool, ?pragmas:Map<String, String>):String {
if (pragmas != null) {
final pragmaKeyword = ~/#pragma\s+(\w+)/g;
source = pragmaKeyword.map(source, (_) -> {
var name = pragmaKeyword.matched(1), pragma:String;
if (pragmas.exists(name)) pragma = pragmas.get(name);
else {
if (name != "header" && name != "body") return '#pragma $name';
pragma = "";
}
return _processGLSLText(pragma, glVersion, isFragment, pragmas);
});
}
inline function tryGetShaderCode(key:String) {
final s = getShaderCode(key, isFragment);
if (s == null) {
Logs.traceColored([
Logs.logText('[Shader] ', RED),
Logs.logText('Failed to import shader $key', RED),
]);
return "";
}
return s;
}
final includeKeyword = ~/#include ['"](.+)['"]/g;
final importKeyword = ~/#import\s+<(.*)>/g;
source = importKeyword.map(source, (_) ->
return _processGLSLText(tryGetShaderCode(importKeyword.matched(1)), glVersion, isFragment, pragmas) ?? "");
return source = includeKeyword.map(source, (_) ->
return _processGLSLText(tryGetShaderCode(includeKeyword.matched(1)), glVersion, isFragment, pragmas) ?? "");
}
private static var __defaultsAvailable:Bool;
private static var __glFragmentSourceDefault:String;
private static var __glVertexSourceDefault:String;
private static var __glFragmentPragmasDefault:Map<String, String>;
private static var __glVertexPragmasDefault:Map<String, String>;
private static var __glFragmentExtensionsDefault:Array<ShaderExtension>;
private static var __glVertexExtensionsDefault:Array<ShaderExtension>;
public var onGLUpdate:FlxTypedSignal<Void->Void> = new FlxTypedSignal<Void->Void>();
public var fileName:String = "FunkinShader";
public var fragFileName:String = "FunkinShader";
public var vertFileName:String = "FunkinShader";
public var shaderPrefix:String = "";
public var fragmentPrefix:String = "";
public var vertexPrefix:String = "";
private var __immediate:Bool;
public function new(?fragmentSource:String, ?vertexSource:String, ?version:String,
?fragmentExtensions:Array<ShaderExtension>, ?vertexExtensions:Array<ShaderExtension>, immediate = false
) {
if (!__defaultsAvailable) {
__glFragmentSourceDefault = __glFragmentSourceRaw;
__glVertexSourceDefault = __glVertexSourceRaw;
__glFragmentPragmasDefault = __glFragmentPragmas.copy();
__glVertexPragmasDefault = __glVertexPragmas.copy();
__glFragmentExtensionsDefault = __glFragmentExtensions ?? [];
__glVertexExtensionsDefault = __glVertexExtensions ?? [];
__defaultsAvailable = true;
}
__immediate = immediate;
if (version != null) glVersion = version;
if (vertexExtensions != null) glVertexExtensions = vertexExtensions;
if (fragmentExtensions != null) glFragmentExtensions = fragmentExtensions;
if (vertexSource != null) glVertexSource = vertexSource;
if (fragmentSource != null) glFragmentSource = fragmentSource;
super();
if (!__isGenerated) {
__isGenerated = true;
__init();
}
}
public function loadShader(name:String, ?version:String, immediate = false):FunkinShader {
final fragment = getShaderCode(name, true), vertex = getShaderCode(name, false);
glVersion = version;
glVertexSource = vertex ?? __glVertexSourceDefault;
glFragmentSource = fragment ?? __glFragmentSourceDefault;
if (immediate) __init();
return this;
}
override function __initGL():Void {
if (__immediate) {
__context = FlxG.stage.context3D;
__enable();
}
super.__initGL();
}
override function __updateGL():Void {
onGLUpdate.dispatch();
super.__updateGL();
}
public function hget(name:String):Dynamic {
if (__glSourceDirty || __data == null) __init();
if (thisHasField(name) || thisHasField('get_${name}')) return Reflect.getProperty(this, name);
else if (!Reflect.hasField(__data, name)) return null;
final field:Dynamic = Reflect.field(__data, name);
var cl:String = Type.getClassName(Type.getClass(field));
// 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 don't 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;
}
public function hset(name:String, val:Dynamic):Dynamic {
if (__glSourceDirty || __data == null) __init();
if (thisHasField(name) || thisHasField('set_${name}')) {
Reflect.setProperty(this, name, val);
return val;
}
else if (!Reflect.hasField(__data, name)) {
// ??? huh
Reflect.setField(__data, name, val);
return val;
}
var field = Reflect.field(__data, name);
var cl = Type.getClassName(Type.getClass(field));
var isNotNull = val != null;
// cant do "field is ShaderInput" for some reason
if (cl.startsWith("openfl.display.ShaderParameter")) {
if (field.__length <= 1) {
// that means we wait for a single number, instead of an array
if (field.__isInt && isNotNull && !(val is Int)) {
throw new ShaderTypeException(name, Type.getClass(val), 'Int');
return null;
} else
if (field.__isBool && isNotNull && !(val is Bool)) {
throw new ShaderTypeException(name, Type.getClass(val), 'Bool');
return null;
} else
if (field.__isFloat && isNotNull && !(val is Float)) {
throw new ShaderTypeException(name, Type.getClass(val), 'Float');
return null;
}
return field.value = isNotNull ? [val] : null;
} else {
if (isNotNull && !(val is Array)) {
throw new ShaderTypeException(name, Type.getClass(val), Array);
return null;
}
return field.value = val;
}
} else if (cl.startsWith("openfl.display.ShaderInput")) {
// shader input!!
var bitmap:BitmapData;
if (!isNotNull) bitmap = null;
else if (val is BitmapData) bitmap = val;
else if (val is FlxGraphic) bitmap = val.bitmap;
else {
throw new ShaderTypeException(name, Type.getClass(val), BitmapData);
return null;
}
field.input = bitmap;
}
return val;
}
override function __buildSourcePrefix(isFragment:Bool):String {
var result = super.__buildSourcePrefix(isFragment) + '\n$shaderPrefix';
return isFragment ? result + '\n$fragmentPrefix' : result + '\n$vertexPrefix';
}
override function set_glFragmentExtensions(value:Array<ShaderExtension>):Array<ShaderExtension> {
if (value == null) value = __glFragmentExtensionsDefault;
if (value != __glFragmentExtensions) __glSourceDirty = true;
return __glFragmentExtensions = value;
}
override function set_glVertexExtensions(value:Array<ShaderExtension>):Array<ShaderExtension> {
if (value == null) value = __glVertexExtensionsDefault;
if (value != __glVertexExtensions) __glSourceDirty = true;
return __glVertexExtensions = value;
}
override function set_glVersion(value:Null<String>):String {
if (value == null || value == "") value = Flags.DEFAULT_GLSL_VERSION;
if ((__glVersionRaw = value) != __glVersion) {
__glSourceDirty = true;
if (__glVertexSourceRaw != null) __glVertexSource = processGLSLText(__glVertexSourceRaw, value, false, __glVertexPragmas);
if (__glFragmentSourceRaw != null) __glFragmentSource = processGLSLText(__glFragmentSourceRaw, value, true, __glFragmentPragmas);
}
return __glVersion = value;
}
override function set_glFragmentSource(value:String):String {
if (value == null || value == "") value = __glFragmentSourceDefault;
if ((__glFragmentSourceRaw = value) != null) {
if (__glVersion != (__glVersion = Shader.getGLSLTextVersion(value, __glVersionRaw)))
__glSourceDirty = true;
value = processGLSLText(value, __glVersion, true, __glFragmentPragmas);
}
if (value != __glFragmentSource) __glSourceDirty = true;
return __glFragmentSource = value;
}
override function set_glVertexSource(value:String):String {
if (value == null || value == "") value = __glVertexSourceDefault;
if ((__glVertexSourceRaw = value) != null) {
if (__glVersion != (__glVersion = Shader.getGLSLTextVersion(value, __glVersionRaw)))
__glSourceDirty = true;
value = processGLSLText(value, __glVersion, false, __glVertexPragmas);
}
if (value != __glVertexSource) __glSourceDirty = true;
return __glVertexSource = value;
}
override function set_glFragmentPragmas(value:Map<String, String>):Map<String, String> {
if (value == null) value = __glFragmentPragmasDefault;
if (value != __glFragmentPragmas)
__glSourceDirty = true;
return __glFragmentPragmas = value;
}
override function set_glVertexPragmas(value:Map<String, String>):Map<String, String> {
if (value == null) value = __glVertexPragmasDefault;
if (value != __glVertexPragmas)
__glSourceDirty = true;
return __glVertexPragmas = value;
}
function registerParameter(name:String, type:String, isUniform:Bool):Void {
__registerParameter(name, Program3D.getParameterTypeFromGLString(type, 1), 1, -1, isUniform, false, null);
}
public function toString():String
return FlxStringUtil.getDebugString([for (field in Reflect.fields(data)) LabelValuePair.weak(field, Reflect.field(data, field))]);
}
class ShaderTemplates {
#if REGION /* Backward Compatibility */
public static final vertHeader:String = "attribute float openfl_Alpha;
attribute vec4 openfl_ColorMultiplier;
attribute vec4 openfl_ColorOffset;
attribute vec4 openfl_Position;
attribute vec2 openfl_TextureCoord;
varying float openfl_Alphav;
varying vec4 openfl_ColorMultiplierv;
varying vec4 openfl_ColorOffsetv;
varying vec2 openfl_TextureCoordv;
uniform mat4 openfl_Matrix;
uniform bool openfl_HasColorTransform;
uniform vec2 openfl_TextureSize;
attribute float alpha;
attribute vec4 colorMultiplier;
attribute vec4 colorOffset;
uniform bool hasColorTransform;";
public static final vertBody:String = "openfl_TextureCoordv = openfl_TextureCoord;
if (hasColorTransform) {
openfl_Alphav = openfl_Alpha * colorMultiplier.a;
if (openfl_HasColorTransform) {
openfl_ColorOffsetv = (openfl_ColorOffset / 255.0 * colorMultiplier) + (colorOffset / 255.0);
openfl_ColorMultiplierv = openfl_ColorMultiplier * vec4(colorMultiplier.rgb, 1.0);
}
else {
openfl_ColorOffsetv = colorOffset / 255.0;
openfl_ColorMultiplierv = vec4(colorMultiplier.rgb, 1.0);
}
}
else {
openfl_Alphav = openfl_Alpha * alpha;
if (openfl_HasColorTransform) {
openfl_ColorOffsetv = (openfl_ColorOffset + colorOffset) / 255.0;
openfl_ColorMultiplierv = openfl_ColorMultiplier;
}
else {
openfl_ColorOffsetv = colorOffset / 255.0;
openfl_ColorMultiplierv = vec4(1.0);
}
}";
public static final fragHeader:String = "varying float openfl_Alphav;
varying vec4 openfl_ColorMultiplierv;
varying vec4 openfl_ColorOffsetv;
varying vec2 openfl_TextureCoordv;
uniform bool openfl_HasColorTransform;
uniform vec2 openfl_TextureSize;
uniform sampler2D bitmap;
uniform bool hasTransform;
uniform bool hasColorTransform;
vec4 apply_flixel_transform(vec4 color) {
if (!hasTransform) return color;
else if (color.a <= 0.0 || openfl_Alphav == 0.0) return vec4(0.0);
color.rgb /= color.a;
color = clamp(openfl_ColorOffsetv + (color * openfl_ColorMultiplierv), 0.0, 1.0);
return vec4(color.rgb * color.a * openfl_Alphav, color.a * openfl_Alphav);
}
#define applyFlixelEffects(color) apply_flixel_transform(color)
vec4 flixel_texture2D(sampler2D bitmap, vec2 coord) {
return apply_flixel_transform(texture2D(bitmap, coord));
}
uniform vec4 _camSize;
float map(float value, float min1, float max1, float min2, float max2) {
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
}
vec2 getCamPos(vec2 pos) {
vec4 size = _camSize / vec4(openfl_TextureSize, openfl_TextureSize);
return vec2(map(pos.x, size.x, size.x + size.z, 0.0, 1.0), map(pos.y, size.y, size.y + size.w, 0.0, 1.0));
}
vec2 camToOg(vec2 pos) {
vec4 size = _camSize / vec4(openfl_TextureSize, openfl_TextureSize);
return vec2(map(pos.x, 0.0, 1.0, size.x, size.x + size.z), map(pos.y, 0.0, 1.0, size.y, size.y + size.w));
}
vec4 textureCam(sampler2D bitmap, vec2 pos) {
return flixel_texture2D(bitmap, camToOg(pos));
}";
public static final fragBody:String = "gl_FragColor = flixel_texture2D(bitmap, openfl_TextureCoordv);
if (gl_FragColor.a == 0.0) discard;";
public static final vertBackCompatVarList:Array<EReg> = [
~/attribute float alpha/,
~/attribute vec4 colorMultiplier/,
~/attribute vec4 colorOffset/,
~/uniform bool hasColorTransform/
];
public static final vertHeaderBackCompat:String = "attribute float openfl_Alpha;
attribute vec4 openfl_ColorMultiplier;
attribute vec4 openfl_ColorOffset;
attribute vec4 openfl_Position;
attribute vec2 openfl_TextureCoord;
varying float openfl_Alphav;
varying vec4 openfl_ColorMultiplierv;
varying vec4 openfl_ColorOffsetv;
varying vec2 openfl_TextureCoordv;
uniform mat4 openfl_Matrix;
uniform bool openfl_HasColorTransform;
uniform vec2 openfl_TextureSize;";
public static final vertBodyBackCompat:String = "openfl_Alphav = openfl_Alpha;
openfl_TextureCoordv = openfl_TextureCoord;
if(openfl_HasColorTransform) {
openfl_ColorMultiplierv = openfl_ColorMultiplier;
openfl_ColorOffsetv = openfl_ColorOffset / 255.0;
}
gl_Position = openfl_Matrix * openfl_Position;";
#end
}
class ShaderTypeException extends Exception {
var has:Class<Dynamic>;
var want:Class<Dynamic>;
var name:String;
public function new(name:String, has:Class<Dynamic>, want:Dynamic) {
this.has = has;
this.want = want;
this.name = name;
super('ShaderTypeException - Tried to set the shader uniform "${name}" as a ${Type.getClassName(has)}, but the shader uniform is a ${Std.string(want)}.');
}
}
+13 -8
View File
@@ -11,6 +11,11 @@ import openfl.display.BlendMode;
import openfl.geom.ColorTransform;
import openfl.geom.Point;
import openfl.geom.Rectangle;
import openfl.display.TriangleCulling;
import openfl.display3D.Context3DWrapMode;
import openfl.display3D.Context3DCompareMode;
import openfl.filters.BitmapFilter;
import openfl.filters.ShaderFilter;
class FakeCamera extends FlxCamera {
public static final instance = new FakeCamera();
@@ -21,14 +26,14 @@ class FakeCamera extends FlxCamera {
visible = false;
}
override function startTrianglesBatch(graphic:FlxGraphic, smoothing:Bool = false, isColored:Bool = false, ?blend:BlendMode, ?hasColorOffsets:Bool, ?shader:FlxShader) { return null;}
override function startQuadBatch(graphic:FlxGraphic, colored:Bool, hasColorOffsets:Bool = false, ?blend:BlendMode, smooth:Bool = false, ?shader:FlxShader) { return null;}
override function startTrianglesBatch(graphic:FlxGraphic, smoothing:Bool = false, isColored:Bool = false, ?blend:BlendMode, ?hasColorOffsets:Bool, ?shader:FlxShader, ?wrapMode:Context3DWrapMode, ?depthCompareMode:Context3DCompareMode, ?culling:TriangleCulling) { return null;}
override function startQuadBatch(graphic:FlxGraphic, colored:Bool, hasColorOffsets:Bool = false, ?blend:BlendMode, smooth:Bool = false, ?shader:FlxShader, ?wrapMode:Context3DWrapMode, ?depthCompareMode:Context3DCompareMode) { return null;}
override function clearDrawStack() {}
override function render() {}
public override function drawPixels(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader) {}
public override function copyPixels(?frame:FlxFrame, ?pixels:BitmapData, ?sourceRect:Rectangle, destPoint:Point, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader) {}
public override function drawTriangles(graphic:FlxGraphic, vertices:DrawData<Float>, indices:DrawData<Int>, uvtData:DrawData<Float>, ?colors:DrawData<Int>, ?position:FlxPoint, ?blend:BlendMode, repeat:Bool = false, smoothing:Bool = false, ?transform:ColorTransform, ?shader:FlxShader):Void {}
public override function drawPixels(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader, ?wrapMode:Context3DWrapMode, ?depthCompareMode:Context3DCompareMode) {}
public override function copyPixels(?frame:FlxFrame, ?pixels:BitmapData, ?sourceRect:Rectangle, destPoint:Point, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader, ?wrapMode:Context3DWrapMode, ?depthCompareMode:Context3DCompareMode) {}
public override function drawTriangles(graphic:FlxGraphic, vertices:DrawData<Float>, indices:DrawData<Int>, uvtData:DrawData<Float>, ?colors:DrawData<Int>, ?position:FlxPoint, ?blend:BlendMode, repeat:Bool = false, smoothing:Bool = false, ?transform:ColorTransform, ?shader:FlxShader, ?wrapMode:Context3DWrapMode, ?depthCompareMode:Context3DCompareMode, ?culling:TriangleCulling):Void {}
public override function update(elapsed:Float) {}
@@ -41,10 +46,10 @@ class FakeCallCamera extends FakeCamera {
public static final instance = new FakeCallCamera();
public var ignoreDraws:Bool = false;
public dynamic function onDraw(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader) {
public dynamic function onDraw(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader, ?wrapMode:Context3DWrapMode, ?depthCompareMode:Context3DCompareMode) {
}
override function drawPixels(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader) {
if (!ignoreDraws) onDraw(frame, pixels, matrix, transform, blend, smoothing, shader);
override function drawPixels(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader, ?wrapMode:Context3DWrapMode, ?depthCompareMode:Context3DCompareMode) {
if (!ignoreDraws) onDraw(frame, pixels, matrix, transform, blend, smoothing, shader, wrapMode, depthCompareMode);
}
}
+31 -10
View File
@@ -13,15 +13,17 @@ import lime.utils.AssetType;
/**
* A class that reads the `flags.ini` file, allowing to read settable Flags (customs too).
*/
@:build(funkin.backend.system.macros.FlagMacro.build("onReset"))
@:build(funkin.backend.system.macros.FlagMacro.build())
class Flags {
public static var overridenFlags:Map<String, Bool> = [];
// -- Codename's Addon Config --
@:bypass public static var addonFlags:Map<String, Dynamic> = [];
public static var CURRENT_API_VERSION:Int = 2;
// -- Codename's ZipFolderLibrary Config --
public static var ALLOWED_ZIP_EXTENSIONS:Array<String> = ["zip"];
// -- Codename's Mod Config --
public static var MOD_NAME:String = "";
public static var MOD_DESCRIPTION:String = "";
@@ -104,6 +106,10 @@ class Flags {
public static var DEFAULT_BEATS_PER_MEASURE:Int = 4;
public static var DEFAULT_STEPS_PER_BEAT:Int = 4;
public static var DEFAULT_LOOP_TIME:Float = 0.0;
public static var ICONS_AUTOPOSITION:Bool = true;
@:lazy public static var DEFAULT_SOUND_TIME_SCALED_PITCH:Null<Bool> = null;
@:lazy public static var USE_FLXTRAIL_FRAMES:Null<Bool> = null;
public static var SUPPORTED_CHART_RUNTIME_FORMATS:Array<String> = ["Legacy", "Psych Engine"];
public static var SUPPORTED_CHART_FORMATS:Array<String> = ["BaseGame"];
@@ -128,6 +134,9 @@ class Flags {
@:also(funkin.game.PlayState.opponentMode)
public static var DEFAULT_OPPONENT_MODE:Bool = false;
public static var EARLY_HIT_WINDOW_RANGE:Float = 1.0; // was 0.5 for easier early hitting, but now 1 to demotivate mashing and getting away with it.
public static var LATE_HIT_WINDOW_RANGE:Float = 1.0;
public static var SHITS_BREAK_COMBO:Bool = true;
public static var USE_LEGACY_TIMING:Null<Bool> = null;
public static var DEFAULT_NOTE_MS_LIMIT:Float = 1500;
@@ -157,10 +166,12 @@ class Flags {
public static var DEFAULT_HUD_ZOOM_LERP:Float = 0.05;
public static var USE_LEGACY_ZOOM_FACTOR:Null<Bool> = null;
// Font configuration
public static var DEFAULT_FONT:String = "vcr.ttf";
public static var DEFAULT_FONT_SIZE:Int = 16;
public static var DEFAULT_ALT_ANIM_SUFFIX:String = "-alt";
// to translate these you need to convert them into ids
// Resume -> pause.resume
@@ -275,7 +286,7 @@ class Flags {
public static var DEFAULT_CHARACTER_GHOSTDISABLE_SOUND:String = "editors/character/ghostDisable";
public static var DEFAULT_CHARACTER_GHOSTENABLE_SOUND:String = "editors/character/ghostEnable";
public static var DEFAULT_GLSL_VERSION:String = "120";
@:lazy public static var DEFAULT_GLSL_VERSION:String = null;
@:also(funkin.backend.utils.HttpUtil.userAgent)
public static var USER_AGENT:String = 'request';
// -- End of Codename's Default Flags --
@@ -310,11 +321,20 @@ class Flags {
if (USE_LEGACY_TIMING == null) USE_LEGACY_TIMING = MOD_API_VERSION < 2;
if (USE_LEGACY_ZOOM_FACTOR == null) USE_LEGACY_ZOOM_FACTOR = MOD_API_VERSION < 2;
if (SUSTAINS_AS_ONE_NOTE == null) SUSTAINS_AS_ONE_NOTE = MOD_API_VERSION >= 2;
}
if (DEFAULT_GLSL_VERSION == null) {
if (MOD_API_VERSION < 2) {
DEFAULT_GLSL_VERSION = #if (android || mac || web) "100" #else "120" #end;
Logs.warn("Blend Mode Extensions won't work in MOD_API_VERSION below than 2");
}
else {
DEFAULT_GLSL_VERSION = openfl.utils.GLSLSourceAssembler.getDefaultVersion();
}
}
if (DEFAULT_SOUND_TIME_SCALED_PITCH == null) DEFAULT_SOUND_TIME_SCALED_PITCH = MOD_API_VERSION >= 2;
if (USE_FLXTRAIL_FRAMES == null) USE_FLXTRAIL_FRAMES = MOD_API_VERSION < 2;
private static function onReset() {
var currentModFolder = ModsFolder.currentModFolder;
if (currentModFolder != null) SAVE_NAME = currentModFolder;
flixel.sound.FlxSound.defaultTimeScaledPitch = cast DEFAULT_SOUND_TIME_SCALED_PITCH;
flixel.addons.effects.FlxTrail.defaultDelayBackwardCompatibility = cast USE_FLXTRAIL_FRAMES;
}
public static function loadFromDatas(datas:Array<String>):Map<String, String> {
@@ -337,8 +357,9 @@ class Flags {
if (!(parsed = parse(name, value))) customFlags.set(name, value);
if (!overridenFlags.exists(name)) overridenFlags.set(name, parsed);
}
#if MODCHARTING_FEATURES
Options.modchartingHoldSubdivisions = DEFAULT_MODCHART_HOLD_SUBDIVISIONS;
#end
}
/**
@@ -389,4 +410,4 @@ class Flags {
}
loadPost();
}
}
}
+4 -5
View File
@@ -8,13 +8,12 @@ class FunkinGame extends FlxGame {
super.switchState();
// draw once to put all images in gpu then put the last update time to now to prevent lag spikes or whatever
draw();
_total = ticks = getTicks();
ticks = getTicks();
skipNextTickUpdate = true;
}
public override function onEnterFrame(t) {
if (skipNextTickUpdate != (skipNextTickUpdate = false))
_total = ticks = getTicks();
super.onEnterFrame(t);
override function __enterFrame(deltaTime:Float) {
if (skipNextTickUpdate != (skipNextTickUpdate = false)) ticks = getTicks();
super.__enterFrame(deltaTime);
}
}
@@ -36,7 +36,7 @@ class GraphicCacheSprite extends FlxSprite {
if (graphic == null) return;
// make their useCount one time higher to prevent them from auto being cleared from cache
graphic.useCount++;
graphic.incrementUseCount();
graphic.destroyOnNoUse = false;
cachedGraphics.push(graphic);
nonRenderedCachedGraphics.push(graphic);
@@ -45,7 +45,7 @@ class GraphicCacheSprite extends FlxSprite {
public override function destroy() {
for(g in cachedGraphics) {
g.destroyOnNoUse = true;
g.useCount--;
g.decrementUseCount();
}
graphic = null;
super.destroy();
+1 -1
View File
@@ -115,7 +115,7 @@ final class Logs {
Sys.print(t.text);
}
NativeAPI.setConsoleColors();
Sys.print("\r\n");
Sys.println("\r");
__showing = false;
#elseif mobile
while(__showing) {
+6 -21
View File
@@ -24,8 +24,8 @@ import openfl.utils.AssetLibrary;
import sys.FileSystem;
import sys.io.File;
#if android
import android.content.Context;
import android.os.Build;
import extension.androidtools.content.Context;
import extension.androidtools.os.Build;
#end
class Main extends Sprite
@@ -33,7 +33,7 @@ class Main extends Sprite
public static var instance:Main;
public static var modToLoad:String = null;
public static var forceGPUOnlyBitmapsOff:Bool = #if desktop false #else true #end;
public static var forceGPUOnlyBitmapsOff:Bool = false;
public static var noTerminalColor:Bool = false;
public static var verbose:Bool = false;
@@ -58,9 +58,11 @@ class Main extends Sprite
// You can pretty much ignore everything from here on - your code should go in your states.
public static function preInit() {
#if sys
funkin.backend.utils.NativeAPI.registerAsDPICompatible();
funkin.backend.system.CommandLineHandler.parseCommandLine(Sys.args());
funkin.backend.system.Main.fixWorkingDirectory();
#end
}
public function new()
@@ -95,16 +97,10 @@ class Main extends Sprite
// DEPRECATED
@:dox(hide) public static function execAsync(func:Void->Void) ThreadUtil.execAsync(func);
private static function getTimer():Int {
return time = Lib.getTimer();
}
public static function loadGameSettings() {
WindowUtils.init();
SaveWarning.init();
MemoryUtil.init();
@:privateAccess
FlxG.game.getTimer = getTimer;
FunkinCache.init();
Paths.assetsTree = new AssetsLibraryList();
@@ -129,12 +125,11 @@ class Main extends Sprite
funkin.options.PlayerSettings.init();
Options.load();
game.focusLostFramerate = 30;
FlxG.fixedTimestep = false;
FlxG.scaleMode = scaleMode = new FunkinRatioScaleMode();
Conductor.init();
AudioSwitchFix.init();
EventManager.init();
FlxG.signals.focusGained.add(onFocus);
FlxG.signals.preStateSwitch.add(onStateSwitch);
@@ -206,16 +201,6 @@ class Main extends Sprite
// manual asset clearing since base openfl one does'nt clear lime one
// does'nt clear bitmaps since flixel fork does it auto
@:privateAccess {
// clear uint8 pools
for(length=>pool in openfl.display3D.utils.UInt8Buff._pools) {
for(b in pool.clear())
b.destroy();
}
openfl.display3D.utils.UInt8Buff._pools.clear();
}
MemoryUtil.clearMajor();
}
+44 -14
View File
@@ -7,12 +7,14 @@ import flixel.FlxState;
import funkin.backend.assets.AssetsLibraryList;
import funkin.backend.assets.ModsFolder;
import funkin.backend.assets.ModsFolderLibrary;
import funkin.backend.assets.ZipFolderLibrary;
import funkin.backend.chart.EventsData;
import funkin.backend.system.framerate.Framerate;
import funkin.editors.ModConfigWarning;
import funkin.menus.TitleState;
import haxe.io.Path;
@dox(hide)
typedef AddonInfo = {
var name:String;
@@ -40,6 +42,7 @@ class MainState extends FlxState {
ControlsUtil.resetCustomControls();
FlxG.bitmap.reset();
FlxG.sound.destroy(true);
FlxG.sound.resetCache();
Paths.assetsTree.reset();
@@ -57,12 +60,32 @@ class MainState extends FlxState {
var _highPriorityAddons:Array<AddonInfo> = [];
var _noPriorityAddons:Array<AddonInfo> = [];
var quick_modsPath = ModsFolder.modsPath + ModsFolder.currentModFolder;
// handing if the loading mod (before it's properly loaded) is a compressed mod
// we just need to use `Paths.assetsTree.hasCompressedLibrary` to complete valid checks for actual loaded compressed mods
var isZipMod = false;
// If we know it's a compressed mod, then we can check if it's using the `cnemod` folder path.
// All it is really is a folder with the mod's name, then a compressed file called "cnemod.[zip|7z|rar|etc]"
var isCneMod = false;
// We are doing it like this because think about it: it's 1 for loop lol
// We just need to know if any of these values is true, so if only one is true and we are not close to being done in the loop, that's fine.
//
for (ext in Flags.ALLOWED_ZIP_EXTENSIONS) {
if (FileSystem.exists(quick_modsPath+"."+ext)) isZipMod = true;
if (FileSystem.exists(quick_modsPath+"/cnemod."+ext)) isCneMod = true;
if (isZipMod && isCneMod) break;
}
// We get the addons folder from relative space (`./`) and then our mod's addons.
var addonPaths = [
ModsFolder.addonsPath,
(
ModsFolder.currentModFolder != null ?
ModsFolder.modsPath + ModsFolder.currentModFolder + "/addons/" :
null
// So to check the mod's addons folder, we need to decompress it. Which is impossible* in this stage of the loading library process.
// TODO: Write a function when the library is loaded to decompress the contents and then load the libraries :)
( (ModsFolder.currentModFolder != null && !isZipMod) ?
quick_modsPath + "/addons/" : null
)
];
@@ -72,12 +95,8 @@ class MainState extends FlxState {
for (addon in FileSystem.readDirectory(path)) {
if (!FileSystem.isDirectory(path + addon)) {
switch(Path.extension(addon).toLowerCase()) {
case 'zip':
addon = Path.withoutExtension(addon);
default:
continue;
}
if (Flags.ALLOWED_ZIP_EXTENSIONS.contains(Path.extension(addon))) addon = Path.withoutExtension(addon);
else continue;
}
var data:AddonInfo = {
@@ -100,9 +119,14 @@ class MainState extends FlxState {
#if MOD_SUPPORT
for (addon in _lowPriorityAddons)
loadLib(addon.path, ltrim(addon.name, "[LOW]"));
if (ModsFolder.currentModFolder != null)
loadLib(ModsFolder.modsPath + ModsFolder.currentModFolder, ModsFolder.currentModFolder);
if (ModsFolder.currentModFolder != null) {
// isCneMod is a guarentee to be a zip mod because we just checked for it, so this will always load as a CompressedLibrary
if (isCneMod)
loadLib(quick_modsPath + "/cnemod", ModsFolder.currentModFolder);
else
loadLib(quick_modsPath, ModsFolder.currentModFolder);
}
for (addon in _noPriorityAddons)
loadLib(addon.path, addon.name);
@@ -134,9 +158,15 @@ class MainState extends FlxState {
CoolUtil.safeAddAttributes('./.temp/', NativeAPI.FileAttribute.HIDDEN);
#end
for (lib in ModsFolder.getLoadedModsLibs()) {
if (!(lib is ZipFolderLibrary)) continue;
if (cast(lib, ZipFolderLibrary).PRELOAD_VIDEOS) cast(lib, ZipFolderLibrary).precacheVideos();
}
var startState:Class<FlxState> = Flags.DISABLE_WARNING_SCREEN ? TitleState : funkin.menus.WarningState;
if (Options.devMode && Options.allowConfigWarning) {
// In this case if the mod we just loaded a compressed modpack, we can't edit or modify files without decompressing it.
if (Options.devMode && Options.allowConfigWarning && !isZipMod) {
var lib:ModsFolderLibrary;
for (e in Paths.assetsTree.libraries) if ((lib = cast AssetsLibraryList.getCleanLibrary(e)) is ModsFolderLibrary
&& lib.modName == ModsFolder.currentModFolder)
@@ -1,62 +1,14 @@
package funkin.backend.system;
import lime.graphics.Image;
import lime.graphics.cairo.CairoImageSurface;
import openfl.display.BitmapData;
import openfl.geom.Rectangle;
@:deprecated("Use openfl.display.BitmapData.toHardware instead.")
class OptimizedBitmapData extends BitmapData {
@SuppressWarnings("checkstyle:Dynamic")
@:noCompletion private override function __fromImage(image:#if lime Image #else Dynamic #end):Void
{
#if lime
if (image != null && image.buffer != null)
{
this.image = image;
width = image.width;
height = image.height;
rect = new Rectangle(0, 0, image.width, image.height);
__textureWidth = width;
__textureHeight = height;
#if sys
image.format = BGRA32;
image.premultiplied = true;
#end
__isValid = true;
readable = true;
if(FlxG.stage.context3D != null) {
lock();
getTexture(FlxG.stage.context3D);
getSurface();
readable = true;
this.image = null;
// @:privateAccess
// if (FlxG.bitmap.__doNotDelete)
// MemoryUtil.clearMinor();
}
}
#end
}
@SuppressWarnings("checkstyle:Dynamic")
@:dox(hide) public override function getSurface():#if lime CairoImageSurface #else Dynamic #end
{
#if lime
if (__surface == null)
{
__surface = CairoImageSurface.fromImage(image);
}
return __surface;
#else
return null;
#end
super.__fromImage(image);
toHardware();
}
}
@@ -8,7 +8,12 @@ class RotatingSpriteGroup extends FlxSpriteGroup {
if (maxSize <= 0)
return super.recycle(ObjectClass, ObjectFactory, Force, Revive);
if (group.members.length < maxSize)
return group.recycleCreateObject(ObjectClass, ObjectFactory);
{
if (ObjectFactory != null) return add(ObjectFactory());
if (ObjectClass != null) return add(Type.createInstance(ObjectClass, []));
return null;
}
var spr = group.members.shift();
group.members.push(spr);
if (Revive)
@@ -14,7 +14,7 @@ class AssetTreeInfo extends FramerateCategory {
super("Asset Libraries Tree Info");
}
public override function __enterFrame(t:Int) {
public override function __enterFrame(t:Float) {
if (alpha <= 0.05) return;
if ((lastUpdateTime += FlxG.rawElapsed) < 1)
@@ -6,15 +6,23 @@ import openfl.text.TextField;
class CodenameBuildField extends TextField {
public function new() {
super();
defaultTextFormat = Framerate.textFormat;
autoSize = LEFT;
multiline = wordWrap = false;
reload();
}
public function reload() {
defaultTextFormat = Framerate.textFormat;
#if TEST_BUILD
text = '${Flags.VERSION_MESSAGE} (Test Build)';
#elseif COMPILE_EXPERIMENTAL
text = '${Flags.VERSION_MESSAGE} (Experimental Build)';
#else
text = '${Flags.VERSION_MESSAGE}';
#if debug
#end
#if (debug || COMPILE_EXPERIMENTAL)
text += '\n${Flags.COMMIT_MESSAGE}';
#end
}
@@ -5,7 +5,7 @@ class ConductorInfo extends FramerateCategory {
super("Conductor Info");
}
public override function __enterFrame(t:Int) {
public override function __enterFrame(t:Float) {
if (alpha <= 0.05) return;
_text = 'Current Song Position: ${Math.floor(Conductor.songPosition * 1000) / 1000}';
_text += '\n - ${Conductor.curBeat} beats';
@@ -7,7 +7,7 @@ class FlixelInfo extends FramerateCategory {
super("Flixel Info");
}
public override function __enterFrame(t:Int) {
public override function __enterFrame(t:Float) {
if (alpha <= 0.05) return;
@@ -76,6 +76,7 @@ class Framerate extends Sprite {
}
public function reload() {
textFormat = new TextFormat(fontName, 12, -1);
for(c in categories)
c.reload();
#if SHOW_BUILD_ON_FPS
@@ -100,7 +101,7 @@ class Framerate extends Sprite {
var debugAlpha:Float = 0;
public override function __enterFrame(t:Int) {
public override function __enterFrame(t:Float) {
alpha = CoolUtil.fpsLerp(alpha, debugMode > 0 ? 1 : 0, 0.5);
debugAlpha = CoolUtil.fpsLerp(debugAlpha, debugMode > 1 ? 1 : 0, 0.5);
@@ -40,9 +40,11 @@ class FramerateCategory extends Sprite {
this.text.y = this.title.y + this.title.height + 2;
}
public function reload() {}
public function reload() {
for(label in [this.title, this.text]) label.defaultTextFormat = new TextFormat(Framerate.fontName, label == this.title ? 18 : 12, -1);
}
public override function __enterFrame(t:Int) {
public override function __enterFrame(t:Float) {
if (alpha <= 0.05) return;
super.__enterFrame(t);
@@ -35,10 +35,11 @@ class FramerateCounter extends Sprite {
}
public function reload() {
for (label in [fpsNum, fpsLabel]) label.defaultTextFormat = new TextFormat(Framerate.fontName, label == fpsNum ? 18 : 12, -1);
lastUpdateTime = 0;
}
public override function __enterFrame(t:Int) {
public override function __enterFrame(t:Float) {
if (alpha <= 0.05) return;
super.__enterFrame(t);
@@ -23,16 +23,18 @@ class MemoryCounter extends Sprite {
label.y = 0;
label.text = "MEM";
label.multiline = label.wordWrap = false;
label.defaultTextFormat = new TextFormat(Framerate.fontName, 12, -1);
label.defaultTextFormat = Framerate.textFormat;
label.selectable = false;
addChild(label);
}
memoryPeakText.alpha = 0.5;
}
public function reload() {}
public function reload() {
for(label in [memoryText, memoryPeakText]) label.defaultTextFormat = Framerate.textFormat;
}
public override function __enterFrame(t:Int) {
public override function __enterFrame(t:Float) {
if (alpha <= 0.05) return;
super.__enterFrame(t);
@@ -9,7 +9,7 @@ class StatsInfo extends FramerateCategory {
super("Asset Libraries Tree Info");
}
public override function __enterFrame(t:Int) {
public override function __enterFrame(t:Float) {
if (alpha <= 0.05) return;
_text = "totalDC: " + Context3DStats.totalDrawCalls();
_text += "\nstageDC: " + Context3DStats.contextDrawCalls(DrawCallContext.STAGE);
@@ -169,7 +169,7 @@ class SystemInfo extends FramerateCategory {
super("System Info");
}
public override function __enterFrame(t:Int) {
public override function __enterFrame(t:Float) {
if (alpha <= 0.05) return;
_text = __formattedSysText;
@@ -0,0 +1,134 @@
package funkin.backend.system.macros;
#if macro
import sys.io.File;
import haxe.macro.ComplexTypeTools;
import haxe.macro.Printer;
import haxe.macro.Expr.Position;
import haxe.macro.Context;
import haxe.macro.Expr.Field;
import haxe.macro.Expr;
class AliasMacro {
public static var aliasMetadata:Metadata = [{
name: ":keep",
pos: Context.currentPos()
},{
name: ":dox",
pos: Context.currentPos(),
params: [
{
expr: EConst(CIdent("hide")),
pos: Context.currentPos()
}
]
}];
public static function build():Array<Field> {
#if display
return Context.getBuildFields();
#end
var fields = Context.getBuildFields();
var ogFieldCount = fields.length;
for(i in 0...ogFieldCount) {
var field = fields[i];
if (field.meta == null) continue;
var previousAliases:Array<{name:String, pos:Position}> = [];
for(meta in field.meta) {
if (meta.name == ":alias" && meta.params != null) {
for(p in meta.params) {
switch(p.expr) {
case EConst(CString(s, kind)):
previousAliases.push({
name: s,
pos: p.pos
});
default:
}
}
}
}
if (previousAliases.length == 0) continue;
var ghostAccess = field.access.copy();
ghostAccess.remove(AOverride);
ghostAccess.remove(APublic);
for(alias in previousAliases) {
var ghostField:Field = {
name: alias.name,
pos: alias.pos,
kind: null,
access: ghostAccess,
meta: aliasMetadata
};
switch(field.kind) {
case FFun(f):
var args:Array<Expr> = [for(a in f.args) {
expr: EConst(CIdent(a.name)),
pos: Context.currentPos()
}];
ghostField.kind = FFun({
args: f.args,
params: f.params,
ret: f.ret,
expr: macro return $i{field.name}($a{args})
});
default:
var type = null;
switch(field.kind) {
case FVar(t, e):
type = t;
case FProp(get, set, t, e):
type = t;
default:
}
ghostField.kind = FProp("get", "set", type, null);
fields.push({
name: 'get_${alias.name}',
kind: FFun({
args: [],
expr: macro return $i{field.name},
ret: type
}),
pos: alias.pos,
meta: aliasMetadata
});
fields.push({
name: 'set_${alias.name}',
kind: FFun({
args: [{
name: '_${field.name}',
type: type
}],
expr: macro return ($i{field.name} = $i{'_${field.name}'}),
ret: type
}),
pos: alias.pos,
meta: aliasMetadata
});
}
fields.push(ghostField);
}
var docFooter = '_Aliases: ${[for(alias in previousAliases) '`${alias.name}`'].join(", ")}_';
if (field.doc != null)
field.doc += '\n\n$docFooter';
else
field.doc = docFooter;
}
trace(fields);
return fields;
}
}
#end
@@ -19,7 +19,7 @@ class FlagMacro {
return false;
}
public static function build(resetCallback:String):Array<Field> {
public static function build():Array<Field> {
var fields = Context.getBuildFields();
var clRef = Context.getLocalClass();
@@ -248,10 +248,7 @@ class FlagMacro {
access: [APublic, AStatic],
kind: FFun({
args: [],
expr: macro {
$b{resetExprs};
$i{resetCallback}();
},
expr: macro $b{resetExprs},
ret: macro: Void
}),
pos: Context.currentPos(),

Some files were not shown because too many files have changed in this diff Show More