Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e62c5a223c | ||
|
|
5fc7491121 | ||
|
|
9598455118 | ||
|
|
0e4b9753a0 | ||
|
|
2bbe3d788d | ||
|
|
cd731d7e40 | ||
|
|
e11e3d51c2 | ||
|
|
b19b78df5d | ||
|
|
1a061cbbcc | ||
|
|
9908c8be32 | ||
|
|
8522deab64 | ||
|
|
7e93521666 | ||
|
|
5aeb3a28fb | ||
|
|
b5db93726a | ||
|
|
20de8db41b | ||
|
|
5d73d65fdc | ||
|
|
8c750d368d | ||
|
|
8d328ace84 | ||
|
|
9d825f00aa | ||
|
|
c7b68507a8 | ||
|
|
970ccf2f4a | ||
|
|
479036a400 | ||
|
|
80d7ace714 | ||
|
|
a7d5736e14 | ||
|
|
b31be1043c | ||
|
|
6c4d27a842 | ||
|
|
fdab26ce56 | ||
|
|
8ead5eeb08 | ||
|
|
c4ebd3175d | ||
|
|
e593bc8a61 | ||
|
|
cb554bd5f7 | ||
|
|
dd54acfbd1 | ||
|
|
6783f04139 | ||
|
|
11eb4060d0 | ||
|
|
b5357acf98 | ||
|
|
f85f2f03d9 | ||
|
|
146a6cde68 | ||
|
|
65105df9ac | ||
|
|
9106ef215a | ||
|
|
38426bc5d7 | ||
|
|
79e8b5d71e | ||
|
|
6e954cfac0 | ||
|
|
041d33b2d3 | ||
|
|
1b5b0925ed | ||
|
|
cd0bc85b76 | ||
|
|
d4929164b6 | ||
|
|
7bc06861b5 | ||
|
|
3ccbed2cbb | ||
|
|
29c0b0f8eb | ||
|
|
7ff0753472 | ||
|
|
19328abb9e | ||
|
|
feb0863358 | ||
|
|
43e51e9a4a | ||
|
|
3b610d8910 | ||
|
|
63ec749c7a | ||
|
|
c8e6a78154 | ||
|
|
89b2b7fcc3 | ||
|
|
1b1c781426 | ||
|
|
5c8a888b77 | ||
|
|
257576b4d3 | ||
|
|
56f0a7780d | ||
|
|
faa47e8f3e | ||
|
|
b99d599bce | ||
|
|
92bc856f5b | ||
|
|
0490ca8145 | ||
|
|
c9b8f21f61 | ||
|
|
60caa80a84 | ||
|
|
477f85a71e | ||
|
|
b5aed5fb4f | ||
|
|
7d714ecfeb | ||
|
|
f3ff132e90 | ||
|
|
1912155b32 | ||
|
|
daa87c8c58 | ||
|
|
ad87832662 | ||
|
|
b8b0a5bf73 | ||
|
|
5a8b681e2f | ||
|
|
5a6a3f5599 | ||
|
|
bab422029b | ||
|
|
88fc5f9ed6 | ||
|
|
f3c7cfd799 | ||
|
|
231439d808 | ||
|
|
d6f80730a5 | ||
|
|
9cfee0398a | ||
|
|
aa5956a30b | ||
|
|
b9d68957e0 | ||
|
|
1b9f5c62fb | ||
|
|
a0a57ca94d | ||
|
|
271451b9df | ||
|
|
21458f26f2 | ||
|
|
c1b4d4d53e | ||
|
|
28d71dc2fe | ||
|
|
a10bbf60ac | ||
|
|
4e572b171f | ||
|
|
cc768c83aa | ||
|
|
035f3770d5 | ||
|
|
2d95754d49 | ||
|
|
47b1cee6d5 | ||
|
|
4ebd00bc06 | ||
|
|
66554ec4b6 | ||
|
|
bfc798c629 | ||
|
|
6b334b941a | ||
|
|
b06090a477 | ||
|
|
ca5fbb65e5 | ||
|
|
c2305f32f0 | ||
|
|
747446e2e4 | ||
|
|
250d2188b9 | ||
|
|
61c710fe20 | ||
|
|
0fd6f5b3b7 | ||
|
|
8a204c606a | ||
|
|
4401ea0c9a | ||
|
|
12ace54b2b | ||
|
|
f15cd73dff | ||
|
|
b39d7bb5a0 | ||
|
|
f1066a2b0d | ||
|
|
b04b555b38 | ||
|
|
f349eedc72 | ||
|
|
ee2f3c32eb | ||
|
|
0f99a1c7c2 | ||
|
|
95aba09cd6 | ||
|
|
811b9e3343 | ||
|
|
37b9823b36 | ||
|
|
555684afda | ||
|
|
0d5c6ac963 | ||
|
|
db67a6928c | ||
|
|
9c34ab5f9c | ||
|
|
f09074b79d | ||
|
|
a5842fbe3f | ||
|
|
8db654e63d | ||
|
|
60144c0dc7 | ||
|
|
830b5dfd71 | ||
|
|
12d81f0f3b | ||
|
|
8c835447c8 | ||
|
|
d9b35b9a96 | ||
|
|
93cac00472 | ||
|
|
ab94fb633c | ||
|
|
bd79c8bf7d | ||
|
|
3ee0894f89 | ||
|
|
735b44c1cc | ||
|
|
d9580c580d | ||
|
|
0ac4bb1ba3 | ||
|
|
7bd9af1f04 | ||
|
|
81b21674e9 | ||
|
|
54ad34e5d0 | ||
|
|
f6fb11de4c | ||
|
|
83aa45a318 | ||
|
|
65186a336d | ||
|
|
3a41b696d3 | ||
|
|
9c08a6ce68 | ||
|
|
62650836b8 | ||
|
|
e4fdf1019a | ||
|
|
9dfda77d1e | ||
|
|
fe6c8cabd6 | ||
|
|
8b8d249813 | ||
|
|
c6ee23fec2 | ||
|
|
345d96a7bc | ||
|
|
7f7fc3fa90 | ||
|
|
7c17e72e63 | ||
|
|
1d2f971a26 | ||
|
|
7d97bb525a | ||
|
|
da74f782d3 | ||
|
|
107ef7c83f | ||
|
|
0412d865f1 | ||
|
|
50e114fc12 | ||
|
|
ce6577a9ed | ||
|
|
7fbe7b55c1 | ||
|
|
fb649c5d48 | ||
|
|
0ae8d62520 | ||
|
|
5b34446469 | ||
|
|
8d1bfa105c | ||
|
|
a2e9277851 | ||
|
|
2425054940 | ||
|
|
2bbfbc8968 | ||
|
|
5922b927b7 | ||
|
|
ebc5133062 | ||
|
|
7e2094070c | ||
|
|
20187540b3 | ||
|
|
c94d6bbb66 | ||
|
|
3d8b9a18b3 | ||
|
|
f428f5860d | ||
|
|
2645d56514 | ||
|
|
3f5ef4abe0 | ||
|
|
75d8c5cc7a | ||
|
|
9c7dded259 | ||
|
|
6a564905c0 | ||
|
|
8a3d36d3fc | ||
|
|
de9e30534e | ||
|
|
d42be225ca | ||
|
|
f7af64111c | ||
|
|
069bebb127 | ||
|
|
da8609f1d9 | ||
|
|
a11ae53c51 | ||
|
|
1d22e073a2 | ||
|
|
9da770f6cd | ||
|
|
d414a4974a | ||
|
|
6f193c4bd8 | ||
|
|
520f7fbe68 | ||
|
|
aaa722abcf | ||
|
|
f878624f44 | ||
|
|
355ea561fa | ||
|
|
7f6c0d56cd | ||
|
|
a21eace70c | ||
|
|
47813eac31 | ||
|
|
943afe2ffc | ||
|
|
89127b2b00 | ||
|
|
aab1330531 | ||
|
|
8bab6196e5 | ||
|
|
4e183a4dc9 | ||
|
|
ec2cc44cc3 | ||
|
|
663987fbcd | ||
|
|
172041d4f7 | ||
|
|
422da38662 | ||
|
|
9b81ebc4f2 | ||
|
|
0b9ad0905e | ||
|
|
1e1b5643a8 | ||
|
|
45ba0cb7a6 | ||
|
|
b1406e07f5 | ||
|
|
4b655879f7 | ||
|
|
fabfaa3a9c | ||
|
|
6d5249df79 | ||
|
|
23b163cb69 | ||
|
|
1b84c21c36 | ||
|
|
a87eb25765 | ||
|
|
df67b642a8 | ||
|
|
6eefe9e31e | ||
|
|
fea34c4a7b | ||
|
|
10e8cbbac3 | ||
|
|
37812ae2f8 | ||
|
|
acb1930d7e | ||
|
|
b98095f8aa | ||
|
|
724992d3b3 | ||
|
|
89e07dac76 | ||
|
|
2fb973049a | ||
|
|
dc20586e95 | ||
|
|
ccb4c03b85 | ||
|
|
f2732cb253 | ||
|
|
bf2b1af185 | ||
|
|
a2b347e31e | ||
|
|
4317f129e7 | ||
|
|
51eec4522e | ||
|
|
21c16c3a50 | ||
|
|
b7a5761730 | ||
|
|
ff09cb88cd | ||
|
|
d1a96f791f | ||
|
|
84bafa43b7 | ||
|
|
223e837fe8 | ||
|
|
50c601a7f0 | ||
|
|
f870ed2858 | ||
|
|
f1d6906616 | ||
|
|
aec3c646d5 | ||
|
|
e7f7f4794f | ||
|
|
517eb4eb48 | ||
|
|
8cba81d207 | ||
|
|
5831852edf | ||
|
|
114bb37c7f | ||
|
|
1db75cc55e | ||
|
|
248516244c | ||
|
|
b108c0fd95 | ||
|
|
2a804f29fd | ||
|
|
b03828adf3 | ||
|
|
657a25996b | ||
|
|
842ec2c1cd | ||
|
|
4268462d90 | ||
|
|
031007992a | ||
|
|
cea7db410c | ||
|
|
0e181877cf | ||
|
|
ef1216de46 | ||
|
|
b4b2e8da9d | ||
|
|
d95f239dfb | ||
|
|
495690f41c | ||
|
|
b166cd9a7e | ||
|
|
7f82b48e3f | ||
|
|
1fc611d130 | ||
|
|
57a276d17c | ||
|
|
9b1b22c9d5 | ||
|
|
f6de4c54d3 | ||
|
|
e3aceacb59 | ||
|
|
546375087c | ||
|
|
c093e0ca1c | ||
|
|
7c6efba577 | ||
|
|
6f5e3a50d2 | ||
|
|
2d0d5f8a2e | ||
|
|
826249f78c | ||
|
|
0af4c82723 | ||
|
|
c16e45049b | ||
|
|
ae00e14a5b | ||
|
|
42a9c43127 | ||
|
|
17ece1423a | ||
|
|
6540faefdd | ||
|
|
eb24d4d19e | ||
|
|
01a2458c12 | ||
|
|
38e7e230d8 | ||
|
|
84f119036b | ||
|
|
74a783c3db | ||
|
|
09d5926455 | ||
|
|
5f8b7787cb | ||
|
|
a7156978a1 | ||
|
|
65349f4714 | ||
|
|
93ad7e8932 | ||
|
|
df388dfaa6 | ||
|
|
c142add8a1 | ||
|
|
a75c41b813 | ||
|
|
7fd74edf2b | ||
|
|
44370c2653 | ||
|
|
1fbb7604dd | ||
|
|
0e52744718 | ||
|
|
feb55b2625 | ||
|
|
4341a53486 | ||
|
|
0566cd3e58 | ||
|
|
a2f7fa9ef4 | ||
|
|
3a30b681b6 | ||
|
|
0bd4ce4c97 | ||
|
|
df0d977e6c | ||
|
|
059b412e85 | ||
|
|
27a072f4e1 | ||
|
|
1df0cb95f6 | ||
|
|
ce83e962bf | ||
|
|
fb293ebcd2 | ||
|
|
bb7b00cf77 | ||
|
|
e16391a05c | ||
|
|
5aba4b54a5 | ||
|
|
cb611f77a0 | ||
|
|
b5345e1da2 | ||
|
|
8d6590e765 | ||
|
|
e39b32bab0 | ||
|
|
d5754c5da2 | ||
|
|
fbe83be936 | ||
|
|
8d14df77ff | ||
|
|
55358463f8 | ||
|
|
4ea99656f2 | ||
|
|
34ce13c5df | ||
|
|
1d8679941e | ||
|
|
086f28fef1 | ||
|
|
fb4967c94b | ||
|
|
293b70bbed | ||
|
|
64f4620b5a | ||
|
|
9c1e22309b | ||
|
|
4ecef6db74 | ||
|
|
b128741075 | ||
|
|
86e69cfbd1 | ||
|
|
aa8690fce3 | ||
|
|
e281bdddca | ||
|
|
19fdda7cd9 | ||
|
|
d72b989bf5 | ||
|
|
cd99905bdf | ||
|
|
3f82f3792b | ||
|
|
1d8ed5198c | ||
|
|
8cd3785e3c | ||
|
|
7e01e7332b | ||
|
|
c3a837b054 | ||
|
|
a92567886c | ||
|
|
4cbfaefc1a | ||
|
|
705e6b3308 | ||
|
|
56878befef | ||
|
|
44cdbb08c4 | ||
|
|
d6fe54ee79 | ||
|
|
32c775ef3f | ||
|
|
1605514424 | ||
|
|
743e8b13c2 | ||
|
|
cf89d672e7 | ||
|
|
661ddb15f7 | ||
|
|
72fa82716d | ||
|
|
a069ca2dc6 | ||
|
|
90a2d7a1ad | ||
|
|
3170346b83 | ||
|
|
e6d737125e | ||
|
|
3d88fbb11f | ||
|
|
0d6bc2bedd | ||
|
|
da5f691865 | ||
|
|
f63cbf073a | ||
|
|
30721c3a30 | ||
|
|
2b1f346097 | ||
|
|
12117557c7 | ||
|
|
6b0e607af0 | ||
|
|
2263b36cd7 | ||
|
|
2dcc528847 | ||
|
|
5cb33e895c | ||
|
|
1b91f3b57c | ||
|
|
e5e3270fef | ||
|
|
e003a38cab | ||
|
|
890d1dafcb | ||
|
|
9d2cfa9686 | ||
|
|
e6fd5d9b12 | ||
|
|
967397311b | ||
|
|
542f59ef72 | ||
|
|
065ee74aea | ||
|
|
312b5c8812 | ||
|
|
e9aa6872a3 | ||
|
|
4f9b63f22c | ||
|
|
962519e7f0 | ||
|
|
34bae4a431 | ||
|
|
79478080f6 | ||
|
|
65a3ccc8fe | ||
|
|
4ac851c387 | ||
|
|
70d5730b70 | ||
|
|
c527fed70c | ||
|
|
054a5cd00b | ||
|
|
19c5de8fe2 | ||
|
|
dbc26fd621 | ||
|
|
eb1986b246 | ||
|
|
d661d93184 | ||
|
|
4a07d0a347 | ||
|
|
832f01345f | ||
|
|
e8d41c938c | ||
|
|
a94bd7f36c | ||
|
|
c185f10e65 | ||
|
|
52f3c63071 | ||
|
|
e71062b914 | ||
|
|
3aa6a36b5e | ||
|
|
a89fa9c121 | ||
|
|
cb2015f51a | ||
|
|
139ce3847c | ||
|
|
87b40c1203 | ||
|
|
b9852c316b | ||
|
|
444697620c | ||
|
|
6abeefb15d | ||
|
|
530bd1f11d | ||
|
|
76c0dea92b | ||
|
|
2d7a2202f5 | ||
|
|
1f18a3d1f4 | ||
|
|
0d57f61ffa | ||
|
|
9fa70775b9 | ||
|
|
463afb43c0 | ||
|
|
2833827fbf | ||
|
|
01cd72e805 | ||
|
|
72e0ff6c9b | ||
|
|
2586154376 | ||
|
|
82367dffc2 | ||
|
|
7c675ecf17 | ||
|
|
b4e52df156 | ||
|
|
cf70bf2c6c | ||
|
|
fb6d1b36d3 | ||
|
|
0c0c63bc03 | ||
|
|
01620fda9b | ||
|
|
3bcd6813c1 | ||
|
|
d44966efd2 | ||
|
|
79c3e2de11 | ||
|
|
8372d47d11 | ||
|
|
d89ebdf58f | ||
|
|
1e8c472084 | ||
|
|
17cef6f897 | ||
|
|
2cc43ee1f6 | ||
|
|
2277acccfa | ||
|
|
351719ab13 | ||
|
|
4ecfe9863e | ||
|
|
48e140e5c0 | ||
|
|
e6bb965d6b | ||
|
|
b00376c88c | ||
|
|
ed86b326ab | ||
|
|
596c5813d7 | ||
|
|
ae68925911 | ||
|
|
d7c3799562 | ||
|
|
47ab14a855 | ||
|
|
940e165612 | ||
|
|
5181023887 | ||
|
|
32e774b005 | ||
|
|
c353cc54a1 | ||
|
|
48d0798e5f | ||
|
|
0463b4e26b | ||
|
|
0c1842038f | ||
|
|
aa0b8cbbbe | ||
|
|
52cd4f6c36 | ||
|
|
96a1796905 | ||
|
|
6be7e89222 | ||
|
|
abea46939f | ||
|
|
3a5f1e14cf | ||
|
|
849e413bb7 | ||
|
|
b4a7bd7462 | ||
|
|
beb64528fb | ||
|
|
eac940bccb | ||
|
|
aa1c71cafd | ||
|
|
f4bedc359a | ||
|
|
01428dd5cf | ||
|
|
541bb78da9 | ||
|
|
c6e19c8512 | ||
|
|
e30a4ebb7b | ||
|
|
949f409cff | ||
|
|
4c5aa9743e | ||
|
|
3fa2b3574b | ||
|
|
1e41ac3052 | ||
|
|
936812ae1e | ||
|
|
ad3bf2d2d2 | ||
|
|
1b1c2a124b | ||
|
|
2aff2fa201 | ||
|
|
7ec602f6ec | ||
|
|
4fbeffb57c | ||
|
|
f029a27a3f | ||
|
|
8a99fa4184 | ||
|
|
f21b015292 | ||
|
|
bc8e35409b | ||
|
|
006f1dce0a | ||
|
|
78186188d7 | ||
|
|
762486639e | ||
|
|
b5bb9721da | ||
|
|
4029e92181 | ||
|
|
9c7f87c225 | ||
|
|
43420092f3 | ||
|
|
d8cd580535 | ||
|
|
13c08b285d | ||
|
|
6238b72d8c | ||
|
|
bf92bf3f60 | ||
|
|
6467cd75a8 | ||
|
|
32dc25bbf6 | ||
|
|
11cb409bd2 | ||
|
|
f245365ed3 | ||
|
|
e0d0230b88 | ||
|
|
f8634e2b81 | ||
|
|
4f68f63e2d | ||
|
|
e9e0567f8b | ||
|
|
8db768fd2a | ||
|
|
cf814ee4e2 | ||
|
|
43b7be4e71 | ||
|
|
7d555b4155 | ||
|
|
88ad99c3ef | ||
|
|
d92b7ff3f5 | ||
|
|
66c6a78319 | ||
|
|
e6a2a09801 | ||
|
|
8944e07fe1 | ||
|
|
188260ea81 | ||
|
|
22c6ce42ba | ||
|
|
d8445fe54a | ||
|
|
c3592ee6f5 | ||
|
|
e402328969 | ||
|
|
150a1d5b0a | ||
|
|
d468477663 | ||
|
|
ecaf51ef41 | ||
|
|
05627a50d5 | ||
|
|
efe333da92 | ||
|
|
e946b54249 | ||
|
|
1d4a94041b | ||
|
|
11da19ce1e | ||
|
|
126ed3a67a | ||
|
|
468197e74e | ||
|
|
7f17ad8bb8 | ||
|
|
e9ef340c63 | ||
|
|
61bda6c2c2 | ||
|
|
07f649ca37 | ||
|
|
11ecd07606 | ||
|
|
822c5ba405 | ||
|
|
d61f89b0e4 | ||
|
|
9dfae07225 | ||
|
|
01fad012f2 | ||
|
|
9843f9549c | ||
|
|
044106e8a9 | ||
|
|
d338be9270 | ||
|
|
e4d3e18e4f | ||
|
|
5f5fff870c | ||
|
|
52acd86cdf | ||
|
|
dd104365e7 | ||
|
|
b0581f728a | ||
|
|
5e50432b30 | ||
|
|
314d8af9c8 | ||
|
|
f91261f748 | ||
|
|
0567849665 | ||
|
|
a701e6a4a9 | ||
|
|
abfc4ca79c | ||
|
|
797a8bfcba | ||
|
|
d70838cca9 | ||
|
|
0d845154ef | ||
|
|
9e04db2c5c | ||
|
|
c0d3b9daa2 | ||
|
|
0f336ae0e6 | ||
|
|
8c8eedf17a | ||
|
|
793b533b88 | ||
|
|
852a74c33d | ||
|
|
bfdafd7f37 | ||
|
|
37d0d1b14e | ||
|
|
2649e247fa | ||
|
|
fafe157a70 | ||
|
|
39a4292dc5 | ||
|
|
aad0a0afb6 | ||
|
|
f8516cfb4d | ||
|
|
29f7aca135 | ||
|
|
35d4d24731 | ||
|
|
c0dde5c936 |
@@ -14,19 +14,20 @@ body:
|
||||
- label: I have read the [Contributing Guide](https://github.com/FunkinCrew/Funkin/blob/main/docs/CONTRIBUTING.md)
|
||||
- label: I have checked the Issues/Discussions pages to see if my issue has already been reported
|
||||
- label: I have properly titled my issue
|
||||
- label: I did not have any mods installed when I encountered this issue
|
||||
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Platform
|
||||
description: Which platform are you playing on?
|
||||
options:
|
||||
- Android
|
||||
- iOS/iPadOS
|
||||
- Newgrounds (Web/HTML5)
|
||||
- Itch.io (Web/HTML5)
|
||||
- Itch.io (Downloadable Build) - Windows
|
||||
- Itch.io (Downloadable Build) - MacOS
|
||||
- Itch.io (Downloadable Build) - Linux
|
||||
- Google Playstore - Android
|
||||
- App Store - iOS
|
||||
- Windows (Downloadable Build)
|
||||
- MacOS (Downloadable Build)
|
||||
- Linux (Downloadable Build)
|
||||
- Compiled from GitHub Source Code
|
||||
validations:
|
||||
required: true
|
||||
@@ -43,11 +44,23 @@ body:
|
||||
- Safari
|
||||
- Other (Specify in Description field)
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: Mobile Device Model
|
||||
description: (Mobile users only) What mobile device are you playing on?
|
||||
placeholder: ex. iPhone 17, Galaxy S25, iPad 11th Gen
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: Mobile OS Version
|
||||
description: (Mobile users only) What version is your Operating System?
|
||||
placeholder: ex. iOS 26.0, Android 15, iPadOS 26.0
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: Version
|
||||
description: Which version are you playing on? The game version is in the bottom left corner of the main menu.
|
||||
placeholder: ex. 0.6.4
|
||||
placeholder: ex. 0.7.5
|
||||
validations:
|
||||
required: true
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "# PLEASE READ THE [CONTRIBUTING GUIDE](https://github.com/FunkinCrew/Funkin/blob/main/docs/CONTRIBUTING.md) BEFORE OPENING ISSUES!"
|
||||
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Issue Checklist
|
||||
@@ -21,35 +21,25 @@ body:
|
||||
label: Platform
|
||||
description: Which platform are you playing on?
|
||||
options:
|
||||
- Android
|
||||
- iOS/iPadOS
|
||||
- Newgrounds (Web/HTML5)
|
||||
- Itch.io (Web/HTML5)
|
||||
- Itch.io (Downloadable Build) - Windows
|
||||
- Itch.io (Downloadable Build) - MacOS
|
||||
- Itch.io (Downloadable Build) - Linux
|
||||
- Windows (Downloadable Build)
|
||||
- MacOS (Downloadable Build)
|
||||
- Linux (Downloadable Build)
|
||||
- Compiled from GitHub Source Code
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Browser
|
||||
description: (Web/HTML5 users only) Which browser are you playing on?
|
||||
options:
|
||||
- Google Chrome
|
||||
- Microsoft Edge
|
||||
- Firefox
|
||||
- Opera
|
||||
- Safari
|
||||
- Other (Specify in Description field)
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: Version
|
||||
description: Which version are you playing on? The game version is in the bottom left corner of the main menu.
|
||||
placeholder: ex. 0.6.4
|
||||
description: Which version are you playing on? The game version is in the bottom left corner of the main menu.
|
||||
placeholder: ex. 0.7.5
|
||||
validations:
|
||||
required: true
|
||||
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "## Describe the charting issue(s)."
|
||||
|
||||
@@ -6,7 +6,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "# PLEASE READ THE [CONTRIBUTING GUIDE](https://github.com/FunkinCrew/Funkin/blob/main/docs/CONTRIBUTING.md) BEFORE OPENING ISSUES!"
|
||||
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Issue Checklist
|
||||
@@ -22,6 +22,8 @@ body:
|
||||
label: Platform
|
||||
description: Which platform are you compiling for?
|
||||
options:
|
||||
- Android
|
||||
- iOS/iPadOS
|
||||
- Web/HTML5
|
||||
- Desktop (Windows)
|
||||
- Desktop (Mac)
|
||||
@@ -33,11 +35,11 @@ body:
|
||||
- type: input
|
||||
attributes:
|
||||
label: Version
|
||||
description: Which version are you compiling? The game version is in the bottom left corner of the main menu or in the project.hxp file.
|
||||
placeholder: ex. 0.6.4
|
||||
description: Which version are you compiling? The game version is in the bottom left corner of the main menu or in the project.hxp file.
|
||||
placeholder: ex. 0.7.5
|
||||
validations:
|
||||
required: true
|
||||
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "## Describe your compiling issue."
|
||||
|
||||
@@ -6,7 +6,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "# PLEASE READ THE [CONTRIBUTING GUIDE](https://github.com/FunkinCrew/Funkin/blob/main/docs/CONTRIBUTING.md) BEFORE OPENING ISSUES!"
|
||||
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Issue Checklist
|
||||
@@ -15,17 +15,20 @@ body:
|
||||
- label: I have read the [Contributing Guide](https://github.com/FunkinCrew/Funkin/blob/main/docs/CONTRIBUTING.md)
|
||||
- label: I have checked the Issues/Discussions pages to see if my issue has already been reported
|
||||
- label: I have properly titled my issue
|
||||
- label: I did not have any mods installed when I encountered this issue
|
||||
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Platform
|
||||
description: Which platform are you playing on?
|
||||
options:
|
||||
- Android
|
||||
- iOS/iPadOS
|
||||
- Newgrounds (Web/HTML5)
|
||||
- Itch.io (Web/HTML5)
|
||||
- Itch.io (Downloadable Build) - Windows
|
||||
- Itch.io (Downloadable Build) - MacOS
|
||||
- Itch.io (Downloadable Build) - Linux
|
||||
- Windows (Downloadable Build)
|
||||
- MacOS (Downloadable Build)
|
||||
- Linux (Downloadable Build)
|
||||
- Compiled from GitHub Source Code
|
||||
validations:
|
||||
required: true
|
||||
@@ -42,11 +45,23 @@ body:
|
||||
- Safari
|
||||
- Other (Specify in Description field)
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: Mobile Device Model
|
||||
description: (Mobile users only) What mobile device are you playing on?
|
||||
placeholder: ex. iPhone 17, Galaxy S25, iPad 11th Gen
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: Mobile OS Version
|
||||
description: (Mobile users only) What version is your Operating System?
|
||||
placeholder: ex. iOS 26.0, Android 15, iPadOS 26.0
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: Version
|
||||
description: Which version are you playing on? The game version is in the bottom left corner of the main menu.
|
||||
placeholder: ex. 0.6.4
|
||||
description: Which version are you playing on? The game version is in the bottom left corner of the main menu.
|
||||
placeholder: ex. 0.7.5
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@@ -61,7 +76,7 @@ body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description
|
||||
description: Include screenshots or videos of the crash happening. Provide as much detail as you can.
|
||||
description: Include screenshots or videos of the crash happening. Provide as much detail as you can.
|
||||
placeholder: Describe the crash here...
|
||||
validations:
|
||||
required: true
|
||||
@@ -77,7 +92,7 @@ body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Crash logs
|
||||
description: These can be found in the logs folder where Funkin.exe is.
|
||||
description: These can be found in the logs folder where Funkin.exe is, or in your mobile device's file explorer.
|
||||
placeholder: Upload your logs here...
|
||||
validations:
|
||||
required: true
|
||||
|
||||
+1
-2
@@ -6,7 +6,6 @@ dump/
|
||||
temp/
|
||||
docs/temp/
|
||||
export/
|
||||
project/
|
||||
astc-textures/
|
||||
RECOVER_*.fla
|
||||
shitAudio/
|
||||
@@ -17,7 +16,7 @@ NewgroundsCredentials.hx
|
||||
# Mobile signing stuff
|
||||
.apple/
|
||||
.env
|
||||
key.keystore
|
||||
*.keystore
|
||||
|
||||
# Exclude JS stuff
|
||||
node_modules/
|
||||
|
||||
+503
-96
@@ -4,119 +4,523 @@ All notable changes will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.7.0] - 2025-06-??
|
||||
## [0.7.5] - 2025-09-19
|
||||
|
||||
### Added
|
||||
|
||||
- Friday Night Funkin' now has an OFFICIAL mobile version, available on the [Google Play Store]() and [Apple App Store]()!
|
||||
- This version is 100% feature complete with the desktop version of the game.
|
||||
- [MOBILE] New touch input compatiblity for all menus.
|
||||
- [MOBILE] Added banner and interstitial advertisements to the game. You can use an in-app purchase to upgrade to the full version to permanently disable advertisements.
|
||||
- [MOBILE] Graphics are compressed using the ASTC algorithm, decreasing memory usage in exchange for a slightly bigger file size.
|
||||
- [MOBILE] Added haptic feedback to several areas in the game.
|
||||
- A whopping ZERO new songs! Woah!
|
||||
- Added null-safety to a bunch of classes within the source code.
|
||||
- Added a blank `Object` class for scripts to extend, and made `FlxObject` and `FlxBasic` scriptable. ([1c36548](https://github.com/FunkinCrew/Funkin/commit/1c36548861a54e2a8ae49f715056139ce31bbd83)) - by @cyn0x8 in [#3119](https://github.com/FunkinCrew/Funkin/pull/3119)
|
||||
- The Chart Editor now highlights and deletes stacked notes and using a customizable threshold. ([8cae34e](https://github.com/FunkinCrew/Funkin/commit/8cae34eed711bff70e5348ffc6178a0fd69b5846)) - by @NotHyper-474 in [#3574](https://github.com/FunkinCrew/Funkin/pull/3574)
|
||||
- Added the ability to press the Chart Editor keybind in Freeplay with a song capsule selected. ([066c2d3](https://github.com/FunkinCrew/Funkin/commit/066c2d3db04162d3df6af883066fc91e05988d58)) - by @Lasercar in [#4114](https://github.com/FunkinCrew/Funkin/pull/4114)
|
||||
- Added more tween types to certain Chart Editor events. ([5177e12](https://github.com/FunkinCrew/Funkin/commit/5177e1275eb2fb2b016224c139e84debb421b895)) - by @Lasercar in [#4249](https://github.com/FunkinCrew/Funkin/pull/4249)
|
||||
- Added default gamepad controls for two recently added Freeplay controls. ([8dad4f5](https://github.com/FunkinCrew/Funkin/commit/8dad4f55b660a01d4e1a3a903fde684e9876f555)) - by @MrMadera in [#4559](https://github.com/FunkinCrew/Funkin/pull/4559)
|
||||
- Added Perfect (Gold) to the list of available ranks in Results Debug menu. ([0261355](https://github.com/FunkinCrew/Funkin/commit/02613557787581b9c5b7532ea6e69001f1989102)) - by @AbnormalPoof in [#4642](https://github.com/FunkinCrew/Funkin/pull/4642)
|
||||
- Added a few sandboxed classes to give mods limited access to the Discord and Newgrounds APIs. ([6bd6066](https://github.com/FunkinCrew/Funkin/commit/6bd6066d169fd1611a706e984bb8d3ad7109e31f)) - by @KoloInDaCrib in [#5040](https://github.com/FunkinCrew/Funkin/pull/5040)
|
||||
- Pressing Ctrl + N now creates a new stage in the Stage Editor. ([bc54634](https://github.com/FunkinCrew/Funkin/commit/bc546345377f9e9e7b69306b72d494cad02ebaba)) - by @Lasercar in [#5175](https://github.com/FunkinCrew/Funkin/pull/5175)
|
||||
- Added script support for Freeplay Backing Cards. ([92e7588](https://github.com/FunkinCrew/Funkin/commit/92e7588370fcbdc0e959e01e7e52eed5d62323f2)) - by @KoloInDaCrib in [#5233](https://github.com/FunkinCrew/Funkin/pull/5233)
|
||||
- Added a variation indicator next to the Chart Editor playbar difficulty. ([dc7fa97](https://github.com/FunkinCrew/Funkin/commit/dc7fa97d3ca3c00edbab0adc171135af0008735d)) - by @KoloInDaCrib in [#5236](https://github.com/FunkinCrew/Funkin/pull/5236)
|
||||
- Added "Flip character horizontally" to the list of shortcuts in the Animation Editor. ([f73e925](https://github.com/FunkinCrew/funkin.assets/commit/f73e925cbc1e99223095e444f9217839c7d8148e)) - by @AbnormalPoof in [funkin.assets#60](https://github.com/FunkinCrew/funkin.assets/pull/60)
|
||||
- Added an `onStateCreate` event to the Module class.
|
||||
|
||||
### Changed
|
||||
|
||||
- Modified several parts of the game to look better on phone screens with wider aspect ratios, up to 20:9.
|
||||
- Fixed a ton of performance issues to help the game run better on mobile devices.
|
||||
- Completely reformatted and optimized every single chart file in the game, along with fixing several chart issues.
|
||||
- Completely reformatted every script file within the game's assets for better readability.
|
||||
- Notes now scroll more smoothly by rendering based on delta timing. ([6ad9ffc](https://github.com/FunkinCrew/Funkin/commit/6ad9ffc7f9d66bbaf6ba343663de4c7268f4be3b)) - by @KutikiPlayz in [#3544](https://github.com/FunkinCrew/Funkin/pull/3544)
|
||||
- Favorite songs in Freeplay are now sorted by Week order instead of alphabetically. ([da0964a](https://github.com/FunkinCrew/Funkin/commit/da0964a7b7bbe4ece1bdbd19233eb6dba0de3ac5)) - by @Hundrec in [#3609](https://github.com/FunkinCrew/Funkin/pull/3609)
|
||||
- The Character Select screen now opens on the currently selected character. ([b233a53](https://github.com/FunkinCrew/Funkin/commit/b233a53710d8ef6b0151d83f5d78e1733fe356f5)) - by @Lasercar in [#4072](https://github.com/FunkinCrew/Funkin/pull/4072)
|
||||
- The undo/redo history is now cleared when loading another song in the Chart Editor. ([4c4045e](https://github.com/FunkinCrew/Funkin/commit/4c4045e274f6a7fa0bc2574468abb3b70ca68f00)) - by @Lasercar in [#4308](https://github.com/FunkinCrew/Funkin/pull/4308)
|
||||
- The Options Menu can now scroll to display more menu items. ([70f0a54](https://github.com/FunkinCrew/Funkin/commit/70f0a54191597bd72a6d30d4d12ef5ece6ba078c)) - by @AbnormalPoof in [#4706](https://github.com/FunkinCrew/Funkin/pull/4706)
|
||||
- The Chart Editor will now only fall back to the first available difficulty if the selected difficulty cannot be found. ([19d75ff](https://github.com/FunkinCrew/Funkin/commit/19d75ffe72f08a6adb5b4ca00cae2f913767047a)) - by @Lasercar in [#4949](https://github.com/FunkinCrew/Funkin/pull/4949)
|
||||
- Adjusted the size of the Beat/Step display in the Chart Editor. ([44b1a77](https://github.com/FunkinCrew/Funkin/commit/44b1a77b3b62146504166b392ea2dfbe6f65b302)) - by @NotHyper-474 in [#4994](https://github.com/FunkinCrew/Funkin/pull/4994)
|
||||
- The Freeplay character select hint now always displays if you have more than one character unlocked. ([7ccf75c](https://github.com/FunkinCrew/Funkin/commit/7ccf75cd869ba4b6f18a5adc01e65e52ae7bb809)) - by @Hundrec in [#5023](https://github.com/FunkinCrew/Funkin/pull/5023)
|
||||
- Raised the FPS cap preference from 300 to 500. ([71d7169](https://github.com/FunkinCrew/Funkin/commit/71d7169ba35c01471b4274671e238b0ac2cf04ed)) - by @Hundrec in [#5044](https://github.com/FunkinCrew/Funkin/pull/5044)
|
||||
- Blacklisted more classes for security reasons. ([cadfa3b](https://github.com/FunkinCrew/Funkin/commit/cadfa3b7ceae2ecabe2d544ddc4c9f453b0dfd56)) - by @NotHyper-474 in [#5185](https://github.com/FunkinCrew/Funkin/pull/5185)
|
||||
- Visualizers now zero out when the game audio is muted. ([3d205e9](https://github.com/FunkinCrew/Funkin/commit/3d205e935553096ab7bbd1879d8cb69bdb550ead)) - by @Lasercar in [#5266](https://github.com/FunkinCrew/Funkin/pull/5266)
|
||||
- Shifted Mommy Mearest's pixel icon to the left in Freeplay. ([d9e8085](https://github.com/FunkinCrew/funkin.assets/commit/d9e8085020cfc516b7c38ec7773081619ab840a4)) - by @KoloInDaCrib in [funkin.assets#197](https://github.com/FunkinCrew/funkin.assets/pull/197)
|
||||
- Gave the debug display a huge upgrade!
|
||||
- Choose from three settings in the Preferences Menu: Off/Simple/Advanced
|
||||
- New “Task memory” counter shows how much RAM the game is using on your computer.
|
||||
- Advanced mode displays graphs for FPS and RAM usage.
|
||||
- Hot reloading now works in scripted states.
|
||||
- Made a few more classes scriptable.
|
||||
- FunkinVideoSprite
|
||||
- FlxStrip
|
||||
- FlxTypedGroup
|
||||
- Strumline
|
||||
- StageProp
|
||||
- The Random capsule now brings up the option to select a random instrumental. ([0d5c6ac](https://github.com/FunkinCrew/Funkin/commit/0d5c6ac9632ee3bf3977b9bd369daab9f2d95fea)) - by @VioletSnowLeopard in [#5891](https://github.com/FunkinCrew/Funkin/pull/5891)
|
||||
- The Character Select menu now returns to Freeplay after pressing a back button. ([250d218](https://github.com/FunkinCrew/Funkin/commit/250d2188b9cb2c92d283d8b12ed7de0286324592)) - by @MrMadera in [#5887](https://github.com/FunkinCrew/Funkin/pull/5887)
|
||||
- Pressing the Shift key in the Credits menu now pauses scrolling. ([479036a](https://github.com/FunkinCrew/Funkin/commit/479036a4008fe1c54adc970c0a476fae6b1b3e94)) - by @JVNpixels in [#2924](https://github.com/FunkinCrew/Funkin/pull/2924)
|
||||
- Chart Editor and Stage Editor backup files are now given relevant filenames. ([b31be10](https://github.com/FunkinCrew/Funkin/commit/b31be1043ccd1e906a656913b947bae160b451fe)) - by @Lasercar in [#4118](https://github.com/FunkinCrew/Funkin/pull/4118)
|
||||
- The Animation Editor's onion skin now properly accounts for offsets and displays the idle animation. ([0fd6f5b](https://github.com/FunkinCrew/Funkin/commit/0fd6f5b3b7bd115a3b6821096daa929c220bd235)) - by @KoloInDaCrib in [#5810](https://github.com/FunkinCrew/Funkin/pull/5810)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Songs no longer skip forward at the beginning with high visual offsets. ([02c64ae](https://github.com/FunkinCrew/Funkin/commit/02c64aea9c2e7fe06f9116312d5ef6c049dc8e9c)) - by @xenkap in [#3732](https://github.com/FunkinCrew/Funkin/pull/3732)
|
||||
- Fixed various issues and added missing functionalities to the Stage Editor. ([15083a4](https://github.com/FunkinCrew/Funkin/commit/15083a477626f67125bfd60a844b42b85a82d8c3)) - by @KoloInDaCrib in [#3974](https://github.com/FunkinCrew/Funkin/pull/3974)
|
||||
- Pressing the Chart Editor keybind during a song now opens to the variation and difficulty you were playing. ([aeb2dd5](https://github.com/FunkinCrew/Funkin/commit/aeb2dd53983b12fa0152861cc51a161115ea2729)) - by @Lasercar in [#4116](https://github.com/FunkinCrew/Funkin/pull/4116)
|
||||
- Dragging a hold note in the Chart Editor now drags its trail along with its head. ([d3d8aaa](https://github.com/FunkinCrew/Funkin/commit/d3d8aaae7bfbfa8975a9573807b9a3ca68a1ff55)) - by @KoloInDaCrib in [#4127](https://github.com/FunkinCrew/Funkin/pull/4127)
|
||||
- The help guide in the Stage Editor can no longer be opened multiple times. ([8c1fa3e](https://github.com/FunkinCrew/Funkin/commit/8c1fa3e630e595eac774e81f2c0f8f32ff97d927)) - by @Lasercar in [#4128](https://github.com/FunkinCrew/Funkin/pull/4128)
|
||||
- The Chart Editor now properly saves audio levels when exiting. ([6da2718](https://github.com/FunkinCrew/Funkin/commit/6da2718f116b45dd969ee74c808b86f63631984c)) - by @Lasercar in [#4149](https://github.com/FunkinCrew/Funkin/pull/4149)
|
||||
- Holding Ctrl and clicking on a hold note trail no longer crashes the Chart Editor. ([279bf2a](https://github.com/FunkinCrew/Funkin/commit/279bf2acd0e61b890a63b2dc4c82c6f6dc3c9ffd)) - by @Lasercar in [#4203](https://github.com/FunkinCrew/Funkin/pull/4203)
|
||||
- Removed spammy console traces from `DiscordClient`. ([e89f9f5](https://github.com/FunkinCrew/Funkin/commit/e89f9f50dc6085e3550736459ce9e4fd02c1fc5b)) - by @AbnormalPoof in [#4207](https://github.com/FunkinCrew/Funkin/pull/4207)
|
||||
- The Debug Menu can no longer be opened after selecting an item in the Main Menu. ([5695bc2](https://github.com/FunkinCrew/Funkin/commit/5695bc20e721f0afd5b97a36167f13e550c12b16)) - by @Lasercar in [#4211](https://github.com/FunkinCrew/Funkin/pull/4211)
|
||||
- Fixed the Chart Editor timer occasionally displaying incorrect millisecond values. ([26dc895](https://github.com/FunkinCrew/Funkin/commit/26dc895a27e0d7e49469251cd68b83be66384e15)) - by @Hundrec in [#4257](https://github.com/FunkinCrew/Funkin/pull/4257)
|
||||
- The Chart Editor "Load Metadata File" and "Load Chart File" buttons now function properly. ([5eecef1](https://github.com/FunkinCrew/Funkin/commit/5eecef17a143cbc8cf2307bc29a20c96b8eed6a8)) - by @Lasercar in [#4278](https://github.com/FunkinCrew/Funkin/pull/4278)
|
||||
- The "New Highscore" text no longer appears more than once in the Results screen. ([c0d8e1b](https://github.com/FunkinCrew/Funkin/commit/c0d8e1b70356ec3492e57602a7d30fc2c595544b)) - by @Lasercar in [#4319](https://github.com/FunkinCrew/Funkin/pull/4319)
|
||||
- The Story Mode Weekend 1 level title no longer clips into other level titles below it. ([b86efaa](https://github.com/FunkinCrew/Funkin/commit/b86efaaf7bc6b96fc3234b8f22420c2178fa4306)) - by @KoloInDaCrib in [#4348](https://github.com/FunkinCrew/Funkin/pull/4348)
|
||||
- The debug cursor is now always hidden when the game starts. ([6222c38](https://github.com/FunkinCrew/Funkin/commit/6222c389e301fa2bb4939697376c4e51e29a9977)) - by @Hundrec in [#4520](https://github.com/FunkinCrew/Funkin/pull/4520)
|
||||
- Fixed Newgrounds score submissions for Lit Up and Lit Up (BF Mix). ([183cec6](https://github.com/FunkinCrew/Funkin/commit/183cec62dc1fd3c7f3f634dd3e2400e6ee77b476)) - by @Raltyro in [#4577](https://github.com/FunkinCrew/Funkin/pull/4577)
|
||||
- Freeplay song ranks no longer disappear after changing variations. ([c00f10a](https://github.com/FunkinCrew/Funkin/commit/c00f10adc8ebc7a6876bf20d6a4d15e44bb7d863)) - by @VioletSnowLeopard in [#4583](https://github.com/FunkinCrew/Funkin/pull/4583)
|
||||
- Freeplay song capsules now cycle through long names consistently. ([ae086e7](https://github.com/FunkinCrew/Funkin/commit/ae086e7810437069efd3a4afbd55a5c303f473fb)) - by @VioletSnowLeopard in [#4677](https://github.com/FunkinCrew/Funkin/pull/4677)
|
||||
- Properly blacklist a certain class from scripts. ([3dc7699](https://github.com/FunkinCrew/Funkin/commit/3dc7699aac737998b637ff9a9f16986a434424be)) - by @charlesisfeline in [#4773](https://github.com/FunkinCrew/Funkin/pull/4773)
|
||||
- The song countdown no longer stacks when restarting or continues behind the Pause Menu. ([63eca96](https://github.com/FunkinCrew/Funkin/commit/63eca96c98a87e7155df8b2a1735f269ea83e1b5)) - by @NotHyper-474 in [#4875](https://github.com/FunkinCrew/Funkin/pull/4875)
|
||||
- The charter field in the song metadata now properly displays the charter in the Chart Editor. ([4d24087](https://github.com/FunkinCrew/Funkin/commit/4d24087c2126f64f0bbdf32557e6f0ee7f2aee24)) - by @Lasercar in [#4879](https://github.com/FunkinCrew/Funkin/pull/4879)
|
||||
- The Results Debug menu now shows the correct rank after recent scoring changes. ([66e36b9](https://github.com/FunkinCrew/Funkin/commit/66e36b99051298ddf306d981b3b0f29ddc88ffe3)) - by @NotHyper-474 in [#4905](https://github.com/FunkinCrew/Funkin/pull/4905)
|
||||
- Opening the logs or backups folder before it's created no longer crashes the game. ([60e2b88](https://github.com/FunkinCrew/Funkin/commit/60e2b88703678776994d7a038687773a1c639019)) - by @NotHyper-474 in [#4940](https://github.com/FunkinCrew/Funkin/pull/4940)
|
||||
- An easter egg now restarts the song using the correct instrumental. ([a499f46](https://github.com/FunkinCrew/Funkin/commit/a499f46e6dcec301ab35e62b9e494c7fac2e9c9b)) - by @KoloInDaCrib in [#4956](https://github.com/FunkinCrew/Funkin/pull/4956)
|
||||
- Girlfriend's and Nene's combo drop animations now play consistently. ([34d5ed1](https://github.com/FunkinCrew/Funkin/commit/34d5ed11695cef7348c13505f13fb1da38b7988c)) - by @VioletSnowLeopard in [#4968](https://github.com/FunkinCrew/Funkin/pull/4968)
|
||||
- Fixed a few visual issues with Freeplay's rank slam animation. ([ab817bb](https://github.com/FunkinCrew/Funkin/commit/ab817bb1eab74ae71c1b1fd74d7512a11e6d4339)) - by @Lasercar in [#4986](https://github.com/FunkinCrew/Funkin/pull/4986)
|
||||
- Nonexistent characters no longer crash the Chart Editor. ([3bbb4b0](https://github.com/FunkinCrew/Funkin/commit/3bbb4b06c8c1a1885a18d4354fcfa4363a0c6c75)) - by @Lasercar in [#5008](https://github.com/FunkinCrew/Funkin/pull/5008)
|
||||
- The Chart Editor playhead can no longer be scrolled to before the beginning of the song. ([03a0975](https://github.com/FunkinCrew/Funkin/commit/03a09752991c830be12befd5488fc8a102273c99)) - by @Hundrec in [#5024](https://github.com/FunkinCrew/Funkin/pull/5024)
|
||||
- Fixed incorrect highlighting and squashed text on Freeplay song capsules. ([0c62428](https://github.com/FunkinCrew/Funkin/commit/0c62428fc883c0fa6d09cd403efb287ff3af8c53)) - by @VioletSnowLeopard in [#5036](https://github.com/FunkinCrew/Funkin/pull/5036)
|
||||
- The Freeplay new rank animation now shows the new rank slamming onto the old one.
|
||||
- Freeplay capsules with a Gold Perfect rank no longer become randomly offset when scrolling.
|
||||
- The Pico Freeplay DJ’s new rank animation now properly renders its lighting.
|
||||
- Freeplay song previews no longer play replaced or deleted audio files.
|
||||
- The strumline no longer disappears after re-entering Lag Adjustment.
|
||||
- Fixed various issues with Week 6 dialogue boxes, portraits, and audio.
|
||||
- [MOBILE] The strumlines are no longer offset to the left in Blazin’.
|
||||
- The preloader no longer disables fullscreen mode after completion.
|
||||
- Attempting to log in to Newgrounds during an ongoing login attempt no longer crashes the game. ([4e572b1](https://github.com/FunkinCrew/Funkin/commit/4e572b171fe901a84f12b4566963fd3c1f4ae6fb)) - by @KoloInDaCrib in [#5922](https://github.com/FunkinCrew/Funkin/pull/5922)
|
||||
- Added null-safety to Leaderboards and Medals to prevent a rare crash. ([88fc5f9](https://github.com/FunkinCrew/Funkin/commit/88fc5f9ed684e287d7411a59fb4fdf170acfed5a)) - by @NotHyper-474 in [#5926](https://github.com/FunkinCrew/Funkin/pull/5926)
|
||||
- Freeplay ranks no longer pop out when scrolling through song capsules. ([747446e](https://github.com/FunkinCrew/Funkin/commit/747446e2e420449f422fbc69aafda6128ac8d16e)) - by @VioletSnowLeopard in [#5822](https://github.com/FunkinCrew/Funkin/pull/5822)
|
||||
- The Freeplay intro no longer plays when returning from a sticker transition. ([63ec749](https://github.com/FunkinCrew/Funkin/commit/63ec749c7a3c90d529e9e8f2f3ed1c8913e8f9a1)) - by @PurSnake in [#5942](https://github.com/FunkinCrew/Funkin/pull/5942)
|
||||
- Hot-reloading with F5 after earning a rank no longer crashes Freeplay. ([79e8b5d](https://github.com/FunkinCrew/Funkin/commit/79e8b5d71e052953b77b81b66e0a83a7bbeeeeed)) - by @KoloInDaCrib in [#5971](https://github.com/FunkinCrew/Funkin/pull/5971)
|
||||
- The Main Menu music now fades in consistently when exiting from Freeplay to the Title Screen. ([a10bbf6](https://github.com/FunkinCrew/Funkin/commit/a10bbf60acbbeadfb5a91930745ef4fd338b1a24)) - by @VirtuGuy in [#5855](https://github.com/FunkinCrew/Funkin/pull/5855)
|
||||
- The game now falls back to default audio files when files specified by the metadata don't exist. ([b5357ac](https://github.com/FunkinCrew/Funkin/commit/b5357acf98bde81a4121a3723061f7c559a0640f)) - by @VioletSnowLeopard in [#5954](https://github.com/FunkinCrew/Funkin/pull/5954)
|
||||
- The cutscene pause menu no longer persists across songs after exiting a video cutscene. ([c2305f3](https://github.com/FunkinCrew/Funkin/commit/c2305f32f0147f6326e8665d21a6b8a793f45033)) - by @KoloInDaCrib in [#5880](https://github.com/FunkinCrew/Funkin/pull/5880)
|
||||
- Mashing to skip the Eggnog Erect cutscene no longer crashes the game. ([5ca3c6a](https://github.com/FunkinCrew/funkin.assets/commit/5ca3c6a5745b61a457db149c289784c08e560ee9)) - by @VioletSnowLeopard in [funkin.assets#258](https://github.com/FunkinCrew/funkin.assets/pull/258)
|
||||
- Stress (Pico Mix) no longer lag spikes when loading in the background tankmen. ([6701405](https://github.com/FunkinCrew/funkin.assets/commit/670140571239ca08c1ae1c5286773d99c2875c2d)) - by @NotHyper-474 and @KoloInDaCrib in [funkin.assets#242](https://github.com/FunkinCrew/funkin.assets/pull/242)
|
||||
- Stress (Pico Mix) no longer lag spikes when Tankman changes sprites. ([aa5956a](https://github.com/FunkinCrew/Funkin/commit/aa5956a30bdc47d53ebebb4b61a7ebb3f04c7dc6)) - by @NotHyper-474 in [#5939](https://github.com/FunkinCrew/Funkin/pull/5939)
|
||||
- The bricks in Stress (Pico Mix) no longer move after restarting the song. ([9cfee03](https://github.com/FunkinCrew/Funkin/commit/9cfee0398a057567f80ad68ff6052964da63af09)) - by @VirtuGuy in [#5875](https://github.com/FunkinCrew/Funkin/pull/5875)
|
||||
- Pico now properly shoots after restarting Stress. ([b0ef0d3](https://github.com/FunkinCrew/funkin.assets/commit/b0ef0d352c199e93903652a95ffdf16a3dc2d569)) - by @7oltan in [funkin.assets#254](https://github.com/FunkinCrew/funkin.assets/pull/254)
|
||||
- A-Bot's visualizer now zeroes out when restarting the song. ([ba3a8b0](https://github.com/FunkinCrew/funkin.assets/commit/ba3a8b0cbbf785a0729dcf85e25b6e59c0c12657)) - by @KoloInDaCrib in [funkin.assets#246](https://github.com/FunkinCrew/funkin.assets/pull/246)
|
||||
- Notekinds now properly receive dispatched events last in PlayState. ([89b2b7f](https://github.com/FunkinCrew/Funkin/commit/89b2b7fcc3130db0af1f782594af72ae1f4ce320)) - by @Az989YT in [#5936](https://github.com/FunkinCrew/Funkin/pull/5936)
|
||||
- Text from .json files is now properly sanitized before it is parsed. ([80d7ace](https://github.com/FunkinCrew/Funkin/commit/80d7ace714efb729cb8f1b23b61fdab4ac655275)) - by @KoloInDaCrib in [#5108](https://github.com/FunkinCrew/Funkin/pull/5108)
|
||||
- Fixed a crash when exiting the Chart Editor after interacting with a text field. ([f85f2f0](https://github.com/FunkinCrew/Funkin/commit/f85f2f03d97fc1332275f088ddce2b4056f0ded2)) - by @NotHyper-474 in [#5992](https://github.com/FunkinCrew/Funkin/pull/5992)
|
||||
- Fixed some issues with variation handling in the Chart Editor. ([970ccf2](https://github.com/FunkinCrew/Funkin/commit/970ccf2f4a9b5802b70d0b3c269c8b9e541d53f2)) - by @NotHyper-474 in [#4396](https://github.com/FunkinCrew/Funkin/pull/4396)
|
||||
- Audio no longer plays when dragging a playhead in the Chart Editor. ([2d95754](https://github.com/FunkinCrew/Funkin/commit/2d95754d492da06920d56de2b2bcbb9b81182af0)) - by @Lasercar in [#4140](https://github.com/FunkinCrew/Funkin/pull/4140)
|
||||
- The Chart Editor Offsets window song preview no longer continues playing during playtesting. ([11eb406](https://github.com/FunkinCrew/Funkin/commit/11eb4060d03b18a2f3604297eb9a24e54077fe3c)) - by @PurSnake and @Lasercar in [#5973](https://github.com/FunkinCrew/Funkin/pull/5973)
|
||||
- The fullscreen keybind no longer triggers when typing in a field. ([4ebd00b](https://github.com/FunkinCrew/Funkin/commit/4ebd00bc06a5c94e935f557ba14ba9729faec104)) - by @lemz1 in [#4131](https://github.com/FunkinCrew/Funkin/pull/4131)
|
||||
- The Stage Editor new stage menu can no longer be opened multiple times at once. ([47b1cee](https://github.com/FunkinCrew/Funkin/commit/47b1cee6d5ee37cd18146ca8098da85610c6b544)) - by @VioletSnowLeopard in [#5873](https://github.com/FunkinCrew/Funkin/pull/5873)
|
||||
- Adjusted the save hotkeys in the Animation Editor to be usable on Windows. ([8ead5ee](https://github.com/FunkinCrew/Funkin/commit/8ead5eeb0840756a843fdcf0f3f347b087e7182d)) - by @VioletSnowLeopard in [#5974](https://github.com/FunkinCrew/Funkin/pull/5974)
|
||||
- A few more tiny fixes.
|
||||
|
||||
## New Contributors for 0.7.5
|
||||
|
||||
* @Az989YT made their first contribution in [#5936](https://github.com/FunkinCrew/Funkin/pull/5936)
|
||||
|
||||
|
||||
|
||||
## [0.7.4] - 2025-09-01
|
||||
|
||||
### Added
|
||||
|
||||
- [MOBILE] Added haptics to the can explosion in 2hot.
|
||||
- Added the `scorable` property to notekinds, which excludes them from tallies.
|
||||
- Added saving and loading save data using Newgrounds! Check out the new "Save Data Options" button in the Options menu after logging in. ([832f013](https://github.com/FunkinCrew/Funkin/commit/832f01345f441631a5372dbc3382dc8a13c150d6)) - by @TechnikTil in [#4900](https://github.com/FunkinCrew/Funkin/pull/4900)
|
||||
- Added variation-specific song scripts, improving compatibility between mods. ([c94d6bb](https://github.com/FunkinCrew/Funkin/commit/c94d6bbb6640f7a9fbce8a202fbecf19d36da2f7)) - by @AbnormalPoof in [#5165](https://github.com/FunkinCrew/Funkin/pull/5165)
|
||||
- Added scoped modules, which only run in a specified state. ([842ec2c](https://github.com/FunkinCrew/Funkin/commit/842ec2c1cd0243741170c431e4095bad2a4842e0)) - by @AbnormalPoof in [#5138](https://github.com/FunkinCrew/Funkin/pull/5138)
|
||||
- Added ModStore, a helper class that stores data across hot reloads until the game is closed. ([3170346](https://github.com/FunkinCrew/Funkin/commit/3170346b83e5f73a88b3e7135e75ec1be2384929)) - by @cyn0x8 in [#4230](https://github.com/FunkinCrew/Funkin/pull/4230)
|
||||
- Added hotkeys to toggle individual audio tracks in the Chart Editor. ([1e1b564](https://github.com/FunkinCrew/Funkin/commit/1e1b5643a8536a3061a237e058c45223b66039da)) - by @Lasercar in [#4247](https://github.com/FunkinCrew/Funkin/pull/4247)
|
||||
- Added visual indicators and tooltips for notekinds. ([32c775e](https://github.com/FunkinCrew/Funkin/commit/32c775ef3f131accd69a04591608420919a607a1)) - by @KoloInDaCrib in [#5284](https://github.com/FunkinCrew/Funkin/pull/5284)
|
||||
- Added a Charter field to the New Chart dialog in the Chart Editor. ([23b163c](https://github.com/FunkinCrew/Funkin/commit/23b163cb69ffbb8d2ae1c12d965a6ed3a26020e0)) - by @NotHyper-474 in [#5657](https://github.com/FunkinCrew/Funkin/pull/5657)
|
||||
- Added a Song ID field to the Chart Editor metadata toolbox. ([55f9d24](https://github.com/FunkinCrew/funkin.assets/commit/55f9d24e9dc475b981e4cc087101425e85d3c1e2)) - by @cyn0x8 in [funkin.assets#229](https://github.com/FunkinCrew/funkin.assets/pull/229)
|
||||
- Added a confirmation prompt when exiting the Chart Editor with an unsaved chart. ([e6d7371](https://github.com/FunkinCrew/Funkin/commit/e6d737125e0031d1efabc73266dfbde6d6c758de)) - by @anysad in [#5091](https://github.com/FunkinCrew/Funkin/pull/5091)
|
||||
- [ANDROID] Added support for monochrome icons on Android 12 and above. ([5de4e76](https://github.com/FunkinCrew/Funkin/commit/5de4e766b7317c50d3ae40b9525b7c391984d52c)) - by @ThatOneCalculator in [#5507](https://github.com/FunkinCrew/Funkin/pull/5507)
|
||||
|
||||
### Changed
|
||||
|
||||
- Reworked the Conductor to make note scrolling smoother.
|
||||
- Reworked Attract Mode.
|
||||
- The Title Screen fades out and plays a video after a certain amount of time.
|
||||
- The video alternates between the Mobile Trailer and the BOYFRIEND EVERYWHERE music video, replacing the previous toy commercial.
|
||||
- The “Input Offsets” menu is now named “Lag Adjustment”.
|
||||
- Freeplay difficulty dots are now displayed as rows of eight when modded difficulties are present.
|
||||
- Optimized the way the game searches for Freeplay pixel icons.
|
||||
- Results Screen and game over haptics are now softcoded.
|
||||
- [WINDOWS] The window title bar now matches the system theme, light or dark.
|
||||
- [LINUX] The game now displays with an icon.
|
||||
- [iOS] The edges of the app icon are now properly filled in.
|
||||
- Made several improvements and fixes to Polymod and HScript:
|
||||
- Significantly optimized mod loading, especially with many installed at once. (Thanks KoloInDaCrib!)
|
||||
- Fixed several cases where script variables would be lost. (Thanks NotHyper-474!)
|
||||
- Zip mod loading on Linux is now case-insensitive. (Thanks NotHyper-474!)
|
||||
- Added the ability to import scripted classes. (Thanks lemz1!)
|
||||
- NOTE: You currently can’t use them in a static context.
|
||||
- Added the ability to use the `??=` operator. (Thanks lemz1!)
|
||||
- Added the ability to use the `using` keyword. (Thanks KoloInDaCrib!)
|
||||
- `final` variables created inside of scripts are now treated as actual `final`s. (Thanks KoloInDaCrib!)
|
||||
- Added null-safe field assign. (ex. `someVar?.someVar2 = new Class();`) (Thanks NotHyper-474!)
|
||||
- Improved properties support, behaving more like regular Haxe. (Thanks NotHyper-474!)
|
||||
- Fixed a null object reference when evaluating static variables with no explicit values. (Thanks NotHyper-474!)
|
||||
- Fixed a null object reference when iterating over a null variable. (Thanks NotHyper-474!)
|
||||
- Scripts are now automatically cleared when Polymod is initialized. (Thanks KoloInDaCrib!)
|
||||
- Polished every chart in the game!
|
||||
- The lengths of hold notes have been adjusted to match the vocals as closely as possible, across all variations and difficulties.
|
||||
- Easy and Normal charts from Week 1 to Week 3 have been adjusted for more consistency between the player and opponent.
|
||||
- Many charting errors have been corrected.
|
||||
- Accept keybinds and gamepad south buttons now work on the Title Screen. ([e281bdd](https://github.com/FunkinCrew/Funkin/commit/e281bdddca5f31982bdc620e8ea92b080dcd416a)) - by @MrMadera in [#5650](https://github.com/FunkinCrew/Funkin/pull/5650)
|
||||
- [ANDROID] Pressing the Back button in the Title Screen now closes the game. ([e6fd5d9](https://github.com/FunkinCrew/Funkin/commit/e6fd5d9b129f74703d6bd96744f63cb201afc941)) - by @NotHyper-474 in [#5527](https://github.com/FunkinCrew/Funkin/pull/5527)
|
||||
- The HOME and END keys now jump to the top and bottom of the Story Mode menu, respectively. ([d1a96f7](https://github.com/FunkinCrew/Funkin/commit/d1a96f791f2ed35accc1c1e9ff548a75b2b9d7ef)) - by @JVNpixels in [#4591](https://github.com/FunkinCrew/Funkin/pull/4591)
|
||||
- Freeplay favorite songs are now separated by variation. ([b4b2e8d](https://github.com/FunkinCrew/Funkin/commit/b4b2e8da9dde41d730556a41e6bb18b0f3d8d7db)) - by @KoloInDaCrib in [#5154](https://github.com/FunkinCrew/Funkin/pull/5154)
|
||||
- Freeplay preview volumes now play at 70% volume, up from 40%. ([4ecef6d](https://github.com/FunkinCrew/Funkin/commit/4ecef6db744bab7e3fe5de0d680d813cc3bd1ea7)) - by @JackXson-Real in [#5645](https://github.com/FunkinCrew/Funkin/pull/5645)
|
||||
- Selecting a song in the Freeplay menu now plays a fade-out transition. ([705e6b3](https://github.com/FunkinCrew/Funkin/commit/705e6b330806c3157bca7301b1e43cd78acdb23a)) - by @VirtuGuy in [#5626](https://github.com/FunkinCrew/Funkin/pull/5626)
|
||||
- Implemented null safety to PlayState and LoadingState. ([34ce13c](https://github.com/FunkinCrew/Funkin/commit/34ce13c5dfd52760675a1d09efa489bcb108e607)) - by @NotHyper-474 in [#4789](https://github.com/FunkinCrew/Funkin/pull/4789)
|
||||
- Health icons now have an offset variable. ([8bab619](https://github.com/FunkinCrew/Funkin/commit/8bab6196e50420c6586441f2d321bd1c139567c3)) - by @PurSnake in [#5760](https://github.com/FunkinCrew/Funkin/pull/5760)
|
||||
- The "hey" notekind now plays the animation for BF (Christmas). ([91d5970](https://github.com/FunkinCrew/funkin.assets/commit/91d5970e0274aa0a31fc6f2b05c114730256408f)) - by @JackXson-Real in [funkin.assets#225](https://github.com/FunkinCrew/funkin.assets/pull/225)
|
||||
- Added an "offset" property to the Set Camera Bop event, enabling more flexible camera bops. ([3f5ef4a](https://github.com/FunkinCrew/Funkin/commit/3f5ef4abe09bbd222bb9e5e212d63973b1b87175)) - by @Burgerballs in [#3575](https://github.com/FunkinCrew/Funkin/pull/3575)
|
||||
- Added caching to multi-sparrow characters and fixed textures not being properly cached. ([feb55b2](https://github.com/FunkinCrew/Funkin/commit/feb55b26258e1dd0c4d209e2fa8af1dfb32ea684)) - by @PurSnake in [#5684](https://github.com/FunkinCrew/Funkin/pull/5684)
|
||||
- Optimized the way Freeplay backing card text is rendered. ([f6de4c5](https://github.com/FunkinCrew/Funkin/commit/f6de4c54d37d3febc01db20d84885ccd3e21e833)) - by @MaybeMaru in [#5730](https://github.com/FunkinCrew/Funkin/pull/5730)
|
||||
- Optimized the rendering of many visual elements in Freeplay. ([6f193c4](https://github.com/FunkinCrew/Funkin/commit/6f193c4bd88675f46d9455a5310129f1517c8e18)) - by @MaybeMaru in [#5773](https://github.com/FunkinCrew/Funkin/pull/5773)
|
||||
- Optimized the way notes are rendered, especially when many are visible at once. ([a2b347e](https://github.com/FunkinCrew/Funkin/commit/a2b347e31e7a539f12131980ffeaf980e3e677af)) - by @MaybeMaru in [#5752](https://github.com/FunkinCrew/Funkin/pull/5752)
|
||||
- Image assets for gradients are now smaller and stretched in-game for better optimization. ([fab646c](https://github.com/FunkinCrew/funkin.assets/commit/fab646ce4a3045dcd6aa2ab86c403a40ee89bfa3)) - by @MaybeMaru in [funkin.assets#227](https://github.com/FunkinCrew/funkin.assets/pull/227)
|
||||
|
||||
### Fixed
|
||||
|
||||
- The song no longer restarts from an earlier point in the song instead of ending.
|
||||
- Perfect ranks no longer occasionally disappear after the rank slam animation.
|
||||
- Later notes are no longer hit before earlier notes on songs with high scroll speeds.
|
||||
- [MOBILE] Clearing save data no longer crashes the game.
|
||||
- [MOBILE] Cutscenes no longer continue playing behind the Pause Menu after losing focus.
|
||||
- [MOBILE] Freeplay capsules now properly shift away from under the letter sort bar.
|
||||
- [MOBILE] The Options button now animates properly after the first interaction.
|
||||
- [HTML5] The “Touch here to play” button is no longer too large.
|
||||
- Shaders now apply to A-Bot.
|
||||
- Adjusted offsets for some of Pico’s special animations.
|
||||
- Trimmed the extra silence at the beginning of Stress.
|
||||
- Trimmed the extra silence at the end of Senpai.
|
||||
- Monster and Winter Horrorland now display the correct album.
|
||||
- The “Haptics intensity” preference no longer displays inconsistent values.
|
||||
- The Lag Adjustment menu no longer permanently stops sending notes.
|
||||
- The Results Screen clear percentage now disappears behind the sound system.
|
||||
- The Debug Menu background now accounts for wider aspect ratios.
|
||||
- The Legacy Chart Importer now imports charts properly.
|
||||
- Fixed the “Starting BPM” text in the Chart Editor being tiny.
|
||||
- Chromebooks no longer use touch controls.
|
||||
- Enabled note recycling, resulting in a significant performance boost during songs. ([57a276d](https://github.com/FunkinCrew/Funkin/commit/57a276d17c293f40d6b27a89816b1659fc8b078f)) - by @KoloInDaCrib and @NotHyper-474 in [#5732](https://github.com/FunkinCrew/Funkin/pull/5732)
|
||||
- Misses are now properly processed for recycled notes. ([e7f7f47](https://github.com/FunkinCrew/Funkin/commit/e7f7f4794f410b74eab79941531f19c68737f94e)) - by @NotHyper-474 in [#5751](https://github.com/FunkinCrew/Funkin/pull/5751)
|
||||
- Bad save data no longer causes the game to immediately crash. ([84f1190](https://github.com/FunkinCrew/Funkin/commit/84f119036b44881488e47136f23f960855d47897)) - by @mikolka9144 in [#5703](https://github.com/FunkinCrew/Funkin/pull/5703)
|
||||
- Spamming the Reset and Accept buttons no longer softlocks the game over screen. ([01a2458](https://github.com/FunkinCrew/Funkin/commit/01a2458c1281440947f1aab586752e7ff490fe37)) - by @KoloInDaCrib in [#5714](https://github.com/FunkinCrew/Funkin/pull/5714)
|
||||
- Pressing F4 while calibrating or testing offsets no longer results in a softlock. ([7f82b48](https://github.com/FunkinCrew/Funkin/commit/7f82b48e3face75791955d28e807b7919d668be6)) - by @KoloInDaCrib in [#5716](https://github.com/FunkinCrew/Funkin/pull/5716)
|
||||
- Spamming through the Freeplay letter sort lists no longer crashes the game. ([0d6bc2b](https://github.com/FunkinCrew/Funkin/commit/0d6bc2bedd4494838db288247c4b13ec4031f0a8)) - by @JVNpixels in [#5578](https://github.com/FunkinCrew/Funkin/pull/5578)
|
||||
- Main menu items can no longer be scrolled and selected again after selecting an item. ([1fc611d](https://github.com/FunkinCrew/Funkin/commit/1fc611d1308e26f50cc01658b0ab7b848f05debe)) - by @JackXson-Real in [#5680](https://github.com/FunkinCrew/Funkin/pull/5680)
|
||||
- Fixed a crash caused by parsing CRLF line endings incorrectly. ([65349f4](https://github.com/FunkinCrew/Funkin/commit/65349f47145f44c94dae8a7a39004968da48cf0d)) - by @NotHyper-474 in [#5656](https://github.com/FunkinCrew/Funkin/pull/5656)
|
||||
- Fixed a script error when playing a Week 3 Erect song after a Week 3 (Pico Mix) song. ([6ecada8](https://github.com/FunkinCrew/funkin.assets/commit/6ecada82ac0072826132cad8f9e11f07006f9977)) - by @ThatRozebudDude in [funkin.assets#131](https://github.com/FunkinCrew/funkin.assets/pull/131)
|
||||
- Boyfriend's vocals no longer double up after restarting in Week 3. ([743e8b1](https://github.com/FunkinCrew/Funkin/commit/743e8b13c28d9f0471b392edc3127973f6fef329)) - by @NotHyper-474 in [#5408](https://github.com/FunkinCrew/Funkin/pull/5408)
|
||||
- Songs with BPM changes now restart at the correct BPM. ([51eec45](https://github.com/FunkinCrew/Funkin/commit/51eec4522e49ed7ed2c9457b5224c3b06e758958)) - by @VioletSnowLeopard in [#4721](https://github.com/FunkinCrew/Funkin/pull/4721)
|
||||
- Dropped hold notes are now properly handled. ([1df0cb9](https://github.com/FunkinCrew/Funkin/commit/1df0cb95f6a86d41dc5ef2d19a28c4c09952a69a)) - by @Lasercar in [#5172](https://github.com/FunkinCrew/Funkin/pull/5172)
|
||||
- Fullscreen keybinds now work properly on Web builds. ([1fbb760](https://github.com/FunkinCrew/Funkin/commit/1fbb7604ddf4fb8d311b9b414cbcfa0fd9bab255)) - by @NotHyper-474 in [#5664](https://github.com/FunkinCrew/Funkin/pull/5664)
|
||||
- Corrected the heights of characters in the intro text font. ([90242e2](https://github.com/FunkinCrew/funkin.assets/commit/90242e2e200fca38f5f535986db49b7a53282d1f)) - by @SpritersBlock in [funkin.assets#190](https://github.com/FunkinCrew/funkin.assets/pull/190)
|
||||
- PureColor shaders now properly apply anti-aliasing. ([8d1bfa1](https://github.com/FunkinCrew/Funkin/commit/8d1bfa105c89f68ab1f14a197f8c0a5e4fe7fb14)) - by @MaybeMaru in [#5781](https://github.com/FunkinCrew/Funkin/pull/5781)
|
||||
- The Preferences menu camera now remembers its position when exiting and re-entering. ([3d88fbb](https://github.com/FunkinCrew/Funkin/commit/3d88fbb11fea2b52d399f37cb8154795329c31c2)) - by @VirtuGuy in [#5608](https://github.com/FunkinCrew/Funkin/pull/5608)
|
||||
- The Freeplay DJ no longer flickers between animations. ([1b91f3b](https://github.com/FunkinCrew/Funkin/commit/1b91f3b57cda3310db2f5196650b89c8d88e69be)) - by @VirtuGuy in [#5598](https://github.com/FunkinCrew/Funkin/pull/5598)
|
||||
- The Freeplay DJ's turntable lights now glow properly. ([0c5a965](https://github.com/FunkinCrew/funkin.assets/commit/0c5a965400937cbdac55ed9317a2a00a9d4343ae)) - by @Johferson in [funkin.assets#211](https://github.com/FunkinCrew/funkin.assets/pull/211)
|
||||
- The Random capsule now opens the selected song with the correct variation. ([1605514](https://github.com/FunkinCrew/Funkin/commit/160551442453fccc0961c570701bdba7bee95ef0)) - by @PurSnake in [#5611](https://github.com/FunkinCrew/Funkin/pull/5611)
|
||||
- Newly earned Freeplay ranks no longer appear larger than others. ([47813ea](https://github.com/FunkinCrew/Funkin/commit/47813eac3157927f851713cc4c41c5eb5fac2e19)) - by @anysad in [#5768](https://github.com/FunkinCrew/Funkin/pull/5768)
|
||||
- Freeplay now displays the correct number of difficulty stars after returning from a song. ([30721c3](https://github.com/FunkinCrew/Funkin/commit/30721c3a30f7e980557d055daa30e7e5501b83e3)) - by @KoloInDaCrib in [#5560](https://github.com/FunkinCrew/Funkin/pull/5560)
|
||||
- Removed stray pixels around pixel icons in Freeplay and Character Select. ([b1d770b](https://github.com/FunkinCrew/funkin.assets/commit/b1d770b7f69cb73bd35a279ba5b26908e0cd94be)) - by @Hundrec in [funkin.assets#69](https://github.com/FunkinCrew/funkin.assets/pull/69)
|
||||
- The nametag in the Character Select screen now fades and moves as other elements do. ([2b1f346](https://github.com/FunkinCrew/Funkin/commit/2b1f346097efadcad19058c4ed9cefe4f84c8b64)) - by @JackXson-Real in [#5583](https://github.com/FunkinCrew/Funkin/pull/5583)
|
||||
- [MOBILE] The touch pointer now displays during songs. ([9d2cfa9](https://github.com/FunkinCrew/Funkin/commit/9d2cfa9686880170c5c398786c72d878974eaf93)) - by @SrtHero278 in [#5565](https://github.com/FunkinCrew/Funkin/pull/5565)
|
||||
- Note splashes are now more centered on the strumline. ([cfa6016](https://github.com/FunkinCrew/funkin.assets/commit/cfa6016eeacb745cb2787c99f8d1f156ab4d16e8)) - by @JVNpixels in [funkin.assets#234](https://github.com/FunkinCrew/funkin.assets/pull/234)
|
||||
- Removed stray pixels from BF's old icon and aligned its losing icon. ([e57dc54](https://github.com/FunkinCrew/funkin.assets/commit/e57dc54fe333f8fa3f3933164b423128c74f4c38)) - by @Hundrec in [funkin.assets#93](https://github.com/FunkinCrew/funkin.assets/pull/93)
|
||||
- Daddy Dearest's idle animation now plays on beat. ([b4c1aa9](https://github.com/FunkinCrew/funkin.assets/commit/b4c1aa95aad45c42256432ec81cce8bf35107fa7)) - by @qt2k4 in [funkin.assets#148](https://github.com/FunkinCrew/funkin.assets/pull/148)
|
||||
- Boyfriend (Dark)'s idle animation now properly syncs with his regular idle. ([d1610f1](https://github.com/FunkinCrew/funkin.assets/commit/d1610f1e6f0d5b0db0af34e3d00e7a1fc1d4a4b5)) - by @TechnikTil in [funkin.assets#203](https://github.com/FunkinCrew/funkin.assets/pull/203)
|
||||
- Spooky Kids (Dark)'s idle animation now properly syncs with their regular idle. ([aa28bd7](https://github.com/FunkinCrew/funkin.assets/commit/aa28bd74a33ab0026649d19e642c41b4f1c5cd06)) - by @Honton129 in [funkin.assets#213](https://github.com/FunkinCrew/funkin.assets/pull/213)
|
||||
- Lightning now appears more regularly during South and Monster in Story Mode. ([c5f4a8e](https://github.com/FunkinCrew/funkin.assets/commit/c5f4a8e55f18cbc2e57a72743320da79358b1816)) - by @JackXson-Real in [funkin.assets#222](https://github.com/FunkinCrew/funkin.assets/pull/222)
|
||||
- The Picos no longer gasp twice in the Week 3 doppelganger cutscene. ([7b30a14](https://github.com/FunkinCrew/funkin.assets/commit/7b30a1418ef4597e567a22a2ea1bc1d9e4b061da)) - by @Lasercar in [funkin.assets#231](https://github.com/FunkinCrew/funkin.assets/pull/231)
|
||||
- The Week 3 train now consistently plays its sound. ([469ce39](https://github.com/FunkinCrew/funkin.assets/commit/469ce397b8eef3be47f8fadaa61a500e1a87ca3a)) - by @Lasercar in [funkin.assets#212](https://github.com/FunkinCrew/funkin.assets/pull/212)
|
||||
- Nene no longer freezes after playing two animations at once. ([d346ebd](https://github.com/FunkinCrew/funkin.assets/commit/d346ebdbf4781b49a081e0719221cf584fc3fe55)) - by @NotHyper-474 in [funkin.assets#228](https://github.com/FunkinCrew/funkin.assets/pull/228)
|
||||
- The Week 4 car now properly pauses with the game. ([26d1cff](https://github.com/FunkinCrew/funkin.assets/commit/26d1cffe19793c67a89f299b7a60be95c5656282)) - by @NotHyper-474 in [funkin.assets#114](https://github.com/FunkinCrew/funkin.assets/pull/114)
|
||||
- Pressing Reset and Pause at the same time no longer breaks the game over animation in Blazin'. ([8cd3785](https://github.com/FunkinCrew/Funkin/commit/8cd3785e3c3e913ed791204814eba86eb7142a5d)) - by @VirtuGuy in [#5639](https://github.com/FunkinCrew/Funkin/pull/5639)
|
||||
- Pico's Blazin' death animation no longer lags and offsets improperly. ([2cb42fe](https://github.com/FunkinCrew/funkin.assets/commit/2cb42fec422313db4e8000c963be0539221c9e21)) - by @KoloInDaCrib in [funkin.assets#217](https://github.com/FunkinCrew/funkin.assets/pull/217)
|
||||
- Pico and Darnell now properly punch with their other arms in Blazin'. ([4fb015f](https://github.com/FunkinCrew/funkin.assets/commit/4fb015f20261995ce41370910989094f4f2f26bb)) - by @Honton129 in [funkin.assets#221](https://github.com/FunkinCrew/funkin.assets/pull/221)
|
||||
- Pico's Perfect Results Screen animation now syncs with the music. ([0531e27](https://github.com/FunkinCrew/funkin.assets/commit/0531e27feed83dcc9a1703b3df654fd3bba1bd8a)) - by @JackXson-Real in [funkin.assets#201](https://github.com/FunkinCrew/funkin.assets/pull/201)
|
||||
- Filled in invisible pixels in the Story Mode button. ([c83ea78](https://github.com/FunkinCrew/funkin.assets/commit/c83ea788485693e22d429d81db8eb4da202e0140)) - by @D4rkJony in [funkin.assets#214](https://github.com/FunkinCrew/funkin.assets/pull/214)
|
||||
- Filled in invisible pixels in Tankman's icons. ([cb46973](https://github.com/FunkinCrew/funkin.assets/commit/cb46973bf8d9f48cd4738d483957c1edb501b386)) - by @JackXson-Real in [funkin.assets#224](https://github.com/FunkinCrew/funkin.assets/pull/224)
|
||||
- Scripted classes are no longer registered twice after hot-reloading. ([f870ed2](https://github.com/FunkinCrew/Funkin/commit/f870ed2858507273c4dbbca3e4b8b97d80a8d2ec)) - by @KoloInDaCrib in [#5743](https://github.com/FunkinCrew/Funkin/pull/5743)
|
||||
- The Chart Editor now properly uses the song ID from the manifest. ([df67b64](https://github.com/FunkinCrew/Funkin/commit/df67b642a8d7f7460e36a42c570a1ff2303751fd)) - by @cyn0x8 in [#4168](https://github.com/FunkinCrew/Funkin/pull/4168)
|
||||
- Dragging and dropping a Chart Editor selection in the same place no longer breaks the selection. ([4b65587](https://github.com/FunkinCrew/Funkin/commit/4b655879f763f6dbe34c89fc4a781cae9ff4abd8)) - by @Lasercar in [#4185](https://github.com/FunkinCrew/Funkin/pull/4185)
|
||||
- Clicking between hold note trails no longer causes visual errors in the Chart Editor. ([0e52744](https://github.com/FunkinCrew/Funkin/commit/0e527447188dbd3d850154a73f61467c1b8e585a)) - by @KoloInDaCrib in [#5683](https://github.com/FunkinCrew/Funkin/pull/5683)
|
||||
- Holding Shift and Right Click over a note no longer produces a solitaire effect in the Chart Editor. ([172041d](https://github.com/FunkinCrew/Funkin/commit/172041d4f779271533e0d1c529297540bfec337a)) - by @Lasercar in [#4139](https://github.com/FunkinCrew/Funkin/pull/4139)
|
||||
- Chart Editor event properties now have minimum values. ([9b81ebc](https://github.com/FunkinCrew/Funkin/commit/9b81ebc4f2c1c70b33d7351210c40c9a0e48ecc8)) - by @Lasercar in [#4110](https://github.com/FunkinCrew/Funkin/pull/4110)
|
||||
- Added missing notekinds to the Chart Editor Notes window. ([b7a5761](https://github.com/FunkinCrew/Funkin/commit/b7a5761730d43f27891dfec1c23fcb5e66daccf1)) - by @Lasercar in [#4286](https://github.com/FunkinCrew/Funkin/pull/4286)
|
||||
- Playback speed is now preserved when a new song or variation is loaded in the Chart Editor. ([3f82f37](https://github.com/FunkinCrew/Funkin/commit/3f82f3792b056a03724a0d1a320b7549a7b59844)) - by @Lasercar in [#4212](https://github.com/FunkinCrew/Funkin/pull/4212)
|
||||
- The Legacy Chart Importer now properly imports scroll speeds. ([2645d56](https://github.com/FunkinCrew/Funkin/commit/2645d56514dd1a27a050ff432c3cd4122f958e10)) - by @VirtuGuy in [#5655](https://github.com/FunkinCrew/Funkin/pull/5655)
|
||||
- Opponent characters now play singing animations when selected as the player character. ([8ee24c8](https://github.com/FunkinCrew/funkin.assets/commit/8ee24c84de6aa6e6313699198f35f61991612d04)) - by @Lasercar in [funkin.assets#141](https://github.com/FunkinCrew/funkin.assets/pull/141)
|
||||
- The Chart Editor character selector window no longer opens when clicking while playtesting. ([223e837](https://github.com/FunkinCrew/Funkin/commit/223e837fe8d9ce227e289a38bdfc095e4d81c48a)) - by @Lasercar in [#4350](https://github.com/FunkinCrew/Funkin/pull/4350)
|
||||
- Renamed Nene's pixel variant to Nene (Pixel) in the Chart Editor. ([69a7898](https://github.com/FunkinCrew/funkin.assets/commit/69a78988e3d6042d2e4779c9a4055c5de73ee775)) - by @JVNpixels in [funkin.assets#208](https://github.com/FunkinCrew/funkin.assets/pull/208)
|
||||
- Renamed Tankman's variants in the Chart Editor. ([70c43b7](https://github.com/FunkinCrew/funkin.assets/commit/70c43b792078d913c4c4d9fc019e378249d08b78)) - by @ExtraCode75 in [funkin.assets#209](https://github.com/FunkinCrew/funkin.assets/pull/209)
|
||||
- Pressing F4 in the Chart Editor now properly resets the window title. ([86e69cf](https://github.com/FunkinCrew/Funkin/commit/86e69cfbd1b1bd3daa49181b827fa813cb716703)) - by @VirtuGuy in [#5651](https://github.com/FunkinCrew/Funkin/pull/5651)
|
||||
- Saving a character in the Animation Editor no longer crashes the game. ([da5f691](https://github.com/FunkinCrew/Funkin/commit/da5f6918656d4a1ad3e83233b358034db92ca675)) - by @anysad in [#5519](https://github.com/FunkinCrew/Funkin/pull/5519)
|
||||
- The Stage Editor can now properly load modded stages. ([50c601a](https://github.com/FunkinCrew/Funkin/commit/50c601a7f0f27fc0f155e2bfbcb8ef54631aeac7)) - by @KoloInDaCrib in [#5744](https://github.com/FunkinCrew/Funkin/pull/5744)
|
||||
- XML files exported from the Stage Editor now account for rotated frames. ([661ddb1](https://github.com/FunkinCrew/Funkin/commit/661ddb15f72c2dae22f41a922a521740ab3617f0)) - by @KoloInDaCrib in [#5303](https://github.com/FunkinCrew/Funkin/pull/5303)
|
||||
- A few more adjustments for good measure.
|
||||
|
||||
## New Contributors for 0.7.4
|
||||
|
||||
* @ThatOneCalculator made their first contribution in [#5507](https://github.com/FunkinCrew/Funkin/pull/5507)
|
||||
* @SrtHero278 made their first contribution in [#5565](https://github.com/FunkinCrew/Funkin/pull/5565)
|
||||
* @VirtuGuy made their first contribution in [#5598](https://github.com/FunkinCrew/Funkin/pull/5598)
|
||||
* @SpritersBlock made their first contribution in [funkin.assets#190](https://github.com/FunkinCrew/funkin.assets/pull/190)
|
||||
* @Johferson made their first contribution in [funkin.assets#211](https://github.com/FunkinCrew/funkin.assets/pull/211)
|
||||
* @Honton129 made their first contribution in [funkin.assets#213](https://github.com/FunkinCrew/funkin.assets/pull/213)
|
||||
* @D4rkJony made their first contribution in [funkin.assets#214](https://github.com/FunkinCrew/funkin.assets/pull/214)
|
||||
|
||||
|
||||
|
||||
## [0.7.3] - 2025-07-21
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed stuttering throughout the game caused by the Polymod upgrade. (Thanks NotHyper-474!)
|
||||
- [MOBILE] Fixed buttons in the Main Menu not working.
|
||||
- [iOS] The Upgrade button no longer appears if you have already purchased it (actually this time).
|
||||
- Fixed the countdown overlapping itself when restarting the song. (Thanks NotHyper-474!)
|
||||
- Optimized the Week 6 Erect stage.
|
||||
- Fixed an oversight when clearing the cache. (Thanks cherrythecool!)
|
||||
- The Input Offset Test menu text now displays in the correct position.
|
||||
- Fixed script errors appearing in the Week 3 Erect stage.
|
||||
- Fixed adding variations in the Chart Editor erasing difficulties. (Thanks NotHyper-474!)
|
||||
|
||||
## New Contributors for 0.7.3
|
||||
|
||||
* @cherrythecool made their first contribution in [#5458](https://github.com/FunkinCrew/Funkin/pull/5458)
|
||||
|
||||
|
||||
|
||||
## [0.7.2] - 2025-07-18
|
||||
|
||||
### Added
|
||||
|
||||
- [ANDROID] Added a button in the Options menu to access the mods folder.
|
||||
- [MOBILE] Added a preference to adjust the intensity of haptic feedback, ranging from 0.1 to 5.
|
||||
- [MOBILE] Added an easter egg when tapping the player's healthbar icon.
|
||||
|
||||
### Changed
|
||||
|
||||
- Changed default OpenAL configuration settings to improve audio quality. (Thanks Smokey555, cyn0x8, and CCobaltDev!)
|
||||
- The difference may be more or less noticeable on different devices and hardware.
|
||||
- Applies to Desktop and Android, but not iOS yet.
|
||||
- Made several improvements to Polymod and HScript. These changes might break some mods, so please update them accordingly!
|
||||
- Fixed an issue where scripted classes can define two or more fields with the same name.
|
||||
- Fixed an issue causing some syntax errors (such as missing commas) to be ignored by the parser.
|
||||
- Scripted classes can now create static fields and functions.
|
||||
- Scripted classes can now create variables with the `final` keyword.
|
||||
- Scripted classes can now access variables from another scripted class with `class.someVariable`, instead of `class.scriptGet("someVariable")`
|
||||
- This applies to functions too: `class.someFunction()`
|
||||
- Scripted classes that don't extend another class can now be created!
|
||||
- This only works if you access the class in a static context. Creating an instance of said class doesn't work just yet!
|
||||
- Added support for properties (`get_` and `set_` functions) (Thanks KoloInDaCrib!)
|
||||
- Added support for abstracts in a static context. (Thanks lemz1!)
|
||||
- You can now use classes like `FlxColor` properly!
|
||||
- Added support for creating and using enums. (Thanks lemz1!)
|
||||
- You can import them in another script as usual.
|
||||
- Added support for renaming imported classes using the `as` keyword. (Thanks KoloInDaCrib!)
|
||||
- Fixed `try`/`catch` blocks not working properly. (Thanks NotHyper-474!)
|
||||
- Fixed null-safe field access not working properly for functions (ex. `class?.someFunction()`). (Thanks KoloInDaCrib!)
|
||||
- Fixed Linux being case-sensitive with filenames. (Thanks mikolka9144!)
|
||||
|
||||
### Fixed
|
||||
|
||||
- [MOBILE] Weekend 1 Story Mode no longer crashes before loading into Blazin'.
|
||||
- [MOBILE] Beating 2hot from Freeplay no longer crashes in the Results screen.
|
||||
- [MOBILE] Retrying and pressing the Back button at the same time no longer crashes the game.
|
||||
- [MOBILE] Pressing the Options and Back buttons at the same time no longer softlocks the game.
|
||||
- [HTML5] Pausing while the train passes by on the Week 3 Erect stage no longer crashes.
|
||||
- [DESKTOP] Getting a Bad/Shit rating on Blazin' no longer breaks animations.
|
||||
- The scroll sound no longer plays once after entering Freeplay.
|
||||
- The Freeplay song preview and album cover now update properly when switching variations.
|
||||
- The Freeplay clear percent counter now consistently displays the correct value on unranked songs.
|
||||
- The Freeplay difficulty star flames no longer become offset from the stars.
|
||||
- The Freeplay difficulty star flames no longer appear during a new rank animation.
|
||||
- The Freeplay menu now correctly assigns the `currentCharacterId`. (Thanks TechnikTil!)
|
||||
- Boyfriend's Perfect (Gold) Results animation now loops properly.
|
||||
- [DESKTOP] The Input Offsets menu no longer activates the debug cursor.
|
||||
- The Input Offsets Test menu no longer generates stacked notes.
|
||||
- The Input Offsets Test menu drums no longer desync from the rest of the track.
|
||||
- The Input Offsets Test menu no longer breaks when a keyboard or controller is connected.
|
||||
- [MOBILE] Sustain trails now display properly with upscroll enabled.
|
||||
- [MOBILE] Added a Back button to the keyboard/gamepad Controls menu.
|
||||
- [iOS] Fixed app name spacing on the Home Screen.
|
||||
- [iOS] Adjusted the preloader to accommodate for different screen sizes.
|
||||
- [iOS] The Upgrade button no longer appears if you have already purchased it.
|
||||
- [ANDROID] Fixed some issues with scrolling.
|
||||
- [ANDROID] Toasts with blank messages no longer appear.
|
||||
- Fixed a critical security vulnerability that could be exploited in mods.
|
||||
- A few more bugfixes and optimizations here and there.
|
||||
|
||||
## New Contributors for 0.7.2
|
||||
|
||||
* @Smokey555 made their first contribution in [#3318](https://github.com/FunkinCrew/Funkin/pull/3318)
|
||||
* @CCobaltDev made their first contribution in [#3318](https://github.com/FunkinCrew/Funkin/pull/3318)
|
||||
* @mikolka9144 made their first contribution in [polymod#212](https://github.com/larsiusprime/polymod/pull/212)
|
||||
|
||||
|
||||
|
||||
## [0.7.1] - 2025-07-15
|
||||
|
||||
### Fixed
|
||||
- Properly implemented ad playback on iOS devices.
|
||||
|
||||
|
||||
|
||||
## [0.7.0] - 2025-07-15
|
||||
|
||||
### Added
|
||||
|
||||
- Friday Night Funkin' now has OFFICIAL mobile versions for Android and iOS, available on the Google Play Store and Apple App Store!
|
||||
- This version contains 100% of the songs from the desktop version of the game.
|
||||
- [MOBILE] New touch input compatibility for all menus.
|
||||
- [MOBILE] Added banner and interstitial advertisements to the game. You can upgrade to the full version through an in-app purchase to permanently disable advertisements.
|
||||
- [MOBILE] Graphics are compressed using the ASTC algorithm, decreasing memory usage in exchange for a slightly larger file size.
|
||||
- [MOBILE] Added haptic feedback to several areas of the game.
|
||||
- Added a visual indicator that shows available difficulties for the currently selected song in Freeplay.
|
||||
- Overhauled the input offsets system, including:
|
||||
- One unified "offset" value.
|
||||
- An "Offset Calibration" screen where the game determines your ideal offset.
|
||||
- A "Test" screen where you can play a short note pattern to try out your offset.
|
||||
- A brand new offset testing theme: Syncobation by Kawai Sprite!
|
||||
- The ability to change your offsets in the Pause Menu, mid-song!
|
||||
- The Input Offsets menu isn't yet available on HTML5, but offsets are still configurable through the Pause Menu.
|
||||
- Added null-safety to a bunch of classes in the source code.
|
||||
- Added the Changelog back to the game files, written by Hundrec and AbnormalPoof!
|
||||
- Added a few sandboxed classes to give mods limited access to the Discord and Newgrounds APIs. ([50d9584](https://github.com/FunkinCrew/Funkin/commit/50d9584a388bd891aa2f8b68a5cde894a6e1ede6)) - by @KoloInDaCrib in [#5040](https://github.com/FunkinCrew/Funkin/pull/5040)
|
||||
- Added script support for Freeplay Backing Cards. ([0001017](https://github.com/FunkinCrew/Funkin/commit/0001017c003be653236c6cc56487c7d0ee33633e)) - by @KoloInDaCrib in [#5233](https://github.com/FunkinCrew/Funkin/pull/5233)
|
||||
- Sparrow results screen animations can now be scriptable. ([7bb2336](https://github.com/FunkinCrew/Funkin/commit/7bb23369727ca4955aa1fbe25e5798809e8169bd)) - by @KoloInDaCrib in [#5168](https://github.com/FunkinCrew/Funkin/pull/5168)
|
||||
- Added a blank `Object` class for scripts to extend, and made `FlxObject` and `FlxBasic` scriptable. ([eb6becc](https://github.com/FunkinCrew/Funkin/commit/eb6becc03fff76117ee3fcbeb32fe254236ca232)) - by @cyn0x8 in [#3119](https://github.com/FunkinCrew/Funkin/pull/3119)
|
||||
- Added default gamepad controls for two recently added Freeplay controls. ([a0d3f8e](https://github.com/FunkinCrew/Funkin/commit/a0d3f8ec553e06b625b463c7989658edbebbbdf5)) - by @MrMadera in [#4559](https://github.com/FunkinCrew/Funkin/pull/4559)
|
||||
- Added the ability to press the Chart Editor keybind in Freeplay with a song capsule selected. ([2221594](https://github.com/FunkinCrew/Funkin/commit/2221594883afa7cd0e518fca7ea975d05626692a)) - by @Lasercar in [#4114](https://github.com/FunkinCrew/Funkin/pull/4114)
|
||||
- The Chart Editor now highlights and deletes stacked notes using a customizable threshold. ([8cae34e](https://github.com/FunkinCrew/Funkin/commit/8cae34eed711bff70e5348ffc6178a0fd69b5846)) - by @NotHyper-474 in [#3574](https://github.com/FunkinCrew/Funkin/pull/3574)
|
||||
- Added a variation indicator next to the Chart Editor playbar difficulty. ([ccd0148](https://github.com/FunkinCrew/Funkin/commit/ccd0148e9b46d512a22b4958d3f289cfc7854965)) - by @KoloInDaCrib in [#5236](https://github.com/FunkinCrew/Funkin/pull/5236)
|
||||
- Added more tween types to certain Chart Editor events. ([5177e12](https://github.com/FunkinCrew/Funkin/commit/5177e1275eb2fb2b016224c139e84debb421b895)) - by @Lasercar in [#4249](https://github.com/FunkinCrew/Funkin/pull/4249)
|
||||
- Pressing Ctrl + N now creates a new stage in the Stage Editor. ([576f8e5](https://github.com/FunkinCrew/Funkin/commit/576f8e54ff8ca8e205241fafa33d0256b62d11d5)) - by @Lasercar in [#5175](https://github.com/FunkinCrew/Funkin/pull/5175)
|
||||
- Added "Flip character horizontally" to the list of shortcuts in the Animation Editor. ([c464cae](https://github.com/FunkinCrew/funkin.assets/commit/c464caec921dcefef7b0b74b2abf95e76ce64491)) - by @AbnormalPoof in [funkin.assets#60](https://github.com/FunkinCrew/funkin.assets/pull/60)
|
||||
- Added Perfect (Gold) to the list of available ranks in Results Debug menu. ([c5308cc](https://github.com/FunkinCrew/Funkin/commit/c5308ccbb9d2b98c62fa4974b8ad7ac1e1ec7d19)) - by @AbnormalPoof in [#4642](https://github.com/FunkinCrew/Funkin/pull/4642)
|
||||
- [MOBILE] Implemented Kevin and Michael.
|
||||
|
||||
### Changed
|
||||
|
||||
- The mod API version now supports v0.7.0, along with v0.6.3. Be sure to check that your mods still work!
|
||||
- Updated the app icon for Desktop platforms.
|
||||
- [MOBILE] Modified several parts of the game to look better on phone screens with wider aspect ratios, up to 20:9.
|
||||
- [DESKTOP] The game now tries to match the window's aspect ratio when changing states, extending as wide as 20:9.
|
||||
- [DESKTOP] Included Mobile stage expansions on Desktop as well. Now you'll have more room for camera events!
|
||||
- Playable Pico and Weekend 1 songs are now always unlocked in Freeplay, even on new saves.
|
||||
- The Freeplay difficulty graphic now scrolls smoothly when changing difficulties.
|
||||
- The "Pause on Unfocus" preference now opens the Pause Menu when unfocusing during a song.
|
||||
- Scripts can now make hold note trails semi-transparent.
|
||||
- Completely reformatted every script file within the game's assets for better readability.
|
||||
- Completely reformatted and optimized every single chart file in the game.
|
||||
- Recharted pico-speaker's chart in Stress
|
||||
- Tweaked charts for the following songs:
|
||||
- Bopeebo [all difficulties] - Removed an extra hey animation event
|
||||
- Bopeebo (Pico Mix) [Hard] - Added a missing note in Section 24
|
||||
- Fresh Erect [Nightmare] - Added a missing grace note for BF in Section 24
|
||||
- South Erect [Nightmare] - Added missing grace notes for BF in Sections 13, 17, and 53
|
||||
- Philly Nice [Hard] - Added missing grace notes for Pico in Sections 30 and 62
|
||||
- Philly Nice [all difficulties] - Added hey animations throughout the song
|
||||
- Philly Nice Erect [Erect] - Added a grace note for BF in Section 33, removed a stacked note for opponent in Section 12
|
||||
- Philly Nice (Pico Mix) [Normal] - Adjusted a left note by 1/96 in Section 60
|
||||
- Blammed (Pico Mix) [Hard] - Added a missing jack in Section 46
|
||||
- Satin Panties [Hard] - Added grace notes in Sections 7-10
|
||||
- Satin Panties [Normal/Hard] - Made Mom sing a sustain rather than two notes in Section 30
|
||||
- High Erect [Erect/Nightmare] - Added a missing note in Section 16
|
||||
- Cocoa [Easy] - Added some notes to reduce sparseness, fixed Mom singing Dad's notes
|
||||
- Cocoa Erect [Erect/Nightmare] - Reimplemented BF's censored notes for Nightmare, adjusted one note by 1/48 in Section 63
|
||||
- Eggnog Erect [Erect/Nightmare] Added two grace notes in Sections 10 and 14 and a missing note for Dad in Section 44
|
||||
- Eggnog (Pico Mix) [Hard] - Added a missing grace note for Pico that was present on Normal in Section 20
|
||||
- Roses [Normal/Hard] - Made Senpai sing a sustain rather than two notes (sneaky)
|
||||
- Roses Erect [Erect/Nightmare] - Mirrored the changes from normal Roses
|
||||
- Guns [all difficulties] - Added a missing note in Sections 28 and 32 and adjusted a hold note's length in Section 73
|
||||
- Stress [Hard] - Split whole notes in halves in Sections 57-60
|
||||
- Darnell [Hard] - Added one missing note for Pico in Section 35
|
||||
- Darnell [all difficulties] - Adjusted camera event timings for consistency
|
||||
- Darnell (BF Mix) [all difficulties] - Removed 3 extra notes and fixed Darnell's pattern being offset
|
||||
- Lit Up [all difficulties] - Added 4 sustains for Darnell throughout the song
|
||||
- Lit Up (BF Mix) [all difficulties] - Added 4 sustains for Darnell throughout the song
|
||||
- 2hot [Easy/Hard] - Fixed remaining offset rhythms (for real this time)
|
||||
- Notes now scroll more smoothly by rendering based on delta timing. ([6ad9ffc](https://github.com/FunkinCrew/Funkin/commit/6ad9ffc7f9d66bbaf6ba343663de4c7268f4be3b)) - by @KutikiPlayz in [#3544](https://github.com/FunkinCrew/Funkin/pull/3544)
|
||||
- The Freeplay character select hint now always displays if you have more than one character unlocked. ([7ccf75c](https://github.com/FunkinCrew/Funkin/commit/7ccf75cd869ba4b6f18a5adc01e65e52ae7bb809)) - by @Hundrec in [#5023](https://github.com/FunkinCrew/Funkin/pull/5023)
|
||||
- Favorite songs in Freeplay are now sorted by Week order instead of alphabetically. ([da0964a](https://github.com/FunkinCrew/Funkin/commit/da0964a7b7bbe4ece1bdbd19233eb6dba0de3ac5)) - by @Hundrec in [#3609](https://github.com/FunkinCrew/Funkin/pull/3609)
|
||||
- Shifted Mommy Mearest's pixel icon to the left in Freeplay. ([d861eba](https://github.com/FunkinCrew/funkin.assets/commit/d861ebac027dd07d0254c79d7c89b59ee04b38f1)) - by @KoloInDaCrib in [funkin.assets#197](https://github.com/FunkinCrew/funkin.assets/pull/197)
|
||||
- The Character Select screen now opens on the currently selected character. ([4819a74](https://github.com/FunkinCrew/Funkin/commit/4819a74c2959cc9b32dfe2cb76c3a4c00e7c7f9a)) - by @Lasercar in [#4072](https://github.com/FunkinCrew/Funkin/pull/4072)
|
||||
- Visualizers now zero out when the game audio is muted. ([6dcec59](https://github.com/FunkinCrew/Funkin/commit/6dcec592f467a0daeb8ff1e0ce122916e36ca869)) - by @Lasercar in [#5266](https://github.com/FunkinCrew/Funkin/pull/5266)
|
||||
- The Options Menu can now scroll to display more menu items. ([70f0a54](https://github.com/FunkinCrew/Funkin/commit/70f0a54191597bd72a6d30d4d12ef5ece6ba078c)) - by @AbnormalPoof in [#4706](https://github.com/FunkinCrew/Funkin/pull/4706)
|
||||
- Raised the FPS cap preference from 300 to 500. ([be73134](https://github.com/FunkinCrew/Funkin/commit/be7313453f70983fff55e69a8b52d741f0cc53b4)) - by @Hundrec in [#5044](https://github.com/FunkinCrew/Funkin/pull/5044)
|
||||
- The Credits menu now uses less memory, especially with many entries. ([1b68c3a](https://github.com/FunkinCrew/Funkin/commit/1b68c3a8d6f66905a9a508a1cb692fe3beb7b4a2)) - by @lemz1 in [#2655](https://github.com/FunkinCrew/Funkin/pull/2655)
|
||||
- Added a timer sequence class to queue up multiple timers in scripts with ease. ([9e182f7](https://github.com/FunkinCrew/Funkin/commit/9e182f70d2bcc92eb68d730d74af143c45f7dcf8)) - by @cyn0x8 in [#2391](https://github.com/FunkinCrew/Funkin/pull/2391)
|
||||
- Replaced smoothLerp and coolLerp with smoothLerpPrecision to fix a few lerp-related bugs. ([94eae11](https://github.com/FunkinCrew/Funkin/commit/94eae116c7a5e6039683d6391208b169378b5ff1)) - by @cyn0x8 in [#3617](https://github.com/FunkinCrew/Funkin/pull/3617)
|
||||
- Fixed empty text strings softlocking the dialogue box. ([88d0e8c](https://github.com/FunkinCrew/Funkin/commit/88d0e8c3b0529654fb7eee8aebb099f7fb346f66)) - by @xenkap in [#4671](https://github.com/FunkinCrew/Funkin/pull/4671)
|
||||
- Adjusted the size of the Beat/Step display in the Chart Editor. ([905181c](https://github.com/FunkinCrew/Funkin/commit/905181c9af29bb11280bda33ef9343069678a762)) - by @NotHyper-474 in [#4994](https://github.com/FunkinCrew/Funkin/pull/4994)
|
||||
- The Chart Editor will now only fall back to the first available difficulty if the selected difficulty cannot be found. ([1c25713](https://github.com/FunkinCrew/Funkin/commit/1c257134648ebd89acf6c9d07f5a0c088fb915c6)) - by @Lasercar in [#4949](https://github.com/FunkinCrew/Funkin/pull/4949)
|
||||
- The undo/redo history is now cleared when loading another song in the Chart Editor. ([426a9c0](https://github.com/FunkinCrew/Funkin/commit/426a9c0c108ac65a042295194679d46444ec1ea5)) - by @Lasercar in [#4308](https://github.com/FunkinCrew/Funkin/pull/4308)
|
||||
- Blacklisted more classes for security reasons. ([cadfa3b](https://github.com/FunkinCrew/Funkin/commit/cadfa3b7ceae2ecabe2d544ddc4c9f453b0dfd56)) - by @NotHyper-474 in [#5185](https://github.com/FunkinCrew/Funkin/pull/5185)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed a ton of performance issues to help the game run better on mobile devices.
|
||||
- Exiting the Freeplay Menu no longer freezes the game for a really long time (thanks NotHyper-474!)
|
||||
- Notestyle graphics are now preloaded before the song starts, fixing the stutter at the beginning of the song.
|
||||
- Hitting many hold note trails in one song no longer leads to a lag spike.
|
||||
- The first lightning strike in Week 2 Erect no longer creates a lag spike.
|
||||
- [DESKTOP] The conductor and music no longer gradually drift out of sync to eventually trigger a resync.
|
||||
- Pixel notestyle strumlines are now properly positioned when Downscroll is enabled.
|
||||
- Added the missing graffiti to the wall in the Weekend 1 Blazin' stage.
|
||||
- Accept keybinds now properly scroll faster through the Credits.
|
||||
- Typing in most text fields in debug editors no longer triggers keyboard shortcuts.
|
||||
- The Chart Editor playback speed feature now works properly.
|
||||
- The Chart Editor metronome and hitsounds now play at exactly the right time.
|
||||
- The Chart Editor notification box no longer covers playbar info.
|
||||
- Selecting a Recent File too quickly in the Stage Editor no longer crashes the game.
|
||||
- Blacklisted a few classes for security.
|
||||
- Opening the logs or backups folder before it's created no longer crashes the game. ([d3490f8](https://github.com/FunkinCrew/Funkin/commit/d3490f8c9929eefb9879ad65ce43038c193642d6)) - by @NotHyper-474 in [#4940](https://github.com/FunkinCrew/Funkin/pull/4940)
|
||||
- Fixed a crash when mashing D or I during startup. ([b52c73f](https://github.com/FunkinCrew/Funkin/commit/b52c73f2b0fa32fbc349804621cf947dff2d364e)) - by @CrusherNotDrip in [#5160](https://github.com/FunkinCrew/Funkin/pull/5160)
|
||||
- Hot-reloading with F5 during gameplay no longer crashes the game. ([d2acb5d](https://github.com/FunkinCrew/Funkin/commit/d2acb5d167afd42299d7200ab8c67972044a09c6)) - by @AbnormalPoof in [#5065](https://github.com/FunkinCrew/Funkin/pull/5065)
|
||||
- Hot-reloading with F5 in the Input Offsets menu no longer crashes the game. ([58257f6](https://github.com/FunkinCrew/Funkin/commit/58257f6ac187925f3b23d3f1eef2c812ae569a6b)) - by @NotHyper-474 in [#5085](https://github.com/FunkinCrew/Funkin/pull/5085)
|
||||
- Songs no longer skip forward at the beginning with high offsets. ([1f75a64](https://github.com/FunkinCrew/Funkin/commit/1f75a641e0c80d15f1af10bae7ee71a6ffecf219)) - by @xenkap in [#3732](https://github.com/FunkinCrew/Funkin/pull/3732)
|
||||
- The song countdown no longer stacks when restarting or continues behind the Pause Menu.
|
||||
([63eca96](https://github.com/FunkinCrew/Funkin/commit/63eca96c98a87e7155df8b2a1735f269ea83e1b5)) - by @KoloInDaCrib and @NotHyper-474 in [#4875](https://github.com/FunkinCrew/Funkin/pull/4875)
|
||||
- Fixed incorrect highlighting and squashed text on Freeplay song capsules. ([0c62428](https://github.com/FunkinCrew/Funkin/commit/0c62428fc883c0fa6d09cd403efb287ff3af8c53)) - by @VioletSnowLeopard in [#5036](https://github.com/FunkinCrew/Funkin/pull/5036)
|
||||
- The Freeplay song preview no longer plays twice after returning from Character
|
||||
Select. ([3d3e2bd](https://github.com/FunkinCrew/Funkin/commit/3d3e2bd3786b858143d214caf55be2ee3e9483fc)) - by @Lasercar in [#5248](https://github.com/FunkinCrew/Funkin/pull/5248)
|
||||
- Freeplay song ranks no longer disappear after changing variations. ([7cc9464](https://github.com/FunkinCrew/Funkin/commit/7cc9464573d07996e4bd0d557f82847809d3a786)) - by @VioletSnowLeopard in [#4583](https://github.com/FunkinCrew/Funkin/pull/4583)
|
||||
- Freeplay song capsules now cycle through long names consistently. ([e193f73](https://github.com/FunkinCrew/Funkin/commit/e193f7392a83a04e4aac85fba4f441a78f7b6668)) - by @VioletSnowLeopard in [#4677](https://github.com/FunkinCrew/Funkin/pull/4677)
|
||||
- Fixed a few visual issues with Freeplay's rank slam animation. ([ab817bb](https://github.com/FunkinCrew/Funkin/commit/ab817bb1eab74ae71c1b1fd74d7512a11e6d4339)) - by @Lasercar in [#4986](https://github.com/FunkinCrew/Funkin/pull/4986)
|
||||
- Fixed visual errors in Freeplay after exiting Character Select. ([56a18e1](https://github.com/FunkinCrew/Funkin/commit/56a18e1cf6a15971feebcc828be8818037948cef)) - by @KoloInDaCrib in [#5245](https://github.com/FunkinCrew/Funkin/pull/5245)
|
||||
- Freeplay styles are now reloaded when hot-reloading with F5. ([f54e140](https://github.com/FunkinCrew/Funkin/commit/f54e140b65e36fcf810c52ce464799dbc0c73c6d)) - by @Keoiki in [#5286](https://github.com/FunkinCrew/Funkin/pull/5286)
|
||||
- Adjusted offsets for Freeplay DJ Pico's fistPump animation. ([382e286](https://github.com/FunkinCrew/funkin.assets/commit/382e286a2478939d3d6aca1c7c90719f33815014)) - by @AbnormalPoof in [funkin.assets#91](https://github.com/FunkinCrew/funkin.assets/pull/91)
|
||||
- The "New Highscore" text no longer appears more than once in the Results screen. ([4e31003](https://github.com/FunkinCrew/Funkin/commit/4e31003a0f60cd394edc2bd4586f9f385b3d07bc)) - by @Lasercar in [#4319](https://github.com/FunkinCrew/Funkin/pull/4319)
|
||||
- The Results Debug menu now shows the correct rank after recent scoring changes. ([11d9998](https://github.com/FunkinCrew/Funkin/commit/11d9998e5c73a3839ea39e06b7f217cbaab69c6d)) - by @NotHyper-474 in [#4905](https://github.com/FunkinCrew/Funkin/pull/4905)
|
||||
- The Input Offsets menu now exits to the Options menu instead of the Main menu. ([5361df2](https://github.com/FunkinCrew/Funkin/commit/5361df254470e68d7571b4534cf456f08d5ffd60)) - by @JackXson-Real in [#5076](https://github.com/FunkinCrew/Funkin/pull/5076)
|
||||
- The Debug Menu can no longer be opened after selecting an item in the Main Menu.
|
||||
([5695bc2](https://github.com/FunkinCrew/Funkin/commit/5695bc20e721f0afd5b97a36167f13e550c12b16)) - by @Lasercar in [#4211](https://github.com/FunkinCrew/Funkin/pull/4211)
|
||||
- The debug cursor is now always hidden when the game starts. ([6222c38](https://github.com/FunkinCrew/Funkin/commit/6222c389e301fa2bb4939697376c4e51e29a9977)) - by @Hundrec in [#4520](https://github.com/FunkinCrew/Funkin/pull/4520)
|
||||
- The Story Mode Weekend 1 level title no longer clips into other level titles below it. ([19d1a8c](https://github.com/FunkinCrew/Funkin/commit/19d1a8c59380009f0d0814c94fd0b4eccb0c80cd)) - by @KoloInDaCrib in [#4348](https://github.com/FunkinCrew/Funkin/pull/4348)
|
||||
- Hold note covers now display properly if a hold note was previously dropped. ([96d1324](https://github.com/FunkinCrew/Funkin/commit/96d1324af140858cb93edd07dc36a969c8ae84c0)) - by @T5mpler in [#5275](https://github.com/FunkinCrew/Funkin/pull/5275)
|
||||
- Girlfriend's and Nene's combo drop animations now play consistently. ([34d5ed1](https://github.com/FunkinCrew/Funkin/commit/34d5ed11695cef7348c13505f13fb1da38b7988c)) - by @VioletSnowLeopard in [#4968](https://github.com/FunkinCrew/Funkin/pull/4968)
|
||||
- Girlfriend (Tankman Stickup) now plays her combo drop animation. ([e329601](https://github.com/FunkinCrew/funkin.assets/commit/e329601834f270910ce80ea5539e4487b9895a8a)) - by @qt2k4 in [funkin.assets#149](https://github.com/FunkinCrew/funkin.assets/pull/149)
|
||||
- Darnell's idle animation now loops consistently. ([df64586](https://github.com/FunkinCrew/funkin.assets/commit/df64586771ea41c544913e049fd0f32bdc655417)) - by @qt2k4 in [funkin.assets#159](https://github.com/FunkinCrew/funkin.assets/pull/159)
|
||||
- Darnell's kneeCan animation now plays properly in 2hot. ([a2e9931](https://github.com/FunkinCrew/funkin.assets/commit/a2e993167aaa2ff6bff8806940f912e444608645)) - by @biomseed in [funkin.assets#78](https://github.com/FunkinCrew/funkin.assets/pull/78)
|
||||
- Otis and Pico (Speaker) no longer spaz out when playtesting Stress. ([3f6d75f](https://github.com/FunkinCrew/funkin.assets/commit/3f6d75f3b6f6c8deb660323e3fb9bf1974c06520)) - by @Lasercar in [funkin.assets#124](https://github.com/FunkinCrew/funkin.assets/pull/124)
|
||||
- The gasp sound now only plays once in the Week 3 Pico Mix doppelganger cutscene. ([ab4598b](https://github.com/FunkinCrew/funkin.assets/commit/ab4598baf3c6790d30cfb727d04c8b57fa18dd0d)) - by @KoloInDaCrib in [funkin.assets#126](https://github.com/FunkinCrew/funkin.assets/pull/126)
|
||||
- Fixed a few issues with the train in Week 3. ([8db2426](https://github.com/FunkinCrew/funkin.assets/commit/8db2426991caebde44d19c81b198e8e2ad86f700)) - by @ShadzXD in [funkin.assets#180](https://github.com/FunkinCrew/funkin.assets/pull/180)
|
||||
- The cars in Week 4 and Weekend 1 no longer get stuck when the song is restarted. ([9c511e3](https://github.com/FunkinCrew/funkin.assets/commit/9c511e371fd08a43ddf834766a6d35667bdef4f7)) - by @MetaBreeze in [funkin.assets#186](https://github.com/FunkinCrew/funkin.assets/pull/186)
|
||||
- A-Bot's visualizer no longer jumps to a random volume when the song ends. ([51cc118](https://github.com/FunkinCrew/funkin.assets/commit/51cc1186bc77a2ee45a47fdbde2d75d9ec69de3a)) - by @VioletSnowLeopard in [funkin.assets#183](https://github.com/FunkinCrew/funkin.assets/pull/183)
|
||||
- Pico's burpShit animation now re-enables volume for player vocals. ([cefda0e](https://github.com/FunkinCrew/funkin.assets/commit/cefda0e52fabbbe04afe60b7aed560267e2cb01e)) - by @Hundrec in [funkin.assets#71](https://github.com/FunkinCrew/funkin.assets/pull/71)
|
||||
- Removed vocals from Monster's instrumental on web builds. ([1c9473f](https://github.com/FunkinCrew/funkin.assets/commit/1c9473f3dfdfb97d97f6c8457001055322abf5ab)) - by @JVNpixels in [funkin.assets#182](https://github.com/FunkinCrew/funkin.assets/pull/182)
|
||||
- Fixed the retry sound not playing after a Tankman death quote finishes. ([e7c4b1b](https://github.com/FunkinCrew/Funkin/commit/e7c4b1ba38ba0739cfe347f6c4763f9811fb95b0)) - by @VioletSnowLeopard in [#4726](https://github.com/FunkinCrew/Funkin/pull/4726)
|
||||
- Darnell (BF Mix)'s alternate instrumental is now properly accessible. ([5abdabf](https://github.com/FunkinCrew/funkin.assets/commit/5abdabf69b39ca4eebd36ae6bbd77fab736d0b86)) - by @Hundrec in [funkin.assets#168](https://github.com/FunkinCrew/funkin.assets/pull/168)
|
||||
- Fixed Newgrounds score submissions for Lit Up and Lit Up (BF Mix). ([183cec6](https://github.com/FunkinCrew/Funkin/commit/183cec62dc1fd3c7f3f634dd3e2400e6ee77b476)) - by @Raltyro in [#4577](https://github.com/FunkinCrew/Funkin/pull/4577)
|
||||
- Inputs are now disabled before Senpai's dialogue appears. ([c43d906](https://github.com/FunkinCrew/funkin.assets/commit/c43d906d19d91d71b9096e65d5e0d3543af8cd31)) - by @anysad in [funkin.assets#165](https://github.com/FunkinCrew/funkin.assets/pull/165)
|
||||
- An easter egg now restarts the song using the correct instrumental. ([e657bc9](https://github.com/FunkinCrew/Funkin/commit/e657bc900bc62cc220276dc171dd47f0a176ac66)) - by @KoloInDaCrib in [#4956](https://github.com/FunkinCrew/Funkin/pull/4956)
|
||||
- Encountering an easter egg during a Chart Editor playtest no longer crashes the game. ([b53b5bd](https://github.com/FunkinCrew/funkin.assets/commit/b53b5bdaecf975555538725a4cdfe71d38565b08)) - by @NotHyper-474 in [funkin.assets#133](https://github.com/FunkinCrew/funkin.assets/pull/133)
|
||||
- Nonexistent characters no longer crash the Chart Editor. ([3bbb4b0](https://github.com/FunkinCrew/Funkin/commit/3bbb4b06c8c1a1885a18d4354fcfa4363a0c6c75)) - by @Lasercar in [#5008](https://github.com/FunkinCrew/Funkin/pull/5008)
|
||||
- Holding Ctrl and clicking on a hold note trail no longer crashes the Chart Editor. ([dc56cca](https://github.com/FunkinCrew/Funkin/commit/dc56ccada50e671996caf0557de1977b7ff8d236)) - by @Lasercar in [#4203](https://github.com/FunkinCrew/Funkin/pull/4203)
|
||||
- Tweens and timers are now canceled when returning to the Chart Editor. ([7e76cf6](https://github.com/FunkinCrew/Funkin/commit/7e76cf66340c00ef6ec84358e6304d62815173b6)) - by @KoloInDaCrib in [#5278](https://github.com/FunkinCrew/Funkin/pull/5278)
|
||||
- Reduced the severity of a memory leak in the Chart Editor. ([cce8c18](https://github.com/FunkinCrew/Funkin/commit/cce8c18822e083910200597f5db4d87b6e3b521f)) - by @NotHyper-474 in [#5247](https://github.com/FunkinCrew/Funkin/pull/5247)
|
||||
- Pressing the Chart Editor keybind during a song now opens to the variation and difficulty you were playing. ([e3fca16](https://github.com/FunkinCrew/Funkin/commit/e3fca167938642bea85398fe57347c10439c1892)) - by @Lasercar in [#4116](https://github.com/FunkinCrew/Funkin/pull/4116)
|
||||
- The Chart Editor now properly saves audio levels when exiting. ([f78ab4d](https://github.com/FunkinCrew/Funkin/commit/f78ab4da1db4f9527a2e1715d5cfb37670e11a74)) - by @Lasercar in [#4149](https://github.com/FunkinCrew/Funkin/pull/4149)
|
||||
- The Chart Editor "Load Metadata File" and "Load Chart File" buttons now function properly. ([9df5395](https://github.com/FunkinCrew/Funkin/commit/9df5395ff888cb6740e21204c8e19116e0472db4)) - by @Lasercar in [#4278](https://github.com/FunkinCrew/Funkin/pull/4278)
|
||||
- FNF Legacy files can now be opened in the Chart Editor on MacOS. ([d98628c](https://github.com/FunkinCrew/Funkin/commit/d98628ca0f9f60357715bd7f95fc686a83201209)) - by @AbnormalPoof in [#4580](https://github.com/FunkinCrew/Funkin/pull/4580)
|
||||
- The Chart Editor now consistently displays the correct waveform for vocal tracks. ([c0e0523](https://github.com/FunkinCrew/Funkin/commit/c0e0523651e8aaaae2a0eed6d5fef6c5ef1b7315)) - by @NotHyper-474 in [#5231](https://github.com/FunkinCrew/Funkin/pull/5231)
|
||||
- Fixed selection boxes duplicating in the Chart Editor. ([65ed583](https://github.com/FunkinCrew/Funkin/commit/65ed58350b798bca0044603510540cfe81b48611)) - by @NotHyper-474 in [#5073](https://github.com/FunkinCrew/Funkin/pull/5073)
|
||||
- Hot-reloading with F5 in the Input Offsets menu no longer crashes the game. ([22372e8](https://github.com/FunkinCrew/Funkin/commit/22372e83886c5ef9821228daa3fb9fe8fbcf0e07)) - by @NotHyper-474 in [#5085](https://github.com/FunkinCrew/Funkin/pull/5085)
|
||||
- The Chart Editor playbar no longer extends past the right of the grid. ([7edc99b](https://github.com/FunkinCrew/Funkin/commit/7edc99b8ba7d1c61eba737560512a07babf5dfe8)) - by @anysad in [#5090](https://github.com/FunkinCrew/Funkin/pull/5090)
|
||||
- Removed a spammy console trace from some Chart Editor events. ([000491c](https://github.com/FunkinCrew/Funkin/commit/000491c3bd3db9de433a4b668b6ceebda2fc6eae)) - by @anysad in [#5097](https://github.com/FunkinCrew/Funkin/pull/5097)
|
||||
- Fixed a crash when mashing D or I during startup. ([790af6d](https://github.com/FunkinCrew/Funkin/commit/790af6d9054a77248ecb7bf34d764186c4fa2243)) - by @CrusherNotDrip in [#5160](https://github.com/FunkinCrew/Funkin/pull/5160)
|
||||
- The Chart Editor now consistently displays the correct waveform for vocal tracks. ([788d0fe](https://github.com/FunkinCrew/Funkin/commit/788d0fe9be5754e4e193de56e4437e8f409564a2)) - by @NotHyper-474 in [#5231](https://github.com/FunkinCrew/Funkin/pull/5231)
|
||||
- Stage Editor windows are now able to be closed. ([990042e](https://github.com/FunkinCrew/Funkin/commit/990042e28f73ad0624dfd38179891163d0c2313a)) - by @Lasercar in [#5238](https://github.com/FunkinCrew/Funkin/pull/5238)
|
||||
- Fixed duplicate exit prompts appearing in the Stage Editor. ([a599d83](https://github.com/FunkinCrew/Funkin/commit/a599d830f08ba697f2b526747280a53e16ebae06)) - by @Lasercar in [#5239](https://github.com/FunkinCrew/Funkin/pull/5239)
|
||||
- Reduced the severity of a memory leak in the Chart Editor. ([6ec3191](https://github.com/FunkinCrew/Funkin/commit/6ec3191b2952533afeded514d582a56f0905afb8)) - by @NotHyper-474 in [#5247](https://github.com/FunkinCrew/Funkin/pull/5247)
|
||||
- The Freeplay song preview no longer plays twice after returning from Character Select. ([f9387c1](https://github.com/FunkinCrew/Funkin/commit/f9387c144a62ecae2ea2b9da7b93ee16693bff02)) - by @Lasercar in [#5248](https://github.com/FunkinCrew/Funkin/pull/5248)
|
||||
- Undoing and redoing hold note length changes now visually updates the trail in the Chart Editor. ([254be57](https://github.com/FunkinCrew/Funkin/commit/254be5798ec0b7b2e79612ae5ade438965e65249)) - by @NotHyper-474 in [#5265](https://github.com/FunkinCrew/Funkin/pull/5265)
|
||||
- Pico's burpShit animation now re-enables volume for player vocals. ([2bf3846](https://github.com/FunkinCrew/funkin.assets/commit/2bf38463c524839e85faec19b7f31e90070e0b87)) - by @Hundrec in [funkin.assets#71](https://github.com/FunkinCrew/funkin.assets/pull/71)
|
||||
- Darnell's kneeCan animation now plays properly in 2hot. ([f8030c4](https://github.com/FunkinCrew/funkin.assets/commit/f8030c441c73d203f7b92c243542f99402faf2a7)) - by @biomseed in [funkin.assets#78](https://github.com/FunkinCrew/funkin.assets/pull/78)
|
||||
- Adjusted offsets for Freeplay DJ Pico's fistPump animation. ([17996db](https://github.com/FunkinCrew/funkin.assets/commit/17996db752c3077e005d4f05286a7795746acb05)) - by @AbnormalPoof in [funkin.assets#91](https://github.com/FunkinCrew/funkin.assets/pull/91)
|
||||
- Chart Editor and Stage Editor windows now consistently show a close button. ([929f61f](https://github.com/FunkinCrew/funkin.assets/commit/929f61fe86bd49d61de27e09503085a04c2cddfb)) - by @Lasercar in [funkin.assets#121](https://github.com/FunkinCrew/funkin.assets/pull/121)
|
||||
- Otis and Pico (Speaker) no longer spaz out when playtesting Stress. ([2fd62d8](https://github.com/FunkinCrew/funkin.assets/commit/2fd62d8f4fdefffc8d4a9cc96b9e993fd0130eb4)) - by @Lasercar in [funkin.assets#124](https://github.com/FunkinCrew/funkin.assets/pull/124)
|
||||
- The gasp sound now only plays once in the Week 3 Pico Mix doppelganger cutscene. ([ecda30d](https://github.com/FunkinCrew/funkin.assets/commit/ecda30d7532df3c34a4b5ad25579cc960cb30c0f)) - by @KoloInDaCrib in [funkin.assets#126](https://github.com/FunkinCrew/funkin.assets/pull/126)
|
||||
- Encountering an easter egg during a Chart Editor playtest no longer crashes the game. ([6cf9fb7](https://github.com/FunkinCrew/funkin.assets/commit/6cf9fb7ba48bb336f63eb940290fa051859330ec)) - by @NotHyper-474 in [funkin.assets#133](https://github.com/FunkinCrew/funkin.assets/pull/133)
|
||||
- Girlfriend (Tankman Stickup) now plays her combo drop animation. ([cb0e506](https://github.com/FunkinCrew/funkin.assets/commit/cb0e506599d387b1d17faee2cf319914eb2dfc80)) - by @qt2k4 in [funkin.assets#149](https://github.com/FunkinCrew/funkin.assets/pull/149)
|
||||
- Changed "Tankman Battlefield (Erect)" to "Tankman Battlefield [Erect]" in the Chart Editor for consistency. ([f9149eb](https://github.com/FunkinCrew/funkin.assets/commit/f9149eb72698ddd275f743080effed08c842644e)) - by @JVN-Pixels in [funkin.assets#155](https://github.com/FunkinCrew/funkin.assets/pull/155)
|
||||
- Fixed Pico (Pixel) having the incorrect name in the Chart Editor. ([a668659](https://github.com/FunkinCrew/funkin.assets/commit/a668659a4bbd2094fde48041c73fd1ebef551288)) - by @ExtraCode75 in [funkin.assets#158](https://github.com/FunkinCrew/funkin.assets/pull/158)
|
||||
- Darnell (BF Mix)'s alternate instrumental is now properly accessible. ([7bf4361](https://github.com/FunkinCrew/funkin.assets/commit/7bf436153081c27fdb354eddb05b72bd87fb18b7)) - by @Hundrec in [funkin.assets#168](https://github.com/FunkinCrew/funkin.assets/pull/168)
|
||||
- Adjusted the font size for Starting BPM in the Chart Editor for consistency. ([801121a](https://github.com/FunkinCrew/funkin.assets/commit/801121a7d31ef3a1ac108bf16941d88009d1b12a)) - by @Lasercar in [funkin.assets#170](https://github.com/FunkinCrew/funkin.assets/pull/170)
|
||||
- Removed vocals from Monster's instrumental on web builds. ([bf7b032](https://github.com/FunkinCrew/funkin.assets/commit/bf7b032154fdc9751fbe8fdf88dbc5fd24f361db)) - by @JVN-Pixels in [funkin.assets#182](https://github.com/FunkinCrew/funkin.assets/pull/182)
|
||||
- A-Bot's visualizer no longer jumps to a random volume when the song ends. ([2904697](https://github.com/FunkinCrew/funkin.assets/commit/2904697b6fda66db4df2b47127f05520fdf831d1)) - by @VioletSnowLeopard in [funkin.assets#183](https://github.com/FunkinCrew/funkin.assets/pull/183)
|
||||
- The cars in Week 4 and Weekend 1 no longer get stuck when the song is restarted. ([ecb1bbd](https://github.com/FunkinCrew/funkin.assets/commit/ecb1bbd8c8ced028b96b2c9b5572d2ea48f36cf4)) - by @MetaBreeze in [funkin.assets#186](https://github.com/FunkinCrew/funkin.assets/pull/186)
|
||||
- Removed a spammy console trace from Spooky Kids (Dark). ([9ee98d6](https://github.com/FunkinCrew/funkin.assets/commit/9ee98d62aa336f1fccbefaf077b4ae3222e00ec4)) - by @NotHyper-474 in [funkin.assets#187](https://github.com/FunkinCrew/funkin.assets/pull/187)
|
||||
- Fixed the Chart Editor timer occasionally displaying incorrect millisecond values. ([26dc895](https://github.com/FunkinCrew/Funkin/commit/26dc895a27e0d7e49469251cd68b83be66384e15)) - by @Hundrec in [#4257](https://github.com/FunkinCrew/Funkin/pull/4257)
|
||||
- The Chart Editor playhead can no longer be scrolled to before the beginning of the song. ([7c7dc11](https://github.com/FunkinCrew/Funkin/commit/7c7dc11f18644882444df97ac927e11adaa4ce50)) - by @Hundrec in [#5024](https://github.com/FunkinCrew/Funkin/pull/5024)
|
||||
- The Chart Editor playbar no longer extends past the right of the grid. ([c7abb19](https://github.com/FunkinCrew/Funkin/commit/c7abb196989476cfa4db6354cc6fac5bacb2e56a)) - by @anysad in [#5090](https://github.com/FunkinCrew/Funkin/pull/5090)
|
||||
- Dragging a hold note in the Chart Editor now drags its trail along with its head. ([d3d8aaa](https://github.com/FunkinCrew/Funkin/commit/d3d8aaae7bfbfa8975a9573807b9a3ca68a1ff55)) - by @KoloInDaCrib in [#4127](https://github.com/FunkinCrew/Funkin/pull/4127)
|
||||
- Hold note trails will no longer disappear when dragged too far in the Chart Editor. ([37dc66b](https://github.com/FunkinCrew/Funkin/commit/37dc66bc189bc1941cf60587e1c068770aeec872)) - by @NotHyper-474 in
|
||||
[#5261](https://github.com/FunkinCrew/Funkin/pull/5261)
|
||||
- Undoing and redoing hold note length changes now visually updates the trail in the Chart Editor. ([06a440f](https://github.com/FunkinCrew/Funkin/commit/06a440f21c285666ce2d2bdf17a91ee82ab01061)) - by @NotHyper-474 in [#5265](https://github.com/FunkinCrew/Funkin/pull/5265)
|
||||
- The Chart Editor hold note context menu now displays the correct options. ([4801316](https://github.com/FunkinCrew/Funkin/commit/48013168ef09ddc09549268a2e5309520d3fcc18)) - by @Lasercar in [#4231](https://github.com/FunkinCrew/Funkin/pull/4231)
|
||||
- The buttons in the Chart Editor context menu for selections now do the right thing. ([62d24fc](https://github.com/FunkinCrew/Funkin/commit/62d24fcf4cbe7be328a995bad04f3eeb265262c5)) - by @Lasercar in [#4233](https://github.com/FunkinCrew/Funkin/pull/4233)
|
||||
- The charter field in the song metadata now properly displays the charter in the Chart Editor. ([894d8cb](https://github.com/FunkinCrew/Funkin/commit/894d8cb4637fd0a64359a5edc805a23403f3045c)) - by @Lasercar in [#4879](https://github.com/FunkinCrew/Funkin/pull/4879)
|
||||
- Chart Editor difficulties are now sorted in a consistent order. ([7aa77a1](https://github.com/FunkinCrew/Funkin/commit/7aa77a11cf7508fc05758045a13b2220aca96dd5)) - by @Lasercar in [#4528](https://github.com/FunkinCrew/Funkin/pull/4528)
|
||||
- Chart Editor and Stage Editor windows now consistently show a close button. ([b23b7b8](https://github.com/FunkinCrew/funkin.assets/commit/b23b7b81d843c8fa2334fbdbe1ef979633956bb9)) - by @Lasercar in [funkin.assets#121](https://github.com/FunkinCrew/funkin.assets/pull/121)
|
||||
- The Chart Editor playbar's font size no longer becomes too small. ([f9c1f7a](https://github.com/FunkinCrew/Funkin/commit/f9c1f7a5f7d3906155c2004ad2ec1d02556b9730)) - by @KoloInDaCrib in [#5253](https://github.com/FunkinCrew/Funkin/pull/5253)
|
||||
- The Chart Editor copy notification no longer chases the mouse cursor. ([0ea42e1](https://github.com/FunkinCrew/Funkin/commit/0ea42e18e93b0b57f1ae5499d70c4681f191dacb)) - by @KoloInDaCrib in [#4029](https://github.com/FunkinCrew/Funkin/pull/4029)
|
||||
- Changed "Tankman Battlefield (Erect)" to "Tankman Battlefield [Erect]" in the Chart Editor for consistency. ([52852a0](https://github.com/FunkinCrew/funkin.assets/commit/52852a02f60df81c281bfd0e49fd8fa09e118409)) - by @JVNpixels in [funkin.assets#155](https://github.com/FunkinCrew/funkin.assets/pull/155)
|
||||
- Fixed Pico (Pixel) having the incorrect name in the Chart Editor. ([3ff0e9c](https://github.com/FunkinCrew/funkin.assets/commit/3ff0e9ca4f8cdc5734c335f2d7d72fa310686d46)) - by @ExtraCode75 in [funkin.assets#158](https://github.com/FunkinCrew/funkin.assets/pull/158)
|
||||
- Fixed various issues and added missing functionalities to the Stage Editor. ([a776ce1](https://github.com/FunkinCrew/Funkin/commit/a776ce1a81a539f75f8bd2220a9768c03d347058)) - by @KoloInDaCrib in [#3974](https://github.com/FunkinCrew/Funkin/pull/3974)
|
||||
- Stage Editor windows are now able to be closed. ([65461d8](https://github.com/FunkinCrew/Funkin/commit/65461d839b3764659aab33f1a35edf64ee514952)) - by @Lasercar in [#5238](https://github.com/FunkinCrew/Funkin/pull/5238)
|
||||
- Fixed duplicate exit prompts appearing in the Stage Editor. ([136a5df](https://github.com/FunkinCrew/Funkin/commit/136a5dfad430b461a909be3a7e89f46c8be1d3b3)) - by @Lasercar in [#5239](https://github.com/FunkinCrew/Funkin/pull/5239)
|
||||
- The help guide in the Stage Editor can no longer be opened multiple times. ([564d679](https://github.com/FunkinCrew/Funkin/commit/564d679f969c500834426ce3cf50507091d69697)) - by @Lasercar in [#4128](https://github.com/FunkinCrew/Funkin/pull/4128)
|
||||
- Removed a spammy console trace from Spooky Kids (Dark). ([5935a61](https://github.com/FunkinCrew/funkin.assets/commit/5935a61dd71f51e6264dcd039f1164cd1ff295ef)) - by @NotHyper-474 in [funkin.assets#187](https://github.com/FunkinCrew/funkin.assets/pull/187)
|
||||
- Removed spammy console traces from `DiscordClient`. ([e89f9f5](https://github.com/FunkinCrew/Funkin/commit/e89f9f50dc6085e3550736459ce9e4fd02c1fc5b)) - by @AbnormalPoof in [#4207](https://github.com/FunkinCrew/Funkin/pull/4207)
|
||||
- Removed a spammy console trace from some Chart Editor events. ([b883ad3](https://github.com/FunkinCrew/Funkin/commit/b883ad3d50b990e605d7b79d042292c7371db5f0)) - by @anysad in [#5097](https://github.com/FunkinCrew/Funkin/pull/5097)
|
||||
- ANSI colors now display in the console on more computers. ([3747b94](https://github.com/FunkinCrew/Funkin/commit/3747b942461c3644fe31f25d2ce847fd74d1b1e0)) - by @AbnormalPoof in [#4676](https://github.com/FunkinCrew/Funkin/pull/4676)
|
||||
- Properly blacklist a certain class from scripts. ([3dc7699](https://github.com/FunkinCrew/Funkin/commit/3dc7699aac737998b637ff9a9f16986a434424be)) - by @charlesisfeline in [#4773](https://github.com/FunkinCrew/Funkin/pull/4773)
|
||||
|
||||
### Removed
|
||||
|
||||
- [MOBILE] The Input Offsets menu has been temporarily removed pending future reworks.
|
||||
- Removed a few non-functional screenshot preferences. ([8e40942](https://github.com/FunkinCrew/Funkin/commit/8e4094227f89ccc8ec7e58be49a5e1ad6911ed12)) - by @Lasercar in [#4895](https://github.com/FunkinCrew/Funkin/pull/4895)
|
||||
- Removed the VSync preference from web builds, where it's non-functional. ([1338834](https://github.com/FunkinCrew/Funkin/commit/1338834519e13326fa21585a236218cd984ed614)) - by @NotHyper-474 in [#5062](https://github.com/FunkinCrew/Funkin/pull/5062)
|
||||
- Removed the VSync preference from web builds, where it's non-functional. ([0b7a94b](https://github.com/FunkinCrew/Funkin/commit/0b7a94b1cc5c5d0dbac5a4c3d595349c4e6eb6e4)) - by @NotHyper-474 in [#5062](https://github.com/FunkinCrew/Funkin/pull/5062)
|
||||
- Removed a few non-functional screenshot preferences. ([93e4f79](https://github.com/FunkinCrew/Funkin/commit/93e4f799f4f0ea435b3d77ca8ef2ab6beeb0a955)) - by @Lasercar in [#4895](https://github.com/FunkinCrew/Funkin/pull/4895)
|
||||
|
||||
## New Contributors for 0.7.0
|
||||
|
||||
* @KutikiPlayz made their first contribution in [#3544](https://github.com/FunkinCrew/Funkin/pull/3544)
|
||||
* @xenkap made their first contribution in [#3732](https://github.com/FunkinCrew/Funkin/pull/3732)
|
||||
* @Raltyro made their first contribution in [#4577](https://github.com/FunkinCrew/Funkin/pull/4577)
|
||||
* @charlesisfeline made their first contribution in [#4773](https://github.com/FunkinCrew/Funkin/pull/4773)
|
||||
* @T5mpler made their first contribution in [#5275](https://github.com/FunkinCrew/Funkin/pull/5275)
|
||||
* @biomseed made their first contribution in [funkin.assets#78](https://github.com/FunkinCrew/funkin.assets/pull/78)
|
||||
* @qt2k4 made their first contribution in [funkin.assets#149](https://github.com/FunkinCrew/funkin.assets/pull/149)
|
||||
* @ExtraCode75 made their first contribution in [funkin.assets#158](https://github.com/FunkinCrew/funkin.assets/pull/158)
|
||||
@@ -253,7 +657,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
* @JackXson-Real made their first contribution in [#4346](https://github.com/FunkinCrew/Funkin/pull/4346)
|
||||
* @VioletSnowLeopard made their first contribution in [#4382](https://github.com/FunkinCrew/Funkin/pull/4382)
|
||||
* @superpowers04 made their first contribution in [#4729](https://github.com/FunkinCrew/Funkin/pull/4729)
|
||||
* @ShadzXD made their first contribution in [#62](https://github.com/FunkinCrew/Funkin/pull/4729)
|
||||
* @ShadzXD made their first contribution in [funkin.assets#62](https://github.com/FunkinCrew/funkin.assets/pull/62)
|
||||
|
||||
|
||||
|
||||
@@ -526,6 +930,7 @@ This patch resolves a critical issue that could cause user's save data to become
|
||||
|
||||
## [0.5.0] - 2024-09-12
|
||||
The Playable Pico Update!
|
||||
|
||||
### Added
|
||||
|
||||
- Added a new Character Select screen to switch between playable characters in Freeplay.
|
||||
@@ -646,7 +1051,7 @@ The Playable Pico Update!
|
||||
### Fixed
|
||||
|
||||
- Control binds in the controls menu no longer overlap their names.
|
||||
- Attempting to exit the gameover screen and retry the song at the same time no longer crashes the game. ([thanks DMMaster636 for the PR!](https://github.com/FunkinCrew/Funkin/pull/2709))
|
||||
- Attempting to exit the gameover screen and retry the song at the same time no longer crashes the game. ([thanks DM-kun for the PR!](https://github.com/FunkinCrew/Funkin/pull/2709))
|
||||
- Botplay mode now handles the player's animations properly during hold notes. ([thanks Hundrec!](https://github.com/FunkinCrew/Funkin/pull/2683))
|
||||
- Camera movement now pauses when the game is paused. ([thanks Matriculaso!](https://github.com/FunkinCrew/Funkin/pull/2684))
|
||||
- Pico's gameplay sprite no longer appears on the gameover screen when dying from an explosion in 2hot.
|
||||
@@ -660,13 +1065,14 @@ The Playable Pico Update!
|
||||
## New Contributors for 0.4.1
|
||||
|
||||
* @Hundrec made their first contribution in [#2661](https://github.com/FunkinCrew/Funkin/pull/2661)
|
||||
* @DMMaster636 made their first contribution in [#2709](https://github.com/FunkinCrew/Funkin/pull/2709)
|
||||
* @DM-kun made their first contribution in [#2709](https://github.com/FunkinCrew/Funkin/pull/2709)
|
||||
* @eltociear made their first contribution in [#2730](https://github.com/FunkinCrew/Funkin/pull/2730)
|
||||
|
||||
|
||||
|
||||
## [0.4.0] - 2024-06-06
|
||||
The Pit Stop 1 update!
|
||||
|
||||
### Added
|
||||
|
||||
- 2 new Erect remixes, Eggnog and Satin Panties. Check them out from the Freeplay menu!
|
||||
@@ -838,6 +1244,7 @@ The Pit Stop 1 update!
|
||||
|
||||
## [0.3.0] - 2024-04-30
|
||||
The Weekend 1 update!
|
||||
|
||||
### Added
|
||||
|
||||
- New Story Level: Weekend 1, starring Pico, Darnell, and Nene.
|
||||
|
||||
@@ -1,14 +1,25 @@
|
||||
# Friday Night Funkin'
|
||||
<div align='center'><img src="https://fridaynightfunkin.wiki.gg/images/FNF_logo.png" width="800">
|
||||
|
||||
Friday Night Funkin' is a rhythm game. Built using HaxeFlixel for Ludum Dare 47.
|
||||
<h2>Friday Night Funkin' is a rhythm game. Built using HaxeFlixel for <a href="https://ldjam.com/events/ludum-dare/47">Ludum Dare 47.</a></h2>
|
||||
|
||||
This game was made with love to Newgrounds and its community. Extra love to Tom Fulp.
|
||||
|
||||
</div>
|
||||
|
||||
- [Playable web demo on Newgrounds!](https://www.newgrounds.com/portal/view/770371)
|
||||
- [Demo download builds for Windows, Mac, and Linux from Itch.io!](https://ninja-muffin24.itch.io/funkin)
|
||||
- [Download Android builds from Google Play!](https://play.google.com/store/apps/details?id=me.funkin.fnf)
|
||||
- [Download iOS builds from the App Store!](https://apps.apple.com/app/id6740428530)
|
||||
|
||||
<div align='center'>
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="https://fridaynightfunkin.wiki.gg/images/d/d7/Title_Card.gif" alt="Title Screen" width="350"/></td>
|
||||
<td><img src="https://fridaynightfunkin.wiki.gg/images/9/99/Menu.png" alt="Main Menu" width="350"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
# Getting Started
|
||||
|
||||
**PLEASE USE THE LINKS ABOVE IF YOU JUST WANT TO PLAY THE GAME**
|
||||
|
||||
+1
-1
Submodule art updated: 67e550dbd2...094ff10919
+1
-1
Submodule assets updated: 414e9a0248...5ca3c6a574
@@ -0,0 +1,135 @@
|
||||
{
|
||||
"input": "./assets",
|
||||
"output": "./astc-textures/",
|
||||
"quality": "medium",
|
||||
"blocksize": "10x10",
|
||||
"colorprofile": "cl",
|
||||
"custom": [
|
||||
{
|
||||
"asset": "asset/shared/images/resultScreen/results-pico/resultsPERFECT/spritemap1.png",
|
||||
"blocksize": "4x4"
|
||||
},
|
||||
{
|
||||
"asset": "asset/shared/images/resultScreen/results-pico/resultsGREAT/spritemap1.png",
|
||||
"blocksize": "4x4"
|
||||
},
|
||||
{
|
||||
"asset": "asset/shared/images/resultScreen/results-pico/resultsGOOD/spritemap1.png",
|
||||
"blocksize": "4x4"
|
||||
},
|
||||
{
|
||||
"asset": "assets/shared/images/resultScreen/results-bf/resultsEXCELLENT/spritemap1.png",
|
||||
"blocksize": "4x4"
|
||||
},
|
||||
{
|
||||
"asset": "asset/shared/images/resultScreen/results-pico/resultsSHIT/spritemap1.png",
|
||||
"blocksize": "4x4"
|
||||
},
|
||||
{
|
||||
"asset": "assets/preload/images/NOTE_assets.png",
|
||||
"blocksize": "4x4"
|
||||
},
|
||||
{
|
||||
"asset": "assets/preload/images/NOTE_hold_assets.png",
|
||||
"blocksize": "4x4"
|
||||
},
|
||||
{
|
||||
"asset": "assets/preload/images/StrumlineNotes.png",
|
||||
"blocksize": "4x4"
|
||||
},
|
||||
{
|
||||
"asset": "assets/preload/images/alphabet.png",
|
||||
"blocksize": "4x4"
|
||||
},
|
||||
{
|
||||
"asset": "assets/shared/images/NOTE_hold_assets.png",
|
||||
"blocksize": "4x4"
|
||||
},
|
||||
{
|
||||
"asset": "assets/shared/images/holdCoverBlue.png",
|
||||
"blocksize": "4x4"
|
||||
},
|
||||
{
|
||||
"asset": "assets/shared/images/holdCoverGreen.png",
|
||||
"blocksize": "4x4"
|
||||
},
|
||||
{
|
||||
"asset": "assets/shared/images/holdCoverPurple.png",
|
||||
"blocksize": "4x4"
|
||||
},
|
||||
{
|
||||
"asset": "assets/shared/images/holdCoverRed.png",
|
||||
"blocksize": "4x4"
|
||||
},
|
||||
{
|
||||
"asset": "assets/shared/images/latencyArrow.png",
|
||||
"blocksize": "4x4"
|
||||
},
|
||||
{
|
||||
"asset": "assets/shared/images/latencyReceptor.png",
|
||||
"blocksize": "4x4"
|
||||
},
|
||||
{
|
||||
"asset": "assets/shared/images/noteSplashes.png",
|
||||
"blocksize": "4x4"
|
||||
},
|
||||
{
|
||||
"asset": "assets/shared/images/noteStrumline.png",
|
||||
"blocksize": "4x4"
|
||||
},
|
||||
{
|
||||
"asset": "assets/shared/images/notes.png",
|
||||
"blocksize": "4x4"
|
||||
},
|
||||
{
|
||||
"asset": "assets/week1/image/erect/bg.png",
|
||||
"blocksize": "8x8"
|
||||
},
|
||||
{
|
||||
"asset": "assets/week1/image/erect/lights.png",
|
||||
"blocksize": "6x6"
|
||||
},
|
||||
{
|
||||
"asset": "assets/week1/images/erect/crowd.png",
|
||||
"blocksize": "8x8"
|
||||
},
|
||||
{
|
||||
"asset": "assets/week1/images/erect/server.png",
|
||||
"blocksize": "8x8"
|
||||
}
|
||||
],
|
||||
"excludes": [
|
||||
"assets/preload/images/cursor/",
|
||||
"assets/preload/images/fonts/",
|
||||
"assets/preload/images/freeplay/",
|
||||
"assets/preload/images/icons/",
|
||||
"assets/preload/images/soundtray/",
|
||||
"assets/preload/images/stageBuild/",
|
||||
"assets/preload/images/titleEnter.png",
|
||||
"assets/preload/images/titleEnter_mobile.png",
|
||||
"assets/preload/images/ui/popup/pixel/*",
|
||||
"assets/shared/images/characters/abotPixel/*",
|
||||
"assets/shared/images/characters/bfPixel.png",
|
||||
"assets/shared/images/characters/bfPixelsDEAD.png",
|
||||
"assets/shared/images/characters/gfPixel.png",
|
||||
"assets/shared/images/characters/nenePixel/*",
|
||||
"assets/shared/images/characters/picoPixel/*",
|
||||
"assets/shared/images/characters/senpai.png",
|
||||
"assets/shared/images/characters/spirit.png",
|
||||
"assets/shared/images/healthBar.png",
|
||||
"assets/shared/images/resultScreen/*",
|
||||
"assets/shared/images/resultScreen/clearPercent/",
|
||||
"assets/shared/images/resultScreen/rankText/",
|
||||
"assets/shared/images/ui/chart-editor/",
|
||||
"assets/shared/images/ui/countdown/pixel/*",
|
||||
"assets/week1/*",
|
||||
"assets/week1/images/erect/brightLightSmall.png",
|
||||
"assets/week1/images/erect/lightAbove.png",
|
||||
"assets/week1/images/erect/lightgreen.png",
|
||||
"assets/week1/images/erect/lightred.png",
|
||||
"assets/week1/images/erect/orangeLight.png",
|
||||
"assets/week2/images/erect/stairsDark.png",
|
||||
"assets/week2/images/erect/stairsLight.png",
|
||||
"assets/week6/"
|
||||
]
|
||||
}
|
||||
+34
-21
@@ -1,10 +1,9 @@
|
||||
{
|
||||
"extendsConfigPath": "",
|
||||
"defineCombinations": [],
|
||||
"defaultSeverity": "INFO",
|
||||
"extendsConfigPath": "",
|
||||
"numberOfCheckerThreads": 5,
|
||||
"baseDefines": [],
|
||||
"version": 1,
|
||||
"exclude": {},
|
||||
"defineCombinations": [],
|
||||
"checks": [
|
||||
{
|
||||
"props": {},
|
||||
@@ -40,12 +39,6 @@
|
||||
"props": {},
|
||||
"type": "AvoidStarImport"
|
||||
},
|
||||
{
|
||||
"props": {
|
||||
"severity": "IGNORE"
|
||||
},
|
||||
"type": "AvoidTernaryOperator"
|
||||
},
|
||||
{
|
||||
"props": {},
|
||||
"type": "BlockBreakingConditional"
|
||||
@@ -71,7 +64,6 @@
|
||||
{
|
||||
"props": {
|
||||
"severity": "IGNORE",
|
||||
|
||||
"policy": "aligned",
|
||||
"allowSingleline": true
|
||||
},
|
||||
@@ -80,7 +72,7 @@
|
||||
{
|
||||
"props": {
|
||||
"ignoreExtern": true,
|
||||
"format": "^[a-zA-Z0-9]+(?:_[a-zA-Z0-9]+)*$",
|
||||
"format": "^?:_[a-zA-Z0-9]+(?:_[a-zA-Z0-9]+)*$",
|
||||
"tokens": ["INLINE", "NOTINLINE"]
|
||||
},
|
||||
"type": "ConstantName"
|
||||
@@ -108,13 +100,12 @@
|
||||
{
|
||||
"props": {
|
||||
"lineStyle": "onestar",
|
||||
"startStyle": "twostars",
|
||||
"severity": "IGNORE"
|
||||
"startStyle": "ignore"
|
||||
},
|
||||
"type": "DocCommentStyle"
|
||||
},
|
||||
{
|
||||
"props": {},
|
||||
"props": { "severity": "IGNORE" },
|
||||
"type": "Dynamic"
|
||||
},
|
||||
{
|
||||
@@ -193,6 +184,14 @@
|
||||
},
|
||||
"type": "FileLength"
|
||||
},
|
||||
{
|
||||
"type": "FileNameCase",
|
||||
"props": {}
|
||||
},
|
||||
{
|
||||
"type": "Final",
|
||||
"props": {}
|
||||
},
|
||||
{
|
||||
"props": {
|
||||
"option": "upperCase"
|
||||
@@ -245,7 +244,7 @@
|
||||
{
|
||||
"props": {
|
||||
"max": 160,
|
||||
"ignorePattern": "^$"
|
||||
"ignorePattern": "^(\\s*['\"][^'\"]*['\"].*)$"
|
||||
},
|
||||
"type": "LineLength"
|
||||
},
|
||||
@@ -348,7 +347,7 @@
|
||||
{
|
||||
"props": {
|
||||
"allowSingleLineStatement": true,
|
||||
"tokens": ["FOR", "ELSE_IF", "WHILE", "DO_WHILE"]
|
||||
"tokens": ["ELSE_IF", "WHILE", "DO_WHILE"]
|
||||
},
|
||||
"type": "NeedBraces"
|
||||
},
|
||||
@@ -580,6 +579,12 @@
|
||||
"props": {},
|
||||
"type": "TrailingWhitespace"
|
||||
},
|
||||
{
|
||||
"type": "Type",
|
||||
"props": {
|
||||
"ignoreEnumAbstractValues": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"props": {
|
||||
"tokens": ["CLASS_DEF", "ENUM_DEF", "INTERFACE_DEF", "TYPEDEF_DEF"]
|
||||
@@ -612,11 +617,18 @@
|
||||
"type": "UnusedLocalVar"
|
||||
},
|
||||
{
|
||||
"type": "VarTypeHint",
|
||||
"props": {
|
||||
"typeHintPolicy": "enforce_all",
|
||||
"ignoreEnumAbstractValues": true
|
||||
},
|
||||
"type": "VarTypeHint"
|
||||
"ignoreEnumAbstractValues": true,
|
||||
"severity": "IGNORE"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "VariableInitialisation",
|
||||
"props": {
|
||||
"allowFinal": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"props": {
|
||||
@@ -665,5 +677,6 @@
|
||||
"type": "WhitespaceAround"
|
||||
}
|
||||
],
|
||||
"numberOfCheckerThreads": 5
|
||||
"exclude": {},
|
||||
"version": 1
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
assets/preload/images/cursor/*
|
||||
assets/preload/images/freeplay/*
|
||||
assets/preload/images/icons/*
|
||||
assets/preload/images/titleEnter.png
|
||||
assets/preload/images/titleEnter_mobile.png
|
||||
assets/preload/images/soundtray/*
|
||||
assets/preload/images/stageBuild/*
|
||||
assets/preload/images/ui/popup/pixel/
|
||||
assets/shared/images/characters/abotPixel/
|
||||
assets/shared/images/characters/bfPixel.png
|
||||
assets/shared/images/characters/bfPixelsDEAD.png
|
||||
assets/shared/images/characters/gfPixel.png
|
||||
assets/shared/images/characters/nenePixel/
|
||||
assets/shared/images/characters/picoPixel/
|
||||
assets/shared/images/characters/senpai.png
|
||||
assets/shared/images/characters/spirit.png
|
||||
assets/shared/images/resultScreen/*
|
||||
assets/shared/images/ui/chart-editor/*
|
||||
assets/shared/images/ui/countdown/pixel/
|
||||
assets/week1/
|
||||
assets/week6/*
|
||||
+7
-10
@@ -60,7 +60,7 @@ This section provides guidelines to follow when [opening an issue](https://githu
|
||||
|
||||
## Requirements
|
||||
Make sure you're playing:
|
||||
- the latest version of the game (currently v0.6.4)
|
||||
- the latest version of the game (currently v0.7.5)
|
||||
- without any mods
|
||||
- on [Newgrounds](https://www.newgrounds.com/portal/view/770371) or downloaded from [itch.io](https://ninja-muffin24.itch.io/funkin)
|
||||
|
||||
@@ -122,9 +122,6 @@ Also only report one issue or enhancement at a time! If you have multiple bug re
|
||||
|
||||
Once you're sure your issue is unique and specific, feel free to submit it.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **DO NOT CLOSE YOUR ISSUE FOR ANY REASON!** Your issue will be taken care of by a moderator!
|
||||
|
||||
**Thank you for opening issues!**
|
||||
|
||||
# Part 3: Pull Requests
|
||||
@@ -132,20 +129,20 @@ Community members are welcome to contribute their changes by [opening pull reque
|
||||
This section covers guidelines for opening and managing pull requests (PRs).
|
||||
|
||||
## Choosing a base branch
|
||||
When creating a branch in your fork, base your branch on either the `main` or `develop` branch depending on the types of changes you want to make.
|
||||
When creating a branch in your fork, base your branch on either the `develop` or `main` branch depending on the types of changes you want to make.
|
||||
|
||||
> [!CAUTION]
|
||||
> Avoid using your fork's default branch (`main` in this case) for your PR. This is considered an [anti-pattern](https://jmeridth.com/posts/do-not-issue-pull-requests-from-your-master-branch/) by GitHub themselves!
|
||||
> Instead, make a separate branch for your additions (ex. `docs/fix-typo` or `minor-bugfix`).
|
||||
|
||||
Choose the `main` branch if you modify:
|
||||
- Documentation (`.md` files)
|
||||
- GitHub files (`.yml` files or anything in the `.github` folder)
|
||||
|
||||
Choose the `develop` branch if you modify:
|
||||
- Game code (`.hx` files)
|
||||
- Any other type of file
|
||||
|
||||
Choose the `main` branch if you modify:
|
||||
- Documentation (`.md` files)
|
||||
- GitHub files (`.yml` files or anything in the `.github` folder)
|
||||
|
||||
> [!TIP]
|
||||
> When in doubt, base your branch on the `develop` branch.
|
||||
|
||||
@@ -399,7 +396,7 @@ If you only modify files in the `assets` folder, open a PR in the `funkin.assets
|
||||
|
||||
If you simultaneously modify files from both repositories, then open two separate PRs and explain the connection in your PR descriptions.
|
||||
|
||||
Be sure to choose `main` as the base branch for `funkin.assets` PRs, as no `develop` branch exists for that repository.
|
||||
Be sure to choose `develop` as the base branch for `funkin.assets` PRs, just as you would in the `Funkin` repository.
|
||||
|
||||
### Charting PRs
|
||||
Charting PRs make changes such as **adjusting chart metadata**.
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"name": "EliteMasterEric"
|
||||
}
|
||||
],
|
||||
"api_version": "0.5.0",
|
||||
"api_version": "0.7.0",
|
||||
"mod_version": "1.0.0",
|
||||
"license": "Apache-2.0"
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"name": "EliteMasterEric"
|
||||
}
|
||||
],
|
||||
"api_version": "0.5.0",
|
||||
"api_version": "0.7.0",
|
||||
"mod_version": "1.0.0",
|
||||
"license": "Apache-2.0"
|
||||
}
|
||||
|
||||
@@ -4,49 +4,49 @@
|
||||
"name": "FlxPartialSound",
|
||||
"type": "git",
|
||||
"dir": null,
|
||||
"ref": "3c9f63e3501c20c0b60442089dc05306f5a87968",
|
||||
"url": "https://github.com/FunkinDroidTeam/FlxPartialSound.git"
|
||||
"ref": "4e86b724ca43489a59ea465a46ffc12598e5df15",
|
||||
"url": "https://github.com/FunkinCrew/FlxPartialSound.git"
|
||||
},
|
||||
{
|
||||
"name": "astc-compressor",
|
||||
"type": "git",
|
||||
"dir": null,
|
||||
"ref": "8c9f56927c523df7b849352c6951f04112fe15cc",
|
||||
"ref": "b7a91b3072dc16e785a9bde847f17ba0ef15dd47",
|
||||
"url": "https://github.com/KarimAkra/astc-compressor"
|
||||
},
|
||||
{
|
||||
"name": "extension-admob",
|
||||
"type": "git",
|
||||
"dir": null,
|
||||
"ref": "b0fe062c5eacd7cde80fd21544fe27616e5b4f9e",
|
||||
"ref": "96385202f6f951b2bde0cbe836c5da21dde1f36e",
|
||||
"url": "https://github.com/FunkinCrew/extension-admob"
|
||||
},
|
||||
{
|
||||
"name": "extension-androidtools",
|
||||
"type": "haxelib",
|
||||
"version": "2.2.1"
|
||||
"version": "2.2.2"
|
||||
},
|
||||
{
|
||||
"name": "extension-haptics",
|
||||
"type": "haxelib",
|
||||
"version": "1.0.3"
|
||||
"version": "1.0.4"
|
||||
},
|
||||
{
|
||||
"name": "extension-iapcore",
|
||||
"type": "haxelib",
|
||||
"version": "1.0.3"
|
||||
"version": "1.0.4"
|
||||
},
|
||||
{
|
||||
"name": "extension-iarcore",
|
||||
"type": "haxelib",
|
||||
"version": "1.0.2"
|
||||
"version": "1.0.3"
|
||||
},
|
||||
{
|
||||
"name": "flixel",
|
||||
"type": "git",
|
||||
"dir": null,
|
||||
"ref": "16962f601431d72ed104ca700d1e99ad4dcfffca",
|
||||
"url": "https://github.com/FunkinCrew/flixel-mobile"
|
||||
"ref": "5cf3515e665812179a9b413629325b608b3a9815",
|
||||
"url": "https://github.com/FunkinCrew/flixel"
|
||||
},
|
||||
{
|
||||
"name": "flixel-addons",
|
||||
@@ -59,7 +59,7 @@
|
||||
"name": "flxanimate",
|
||||
"type": "git",
|
||||
"dir": null,
|
||||
"ref": "39c1572add28869c558b218fffed13df1b64f376",
|
||||
"ref": "49214278b9124823582cdcecd94f4a1de9a4b36b",
|
||||
"url": "https://github.com/FunkinCrew/flxanimate"
|
||||
},
|
||||
{
|
||||
@@ -104,21 +104,21 @@
|
||||
"name": "hscript",
|
||||
"type": "git",
|
||||
"dir": null,
|
||||
"ref": "27c86f9a761c1d16d4433c4cf252eccb7b2e18de",
|
||||
"ref": "8c1d238b069ef97cec13f5121b29d2afe2b8985d",
|
||||
"url": "https://github.com/FunkinCrew/hscript"
|
||||
},
|
||||
{
|
||||
"name": "hxcpp",
|
||||
"type": "git",
|
||||
"dir": null,
|
||||
"ref": "4e24283a047f11bded6affabbc9ec405156e026e",
|
||||
"ref": "363d3d0a8d3ac450f5ba1b4c3357353656b71e82",
|
||||
"url": "https://github.com/FunkinCrew/hxcpp"
|
||||
},
|
||||
{
|
||||
"name": "hxcpp-debug-server",
|
||||
"type": "git",
|
||||
"dir": "hxcpp-debug-server",
|
||||
"ref": "147294123f983e35f50a966741474438069a7a8f",
|
||||
"ref": "7459934666a473a4cc4d066ba4a93ef92f1ce94c",
|
||||
"url": "https://github.com/FunkinCrew/hxcpp-debugger"
|
||||
},
|
||||
{
|
||||
@@ -143,7 +143,7 @@
|
||||
{
|
||||
"name": "hxvlc",
|
||||
"type": "haxelib",
|
||||
"version": "2.2.2"
|
||||
"version": "2.2.4"
|
||||
},
|
||||
{
|
||||
"name": "json2object",
|
||||
@@ -170,36 +170,8 @@
|
||||
"name": "lime",
|
||||
"type": "git",
|
||||
"dir": null,
|
||||
"ref": "2d3784fe3fdbd81ce59d6ad035f52e12c59cf059",
|
||||
"url": "https://github.com/FunkinCrew/lime-mobile"
|
||||
},
|
||||
{
|
||||
"name": "mconsole",
|
||||
"type": "git",
|
||||
"dir": null,
|
||||
"ref": "06c0499ed8f80628a0e6e55ffa32c3cbd688a838",
|
||||
"url": "https://github.com/massive-oss/mconsole"
|
||||
},
|
||||
{
|
||||
"name": "mcover",
|
||||
"type": "git",
|
||||
"dir": "src",
|
||||
"ref": "c3c47cd682b0b202a41caee95321989391b617ef",
|
||||
"url": "https://github.com/massive-oss/mcover"
|
||||
},
|
||||
{
|
||||
"name": "mockatoo",
|
||||
"type": "git",
|
||||
"dir": "src",
|
||||
"ref": "13d77a0a8eaf5e789ef5dae6cd33eee812deda36",
|
||||
"url": "https://github.com/FunkinCrew/mockatoo"
|
||||
},
|
||||
{
|
||||
"name": "munit",
|
||||
"type": "git",
|
||||
"dir": "src",
|
||||
"ref": "f61be7f7ba796595f45023ca65164a485aba0e7e",
|
||||
"url": "https://github.com/FunkinCrew/MassiveUnit"
|
||||
"ref": "f109a083023a9e5622342257993fc745d9bbb959",
|
||||
"url": "https://github.com/FunkinCrew/lime"
|
||||
},
|
||||
{
|
||||
"name": "newgrounds",
|
||||
@@ -212,21 +184,21 @@
|
||||
"name": "openfl",
|
||||
"type": "git",
|
||||
"dir": null,
|
||||
"ref": "db060809f0ac293fb873964d7a076762c85adb71",
|
||||
"url": "https://github.com/FunkinCrew/openfl-mobile"
|
||||
"ref": "e6296200292a76b5f7b8684a991ead6b05ae4507",
|
||||
"url": "https://github.com/FunkinCrew/openfl"
|
||||
},
|
||||
{
|
||||
"name": "polymod",
|
||||
"type": "git",
|
||||
"dir": null,
|
||||
"ref": "6a3f3793c29ec2922630854ba5186f6f1d73d25a",
|
||||
"ref": "47d9a2775e3fd8f6dd17d6f4b99b8798709da435",
|
||||
"url": "https://github.com/larsiusprime/polymod"
|
||||
},
|
||||
{
|
||||
"name": "thx.core",
|
||||
"type": "git",
|
||||
"dir": null,
|
||||
"ref": "76d87418fadd92eb8e1b61f004cff27d656e53dd",
|
||||
"ref": "2bf2b992e06159510f595554e6b952e47922f128",
|
||||
"url": "https://github.com/fponticelli/thx.core"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# Organizes astc-compression-data alphabetically because i hate it when it's not organized -zack
|
||||
|
||||
$InputFile = "./astc-compression-data.json"
|
||||
$OutputFile = "./astc-compression-data.json"
|
||||
|
||||
if (-not (Test-Path $InputFile)) {
|
||||
Write-Host "❌ File $InputFile not found"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if (-not (Get-Command jq -ErrorAction SilentlyContinue)) {
|
||||
Write-Host "jq is not installed. Download from https://jqlang.github.io/jq/ or install via:"
|
||||
Write-Host " winget install jqlang.jq"
|
||||
exit 1
|
||||
}
|
||||
|
||||
jq '.
|
||||
| .custom = ( .custom | sort_by(.asset) )
|
||||
| .excludes = ( .excludes | sort )
|
||||
' $InputFile | Out-File -Encoding utf8 $OutputFile
|
||||
|
||||
Write-Host "✅ Sorted JSON written to $OutputFile WOOHOOO !!"
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
# Organizes astc-compression-data alphabetically because i hate it when it's not organized -zack
|
||||
|
||||
INPUT_FILE="./astc-compression-data.json"
|
||||
OUTPUT_FILE="./astc-compression-data.json"
|
||||
|
||||
# Check jq
|
||||
if ! command -v jq &> /dev/null; then
|
||||
echo "jq is not installed. Install it with:"
|
||||
echo " macOS: brew install jq"
|
||||
echo " Linux (Debian/Ubuntu): sudo apt-get install jq"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$INPUT_FILE" ]; then
|
||||
echo "❌ File $INPUT_FILE not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
jq '.
|
||||
| .custom = ( .custom | sort_by(.asset) )
|
||||
| .excludes = ( .excludes | sort )
|
||||
' "$INPUT_FILE" > "$OUTPUT_FILE".tmp && mv "$OUTPUT_FILE".tmp "$OUTPUT_FILE"
|
||||
|
||||
echo "✅ Sorted JSON written to $OUTPUT_FILE WOOHOOO !!"
|
||||
+402
-129
@@ -5,8 +5,10 @@ import hxp.*;
|
||||
import lime.tools.*;
|
||||
import sys.FileSystem;
|
||||
import sys.io.File;
|
||||
import haxe.io.Bytes;
|
||||
import haxe.io.Path;
|
||||
import haxe.ds.Map;
|
||||
import haxe.xml.Printer;
|
||||
|
||||
using StringTools;
|
||||
|
||||
@@ -29,13 +31,13 @@ class Project extends HXProject
|
||||
* REMEMBER TO CHANGE THIS WHEN THE GAME UPDATES!
|
||||
* You only have to change it here, the rest of the game will query this value.
|
||||
*/
|
||||
static final VERSION:String = "0.7.0";
|
||||
static final VERSION:String = "0.7.5";
|
||||
|
||||
/**
|
||||
* The build's number and version code.
|
||||
* Used when publishing the game to mobile app stores. Should increment with each patch.
|
||||
*/
|
||||
static final BUILD_NUMBER:Int = 2;
|
||||
static final BUILD_NUMBER:Int = 56;
|
||||
|
||||
/**
|
||||
* The game's name. Used as the default window title.
|
||||
@@ -58,6 +60,11 @@ class Project extends HXProject
|
||||
*/
|
||||
static final SOURCE_DIR:String = "source";
|
||||
|
||||
/**
|
||||
* The relative location of the templates folder.
|
||||
*/
|
||||
static final TEMPLATES_DIR:String = "templates";
|
||||
|
||||
/**
|
||||
* The fully qualified class path for the game's preloader.
|
||||
* Particularly important on HTML5 but we use it on all platforms.
|
||||
@@ -101,30 +108,13 @@ class Project extends HXProject
|
||||
*/
|
||||
static final ANDROID_TARGET_SDK_VERSION:Int = 35;
|
||||
|
||||
//
|
||||
// ASTC COMPRESSION
|
||||
//
|
||||
|
||||
/**
|
||||
* The quality of the compression process.
|
||||
* This doesn't exactly reduce the quality of the outputted texture..
|
||||
* But it changes how hard the CPU gotta work to maintin the quality and details of the image while compressing.
|
||||
* possible values: fastest, fast, medium, thorough, exhaustive.
|
||||
*/
|
||||
static var ASTC_QUALITY:String = "medium";
|
||||
static final ANDROID_EXTENSIONS:Array<String> = ["funkin.extensions.CallbackUtil"];
|
||||
|
||||
/**
|
||||
* The team ID to use for the iOS app. Configured in XCode.
|
||||
*/
|
||||
static var IOS_TEAM_ID:String = "Z7G7AVNGSH";
|
||||
|
||||
/**
|
||||
* The block size of the ASTC compressed textures.
|
||||
* Higher block size means lower quality and lighter file size for the generated compressed textures.
|
||||
* possible block sizes: 4x4, 4x6, 6x6, 8x8 ... 12x12.
|
||||
*/
|
||||
static var ASTC_BLOCKSIZE:String = "10x10";
|
||||
|
||||
/**
|
||||
* A list of asset file globs to exclude from ASTC compression when creating optimized mobile builds.
|
||||
*/
|
||||
@@ -328,10 +318,10 @@ class Project extends HXProject
|
||||
static final FEATURE_HAPTICS:FeatureFlag = "FEATURE_HAPTICS";
|
||||
|
||||
/**
|
||||
* `-DFEATURE_INPUT_OFFSETS`
|
||||
* `-DFEATURE_LAG_ADJUSTMENT`
|
||||
* If this flag is enabled, the input offsets menu will be available to configure your audio and visual offsets.
|
||||
*/
|
||||
static final FEATURE_INPUT_OFFSETS:FeatureFlag = "FEATURE_INPUT_OFFSETS";
|
||||
static final FEATURE_LAG_ADJUSTMENT:FeatureFlag = "FEATURE_LAG_ADJUSTMENT";
|
||||
|
||||
/**
|
||||
* `-DFEATURE_LOG_TRACE`
|
||||
@@ -340,6 +330,13 @@ class Project extends HXProject
|
||||
*/
|
||||
static final FEATURE_LOG_TRACE:FeatureFlag = "FEATURE_LOG_TRACE";
|
||||
|
||||
/**
|
||||
* `-DFEATURE_DEBUG_FILE_LOGGING`
|
||||
* If this flag is enabled, the game will print debug traces to a log file near the game's executable.
|
||||
* Disable to improve performance a bunch.
|
||||
*/
|
||||
static final FEATURE_DEBUG_FILE_LOGGING:FeatureFlag = "FEATURE_DEBUG_FILE_LOGGING";
|
||||
|
||||
/**
|
||||
* `-DFEATURE_MOBILE_ADVERTISEMENTS`
|
||||
* If this flag is enabled, Google AdMob will be enabled.
|
||||
@@ -485,9 +482,11 @@ class Project extends HXProject
|
||||
envConfig = readEnvironmentFile("./.env");
|
||||
|
||||
flair();
|
||||
|
||||
configureApp();
|
||||
|
||||
displayTarget();
|
||||
|
||||
configureFeatureFlags();
|
||||
configureCompileDefines();
|
||||
configureIncludeMacros();
|
||||
@@ -495,14 +494,12 @@ class Project extends HXProject
|
||||
configureOutputDir();
|
||||
configurePolymod();
|
||||
configureHaxelibs();
|
||||
configureASTCTextures();
|
||||
configureAssets();
|
||||
configureIcons();
|
||||
|
||||
readASTCExclusion();
|
||||
|
||||
if (FEATURE_COMPRESSED_TEXTURES.isEnabled(this))
|
||||
if (!isLinux())
|
||||
{
|
||||
runASTCCompressor();
|
||||
configureIcons();
|
||||
}
|
||||
|
||||
if (FEATURE_MOBILE_ADVERTISEMENTS.isEnabled(this))
|
||||
@@ -510,26 +507,20 @@ class Project extends HXProject
|
||||
configureAdMobKeys();
|
||||
}
|
||||
|
||||
// To sign in ios, use -xcode.
|
||||
if (isAndroid())
|
||||
{
|
||||
if (isRelease())
|
||||
{
|
||||
configureAndroidRelease();
|
||||
}
|
||||
configureAndroid();
|
||||
}
|
||||
|
||||
if (isIOS())
|
||||
{
|
||||
config.set("ios.non-exempt-encryption", "false");
|
||||
config.set("ios.team-id", IOS_TEAM_ID);
|
||||
config.set("ios.deployment", "16.0");
|
||||
|
||||
// launchStoryboard = new LaunchStoryboard();
|
||||
// launchStoryboard.path = "./LaunchScreen.storyboard";
|
||||
configureIOS();
|
||||
}
|
||||
|
||||
info("Done configuring project.");
|
||||
if (!isDisplay())
|
||||
{
|
||||
checkLibraries();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -538,10 +529,9 @@ class Project extends HXProject
|
||||
function flair()
|
||||
{
|
||||
// TODO: Implement this.
|
||||
info("Friday Night Funkin'");
|
||||
info("Friday Night Funkin' - " + VERSION);
|
||||
info("Initializing build...");
|
||||
|
||||
info("Target Version: " + VERSION);
|
||||
info("Git Branch: " + getGitBranch());
|
||||
info("Git Commit: " + getGitCommit());
|
||||
info("Git Modified? " + getGitModified());
|
||||
@@ -555,6 +545,10 @@ class Project extends HXProject
|
||||
function configureApp()
|
||||
{
|
||||
this.meta.title = TITLE;
|
||||
|
||||
// ios uses this character code instead of spaces...
|
||||
if (isIOS()) this.meta.title = ~/ /ig.replace(TITLE, "\u2002");
|
||||
|
||||
this.meta.version = VERSION;
|
||||
this.meta.packageName = PACKAGE_NAME;
|
||||
this.meta.company = COMPANY;
|
||||
@@ -567,6 +561,9 @@ class Project extends HXProject
|
||||
// If for some reason we have multiple source directories, we can add more entries here.
|
||||
this.sources.push(SOURCE_DIR);
|
||||
|
||||
// Templates stuff
|
||||
this.templatePaths.push(TEMPLATES_DIR);
|
||||
|
||||
// Tell Lime to run some prebuild and postbuild scripts.
|
||||
this.preBuildCallbacks.push(buildHaxeCLICommand(PREBUILD_HX));
|
||||
this.postBuildCallbacks.push(buildHaxeCLICommand(POSTBUILD_HX));
|
||||
@@ -796,8 +793,13 @@ class Project extends HXProject
|
||||
// FEATURE FLAGS
|
||||
//
|
||||
|
||||
// Should be true on debug builds or if GITHUB_BUILD is enabled.
|
||||
FEATURE_DEBUG_FUNCTIONS.apply(this, isDebug() || GITHUB_BUILD.isEnabled(this));
|
||||
FEATURE_RESULTS_DEBUG.apply(this, isDebug() || GITHUB_BUILD.isEnabled(this));
|
||||
|
||||
FEATURE_FUNKVIS.apply(this, true);
|
||||
FEATURE_LOG_TRACE.apply(this, true);
|
||||
FEATURE_DEBUG_FILE_LOGGING.apply(this, FEATURE_DEBUG_FUNCTIONS.isEnabled(this));
|
||||
FEATURE_NAUGHTYNESS.apply(this, true);
|
||||
FEATURE_OPEN_URL.apply(this, true);
|
||||
FEATURE_PARTIAL_SOUNDS.apply(this, true);
|
||||
@@ -807,10 +809,6 @@ class Project extends HXProject
|
||||
// HXCPP has trouble with iOS simulator builds though...
|
||||
FEATURE_VIDEO_PLAYBACK.apply(this, !isIOSSimulator());
|
||||
|
||||
// Should be true on debug builds or if GITHUB_BUILD is enabled.
|
||||
FEATURE_DEBUG_FUNCTIONS.apply(this, isDebug() || GITHUB_BUILD.isEnabled(this));
|
||||
FEATURE_RESULTS_DEBUG.apply(this, isDebug() || GITHUB_BUILD.isEnabled(this));
|
||||
|
||||
// Should be true on desktop, non-tester builds.
|
||||
// We don't want testers to accidentally leak songs to their Discord friends!
|
||||
FEATURE_DISCORD_RPC.apply(this, isDesktop() && !FEATURE_DEBUG_FUNCTIONS.isEnabled(this));
|
||||
@@ -830,7 +828,7 @@ class Project extends HXProject
|
||||
FEATURE_STAGE_EDITOR.apply(this, !(isWeb() || isMobile()));
|
||||
|
||||
// Should be true except on web builds (some asset stuff breaks it)
|
||||
FEATURE_INPUT_OFFSETS.apply(this, !isWeb());
|
||||
FEATURE_LAG_ADJUSTMENT.apply(this, !isWeb());
|
||||
|
||||
// Should be true except on web and mobile builds.
|
||||
// Screenshots doesn't work there, and mobile has its own screenshots anyway.
|
||||
@@ -861,6 +859,73 @@ class Project extends HXProject
|
||||
// Since mobile is pretty memory safe (I'm looking at you Apple...) we need them BADLY to have the game run properly.
|
||||
// It's kept off for desktop due to the low ASTC support on desktop GPUs (which seem to be only among Intergrated Graphics).
|
||||
FEATURE_COMPRESSED_TEXTURES.apply(this, isMobile() && isRelease());
|
||||
|
||||
renderFlagsTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a cute little table of which feature flags are enabled and which are disabled
|
||||
*/
|
||||
function renderFlagsTable():Void
|
||||
{
|
||||
var enabledWidth:Int = 0;
|
||||
var disabledWidth:Int = 0;
|
||||
var enabledFlags:Array<String> = [];
|
||||
var disabledFlags:Array<String> = [];
|
||||
var unicodeCheck:String = "✓ ";
|
||||
var unicodeCross:String = "× ";
|
||||
|
||||
if (isWindowsHost())
|
||||
{
|
||||
#if (!target.unicode)
|
||||
// lime build tools uses neko (unless compiling with `-eval`), and neko on windows doesn't support UTF8/unicode characters
|
||||
// so we need to remove our cute emoji!
|
||||
unicodeCheck = "o ";
|
||||
unicodeCross = "x ";
|
||||
#end
|
||||
}
|
||||
|
||||
for (flagStr in this.haxedefs.keys())
|
||||
{
|
||||
if (!flagStr.startsWith(FeatureFlag.INVERSE_PREFIX))
|
||||
{
|
||||
// we do flagStr.length + 3 to accomodate for adding the "✓ " at the beginning
|
||||
enabledWidth = Std.int(Math.max(flagStr.length + 3, enabledWidth));
|
||||
enabledFlags.push(unicodeCheck + flagStr);
|
||||
}
|
||||
else
|
||||
{
|
||||
disabledWidth = Std.int(Math.max(flagStr.length, disabledWidth));
|
||||
disabledFlags.push(unicodeCross + flagStr.substring(FeatureFlag.INVERSE_PREFIX.length));
|
||||
}
|
||||
}
|
||||
|
||||
enabledFlags.sort(function(a, b) return a > b ? 1 : -1);
|
||||
disabledFlags.sort(function(a, b) return a > b ? 1 : -1);
|
||||
|
||||
var horizontalDivider:String = "".rpad("-", enabledWidth + disabledWidth);
|
||||
|
||||
info(horizontalDivider);
|
||||
// Header
|
||||
info("FEATURE FLAGS");
|
||||
info('Enabled Flags $unicodeCheck'.rpad(" ", enabledWidth + 5) + 'Disabled Flags $unicodeCross');
|
||||
info(horizontalDivider);
|
||||
|
||||
while (enabledFlags.length > 0 || disabledFlags.length > 0)
|
||||
{
|
||||
var outputLine:String = "";
|
||||
|
||||
if (enabledFlags.length > 0) outputLine += enabledFlags.shift();
|
||||
|
||||
outputLine = outputLine.rpad(" ", enabledWidth + 5);
|
||||
outputLine += "| ";
|
||||
|
||||
if (disabledFlags.length > 0) outputLine += disabledFlags.shift() ?? "";
|
||||
|
||||
info(outputLine);
|
||||
}
|
||||
|
||||
info(horizontalDivider);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -889,6 +954,11 @@ class Project extends HXProject
|
||||
setHaxedef("FLX_NO_DEBUG");
|
||||
}
|
||||
|
||||
if (FEATURE_LOG_TRACE.isDisabled(this))
|
||||
{
|
||||
setHaxedef("no-traces");
|
||||
}
|
||||
|
||||
// Disable the built in pause screen when unfocusing the game.
|
||||
setHaxedef("FLX_NO_FOCUS_LOST_SCREEN");
|
||||
|
||||
@@ -969,48 +1039,82 @@ class Project extends HXProject
|
||||
// we use a dedicated 'tracy' folder, since it generally needs a recompile when in use
|
||||
if (FEATURE_DEBUG_TRACY.isEnabled(this)) buildDir += "-tracy";
|
||||
|
||||
info('Output directory: $buildDir');
|
||||
|
||||
// trailing slash might not be needed, works fine on macOS without it, but I haven't tested on Windows!
|
||||
buildDir += "/";
|
||||
|
||||
info('Output directory: $buildDir');
|
||||
// setenv('BUILD_DIR', buildDir);
|
||||
app.path = buildDir;
|
||||
}
|
||||
|
||||
function configureAndroidRelease()
|
||||
function configureAndroid()
|
||||
{
|
||||
if (envConfig != null)
|
||||
javaPaths.push(Path.join([SOURCE_DIR, 'funkin/external/android/java']));
|
||||
|
||||
if (isRelease())
|
||||
{
|
||||
keystore = new Keystore();
|
||||
keystore.path = Std.string(envConfig.get('ANDROID_KEYSTORE_PATH'));
|
||||
keystore.alias = Std.string(envConfig.get('ANDROID_KEYSTORE_ALIAS'));
|
||||
keystore.password = Std.string(envConfig.get('ANDROID_KEYSTORE_PASSWORD'));
|
||||
if (envConfig != null)
|
||||
{
|
||||
keystore = new Keystore();
|
||||
keystore.path = Std.string(envConfig.get('KEYSTORE_PATH'));
|
||||
keystore.alias = Std.string(envConfig.get('KEYSTORE_ALIAS'));
|
||||
keystore.password = Std.string(envConfig.get('KEYSTORE_PASSWORD'));
|
||||
}
|
||||
|
||||
if (isBundle())
|
||||
{
|
||||
config.set("android.gradle-project-directory", "bin-bundle");
|
||||
}
|
||||
}
|
||||
|
||||
Reflect.setField(config.get('android.manifest'), 'xmlns:tools', 'http://schemas.android.com/tools');
|
||||
final modsFolderProvider:Xml = Xml.createElement('provider');
|
||||
modsFolderProvider.set('android:authorities', '$PACKAGE_NAME.docprovider');
|
||||
modsFolderProvider.set('android:name', 'funkin.provider.DataFolderProvider');
|
||||
modsFolderProvider.set('android:grantUriPermissions', 'true');
|
||||
modsFolderProvider.set('android:exported', 'true');
|
||||
modsFolderProvider.set('android:permission', 'android.permission.MANAGE_DOCUMENTS');
|
||||
|
||||
final permissionsConfig:Array<String> = [
|
||||
'<uses-permission android:name="android.permission.READ_PHONE_STATE" tools:node="remove" />',
|
||||
'<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="remove" />'
|
||||
];
|
||||
final intentFilter:Xml = Xml.createElement('intent-filter');
|
||||
|
||||
final xmlChildren:Null<Array<String>> = config.get('android.manifest').xmlChildren;
|
||||
final action:Xml = Xml.createElement('action');
|
||||
action.set('android:name', 'android.content.action.DOCUMENTS_PROVIDER');
|
||||
intentFilter.addChild(action);
|
||||
|
||||
if (xmlChildren != null)
|
||||
modsFolderProvider.addChild(intentFilter);
|
||||
|
||||
@:nullSafety(Off)
|
||||
{
|
||||
config.get('android.manifest').xmlChildren = xmlChildren.concat(permissionsConfig);
|
||||
}
|
||||
else
|
||||
{
|
||||
config.get('android.manifest').xmlChildren = permissionsConfig;
|
||||
if (config.get('android.application').xmlChildren != null)
|
||||
{
|
||||
config.get('android.application').xmlChildren.push(Printer.print(modsFolderProvider));
|
||||
}
|
||||
else
|
||||
{
|
||||
config.get('android.application').xmlChildren = [Printer.print(modsFolderProvider)];
|
||||
}
|
||||
}
|
||||
|
||||
if (isBundle())
|
||||
final extensions:Null<Array<String>> = config.getArrayString('android.extension');
|
||||
|
||||
for (extension in ANDROID_EXTENSIONS)
|
||||
{
|
||||
config.set("android.gradle-project-directory", "bin-bundle");
|
||||
if (extensions == null || extensions != null && extensions.indexOf(extension) == -1)
|
||||
{
|
||||
config.push("android.extension", extension);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function configureIOS()
|
||||
{
|
||||
config.set("ios.non-exempt-encryption", "false");
|
||||
config.set("ios.team-id", IOS_TEAM_ID);
|
||||
config.set("ios.deployment", "16.0");
|
||||
|
||||
// launchStoryboard = new LaunchStoryboard();
|
||||
// launchStoryboard.path = "./LaunchScreen.storyboard";
|
||||
}
|
||||
|
||||
function configurePolymod()
|
||||
{
|
||||
// The file extension to use for script files.
|
||||
@@ -1190,7 +1294,14 @@ class Project extends HXProject
|
||||
addAsset("LICENSE.md", "LICENSE.md", "art", shouldEmbedArt);
|
||||
addAsset("CHANGELOG.md", "CHANGELOG.md", "art", shouldEmbedArt);
|
||||
|
||||
info('Done configuring assets.');
|
||||
if (shouldEmbed)
|
||||
{
|
||||
info('Done embedding assets.');
|
||||
}
|
||||
else
|
||||
{
|
||||
info('Done including assets.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1203,27 +1314,7 @@ class Project extends HXProject
|
||||
if (isAndroid())
|
||||
{
|
||||
// Adaptive icons
|
||||
// TODO: Add Adapative Icons in Lime
|
||||
templatePaths.push("templates");
|
||||
|
||||
var androidTheme:String = "@style/LimeAppMainTheme";
|
||||
if (window.fullscreen != null && window.fullscreen)
|
||||
{
|
||||
androidTheme += "Fullscreen";
|
||||
}
|
||||
|
||||
final iconXmlChild:Dynamic = {
|
||||
"android:label": meta.title,
|
||||
"android:allowBackup": "true",
|
||||
"android:theme": androidTheme,
|
||||
"android:hardwareAccelerated": "true",
|
||||
"android:allowNativeHeapPointerTagging": ANDROID_TARGET_SDK_VERSION >= 30 ? "false" : null,
|
||||
"android:largeHeap": "true",
|
||||
"android:icon": "@mipmap/ic_launcher",
|
||||
"android:roundIcon": "@mipmap/ic_launcher_round"
|
||||
};
|
||||
|
||||
config.set('android.application', iconXmlChild);
|
||||
adaptiveIcon = new AdaptiveIcon('art/icons/android/', true);
|
||||
}
|
||||
else if (isIOS())
|
||||
{
|
||||
@@ -1254,8 +1345,24 @@ class Project extends HXProject
|
||||
addIcon("art/icons/icon32.png", 32);
|
||||
addIcon("art/icons/icon64.png", 64);
|
||||
addIcon("art/icons/iconOG.png");
|
||||
}
|
||||
|
||||
info('Done configuring icons.');
|
||||
info('Done configuring icons.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the astc textures.
|
||||
*/
|
||||
function configureASTCTextures()
|
||||
{
|
||||
if (!(isDisplay() || isClean()))
|
||||
{
|
||||
readASTCExclusion();
|
||||
|
||||
if (FEATURE_COMPRESSED_TEXTURES.isEnabled(this))
|
||||
{
|
||||
runASTCCompressor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1266,15 +1373,7 @@ class Project extends HXProject
|
||||
{
|
||||
if (envConfig == null) return;
|
||||
|
||||
if (isAndroid())
|
||||
{
|
||||
setenv("ADMOB_APPID", Std.string(envConfig.get('ANDROID_ADMOB_APP_ID')));
|
||||
}
|
||||
|
||||
if (isIOS())
|
||||
{
|
||||
setenv("ADMOB_APPID", Std.string(envConfig.get('IOS_ADMOB_APP_ID')));
|
||||
}
|
||||
setenv("ADMOB_APPID", Std.string(envConfig.get('ADMOB_APP_ID')));
|
||||
}
|
||||
|
||||
//
|
||||
@@ -1312,6 +1411,21 @@ class Project extends HXProject
|
||||
return this.architectures.contains(Architecture.X64);
|
||||
}
|
||||
|
||||
public function isWindowsHost():Bool
|
||||
{
|
||||
return System.hostPlatform == WINDOWS;
|
||||
}
|
||||
|
||||
public function isMacHost():Bool
|
||||
{
|
||||
return System.hostPlatform == MAC;
|
||||
}
|
||||
|
||||
public function isLinuxHost():Bool
|
||||
{
|
||||
return System.hostPlatform == LINUX;
|
||||
}
|
||||
|
||||
public function isWindows():Bool
|
||||
{
|
||||
return this.target == Platform.WINDOWS;
|
||||
@@ -1372,6 +1486,11 @@ class Project extends HXProject
|
||||
return this.command == "display";
|
||||
}
|
||||
|
||||
public function isClean():Bool
|
||||
{
|
||||
return this.command == "clean";
|
||||
}
|
||||
|
||||
public function isDebug():Bool
|
||||
{
|
||||
return this.debug;
|
||||
@@ -1594,6 +1713,101 @@ class Project extends HXProject
|
||||
return commitHashSplice;
|
||||
}
|
||||
|
||||
@SuppressWarnings('checkstyle:Dynamic')
|
||||
static function checkLibraries():Void
|
||||
{
|
||||
var outdatedLibraries:Map<String, Array<String>> = new Map<String, Array<String>>();
|
||||
|
||||
var hmmData:Dynamic = haxe.Json.parse(sys.io.File.getContent(#if ios '../../../../../' + #end 'hmm.json'));
|
||||
|
||||
var dependencies:Array<Dynamic> = cast hmmData.dependencies;
|
||||
|
||||
for (library in dependencies)
|
||||
{
|
||||
var libraryName:String = cast(library.name, String).replace(".", ",");
|
||||
|
||||
var libraryDev:String = readLibraryDev(libraryName);
|
||||
|
||||
var libraryCurrentVersion:String = readLibraryCurrentVersion(libraryName);
|
||||
|
||||
switch (library.type)
|
||||
{
|
||||
case 'haxelib':
|
||||
if (libraryDev != "")
|
||||
{
|
||||
outdatedLibraries.set(libraryName, [libraryDev, library.version]);
|
||||
}
|
||||
else if (library.version != libraryCurrentVersion)
|
||||
{
|
||||
outdatedLibraries.set(libraryName, [libraryCurrentVersion, library.version]);
|
||||
}
|
||||
case 'git':
|
||||
if (libraryDev != "")
|
||||
{
|
||||
outdatedLibraries.set(libraryName, [libraryDev, library.ref]);
|
||||
}
|
||||
else
|
||||
{
|
||||
var commitHash:String = readLibraryGitCommitHash(libraryName);
|
||||
|
||||
if (commitHash != library.ref && commitHash != "")
|
||||
outdatedLibraries.set(libraryName, [commitHash, library.ref]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Lambda.count(outdatedLibraries) > 0)
|
||||
{
|
||||
Sys.println("\x1b[1;33m\nWARNING: The following haxelibs diverge from the versions set in hmm.json."
|
||||
+ "\n\nThey may be outdated, so it is recommended to abort compilation and run `hmm reinstall [library]` to update each library."
|
||||
+ "\n\nYou may ignore this warning if your libraries are newer than the versions in hmm.json, or if you know what you're doing.\n\x1b[0m");
|
||||
|
||||
for (libraryName in outdatedLibraries.keys())
|
||||
{
|
||||
var versions:Null<Array<String>> = outdatedLibraries.get(libraryName);
|
||||
if (versions == null) continue;
|
||||
|
||||
var outdatedVersion:String = versions[0];
|
||||
var expectedVersion:String = versions[1];
|
||||
|
||||
var isDev:Bool = outdatedVersion.contains("/");
|
||||
|
||||
Sys.println("- " + libraryName.replace(",", ".") + (isDev ? "\x1b[1;34m (Development Build)\x1b[0m" : ""));
|
||||
Sys.println(" \x1b[38;5;203mCurrent version: " + outdatedVersion + "\x1b[0m");
|
||||
Sys.println(" \x1b[38;5;82mExpected version: " + expectedVersion + "\x1b[0m\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static function readLibraryCurrentVersion(libraryName:String):String
|
||||
{
|
||||
var path = haxe.io.Path.join([haxe.io.Path.addTrailingSlash(Sys.getCwd()), '.haxelib', libraryName, '.current']);
|
||||
|
||||
if (sys.FileSystem.exists(path))
|
||||
return sys.io.File.getContent(path);
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
static function readLibraryDev(libraryName:String):String
|
||||
{
|
||||
var path = haxe.io.Path.join([haxe.io.Path.addTrailingSlash(Sys.getCwd()), '.haxelib', libraryName, '.dev']);
|
||||
|
||||
if (sys.FileSystem.exists(path))
|
||||
return sys.io.File.getContent(path);
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
static function readLibraryGitCommitHash(libraryName:String):String
|
||||
{
|
||||
var gitProccess = new sys.io.Process("git", ["-C", ".haxelib/" + libraryName + "/git", "rev-parse", "HEAD"]);
|
||||
|
||||
gitProccess.exitCode(true);
|
||||
|
||||
return gitProccess.stdout.readAll().toString().trim();
|
||||
}
|
||||
|
||||
public function getGitBranch():String
|
||||
{
|
||||
// Cannibalized from GitCommit.hx
|
||||
@@ -1655,7 +1869,8 @@ class Project extends HXProject
|
||||
*/
|
||||
public function error(message:String):Void
|
||||
{
|
||||
Log.error('${message}');
|
||||
Sys.stderr().write(Bytes.ofString('[ERROR] ${message}'));
|
||||
Sys.exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1663,9 +1878,9 @@ class Project extends HXProject
|
||||
*/
|
||||
public function info(message:String):Void
|
||||
{
|
||||
if (command != "display")
|
||||
if (!(isDisplay() || isClean()))
|
||||
{
|
||||
Log.info('[INFO] ${message}');
|
||||
Sys.println('[INFO] ${message}');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1690,48 +1905,114 @@ class Project extends HXProject
|
||||
}
|
||||
|
||||
var env = new Map<String, Dynamic>();
|
||||
|
||||
for (line in envFile.split('\n'))
|
||||
{
|
||||
if (line == "" || line.startsWith("#")) continue;
|
||||
line = line.trim();
|
||||
|
||||
var parts = line.split('=');
|
||||
if (parts.length != 2) continue;
|
||||
if (line.length <= 0 || line.startsWith('#') || shouldExcludeEnvKey(line))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
env.set(parts[0], parts[1]);
|
||||
final index:Int = line.indexOf('=');
|
||||
|
||||
if (index == -1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
final value:String = line.substr(index + 1);
|
||||
|
||||
if (value.length == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
env.set(stripEnvTargetPrefix(line.substr(0, index)), value);
|
||||
}
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
public function shouldExcludeEnvKey(key:String):Bool
|
||||
{
|
||||
final android:Bool = key.startsWith('ANDROID_');
|
||||
final ios:Bool = key.startsWith('IOS_');
|
||||
final mobile:Bool = key.startsWith('MOBILE_') || ios || android;
|
||||
final web:Bool = key.startsWith('WEB_');
|
||||
final desktop:Bool = key.startsWith('DESKTOP_');
|
||||
|
||||
if (isWeb() && (mobile || desktop)) return true;
|
||||
if (isDesktop() && (mobile || web)) return true;
|
||||
if (isAndroid() && (ios || web || desktop)) return true;
|
||||
if (isIOS() && (android || web || desktop)) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function stripEnvTargetPrefix(key:String):String
|
||||
{
|
||||
final index:Int = key.indexOf('_');
|
||||
|
||||
if (index == -1)
|
||||
{
|
||||
return key;
|
||||
}
|
||||
|
||||
final prefix:String = key.substr(0, index);
|
||||
final rest:String = key.substr(index + 1);
|
||||
|
||||
if (isAndroid() && (prefix == 'ANDROID' || prefix == 'MOBILE'))
|
||||
{
|
||||
return rest;
|
||||
}
|
||||
else if (isIOS() && (prefix == 'IOS' || prefix == 'MOBILE'))
|
||||
{
|
||||
return rest;
|
||||
}
|
||||
else if (isWeb() && prefix == 'WEB')
|
||||
{
|
||||
return rest;
|
||||
}
|
||||
else if (isDesktop() && prefix == 'DESKTOP')
|
||||
{
|
||||
return rest;
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
public function readASTCExclusion():Void
|
||||
{
|
||||
astcExcludes = File.getContent('./compression-excludes.txt').trim().split('\n');
|
||||
@:nullSafety(Off)
|
||||
astcExcludes = haxe.Json.parse(File.getContent('./astc-compression-data.json')).excludes;
|
||||
|
||||
for (i in 0...astcExcludes.length)
|
||||
astcExcludes[i] = astcExcludes[i].trim();
|
||||
}
|
||||
|
||||
public function isASTCExcluded(filePath:String):Bool
|
||||
public function isASTCExcluded(file:String):Bool
|
||||
{
|
||||
for (exclusion in astcExcludes)
|
||||
{
|
||||
if (exclusion.endsWith("/*"))
|
||||
if (exclusion.endsWith("/"))
|
||||
{
|
||||
var normalizedFilePath = Path.normalize(filePath);
|
||||
var normalizedExclusion = Path.normalize(exclusion.substr(0, exclusion.length - 2));
|
||||
var normalizedFilePath = Path.normalize(file);
|
||||
var normalizedExclusion = Path.normalize(exclusion);
|
||||
|
||||
if (normalizedFilePath.startsWith(normalizedExclusion)) return true;
|
||||
}
|
||||
else if (exclusion.endsWith("/"))
|
||||
else if (exclusion.endsWith("/*"))
|
||||
{
|
||||
var normalizedExclusion = Path.normalize(exclusion);
|
||||
var fileDirectory = Path.directory(Path.normalize(filePath));
|
||||
var normalizedExclusion = Path.normalize(exclusion.substr(0, exclusion.length - 2));
|
||||
var fileDirectory = Path.directory(Path.normalize(file));
|
||||
|
||||
if (fileDirectory == normalizedExclusion) return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (filePath == exclusion) return true;
|
||||
if (file == exclusion) return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1742,16 +2023,12 @@ class Project extends HXProject
|
||||
{
|
||||
info('Compressing ASTC textures...');
|
||||
|
||||
var args:Array<String> = ['run', 'astc-compressor'];
|
||||
args = args.concat(['-i', './assets']);
|
||||
args = args.concat(['-o', './astc-textures/assets/']);
|
||||
args = args.concat(['-blocksize', ASTC_BLOCKSIZE]);
|
||||
args = args.concat(['-quality', ASTC_QUALITY]);
|
||||
args = args.concat(['-excludes', './compression-excludes.txt']);
|
||||
var args:Array<String> = ['run', 'astc-compressor', 'compress-from-json'];
|
||||
args = args.concat(['-json', './astc-compression-data.json']);
|
||||
|
||||
Sys.command('haxelib', args);
|
||||
|
||||
info('Finished compressing ASTC textures!');
|
||||
info('Done compressing ASTC textures.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1759,9 +2036,9 @@ class Project extends HXProject
|
||||
* An object representing a feature flag, which can be enabled or disabled.
|
||||
* Includes features such as automatic generation of compile defines and inversion.
|
||||
*/
|
||||
abstract FeatureFlag(String)
|
||||
abstract FeatureFlag(String) from String to String
|
||||
{
|
||||
static final INVERSE_PREFIX:String = "NO_";
|
||||
public static final INVERSE_PREFIX:String = "NO_";
|
||||
|
||||
public function new(input:String)
|
||||
{
|
||||
@@ -1786,13 +2063,11 @@ abstract FeatureFlag(String)
|
||||
if (isEnabled(project))
|
||||
{
|
||||
// If this flag was already enabled, disable the inverse.
|
||||
project.info('Enabling feature flag ${this}');
|
||||
getInverse().disable(project, false);
|
||||
}
|
||||
else if (getInverse().isEnabled(project))
|
||||
{
|
||||
// If the inverse flag was already enabled, disable this flag.
|
||||
project.info('Disabling feature flag ${this}');
|
||||
disable(project, false);
|
||||
}
|
||||
else
|
||||
@@ -1800,13 +2075,11 @@ abstract FeatureFlag(String)
|
||||
if (enableByDefault)
|
||||
{
|
||||
// Enable this flag if it was unset, and disable the inverse.
|
||||
project.info('Enabling feature flag ${this}');
|
||||
enable(project, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Disable this flag if it was unset, and enable the inverse.
|
||||
project.info('Disabling feature flag ${this}');
|
||||
disable(project, true);
|
||||
}
|
||||
}
|
||||
|
||||
+27
-52
@@ -6,13 +6,12 @@ import flixel.FlxState;
|
||||
import funkin.ui.FullScreenScaleMode;
|
||||
import funkin.Preferences;
|
||||
import funkin.util.logging.CrashHandler;
|
||||
import funkin.ui.debug.MemoryCounter;
|
||||
import funkin.ui.debug.FunkinDebugDisplay;
|
||||
import funkin.save.Save;
|
||||
import haxe.ui.Toolkit;
|
||||
#if hxvlc
|
||||
import hxvlc.util.Handle;
|
||||
#end
|
||||
import openfl.display.FPS;
|
||||
import openfl.display.Sprite;
|
||||
import openfl.events.Event;
|
||||
import openfl.Lib;
|
||||
@@ -30,7 +29,6 @@ class Main extends Sprite
|
||||
var initialState:Class<FlxState> = funkin.InitState; // The FlxState the game starts with.
|
||||
var zoom:Float = -1; // If -1, zoom is automatically calculated to fit the window dimensions.
|
||||
var skipSplash:Bool = true; // Whether to skip the flixel splash screen that appears in release mode.
|
||||
var startFullscreen:Bool = false; // Whether to start the game in fullscreen on desktop targets
|
||||
|
||||
// You can pretty much ignore everything from here on - your code should go in your states.
|
||||
|
||||
@@ -38,12 +36,11 @@ class Main extends Sprite
|
||||
{
|
||||
// Set the current working directory for Android and iOS devices
|
||||
#if android
|
||||
// For Android we determine the appropriate directory based on Android version
|
||||
Sys.setCwd(haxe.io.Path.addTrailingSlash(extension.androidtools.os.Build.VERSION.SDK_INT > 30 ? extension.androidtools.content.Context.getObbDir() : // Use Obb directory for Android SDK version > 30
|
||||
extension.androidtools.content.Context.getExternalFilesDir() // Use External Files directory for Android SDK version < 30
|
||||
));
|
||||
// On Android use External Files Dir.
|
||||
Sys.setCwd(haxe.io.Path.addTrailingSlash(extension.androidtools.content.Context.getExternalFilesDir()));
|
||||
#elseif ios
|
||||
Sys.setCwd(haxe.io.Path.addTrailingSlash(lime.system.System.documentsDirectory)); // For iOS we use documents directory and this is only way we can do.
|
||||
// On iOS use Documents Dir.
|
||||
Sys.setCwd(haxe.io.Path.addTrailingSlash(lime.system.System.documentsDirectory));
|
||||
#end
|
||||
|
||||
// We need to make the crash handler LITERALLY FIRST so nothing EVER gets past it.
|
||||
@@ -85,32 +82,17 @@ class Main extends Sprite
|
||||
setupGame();
|
||||
}
|
||||
|
||||
var video:Video;
|
||||
var netStream:NetStream;
|
||||
var overlay:Sprite;
|
||||
|
||||
/**
|
||||
* A frame counter displayed at the top left.
|
||||
* The debug display at the top left.
|
||||
*/
|
||||
public static var fpsCounter:FPS;
|
||||
|
||||
/**
|
||||
* A RAM counter displayed at the top left.
|
||||
*/
|
||||
public static var memoryCounter:MemoryCounter;
|
||||
public static var debugDisplay:FunkinDebugDisplay;
|
||||
|
||||
function setupGame():Void
|
||||
{
|
||||
initHaxeUI();
|
||||
|
||||
// addChild gets called by the user settings code.
|
||||
fpsCounter = new FPS(10, 3, 0xFFFFFF);
|
||||
|
||||
#if !html5
|
||||
// addChild gets called by the user settings code.
|
||||
// TODO: disabled on HTML5 (todo: find another method that works?)
|
||||
memoryCounter = new MemoryCounter(10, 13, 0xFFFFFF);
|
||||
#end
|
||||
debugDisplay = new FunkinDebugDisplay(10, 10, 0xFFFFFF);
|
||||
|
||||
#if mobile
|
||||
// Add this signal so we can reposition and resize the memory and fps counter.
|
||||
@@ -122,7 +104,16 @@ class Main extends Sprite
|
||||
|
||||
#if hxvlc
|
||||
// Initialize hxvlc's Handle here so the videos are loading faster.
|
||||
Handle.init();
|
||||
Handle.initAsync(function(success:Bool):Void {
|
||||
if (success)
|
||||
{
|
||||
trace('[HXVLC] LibVLC instance initialized!');
|
||||
}
|
||||
else
|
||||
{
|
||||
trace('[HXVLC] LibVLC instance failed to initialize!');
|
||||
}
|
||||
});
|
||||
#end
|
||||
|
||||
// Don't call anything from the preferences until the save is loaded!
|
||||
@@ -134,7 +125,8 @@ class Main extends Sprite
|
||||
|
||||
WindowUtil.setVSyncMode(funkin.Preferences.vsyncMode);
|
||||
|
||||
var game:FlxGame = new FlxGame(gameWidth, gameHeight, initialState, Preferences.framerate, Preferences.framerate, skipSplash, startFullscreen);
|
||||
var game:FlxGame = new FlxGame(gameWidth, gameHeight, initialState, Preferences.framerate, Preferences.framerate, skipSplash,
|
||||
(FlxG.stage.window.fullscreen || Preferences.autoFullscreen));
|
||||
|
||||
// FlxG.game._customSoundTray wants just the class, it calls new from
|
||||
// create() in there, which gets called when it's added to the stage
|
||||
@@ -146,6 +138,7 @@ class Main extends Sprite
|
||||
|
||||
#if FEATURE_DEBUG_FUNCTIONS
|
||||
game.debugger.interaction.addTool(new funkin.util.TrackerToolButtonUtil());
|
||||
funkin.util.macro.ConsoleMacro.init();
|
||||
#end
|
||||
|
||||
#if !html5
|
||||
@@ -191,41 +184,23 @@ class Main extends Sprite
|
||||
scale = Math.min(scale, 1);
|
||||
#end
|
||||
final thypos:Float = Math.max(FullScreenScaleMode.notchSize.x, 10);
|
||||
if (fpsCounter != null)
|
||||
|
||||
if (debugDisplay != null)
|
||||
{
|
||||
fpsCounter.scaleX = fpsCounter.scaleY = scale;
|
||||
debugDisplay.scaleX = debugDisplay.scaleY = scale;
|
||||
|
||||
if (FlxG.game != null)
|
||||
{
|
||||
if (lerp)
|
||||
{
|
||||
fpsCounter.x = flixel.math.FlxMath.lerp(fpsCounter.x, FlxG.game.x + thypos, FlxG.elapsed * 3);
|
||||
debugDisplay.x = flixel.math.FlxMath.lerp(debugDisplay.x, FlxG.game.x + thypos, FlxG.elapsed * 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
fpsCounter.x = FlxG.game.x + FullScreenScaleMode.notchSize.x + 10;
|
||||
debugDisplay.x = FlxG.game.x + FullScreenScaleMode.notchSize.x + 10;
|
||||
}
|
||||
|
||||
fpsCounter.y = FlxG.game.y + (3 * scale);
|
||||
}
|
||||
}
|
||||
|
||||
if (memoryCounter != null)
|
||||
{
|
||||
memoryCounter.scaleX = memoryCounter.scaleY = scale;
|
||||
|
||||
if (FlxG.game != null)
|
||||
{
|
||||
if (lerp)
|
||||
{
|
||||
memoryCounter.x = flixel.math.FlxMath.lerp(memoryCounter.x, FlxG.game.x + thypos, FlxG.elapsed * 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
memoryCounter.x = FlxG.game.x + FullScreenScaleMode.notchSize.x + 10;
|
||||
}
|
||||
|
||||
memoryCounter.y = FlxG.game.y + (13 * scale);
|
||||
debugDisplay.y = FlxG.game.y + (3 * scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+36
-5
@@ -3,6 +3,8 @@ package source; // Yeah, I know...
|
||||
import sys.FileSystem;
|
||||
import sys.io.File;
|
||||
|
||||
using StringTools;
|
||||
|
||||
/**
|
||||
* A script which executes after the game is built.
|
||||
*/
|
||||
@@ -27,14 +29,43 @@ class Postbuild
|
||||
|
||||
sys.FileSystem.deleteFile(BUILD_TIME_FILE);
|
||||
|
||||
var buildTime:Float = roundToTwoDecimals(end - start);
|
||||
|
||||
trace('Build took: ${buildTime} seconds');
|
||||
Sys.println('[INFO] Build took: ${format(end - start)}');
|
||||
}
|
||||
}
|
||||
|
||||
static function roundToTwoDecimals(value:Float):Float
|
||||
static function format(time:Float, decimals:Int = 1):String
|
||||
{
|
||||
return Math.round(value * 100) / 100;
|
||||
var units = [
|
||||
{name: "day", secs: 86400},
|
||||
{name: "hour", secs: 3600},
|
||||
{name: "minute", secs: 60},
|
||||
{name: "second", secs: 1}
|
||||
];
|
||||
|
||||
var parts:Array<String> = [];
|
||||
var remaining:Float = time;
|
||||
|
||||
for (unit in units)
|
||||
{
|
||||
var value:Float;
|
||||
if (unit.name == "second")
|
||||
{
|
||||
// handle seconds with decimals
|
||||
value = Math.round(remaining * Math.pow(10, decimals)) / Math.pow(10, decimals);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = Math.floor(remaining / unit.secs);
|
||||
remaining %= unit.secs;
|
||||
}
|
||||
|
||||
//
|
||||
if (value > 0 || (unit.name == "second" && parts.length == 0))
|
||||
{
|
||||
parts.push('${value} ${unit.name}${value == 1 ? "" : "s"}');
|
||||
}
|
||||
}
|
||||
|
||||
return parts.join(" ");
|
||||
}
|
||||
}
|
||||
|
||||
+2
-30
@@ -9,28 +9,16 @@ class Prebuild
|
||||
{
|
||||
static inline final BUILD_TIME_FILE:String = '.build_time';
|
||||
|
||||
static final NG_CREDS_PATH:String = './source/funkin/api/newgrounds/NewgroundsCredentials.hx';
|
||||
|
||||
static final NG_CREDS_TEMPLATE:String = "package funkin.api.newgrounds;
|
||||
|
||||
class NewgroundsCredentials
|
||||
{
|
||||
public static final APP_ID:String = #if API_NG_APP_ID haxe.macro.Compiler.getDefine(\"API_NG_APP_ID\") #else 'INSERT APP ID HERE' #end;
|
||||
public static final ENCRYPTION_KEY:String = #if API_NG_ENC_KEY haxe.macro.Compiler.getDefine(\"API_NG_ENC_KEY\") #else 'INSERT ENCRYPTION KEY HERE' #end;
|
||||
}";
|
||||
|
||||
static function main():Void
|
||||
{
|
||||
var start:Float = Sys.time();
|
||||
trace('[PREBUILD] Performing pre-build tasks...');
|
||||
// Sys.println('[INFO] Performing pre-build tasks...');
|
||||
|
||||
saveBuildTime();
|
||||
|
||||
buildCredsFile();
|
||||
|
||||
var end:Float = Sys.time();
|
||||
var duration:Float = end - start;
|
||||
trace('[PREBUILD] Finished pre-build tasks in $duration seconds.');
|
||||
// Sys.println('[INFO] Finished pre-build tasks in $duration seconds.');
|
||||
}
|
||||
|
||||
static function saveBuildTime():Void
|
||||
@@ -41,20 +29,4 @@ class NewgroundsCredentials
|
||||
fo.writeDouble(now);
|
||||
fo.close();
|
||||
}
|
||||
|
||||
static function buildCredsFile():Void
|
||||
{
|
||||
if (sys.FileSystem.exists(NG_CREDS_PATH))
|
||||
{
|
||||
trace('[PREBUILD] NewgroundsCredentials.hx already exists, skipping.');
|
||||
}
|
||||
else
|
||||
{
|
||||
trace('[PREBUILD] Creating NewgroundsCredentials.hx...');
|
||||
|
||||
var fileContents:String = NG_CREDS_TEMPLATE;
|
||||
|
||||
sys.io.File.saveContent(NG_CREDS_PATH, fileContents);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import flixel.util.FlxSignal;
|
||||
import flixel.math.FlxMath;
|
||||
import funkin.data.song.SongData.SongTimeChange;
|
||||
import funkin.data.song.SongDataUtils;
|
||||
import funkin.play.PlayState;
|
||||
import funkin.save.Save;
|
||||
import funkin.util.TimerUtil.SongSequence;
|
||||
import haxe.Timer;
|
||||
@@ -113,6 +114,17 @@ class Conductor
|
||||
|
||||
if (currentTimeChange == null) return Constants.DEFAULT_BPM;
|
||||
|
||||
@:privateAccess
|
||||
if (PlayState.instance != null && PlayState.instance.startingSong)
|
||||
{
|
||||
for (i in 0...timeChanges.length)
|
||||
{
|
||||
if (PlayState.instance.startTimestamp >= timeChanges[i].timeStamp) currentTimeChange = timeChanges[i];
|
||||
|
||||
if (PlayState.instance.startTimestamp < timeChanges[i].timeStamp) break;
|
||||
}
|
||||
}
|
||||
|
||||
return currentTimeChange.bpm;
|
||||
}
|
||||
|
||||
@@ -417,7 +429,7 @@ class Conductor
|
||||
// If the song is playing, limit the song position to the length of the song or beginning of the song.
|
||||
if (FlxG.sound.music != null && FlxG.sound.music.playing)
|
||||
{
|
||||
this.songPosition = FlxMath.bound(Math.min(this.combinedOffset, 0), songPos, currentLength);
|
||||
this.songPosition = Math.min(this.combinedOffset, 0).clamp(songPos, currentLength);
|
||||
this.songPositionDelta += FlxG.elapsed * 1000 * FlxG.sound.music.pitch;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -117,10 +117,7 @@ class FunkinMemory
|
||||
*/
|
||||
public static function cacheTexture(key:String):Void
|
||||
{
|
||||
if (currentCachedTextures.exists(key))
|
||||
{
|
||||
return; // Already cached.
|
||||
}
|
||||
if (currentCachedTextures.exists(key)) return;
|
||||
|
||||
if (previousCachedTextures.exists(key))
|
||||
{
|
||||
@@ -135,13 +132,13 @@ class FunkinMemory
|
||||
if (graphic == null)
|
||||
{
|
||||
FlxG.log.warn('Failed to cache graphic: $key');
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
trace('Successfully cached graphic: $key');
|
||||
graphic.persist = true;
|
||||
currentCachedTextures.set(key, graphic);
|
||||
}
|
||||
|
||||
trace('Successfully cached graphic: $key');
|
||||
graphic.persist = true;
|
||||
currentCachedTextures.set(key, graphic);
|
||||
forceRender(graphic);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -150,26 +147,55 @@ class FunkinMemory
|
||||
*/
|
||||
static function permanentCacheTexture(key:String):Void
|
||||
{
|
||||
if (permanentCachedTextures.exists(key))
|
||||
{
|
||||
return; // Already cached.
|
||||
}
|
||||
if (permanentCachedTextures.exists(key)) return;
|
||||
|
||||
var graphic:Null<FlxGraphic> = FlxGraphic.fromAssetKey(key, false, null, true);
|
||||
if (graphic == null)
|
||||
{
|
||||
FlxG.log.warn('Failed to cache graphic: $key');
|
||||
}
|
||||
else
|
||||
{
|
||||
trace('Successfully cached graphic: $key');
|
||||
graphic.persist = true;
|
||||
permanentCachedTextures.set(key, graphic);
|
||||
return;
|
||||
}
|
||||
|
||||
trace('Successfully cached graphic: $key');
|
||||
graphic.persist = true;
|
||||
permanentCachedTextures.set(key, graphic);
|
||||
forceRender(graphic);
|
||||
currentCachedTextures = permanentCachedTextures;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces the GPU to load and upload a FlxGraphic.
|
||||
*/
|
||||
private static function forceRender(graphic:FlxGraphic):Void
|
||||
{
|
||||
if (graphic == null) return;
|
||||
|
||||
var bmp:Null<FlxGraphic> = FlxG.bitmap.get(graphic.key);
|
||||
if (bmp != null && bmp.bitmap != null) var _:Int = bmp.bitmap.width; // Trigger
|
||||
|
||||
// Draws sprite and actually caches it.
|
||||
var sprite = new flixel.FlxSprite();
|
||||
sprite.loadGraphic(graphic);
|
||||
sprite.draw(); // Draw sprite and load it into game's memory.
|
||||
graphic.bitmap?.getTexture(FlxG.stage.context3D); // Just in case that didn't work...
|
||||
sprite.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks, if graphic with given path cached in memory.
|
||||
*/
|
||||
public static inline function isGraphicCached(path:String):Bool
|
||||
return permanentCachedTextures.exists(path) || currentCachedTextures.exists(path) || previousCachedTextures.exists(path);
|
||||
|
||||
public static function getCachedGraphic(path:String):Null<FlxGraphic>
|
||||
{
|
||||
if (permanentCachedTextures.exists(path)) return permanentCachedTextures.get(path);
|
||||
if (currentCachedTextures.exists(path)) return currentCachedTextures.get(path);
|
||||
if (previousCachedTextures.exists(path)) return previousCachedTextures.get(path); // just in case
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the cache for purging unused textures.
|
||||
*/
|
||||
@@ -350,7 +376,7 @@ class FunkinMemory
|
||||
if (sound != null)
|
||||
{
|
||||
Assets.cache.removeSound(key);
|
||||
previousCachedTextures.remove(key);
|
||||
previousCachedSounds.remove(key);
|
||||
}
|
||||
}
|
||||
Assets.cache.clear("songs");
|
||||
|
||||
+145
-130
@@ -11,9 +11,9 @@ import flixel.math.FlxRect;
|
||||
import flixel.system.debug.log.LogStyle;
|
||||
import flixel.util.FlxColor;
|
||||
import funkin.graphics.FunkinSprite;
|
||||
import funkin.data.dialogue.conversation.ConversationRegistry;
|
||||
import funkin.data.dialogue.dialoguebox.DialogueBoxRegistry;
|
||||
import funkin.data.dialogue.speaker.SpeakerRegistry;
|
||||
import funkin.data.dialogue.ConversationRegistry;
|
||||
import funkin.data.dialogue.DialogueBoxRegistry;
|
||||
import funkin.data.dialogue.SpeakerRegistry;
|
||||
import funkin.data.freeplay.album.AlbumRegistry;
|
||||
import funkin.data.freeplay.player.PlayerRegistry;
|
||||
import funkin.data.freeplay.style.FreeplayStyleRegistry;
|
||||
@@ -24,7 +24,7 @@ import funkin.data.event.SongEventRegistry;
|
||||
import funkin.data.stage.StageRegistry;
|
||||
import funkin.data.story.level.LevelRegistry;
|
||||
import funkin.modding.module.ModuleHandler;
|
||||
import funkin.play.character.CharacterData.CharacterDataParser;
|
||||
import funkin.data.character.CharacterData.CharacterDataParser;
|
||||
import funkin.play.notes.notekind.NoteKindManager;
|
||||
import funkin.play.PlayStatePlaylist;
|
||||
import funkin.ui.debug.charting.ChartEditorState;
|
||||
@@ -55,6 +55,13 @@ import funkin.api.newgrounds.NewgroundsClient;
|
||||
@:nullSafety
|
||||
class InitState extends FlxState
|
||||
{
|
||||
/**
|
||||
* Simply states whether the "core stuff" is ready or not.
|
||||
* This is used to prevent re-initialization of specific core features.
|
||||
*/
|
||||
@:noCompletion
|
||||
static var _coreInitialized:Bool = false;
|
||||
|
||||
/**
|
||||
* Perform a bunch of game setup, then immediately transition to the title screen.
|
||||
*/
|
||||
@@ -78,158 +85,163 @@ class InitState extends FlxState
|
||||
*/
|
||||
function setupShit():Void
|
||||
{
|
||||
//
|
||||
// GAME SETUP
|
||||
//
|
||||
if (!_coreInitialized)
|
||||
{
|
||||
//
|
||||
// GAME SETUP
|
||||
//
|
||||
|
||||
// Setup window events (like callbacks for onWindowClose)
|
||||
// and fullscreen keybind setup
|
||||
WindowUtil.initWindowEvents();
|
||||
// Disable the thing on Windows where it tries to send a bug report to Microsoft because why do they care?
|
||||
WindowUtil.disableCrashHandler();
|
||||
// Setup window events (like callbacks for onWindowClose) and fullscreen keybind setup
|
||||
WindowUtil.initWindowEvents();
|
||||
|
||||
#if FEATURE_DEBUG_TRACY
|
||||
funkin.util.WindowUtil.initTracy();
|
||||
#end
|
||||
#if FEATURE_DEBUG_TRACY
|
||||
funkin.util.WindowUtil.initTracy();
|
||||
#end
|
||||
|
||||
#if FEATURE_HAPTICS
|
||||
// Setup Haptic feedback
|
||||
extension.haptics.Haptic.initialize();
|
||||
#end
|
||||
#if FEATURE_HAPTICS
|
||||
// Setup Haptic feedback
|
||||
extension.haptics.Haptic.initialize();
|
||||
#end
|
||||
|
||||
#if FEATURE_MOBILE_ADVERTISEMENTS
|
||||
// Setup Admob
|
||||
funkin.mobile.util.AdMobUtil.init();
|
||||
#end
|
||||
#if FEATURE_MOBILE_ADVERTISEMENTS
|
||||
// Setup Admob
|
||||
funkin.mobile.util.AdMobUtil.init();
|
||||
#end
|
||||
|
||||
#if FEATURE_MOBILE_IAP
|
||||
// Setup In-App purchases
|
||||
funkin.mobile.util.InAppPurchasesUtil.init();
|
||||
#end
|
||||
#if FEATURE_MOBILE_IAP
|
||||
// Setup In-App purchases
|
||||
funkin.mobile.util.InAppPurchasesUtil.init();
|
||||
#end
|
||||
|
||||
#if FEATURE_MOBILE_IAR
|
||||
// Setup In-App purchases
|
||||
funkin.mobile.util.InAppReviewUtil.init();
|
||||
#end
|
||||
#if FEATURE_MOBILE_IAR
|
||||
// Setup In-App reviews
|
||||
funkin.mobile.util.InAppReviewUtil.init();
|
||||
#end
|
||||
|
||||
#if ios
|
||||
// Setup Audio session
|
||||
funkin.mobile.external.AudioSession.initialize();
|
||||
#end
|
||||
#if android
|
||||
// Setup Callback util.
|
||||
funkin.external.android.CallbackUtil.init();
|
||||
#end
|
||||
|
||||
// This ain't a pixel art game! (most of the time)
|
||||
FlxSprite.defaultAntialiasing = true;
|
||||
#if ios
|
||||
// Setup Audio session
|
||||
funkin.external.apple.AudioSession.initialize();
|
||||
#end
|
||||
|
||||
// Disable default keybinds for volume (we manually control volume in MusicBeatState with custom binds)
|
||||
FlxG.sound.volumeUpKeys = [];
|
||||
FlxG.sound.volumeDownKeys = [];
|
||||
FlxG.sound.muteKeys = [];
|
||||
// This ain't a pixel art game! (most of the time)
|
||||
FlxSprite.defaultAntialiasing = true;
|
||||
|
||||
// A small jumpstart to the soundtray, it usually sets itself to inactive (somewhere...)
|
||||
// but that makes our soundtray not show up on init if we have the game muted.
|
||||
// We set it to active so it at least calls it's update function once (see FlxGame.onEnterFrame(), it's called there)
|
||||
// and also see FunkinSoundTray.update() to see what we do and how we check if we are muted or not
|
||||
#if !mobile
|
||||
FlxG.game.soundTray.active = true;
|
||||
#end
|
||||
// Disable default keybinds for volume (we manually control volume in MusicBeatState with custom binds)
|
||||
FlxG.sound.volumeUpKeys = [];
|
||||
FlxG.sound.volumeDownKeys = [];
|
||||
FlxG.sound.muteKeys = [];
|
||||
|
||||
// Set the game to a lower frame rate while it is in the background.
|
||||
FlxG.game.focusLostFramerate = 30;
|
||||
// A small jumpstart to the soundtray, it usually sets itself to inactive (somewhere...)
|
||||
// but that makes our soundtray not show up on init if we have the game muted.
|
||||
// We set it to active so it at least calls it's update function once (see FlxGame.onEnterFrame(), it's called there)
|
||||
// and also see FunkinSoundTray.update() to see what we do and how we check if we are muted or not
|
||||
#if !mobile
|
||||
FlxG.game.soundTray.active = true;
|
||||
#end
|
||||
|
||||
// Makes Flixel use frame times instead of locked movements per frame for things like tweens
|
||||
FlxG.fixedTimestep = false;
|
||||
// Set the game to a lower frame rate while it is in the background.
|
||||
FlxG.game.focusLostFramerate = 30;
|
||||
|
||||
setupFlixelDebug();
|
||||
// Makes Flixel use frame times instead of locked movements per frame for things like tweens
|
||||
FlxG.fixedTimestep = false;
|
||||
|
||||
//
|
||||
// FLIXEL TRANSITIONS
|
||||
//
|
||||
setupFlixelDebug();
|
||||
|
||||
// Diamond Transition
|
||||
var diamond:FlxGraphic = FlxGraphic.fromClass(GraphicTransTileDiamond);
|
||||
diamond.persist = true;
|
||||
diamond.destroyOnNoUse = false;
|
||||
//
|
||||
// FLIXEL TRANSITIONS
|
||||
//
|
||||
|
||||
// NOTE: tileData is ignored if TransitionData.type is FADE instead of TILES.
|
||||
var tileData:TransitionTileData = {asset: diamond, width: 32, height: 32};
|
||||
// Diamond Transition
|
||||
var diamond:FlxGraphic = FlxGraphic.fromClass(GraphicTransTileDiamond);
|
||||
diamond.persist = true;
|
||||
diamond.destroyOnNoUse = false;
|
||||
|
||||
FlxTransitionableState.defaultTransIn = new TransitionData(FADE, FlxColor.BLACK, 1, new FlxPoint(0, -1), tileData,
|
||||
new FlxRect(-200, -200, FlxG.width * 1.4, FlxG.height * 1.4));
|
||||
FlxTransitionableState.defaultTransOut = new TransitionData(FADE, FlxColor.BLACK, 0.7, new FlxPoint(0, 1), tileData,
|
||||
new FlxRect(-200, -200, FlxG.width * 1.4, FlxG.height * 1.4));
|
||||
// Don't play transition in when entering the title state.
|
||||
FlxTransitionableState.skipNextTransIn = true;
|
||||
// NOTE: tileData is ignored if TransitionData.type is FADE instead of TILES.
|
||||
var tileData:TransitionTileData = {asset: diamond, width: 32, height: 32};
|
||||
|
||||
FlxG.signals.gameResized.add(function(width:Int, height:Int) {
|
||||
FlxTransitionableState.defaultTransIn = new TransitionData(FADE, FlxColor.BLACK, 1, new FlxPoint(0, -1), tileData,
|
||||
new FlxRect(-200, -200, FlxG.width * 1.4, FlxG.height * 1.4));
|
||||
FlxTransitionableState.defaultTransOut = new TransitionData(FADE, FlxColor.BLACK, 0.7, new FlxPoint(0, 1), tileData,
|
||||
new FlxRect(-200, -200, FlxG.width * 1.4, FlxG.height * 1.4));
|
||||
});
|
||||
|
||||
// SDL for some reason enables VSync on focus lost/gained in Android
|
||||
// Since we don't really need VSync on Android we're gonna forcefully disable it on these signals for now
|
||||
// This is fixed on SDL3 from what I've heared but that doodoo isn't working poperly for Android
|
||||
#if android
|
||||
FlxG.signals.focusLost.add(function() {
|
||||
WindowUtil.setVSyncMode(lime.ui.WindowVSyncMode.OFF);
|
||||
});
|
||||
FlxG.signals.focusGained.add(function() {
|
||||
WindowUtil.setVSyncMode(lime.ui.WindowVSyncMode.OFF);
|
||||
});
|
||||
#end
|
||||
FlxG.signals.gameResized.add(function(width:Int, height:Int) {
|
||||
FlxTransitionableState.defaultTransIn = new TransitionData(FADE, FlxColor.BLACK, 1, new FlxPoint(0, -1), tileData,
|
||||
new FlxRect(-200, -200, FlxG.width * 1.4, FlxG.height * 1.4));
|
||||
FlxTransitionableState.defaultTransOut = new TransitionData(FADE, FlxColor.BLACK, 0.7, new FlxPoint(0, 1), tileData,
|
||||
new FlxRect(-200, -200, FlxG.width * 1.4, FlxG.height * 1.4));
|
||||
});
|
||||
|
||||
//
|
||||
// NEWGROUNDS API SETUP
|
||||
//
|
||||
#if FEATURE_NEWGROUNDS
|
||||
NewgroundsClient.instance.init();
|
||||
#end
|
||||
// SDL for some reason enables VSync on focus lost/gained in Android
|
||||
// Since we don't really need VSync on Android we're gonna forcefully disable it on these signals for now
|
||||
// This is fixed on SDL3 from what I've heared but that doodoo isn't working poperly for Android
|
||||
#if android
|
||||
FlxG.signals.focusLost.add(function() {
|
||||
WindowUtil.setVSyncMode(lime.ui.WindowVSyncMode.OFF);
|
||||
});
|
||||
FlxG.signals.focusGained.add(function() {
|
||||
WindowUtil.setVSyncMode(lime.ui.WindowVSyncMode.OFF);
|
||||
});
|
||||
#end
|
||||
|
||||
//
|
||||
// DISCORD API SETUP
|
||||
//
|
||||
#if FEATURE_DISCORD_RPC
|
||||
DiscordClient.instance.init();
|
||||
//
|
||||
// NEWGROUNDS API SETUP
|
||||
//
|
||||
#if FEATURE_NEWGROUNDS
|
||||
NewgroundsClient.instance.init();
|
||||
#end
|
||||
|
||||
lime.app.Application.current.onExit.add(function(exitCode) {
|
||||
DiscordClient.instance.shutdown();
|
||||
});
|
||||
#end
|
||||
//
|
||||
// DISCORD API SETUP
|
||||
//
|
||||
#if FEATURE_DISCORD_RPC
|
||||
DiscordClient.instance.init();
|
||||
|
||||
//
|
||||
// ANDROID SETUP
|
||||
//
|
||||
#if android
|
||||
FlxG.android.preventDefaultKeys = [flixel.input.android.FlxAndroidKey.BACK];
|
||||
#end
|
||||
lime.app.Application.current.onExit.add(function(exitCode) {
|
||||
DiscordClient.instance.shutdown();
|
||||
});
|
||||
#end
|
||||
|
||||
//
|
||||
// FLIXEL PLUGINS
|
||||
//
|
||||
// Plugins provide a useful interface for globally active Flixel objects,
|
||||
// that receive update events regardless of the current state.
|
||||
// TODO: Move scripted Module behavior to a Flixel plugin.
|
||||
#if FEATURE_DEBUG_FUNCTIONS
|
||||
funkin.util.plugins.MemoryGCPlugin.initialize();
|
||||
#end
|
||||
#if FEATURE_SCREENSHOTS
|
||||
funkin.util.plugins.ScreenshotPlugin.initialize();
|
||||
#end
|
||||
#if FEATURE_NEWGROUNDS
|
||||
funkin.util.plugins.NewgroundsMedalPlugin.initialize();
|
||||
#end
|
||||
funkin.util.plugins.EvacuateDebugPlugin.initialize();
|
||||
funkin.util.plugins.ForceCrashPlugin.initialize();
|
||||
funkin.util.plugins.ReloadAssetsDebugPlugin.initialize();
|
||||
#if !mobile
|
||||
funkin.util.plugins.VolumePlugin.initialize();
|
||||
#end
|
||||
funkin.util.plugins.WatchPlugin.initialize();
|
||||
#if mobile
|
||||
funkin.util.plugins.TouchPointerPlugin.initialize();
|
||||
funkin.mobile.input.ControlsHandler.initInputTrackers();
|
||||
#end
|
||||
//
|
||||
// ANDROID SETUP
|
||||
//
|
||||
#if android
|
||||
FlxG.android.preventDefaultKeys = [flixel.input.android.FlxAndroidKey.BACK];
|
||||
#end
|
||||
|
||||
//
|
||||
// FLIXEL PLUGINS
|
||||
//
|
||||
// Plugins provide a useful interface for globally active Flixel objects,
|
||||
// that receive update events regardless of the current state.
|
||||
// TODO: Move scripted Module behavior to a Flixel plugin.
|
||||
#if FEATURE_DEBUG_FUNCTIONS
|
||||
funkin.util.plugins.MemoryGCPlugin.initialize();
|
||||
#end
|
||||
#if FEATURE_SCREENSHOTS
|
||||
funkin.util.plugins.ScreenshotPlugin.initialize();
|
||||
#end
|
||||
#if FEATURE_NEWGROUNDS
|
||||
funkin.util.plugins.NewgroundsMedalPlugin.initialize();
|
||||
#end
|
||||
funkin.util.plugins.EvacuateDebugPlugin.initialize();
|
||||
funkin.util.plugins.ForceCrashPlugin.initialize();
|
||||
funkin.util.plugins.ReloadAssetsDebugPlugin.initialize();
|
||||
#if !mobile
|
||||
funkin.util.plugins.VolumePlugin.initialize();
|
||||
#end
|
||||
funkin.util.plugins.WatchPlugin.initialize();
|
||||
#if mobile
|
||||
funkin.util.plugins.TouchPointerPlugin.initialize();
|
||||
funkin.mobile.input.ControlsHandler.initInputTrackers();
|
||||
#end
|
||||
|
||||
_coreInitialized = true;
|
||||
}
|
||||
|
||||
//
|
||||
// GAME DATA PARSING
|
||||
@@ -278,6 +290,9 @@ class InitState extends FlxState
|
||||
*/
|
||||
function startGame():Void
|
||||
{
|
||||
// Don't play transition in when entering the title state.
|
||||
FlxTransitionableState.skipNextTransIn = true;
|
||||
|
||||
#if SONG
|
||||
// -DSONG=bopeebo
|
||||
startSong(defineSong(), defineDifficulty());
|
||||
@@ -385,7 +400,7 @@ class InitState extends FlxState
|
||||
*/
|
||||
function startSong(songId:String, difficultyId:String = 'normal'):Void
|
||||
{
|
||||
var songData:Null<funkin.play.song.Song> = funkin.data.song.SongRegistry.instance.fetchEntry(songId);
|
||||
var songData:Null<funkin.play.song.Song> = funkin.data.song.SongRegistry.instance.fetchEntry(songId, {variation: Constants.DEFAULT_VARIATION});
|
||||
|
||||
if (songData == null)
|
||||
{
|
||||
@@ -457,7 +472,7 @@ class InitState extends FlxState
|
||||
|
||||
var targetSong:Null<funkin.play.song.Song> = null;
|
||||
|
||||
if (targetSongId != null) targetSong = SongRegistry.instance.fetchEntry(targetSongId);
|
||||
if (targetSongId != null) targetSong = SongRegistry.instance.fetchEntry(targetSongId, {variation: Constants.DEFAULT_VARIATION});
|
||||
|
||||
if (targetSongId == null)
|
||||
{
|
||||
|
||||
+118
-32
@@ -2,10 +2,12 @@ package funkin;
|
||||
|
||||
#if mobile
|
||||
import funkin.mobile.ui.FunkinHitbox;
|
||||
import funkin.mobile.util.InAppPurchasesUtil;
|
||||
#end
|
||||
import funkin.save.Save;
|
||||
import funkin.util.WindowUtil;
|
||||
import funkin.util.HapticUtil.HapticsMode;
|
||||
import funkin.ui.debug.FunkinDebugDisplay.DebugDisplayMode;
|
||||
|
||||
/**
|
||||
* A core class which provides a store of user-configurable, globally relevant values.
|
||||
@@ -136,27 +138,70 @@ class Preferences
|
||||
/**
|
||||
* If enabled, an FPS and memory counter will be displayed even if this is not a debug build.
|
||||
* Always disabled on mobile.
|
||||
* @default `false`
|
||||
* @default `Off`
|
||||
*/
|
||||
public static var debugDisplay(get, set):Bool;
|
||||
public static var debugDisplay(get, set):DebugDisplayMode;
|
||||
|
||||
static function get_debugDisplay():Bool
|
||||
static function get_debugDisplay():DebugDisplayMode
|
||||
{
|
||||
#if mobile
|
||||
return false;
|
||||
return DebugDisplayMode.OFF;
|
||||
#end
|
||||
return Save?.instance?.options?.debugDisplay ?? false;
|
||||
var value = Save?.instance?.options?.debugDisplay ?? 'Off';
|
||||
|
||||
return switch (value)
|
||||
{
|
||||
case "Simple":
|
||||
DebugDisplayMode.SIMPLE;
|
||||
case "Advanced":
|
||||
DebugDisplayMode.ADVANCED;
|
||||
default:
|
||||
DebugDisplayMode.OFF;
|
||||
};
|
||||
}
|
||||
|
||||
static function set_debugDisplay(value:Bool):Bool
|
||||
static function set_debugDisplay(value:DebugDisplayMode):DebugDisplayMode
|
||||
{
|
||||
if (value != Save.instance.options.debugDisplay)
|
||||
var string;
|
||||
|
||||
switch (value)
|
||||
{
|
||||
toggleDebugDisplay(value);
|
||||
case DebugDisplayMode.SIMPLE:
|
||||
string = "Simple";
|
||||
case DebugDisplayMode.ADVANCED:
|
||||
string = "Advanced";
|
||||
default:
|
||||
string = "Off";
|
||||
};
|
||||
|
||||
if (string != Save.instance.options.debugDisplay)
|
||||
{
|
||||
setDebugDisplayMode(value);
|
||||
}
|
||||
|
||||
var save = Save.instance;
|
||||
save.options.debugDisplay = value;
|
||||
save.options.debugDisplay = string;
|
||||
save.flush();
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opacity of the debug display's background.
|
||||
* @default `50`
|
||||
*/
|
||||
public static var debugDisplayBGOpacity(get, set):Int;
|
||||
|
||||
static function get_debugDisplayBGOpacity():Int
|
||||
{
|
||||
return Save?.instance?.options?.debugDisplayBGOpacity ?? 50;
|
||||
}
|
||||
|
||||
static function set_debugDisplayBGOpacity(value:Int):Int
|
||||
{
|
||||
setDebugDisplayBGOpacity(value / 100);
|
||||
|
||||
var save:Save = Save.instance;
|
||||
save.options.debugDisplayBGOpacity = value;
|
||||
save.flush();
|
||||
return value;
|
||||
}
|
||||
@@ -202,6 +247,25 @@ class Preferences
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplier of intensity for all the haptic feedback effects.
|
||||
* @default `2.5`
|
||||
*/
|
||||
public static var hapticsIntensityMultiplier(get, set):Float;
|
||||
|
||||
static function get_hapticsIntensityMultiplier():Float
|
||||
{
|
||||
return Save?.instance?.options?.hapticsIntensityMultiplier ?? 1;
|
||||
}
|
||||
|
||||
static function set_hapticsIntensityMultiplier(value:Float):Float
|
||||
{
|
||||
var save:Save = Save.instance;
|
||||
save.options.hapticsIntensityMultiplier = value;
|
||||
save.flush();
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* If enabled, the game will automatically pause when tabbing out.
|
||||
* Always enabled on mobile.
|
||||
@@ -439,18 +503,15 @@ class Preferences
|
||||
{
|
||||
// Apply the autoPause setting (enables automatic pausing on focus lost).
|
||||
FlxG.autoPause = Preferences.autoPause;
|
||||
// WindowUtil.setVSyncMode(Preferences.vsyncMode);
|
||||
|
||||
// Apply the debugDisplay setting (enables the FPS and RAM display).
|
||||
toggleDebugDisplay(Preferences.debugDisplay);
|
||||
setDebugDisplayMode(Preferences.debugDisplay);
|
||||
setDebugDisplayBGOpacity(Preferences.debugDisplayBGOpacity / 100);
|
||||
|
||||
#if web
|
||||
toggleFramerateCap(Preferences.unlockedFramerate);
|
||||
#end
|
||||
|
||||
#if desktop
|
||||
// Apply the autoFullscreen setting (launches the game in fullscreen automatically)
|
||||
FlxG.fullscreen = Preferences.autoFullscreen;
|
||||
#end
|
||||
|
||||
#if mobile
|
||||
// Apply the allowScreenTimeout setting.
|
||||
lime.system.System.allowScreenTimeout = Preferences.screenTimeout;
|
||||
@@ -465,26 +526,25 @@ class Preferences
|
||||
#end
|
||||
}
|
||||
|
||||
static function toggleDebugDisplay(show:Bool):Void
|
||||
static function setDebugDisplayMode(mode:DebugDisplayMode):Void
|
||||
{
|
||||
if (show)
|
||||
if (FlxG.game.parent.contains(Main.debugDisplay))
|
||||
{
|
||||
// Enable the debug display.
|
||||
FlxG.game.parent.addChild(Main.fpsCounter);
|
||||
|
||||
#if !html5
|
||||
FlxG.game.parent.addChild(Main.memoryCounter);
|
||||
#end
|
||||
FlxG.game.parent.removeChild(Main.debugDisplay);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Disable the debug display.
|
||||
FlxG.game.parent.removeChild(Main.fpsCounter);
|
||||
|
||||
#if !html5
|
||||
FlxG.game.parent.removeChild(Main.memoryCounter);
|
||||
#end
|
||||
}
|
||||
if (mode == DebugDisplayMode.OFF) return;
|
||||
|
||||
Main.debugDisplay.isAdvanced = (mode == DebugDisplayMode.ADVANCED);
|
||||
|
||||
FlxG.game.parent.addChild(Main.debugDisplay);
|
||||
}
|
||||
|
||||
static function setDebugDisplayBGOpacity(value:Float):Void
|
||||
{
|
||||
if (Main.debugDisplay == null) return;
|
||||
|
||||
Main.debugDisplay.backgroundOpacity = value;
|
||||
}
|
||||
|
||||
#if mobile
|
||||
@@ -527,5 +587,31 @@ class Preferences
|
||||
save.flush();
|
||||
return value;
|
||||
}
|
||||
|
||||
#if FEATURE_MOBILE_IAP
|
||||
/**
|
||||
* If bought, the game will not show any ads.
|
||||
* @default `false`
|
||||
*/
|
||||
@:unreflective
|
||||
public static var noAds(get, set):Bool;
|
||||
|
||||
@:unreflective
|
||||
static function get_noAds():Bool
|
||||
{
|
||||
if (InAppPurchasesUtil.hasInitialized) noAds = InAppPurchasesUtil.isPurchased(InAppPurchasesUtil.UPGRADE_PRODUCT_ID);
|
||||
var returnedValue = Save?.instance?.mobileOptions?.noAds ?? false;
|
||||
return returnedValue;
|
||||
}
|
||||
|
||||
@:unreflective
|
||||
static function set_noAds(value:Bool):Bool
|
||||
{
|
||||
var save:Save = Save.instance;
|
||||
save.mobileOptions.noAds = value;
|
||||
save.flush();
|
||||
return value;
|
||||
}
|
||||
#end
|
||||
#end
|
||||
}
|
||||
|
||||
@@ -8,10 +8,12 @@ import hxdiscord_rpc.Types.DiscordRichPresence;
|
||||
import hxdiscord_rpc.Types.DiscordUser;
|
||||
import sys.thread.Thread;
|
||||
|
||||
@:build(funkin.util.macro.EnvironmentMacro.build())
|
||||
@:nullSafety
|
||||
class DiscordClient
|
||||
{
|
||||
static final CLIENT_ID:String = "816168432860790794";
|
||||
@:envField
|
||||
static final DISCORD_CLIENT_ID:Null<String>;
|
||||
|
||||
public static var instance(get, never):DiscordClient;
|
||||
static var _instance:Null<DiscordClient> = null;
|
||||
@@ -40,12 +42,28 @@ class DiscordClient
|
||||
{
|
||||
trace('[DISCORD] Initializing connection...');
|
||||
|
||||
// Discord.initialize(CLIENT_ID, handlers, true, null);
|
||||
Discord.Initialize(CLIENT_ID, cpp.RawPointer.addressOf(handlers), 1, "");
|
||||
if (!hasValidCredentials())
|
||||
{
|
||||
FlxG.log.warn("Tried to initialize Discord connection, but credentials are invalid!");
|
||||
return;
|
||||
}
|
||||
|
||||
@:nullSafety(Off)
|
||||
{
|
||||
Discord.Initialize(DISCORD_CLIENT_ID, cpp.RawPointer.addressOf(handlers), 1, "");
|
||||
}
|
||||
|
||||
createDaemon();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns `false` if the client ID is invalid.
|
||||
*/
|
||||
static function hasValidCredentials():Bool
|
||||
{
|
||||
return !(DISCORD_CLIENT_ID == null || DISCORD_CLIENT_ID == "" || (DISCORD_CLIENT_ID != null && DISCORD_CLIENT_ID.contains(" ")));
|
||||
}
|
||||
|
||||
var daemon:Null<Thread> = null;
|
||||
|
||||
function createDaemon():Void
|
||||
|
||||
@@ -37,10 +37,7 @@ class Leaderboards
|
||||
|
||||
if (NewgroundsClient.instance.isLoggedIn())
|
||||
{
|
||||
var leaderboardList = NewgroundsClient.instance.leaderboards;
|
||||
if (leaderboardList == null) return;
|
||||
|
||||
var leaderboardData:Null<LeaderboardData> = leaderboardList.get(leaderboard.getId());
|
||||
var leaderboardData:Null<LeaderboardData> = listLeaderboardData().get(leaderboard.getId());
|
||||
if (leaderboardData != null)
|
||||
{
|
||||
leaderboardData.postScore(score, function(outcome:Outcome<CallError>):Void {
|
||||
@@ -67,10 +64,7 @@ class Leaderboards
|
||||
// Silently reject retrieving scores from unknown leaderboards.
|
||||
if (leaderboard == Leaderboard.Unknown) return;
|
||||
|
||||
var leaderboardList = NewgroundsClient.instance.leaderboards;
|
||||
if (leaderboardList == null) return;
|
||||
|
||||
var leaderboardData:Null<LeaderboardData> = leaderboardList.get(leaderboard.getId());
|
||||
var leaderboardData:Null<LeaderboardData> = listLeaderboardData().get(leaderboard.getId());
|
||||
if (leaderboardData == null) return;
|
||||
|
||||
var user:Null<User> = null;
|
||||
|
||||
@@ -30,11 +30,7 @@ class Medals
|
||||
{
|
||||
if (NewgroundsClient.instance.isLoggedIn())
|
||||
{
|
||||
var medalList = NewgroundsClient.instance.medals;
|
||||
@:privateAccess
|
||||
if (medalList == null || medalList._map == null) return;
|
||||
|
||||
var medalData:Null<MedalData> = medalList.get(medal.getId());
|
||||
var medalData:Null<MedalData> = listMedalData().get(medal.getId());
|
||||
@:privateAccess
|
||||
if (medalData == null || medalData._data == null)
|
||||
{
|
||||
@@ -120,11 +116,7 @@ class Medals
|
||||
|
||||
public static function fetchMedalData(medal:Medal):Null<FetchedMedalData>
|
||||
{
|
||||
var medalList = NewgroundsClient.instance.medals;
|
||||
@:privateAccess
|
||||
if (medalList == null || medalList._map == null) return null;
|
||||
|
||||
var medalData:Null<MedalData> = medalList.get(medal.getId());
|
||||
var medalData:Null<MedalData> = listMedalData().get(medal.getId());
|
||||
@:privateAccess
|
||||
if (medalData == null || medalData._data == null)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
package funkin.api.newgrounds;
|
||||
|
||||
#if FEATURE_NEWGROUNDS
|
||||
import io.newgrounds.utils.SaveSlotList;
|
||||
import io.newgrounds.objects.SaveSlot;
|
||||
import io.newgrounds.Call.CallError;
|
||||
import io.newgrounds.objects.events.Outcome;
|
||||
import funkin.save.Save;
|
||||
|
||||
@:nullSafety
|
||||
@:access(funkin.save.Save)
|
||||
class NGSaveSlot
|
||||
{
|
||||
public static var instance(get, never):NGSaveSlot;
|
||||
static var _instance:Null<NGSaveSlot> = null;
|
||||
|
||||
static function get_instance():NGSaveSlot
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
return loadInstance();
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
|
||||
public static function loadInstance():NGSaveSlot
|
||||
{
|
||||
var loadedSave:NGSaveSlot = loadSlot(Save.BASE_SAVE_SLOT);
|
||||
if (_instance == null) _instance = loadedSave;
|
||||
|
||||
return loadedSave;
|
||||
}
|
||||
|
||||
static function loadSlot(slot:Int):NGSaveSlot
|
||||
{
|
||||
trace('[NEWGROUNDS] Getting save slot from ID $slot');
|
||||
|
||||
var saveSlot:Null<SaveSlot> = NewgroundsClient.instance.saveSlots?.getById(slot);
|
||||
|
||||
var saveSlotObj:NGSaveSlot = new NGSaveSlot(saveSlot);
|
||||
return saveSlotObj;
|
||||
}
|
||||
|
||||
public var ngSaveSlot:Null<SaveSlot> = null;
|
||||
|
||||
public function new(?ngSaveSlot:Null<SaveSlot>)
|
||||
{
|
||||
this.ngSaveSlot = ngSaveSlot;
|
||||
|
||||
#if FLX_DEBUG
|
||||
FlxG.console.registerClass(NGSaveSlot);
|
||||
FlxG.console.registerClass(Save);
|
||||
#end
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves `data` to the newgrounds save slot.
|
||||
* @param data The raw save data.
|
||||
*/
|
||||
public function save(data:RawSaveData):Void
|
||||
{
|
||||
var encodedData:String = haxe.Serializer.run(data);
|
||||
|
||||
try
|
||||
{
|
||||
ngSaveSlot?.save(encodedData, function(outcome:Outcome<CallError>) {
|
||||
switch (outcome)
|
||||
{
|
||||
case SUCCESS:
|
||||
trace('[NEWGROUNDS] Successfully saved save data to save slot!');
|
||||
case FAIL(error):
|
||||
trace('[NEWGROUNDS] Failed to save data to save slot!');
|
||||
trace(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (error:String)
|
||||
{
|
||||
trace('[NEWGROUNDS] Failed to save data to save slot!');
|
||||
trace(error);
|
||||
}
|
||||
}
|
||||
|
||||
public function load(?onComplete:Null<Dynamic->Void>, ?onError:Null<CallError->Void>):Void
|
||||
{
|
||||
try
|
||||
{
|
||||
ngSaveSlot?.load(function(outcome:SaveSlotOutcome):Void {
|
||||
switch (outcome)
|
||||
{
|
||||
case SUCCESS(value):
|
||||
trace('[NEWGROUNDS] Loaded save slot with the ID of ${ngSaveSlot?.id}!');
|
||||
#if FEATURE_DEBUG_FUNCTIONS
|
||||
trace('Save Slot Data:');
|
||||
trace(value);
|
||||
#end
|
||||
|
||||
if (onComplete != null && value != null)
|
||||
{
|
||||
var decodedData:Dynamic = haxe.Unserializer.run(value);
|
||||
onComplete(decodedData);
|
||||
}
|
||||
case FAIL(error):
|
||||
trace('[NEWGROUNDS] Failed to load save slot with the ID of ${ngSaveSlot?.id}!');
|
||||
trace(error);
|
||||
|
||||
if (onError != null)
|
||||
{
|
||||
onError(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (error:String)
|
||||
{
|
||||
trace('[NEWGROUNDS] Failed to load save slot with the ID of ${ngSaveSlot?.id}!');
|
||||
trace(error);
|
||||
|
||||
if (onError != null)
|
||||
{
|
||||
onError(RESPONSE({message: error, code: 500}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function clear():Void
|
||||
{
|
||||
try
|
||||
{
|
||||
ngSaveSlot?.clear(function(outcome:Outcome<CallError>) {
|
||||
switch (outcome)
|
||||
{
|
||||
case SUCCESS:
|
||||
trace('[NEWGROUNDS] Successfully cleared save slot!');
|
||||
case FAIL(error):
|
||||
trace('[NEWGROUNDS] Failed to clear save slot!');
|
||||
trace(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (error:String)
|
||||
{
|
||||
trace('[NEWGROUNDS] Failed to clear save slot!');
|
||||
trace(error);
|
||||
}
|
||||
}
|
||||
|
||||
public function checkSlot():Void
|
||||
{
|
||||
trace('[NEWGROUNDS] Checking save slot with the ID of ${ngSaveSlot?.id}...');
|
||||
|
||||
trace(' Is null? ${ngSaveSlot == null}');
|
||||
trace(' Is empty? ${ngSaveSlot?.isEmpty() ?? false}');
|
||||
}
|
||||
}
|
||||
#end
|
||||
@@ -10,13 +10,22 @@ import io.newgrounds.NGLite.LoginOutcome;
|
||||
import io.newgrounds.NGLite.LoginFail;
|
||||
import io.newgrounds.objects.events.Outcome;
|
||||
import io.newgrounds.utils.MedalList;
|
||||
import io.newgrounds.utils.SaveSlotList;
|
||||
import io.newgrounds.utils.ScoreBoardList;
|
||||
import io.newgrounds.objects.User;
|
||||
|
||||
@:build(funkin.util.macro.EnvironmentMacro.build())
|
||||
@:nullSafety
|
||||
class NewgroundsClient
|
||||
{
|
||||
@:envField
|
||||
static final API_NG_APP_ID:Null<String>;
|
||||
|
||||
@:envField
|
||||
static final API_NG_ENC_KEY:Null<String>;
|
||||
|
||||
public static var instance(get, never):NewgroundsClient;
|
||||
|
||||
static var _instance:Null<NewgroundsClient> = null;
|
||||
|
||||
static function get_instance():NewgroundsClient
|
||||
@@ -29,14 +38,15 @@ class NewgroundsClient
|
||||
public var user(get, never):Null<User>;
|
||||
public var medals(get, never):Null<MedalList>;
|
||||
public var leaderboards(get, never):Null<ScoreBoardList>;
|
||||
public var saveSlots(get, never):Null<SaveSlotList>;
|
||||
|
||||
private function new()
|
||||
{
|
||||
trace('[NEWGROUNDS] Initializing client...');
|
||||
|
||||
#if FEATURE_NEWGROUNDS_DEBUG
|
||||
trace('[NEWGROUNDS] App ID: ${NewgroundsCredentials.APP_ID}');
|
||||
trace('[NEWGROUNDS] Encryption Key: ${NewgroundsCredentials.ENCRYPTION_KEY}');
|
||||
trace('[NEWGROUNDS] App ID: ${API_NG_APP_ID}');
|
||||
trace('[NEWGROUNDS] Encryption Key: ${API_NG_ENC_KEY}');
|
||||
#end
|
||||
|
||||
if (!hasValidCredentials())
|
||||
@@ -45,9 +55,12 @@ class NewgroundsClient
|
||||
return;
|
||||
}
|
||||
|
||||
var debug = #if FEATURE_NEWGROUNDS_DEBUG true #else false #end;
|
||||
NG.create(NewgroundsCredentials.APP_ID, getSessionId(), debug, onLoginResolved);
|
||||
NG.core.setupEncryption(NewgroundsCredentials.ENCRYPTION_KEY);
|
||||
@:nullSafety(Off)
|
||||
{
|
||||
NG.create(API_NG_APP_ID, getSessionId(), #if FEATURE_NEWGROUNDS_DEBUG true #else false #end, onLoginResolved);
|
||||
|
||||
NG.core.setupEncryption(API_NG_ENC_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
public function init()
|
||||
@@ -92,6 +105,12 @@ class NewgroundsClient
|
||||
return;
|
||||
}
|
||||
|
||||
if (NG.core.attemptingLogin)
|
||||
{
|
||||
trace("[NEWGROUNDS] Login attempt ongoing, will not login until finished.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (onSuccess != null && onError != null)
|
||||
{
|
||||
NG.core.requestLogin(onLoginResolvedWithCallbacks.bind(_, onSuccess, onError));
|
||||
@@ -166,12 +185,12 @@ class NewgroundsClient
|
||||
*/
|
||||
static function hasValidCredentials():Bool
|
||||
{
|
||||
return !(NewgroundsCredentials.APP_ID == null
|
||||
|| NewgroundsCredentials.APP_ID == ""
|
||||
|| NewgroundsCredentials.APP_ID.contains(" ")
|
||||
|| NewgroundsCredentials.ENCRYPTION_KEY == null
|
||||
|| NewgroundsCredentials.ENCRYPTION_KEY == ""
|
||||
|| NewgroundsCredentials.ENCRYPTION_KEY.contains(" "));
|
||||
return !(API_NG_APP_ID == null
|
||||
|| API_NG_APP_ID == ""
|
||||
|| (API_NG_APP_ID != null && API_NG_APP_ID.contains(" "))
|
||||
|| API_NG_ENC_KEY == null
|
||||
|| API_NG_ENC_KEY == ""
|
||||
|| (API_NG_ENC_KEY != null && API_NG_ENC_KEY.contains(" ")));
|
||||
}
|
||||
|
||||
function onLoginResolved(outcome:LoginOutcome):Void
|
||||
@@ -236,6 +255,8 @@ class NewgroundsClient
|
||||
|
||||
trace('[NEWGROUNDS] Submitting leaderboard request...');
|
||||
NG.core.scoreBoards.loadList(onFetchedLeaderboards);
|
||||
trace('[NEWGROUNDS] Submitting save slot request...');
|
||||
NG.core.saveSlots.loadList(onFetchedSaveSlots);
|
||||
}
|
||||
|
||||
function onLoginFailed(result:LoginFail):Void
|
||||
@@ -301,6 +322,13 @@ class NewgroundsClient
|
||||
// trace(funkin.api.newgrounds.Leaderboards.listLeaderboardData());
|
||||
}
|
||||
|
||||
function onFetchedSaveSlots(outcome:Outcome<CallError>):Void
|
||||
{
|
||||
trace('[NEWGROUNDS] Fetched save slots!');
|
||||
|
||||
NGSaveSlot.instance.checkSlot();
|
||||
}
|
||||
|
||||
function get_user():Null<User>
|
||||
{
|
||||
if (NG.core == null || !this.isLoggedIn()) return null;
|
||||
@@ -319,6 +347,12 @@ class NewgroundsClient
|
||||
return NG.core.scoreBoards;
|
||||
}
|
||||
|
||||
function get_saveSlots():Null<SaveSlotList>
|
||||
{
|
||||
if (NG.core == null || !this.isLoggedIn()) return null;
|
||||
return NG.core.saveSlots;
|
||||
}
|
||||
|
||||
static function getSessionId():Null<String>
|
||||
{
|
||||
#if js
|
||||
|
||||
@@ -72,7 +72,7 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
|
||||
override function set_volume(value:Float):Float
|
||||
{
|
||||
// Uncap the volume.
|
||||
_volume = FlxMath.bound(value, 0.0, MAX_VOLUME);
|
||||
_volume = value.clamp(0.0, MAX_VOLUME);
|
||||
updateTransform();
|
||||
return _volume;
|
||||
}
|
||||
@@ -568,8 +568,8 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
|
||||
if (_sound == null) return;
|
||||
|
||||
// Create a channel manually if the sound is considered important.
|
||||
var pan:Float = FlxMath.bound(SoundMixer.__soundTransform.pan + _transform.pan, -1, 1);
|
||||
var volume:Float = FlxMath.bound(SoundMixer.__soundTransform.volume * _transform.volume, 0, MAX_VOLUME);
|
||||
var pan:Float = (SoundMixer.__soundTransform.pan + _transform.pan).clamp(-1, 1);
|
||||
var volume:Float = (SoundMixer.__soundTransform.volume * _transform.volume).clamp(0, MAX_VOLUME);
|
||||
|
||||
var audioSource:AudioSource = new AudioSource(_sound.__buffer);
|
||||
audioSource.offset = Std.int(startTime);
|
||||
|
||||
@@ -243,9 +243,10 @@ class WaveformDataChannel
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a given minimum point at an index.
|
||||
* @param i Index
|
||||
* @return minimum point at an index.
|
||||
*/
|
||||
public function minSample(i:Int)
|
||||
public function minSample(i:Int):Int
|
||||
{
|
||||
var offset = (i * parent.channels + this.channelId) * 2;
|
||||
return inline parent.get(offset);
|
||||
|
||||
@@ -43,69 +43,58 @@ class WaveformDataParser
|
||||
|
||||
public static function interpretAudioBuffer(soundBuffer:lime.media.AudioBuffer):Null<WaveformData>
|
||||
{
|
||||
var sampleRate = soundBuffer.sampleRate;
|
||||
var channels = soundBuffer.channels;
|
||||
var bitsPerSample = soundBuffer.bitsPerSample;
|
||||
var samplesPerPoint:Int = 256; // I don't think we need to configure this.
|
||||
var pointsPerSecond:Float = sampleRate / samplesPerPoint; // 172 samples per second for most songs is plenty precise while still being performant..
|
||||
|
||||
// TODO: Make this work better on HTML5.
|
||||
var soundData:lime.utils.Int16Array = cast soundBuffer.data;
|
||||
|
||||
var soundDataRawLength:Int = soundData.length;
|
||||
var soundDataSampleCount:Int = Std.int(Math.ceil(soundDataRawLength / channels / (bitsPerSample == 16 ? 2 : 1)));
|
||||
var soundDataSampleCount:Int = Std.int(Math.ceil(soundData.length / channels / (bitsPerSample == 16 ? 2 : 1)));
|
||||
var outputPointCount:Int = Std.int(Math.ceil(soundDataSampleCount / samplesPerPoint));
|
||||
|
||||
// trace('Interpreting audio buffer:');
|
||||
// trace(' sampleRate: ${sampleRate}');
|
||||
// trace(' channels: ${channels}');
|
||||
// trace(' bitsPerSample: ${bitsPerSample}');
|
||||
// trace(' samplesPerPoint: ${samplesPerPoint}');
|
||||
// trace(' pointsPerSecond: ${pointsPerSecond}');
|
||||
// trace(' soundDataRawLength: ${soundDataRawLength}');
|
||||
// trace(' soundDataSampleCount: ${soundDataSampleCount}');
|
||||
// trace(' soundDataRawLength/4: ${soundDataRawLength / 4}');
|
||||
// trace(' outputPointCount: ${outputPointCount}');
|
||||
// Pre-allocate Vector with exact final size for better performance and memory efficiency
|
||||
var outputDataLength:Int = outputPointCount * channels * 2;
|
||||
var outputData = new haxe.ds.Vector<Int>(outputDataLength);
|
||||
|
||||
var minSampleValue:Int = bitsPerSample == 16 ? INT16_MIN : INT8_MIN;
|
||||
var maxSampleValue:Int = bitsPerSample == 16 ? INT16_MAX : INT8_MAX;
|
||||
|
||||
var outputData:Array<Int> = [];
|
||||
// Reusable min/max tracking arrays to avoid allocation in the loop
|
||||
var minValues = new haxe.ds.Vector<Int>(channels);
|
||||
var maxValues = new haxe.ds.Vector<Int>(channels);
|
||||
|
||||
for (pointIndex in 0...outputPointCount)
|
||||
{
|
||||
// minChannel1, maxChannel1, minChannel2, maxChannel2, ...
|
||||
var values:Array<Int> = [];
|
||||
var rangeStart:Int = pointIndex * samplesPerPoint;
|
||||
var rangeEnd:Int = Std.int(Math.min(rangeStart + samplesPerPoint, soundDataSampleCount));
|
||||
|
||||
// Reset min/max values for this range
|
||||
for (i in 0...channels)
|
||||
{
|
||||
values.push(bitsPerSample == 16 ? INT16_MAX : INT8_MAX);
|
||||
values.push(bitsPerSample == 16 ? INT16_MIN : INT8_MIN);
|
||||
minValues[i] = bitsPerSample == 16 ? INT16_MAX : INT8_MAX;
|
||||
maxValues[i] = bitsPerSample == 16 ? INT16_MIN : INT8_MIN;
|
||||
}
|
||||
|
||||
var rangeStart = pointIndex * samplesPerPoint;
|
||||
var rangeEnd = rangeStart + samplesPerPoint;
|
||||
if (rangeEnd > soundDataSampleCount) rangeEnd = soundDataSampleCount;
|
||||
|
||||
// Process all samples in this range
|
||||
for (sampleIndex in rangeStart...rangeEnd)
|
||||
{
|
||||
for (channelIndex in 0...channels)
|
||||
{
|
||||
var sampleIndex:Int = sampleIndex * channels + channelIndex;
|
||||
var sampleValue = soundData[sampleIndex];
|
||||
var sampleValue:Int = soundData[sampleIndex * channels + channelIndex];
|
||||
|
||||
if (sampleValue < values[channelIndex * 2]) values[(channelIndex * 2)] = sampleValue;
|
||||
if (sampleValue > values[channelIndex * 2 + 1]) values[(channelIndex * 2) + 1] = sampleValue;
|
||||
if (sampleValue < minValues[channelIndex]) minValues[channelIndex] = sampleValue;
|
||||
if (sampleValue > maxValues[channelIndex]) maxValues[channelIndex] = sampleValue;
|
||||
}
|
||||
}
|
||||
|
||||
// We now have the min and max values for the range.
|
||||
for (value in values)
|
||||
outputData.push(value);
|
||||
// Write directly to final positions in output Vector
|
||||
var baseIndex:Int = pointIndex * channels * 2;
|
||||
for (channelIndex in 0...channels)
|
||||
{
|
||||
outputData[baseIndex + channelIndex * 2] = minValues[channelIndex];
|
||||
outputData[baseIndex + channelIndex * 2 + 1] = maxValues[channelIndex];
|
||||
}
|
||||
}
|
||||
|
||||
var outputDataLength:Int = Std.int(outputData.length / channels / 2);
|
||||
var result = new WaveformData(null, channels, sampleRate, samplesPerPoint, bitsPerSample, outputPointCount, outputData);
|
||||
var result = new WaveformData(null, channels, soundBuffer.sampleRate, samplesPerPoint, bitsPerSample, outputPointCount, outputData.toArray());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -5,20 +5,21 @@ import funkin.util.VersionUtil;
|
||||
import haxe.Constraints.Constructible;
|
||||
|
||||
/**
|
||||
* The entry's constructor function must take a single argument, the entry's ID.
|
||||
* The entry's constructor function takes 2 arguments, the entry ID and optional parameters.
|
||||
*/
|
||||
typedef EntryConstructorFunction = String->Void;
|
||||
typedef EntryConstructorFunction = (String, ?Dynamic) -> Void;
|
||||
|
||||
/**
|
||||
* A base type for a Registry, which is an object which handles loading scriptable objects.
|
||||
*
|
||||
* @param T The type to construct. Must implement `IRegistryEntry`.
|
||||
* @param J The type of the JSON data used when constructing.
|
||||
* @param P The type of the parameters used for `fetchEntry()`.
|
||||
*/
|
||||
@:nullSafety
|
||||
@:generic
|
||||
@:autoBuild(funkin.util.macro.DataRegistryMacro.buildRegistry())
|
||||
abstract class BaseRegistry<T:(IRegistryEntry<J> & Constructible<EntryConstructorFunction>), J>
|
||||
abstract class BaseRegistry<T:(IRegistryEntry<J> & Constructible<EntryConstructorFunction>), J, P>
|
||||
{
|
||||
/**
|
||||
* The ID of the registry. Used when logging.
|
||||
@@ -186,7 +187,7 @@ abstract class BaseRegistry<T:(IRegistryEntry<J> & Constructible<EntryConstructo
|
||||
* @param id The ID of the entry to fetch.
|
||||
* @return The entry, or `null` if it does not exist.
|
||||
*/
|
||||
public function fetchEntry(id:String):Null<T>
|
||||
public function fetchEntry(id:String, ?params:Null<P>):Null<T>
|
||||
{
|
||||
return entries.get(id);
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ class DataParse
|
||||
case JArray(values):
|
||||
return Either.Left(legacyNoteSectionArray(json, name));
|
||||
case JObject(fields):
|
||||
return Either.Right(cast Tools.getValue(json));
|
||||
return Either.Right(legacyNoteData(json, name));
|
||||
default:
|
||||
throw 'Expected property $name to be note data, but it was ${json.value}.';
|
||||
}
|
||||
@@ -121,7 +121,7 @@ class DataParse
|
||||
}
|
||||
}
|
||||
|
||||
public static function backdropData(json:Json, name:String):funkin.data.dialogue.conversation.ConversationData.BackdropData
|
||||
public static function backdropData(json:Json, name:String):funkin.data.dialogue.ConversationData.BackdropData
|
||||
{
|
||||
switch (json.value)
|
||||
{
|
||||
@@ -152,7 +152,7 @@ class DataParse
|
||||
}
|
||||
}
|
||||
|
||||
public static function outroData(json:Json, name:String):Null<funkin.data.dialogue.conversation.ConversationData.OutroData>
|
||||
public static function outroData(json:Json, name:String):Null<funkin.data.dialogue.ConversationData.OutroData>
|
||||
{
|
||||
switch (json.value)
|
||||
{
|
||||
|
||||
+20
-27
@@ -1,4 +1,4 @@
|
||||
package funkin.play.character;
|
||||
package funkin.data.character;
|
||||
|
||||
import funkin.data.animation.AnimationData;
|
||||
import funkin.modding.events.ScriptEvent;
|
||||
@@ -8,6 +8,11 @@ import funkin.play.character.ScriptedCharacter.ScriptedBaseCharacter;
|
||||
import funkin.play.character.ScriptedCharacter.ScriptedMultiSparrowCharacter;
|
||||
import funkin.play.character.ScriptedCharacter.ScriptedPackerCharacter;
|
||||
import funkin.play.character.ScriptedCharacter.ScriptedSparrowCharacter;
|
||||
import funkin.play.character.AnimateAtlasCharacter;
|
||||
import funkin.play.character.BaseCharacter;
|
||||
import funkin.play.character.SparrowCharacter;
|
||||
import funkin.play.character.MultiSparrowCharacter;
|
||||
import funkin.play.character.PackerCharacter;
|
||||
import funkin.util.assets.DataAssets;
|
||||
import funkin.util.VersionUtil;
|
||||
import haxe.Json;
|
||||
@@ -288,35 +293,23 @@ class CharacterDataParser
|
||||
{
|
||||
var charPath:String = "freeplay/icons/";
|
||||
|
||||
// FunkinCrew please dont skin me alive for copying pixelated icon and changing it a tiny bit
|
||||
switch (char)
|
||||
final charIDParts:Array<String> = char.split("-");
|
||||
var iconName:String = "";
|
||||
var lastValidIconName:String = "";
|
||||
for (i in 0...charIDParts.length)
|
||||
{
|
||||
case "bf-christmas" | "bf-car" | "bf-pixel" | "bf-holding-gf" | "bf-dark":
|
||||
charPath += "bfpixel";
|
||||
case "monster-christmas":
|
||||
charPath += "monsterpixel";
|
||||
case "mom" | "mom-car":
|
||||
charPath += "mommypixel";
|
||||
case "pico-blazin" | "pico-playable" | "pico-speaker" | "pico-pixel" | "pico-holding-nene":
|
||||
charPath += "picopixel";
|
||||
case "gf-christmas" | "gf-car" | "gf-pixel" | "gf-tankmen" | "gf-dark":
|
||||
charPath += "gfpixel";
|
||||
case "dad":
|
||||
charPath += "dadpixel";
|
||||
case "darnell-blazin":
|
||||
charPath += "darnellpixel";
|
||||
case "senpai-angry":
|
||||
charPath += "senpaipixel";
|
||||
case "spooky-dark":
|
||||
charPath += "spookypixel";
|
||||
case "tankman-atlas" | "tankman-bloody":
|
||||
charPath += "tankmanpixel";
|
||||
case "pico-christmas" | "pico-dark":
|
||||
charPath += "picopixel";
|
||||
default:
|
||||
charPath += '${char}pixel';
|
||||
iconName += charIDParts[i];
|
||||
|
||||
if (Assets.exists(Paths.image(charPath + '${iconName}pixel')))
|
||||
{
|
||||
lastValidIconName = iconName;
|
||||
}
|
||||
|
||||
if (i < charIDParts.length - 1) iconName += '-';
|
||||
}
|
||||
|
||||
charPath += '${lastValidIconName}pixel';
|
||||
|
||||
if (!Assets.exists(Paths.image(charPath)))
|
||||
{
|
||||
trace('[WARN] Character ${char} has no freeplay icon.');
|
||||
@@ -0,0 +1,39 @@
|
||||
# Dialogue Conversation Data Schema Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.0.0]
|
||||
Initial release.
|
||||
|
||||
|
||||
|
||||
|
||||
# Dialogue Box Data Schema Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.1.0]
|
||||
### Added
|
||||
- Added an option to specify the font used by the dialogue box. Defaults to `Arial` if unspecified.
|
||||
|
||||
## [1.0.0]
|
||||
Initial release.
|
||||
|
||||
|
||||
|
||||
|
||||
# Dialogue Speaker Data Schema Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.0.0]
|
||||
Initial release.
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package funkin.data.dialogue.conversation;
|
||||
package funkin.data.dialogue;
|
||||
|
||||
/**
|
||||
* A type definition for the data for a specific conversation.
|
||||
+7
-2
@@ -1,4 +1,4 @@
|
||||
package funkin.data.dialogue.conversation;
|
||||
package funkin.data.dialogue;
|
||||
|
||||
import funkin.play.cutscene.dialogue.Conversation;
|
||||
import funkin.play.cutscene.dialogue.ScriptedConversation;
|
||||
@@ -6,7 +6,7 @@ import funkin.util.tools.ISingleton;
|
||||
import funkin.data.DefaultRegistryImpl;
|
||||
|
||||
@:nullSafety
|
||||
class ConversationRegistry extends BaseRegistry<Conversation, ConversationData> implements ISingleton implements DefaultRegistryImpl
|
||||
class ConversationRegistry extends BaseRegistry<Conversation, ConversationData, ConversationEntryParams> implements ISingleton implements DefaultRegistryImpl
|
||||
{
|
||||
/**
|
||||
* The current version string for the dialogue box data format.
|
||||
@@ -22,3 +22,8 @@ class ConversationRegistry extends BaseRegistry<Conversation, ConversationData>
|
||||
super('CONVERSATION', 'dialogue/conversations', CONVERSATION_DATA_VERSION_RULE);
|
||||
}
|
||||
}
|
||||
|
||||
typedef ConversationEntryParams =
|
||||
{
|
||||
var placeholder:String;
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package funkin.data.dialogue.dialoguebox;
|
||||
package funkin.data.dialogue;
|
||||
|
||||
import funkin.data.animation.AnimationData;
|
||||
|
||||
+5
-3
@@ -1,13 +1,13 @@
|
||||
package funkin.data.dialogue.dialoguebox;
|
||||
package funkin.data.dialogue;
|
||||
|
||||
import funkin.play.cutscene.dialogue.DialogueBox;
|
||||
import funkin.data.dialogue.dialoguebox.DialogueBoxData;
|
||||
import funkin.data.dialogue.DialogueBoxData;
|
||||
import funkin.play.cutscene.dialogue.ScriptedDialogueBox;
|
||||
import funkin.util.tools.ISingleton;
|
||||
import funkin.data.DefaultRegistryImpl;
|
||||
|
||||
@:nullSafety
|
||||
class DialogueBoxRegistry extends BaseRegistry<DialogueBox, DialogueBoxData> implements ISingleton implements DefaultRegistryImpl
|
||||
class DialogueBoxRegistry extends BaseRegistry<DialogueBox, DialogueBoxData, DialogueBoxEntryParams> implements ISingleton implements DefaultRegistryImpl
|
||||
{
|
||||
/**
|
||||
* The current version string for the dialogue box data format.
|
||||
@@ -23,3 +23,5 @@ class DialogueBoxRegistry extends BaseRegistry<DialogueBox, DialogueBoxData> imp
|
||||
super('DIALOGUEBOX', 'dialogue/boxes', DIALOGUEBOX_DATA_VERSION_RULE);
|
||||
}
|
||||
}
|
||||
|
||||
typedef DialogueBoxEntryParams = Dynamic;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package funkin.data.dialogue.speaker;
|
||||
package funkin.data.dialogue;
|
||||
|
||||
import funkin.data.animation.AnimationData;
|
||||
|
||||
+4
-2
@@ -1,4 +1,4 @@
|
||||
package funkin.data.dialogue.speaker;
|
||||
package funkin.data.dialogue;
|
||||
|
||||
import funkin.play.cutscene.dialogue.Speaker;
|
||||
import funkin.play.cutscene.dialogue.ScriptedSpeaker;
|
||||
@@ -6,7 +6,7 @@ import funkin.util.tools.ISingleton;
|
||||
import funkin.data.DefaultRegistryImpl;
|
||||
|
||||
@:nullSafety
|
||||
class SpeakerRegistry extends BaseRegistry<Speaker, SpeakerData> implements ISingleton implements DefaultRegistryImpl
|
||||
class SpeakerRegistry extends BaseRegistry<Speaker, SpeakerData, SpeakerEntryParams> implements ISingleton implements DefaultRegistryImpl
|
||||
{
|
||||
/**
|
||||
* The current version string for the speaker data format.
|
||||
@@ -22,3 +22,5 @@ class SpeakerRegistry extends BaseRegistry<Speaker, SpeakerData> implements ISin
|
||||
super('SPEAKER', 'dialogue/speakers', SPEAKER_DATA_VERSION_RULE);
|
||||
}
|
||||
}
|
||||
|
||||
typedef SpeakerEntryParams = {}
|
||||
@@ -1,9 +0,0 @@
|
||||
# Dialogue Conversation Data Schema Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.0.0]
|
||||
Initial release.
|
||||
@@ -1,13 +0,0 @@
|
||||
# Dialogue Box Data Schema Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.1.0]
|
||||
### Added
|
||||
- Added an option to specify the font used by the dialogue box. Defaults to `Arial` if unspecified.
|
||||
|
||||
## [1.0.0]
|
||||
Initial release.
|
||||
@@ -1,9 +0,0 @@
|
||||
# Dialogue Speaker Data Schema Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.0.0]
|
||||
Initial release.
|
||||
@@ -7,7 +7,7 @@ import funkin.util.tools.ISingleton;
|
||||
import funkin.data.DefaultRegistryImpl;
|
||||
|
||||
@:nullSafety
|
||||
class AlbumRegistry extends BaseRegistry<Album, AlbumData> implements ISingleton implements DefaultRegistryImpl
|
||||
class AlbumRegistry extends BaseRegistry<Album, AlbumData, AlbumEntryParams> implements ISingleton implements DefaultRegistryImpl
|
||||
{
|
||||
/**
|
||||
* The current version string for the album data format.
|
||||
@@ -23,3 +23,5 @@ class AlbumRegistry extends BaseRegistry<Album, AlbumData> implements ISingleton
|
||||
super('ALBUM', 'ui/freeplay/albums', ALBUM_DATA_VERSION_RULE);
|
||||
}
|
||||
}
|
||||
|
||||
typedef AlbumEntryParams = {}
|
||||
|
||||
@@ -8,7 +8,7 @@ import funkin.util.tools.ISingleton;
|
||||
import funkin.data.DefaultRegistryImpl;
|
||||
|
||||
@:nullSafety
|
||||
class PlayerRegistry extends BaseRegistry<PlayableCharacter, PlayerData> implements ISingleton implements DefaultRegistryImpl
|
||||
class PlayerRegistry extends BaseRegistry<PlayableCharacter, PlayerData, PlayerEntryParams> implements ISingleton implements DefaultRegistryImpl
|
||||
{
|
||||
/**
|
||||
* The current version string for the stage data format.
|
||||
@@ -147,3 +147,5 @@ class PlayerRegistry extends BaseRegistry<PlayableCharacter, PlayerData> impleme
|
||||
#end
|
||||
}
|
||||
}
|
||||
|
||||
typedef PlayerEntryParams = {}
|
||||
|
||||
@@ -7,7 +7,8 @@ import funkin.util.tools.ISingleton;
|
||||
import funkin.data.DefaultRegistryImpl;
|
||||
|
||||
@:nullSafety
|
||||
class FreeplayStyleRegistry extends BaseRegistry<FreeplayStyle, FreeplayStyleData> implements ISingleton implements DefaultRegistryImpl
|
||||
class FreeplayStyleRegistry extends BaseRegistry<FreeplayStyle, FreeplayStyleData, FreeplayStyleEntryParams> implements ISingleton
|
||||
implements DefaultRegistryImpl
|
||||
{
|
||||
/**
|
||||
* The current version string for the style data format.
|
||||
@@ -23,3 +24,5 @@ class FreeplayStyleRegistry extends BaseRegistry<FreeplayStyle, FreeplayStyleDat
|
||||
super('FREEPLAYSTYLE', 'ui/freeplay/styles', FREEPLAYSTYLE_DATA_VERSION_RULE);
|
||||
}
|
||||
}
|
||||
|
||||
typedef FreeplayStyleEntryParams = {}
|
||||
|
||||
@@ -165,7 +165,7 @@ typedef NoteStyleAssetData<T> =
|
||||
var assetPath:String;
|
||||
|
||||
/**
|
||||
* The scale to render the prop at.
|
||||
* The scale to render the note at.
|
||||
* @default 1.0
|
||||
*/
|
||||
@:default(1.0)
|
||||
@@ -181,7 +181,7 @@ typedef NoteStyleAssetData<T> =
|
||||
var offsets:Null<Array<Float>>;
|
||||
|
||||
/**
|
||||
* If true, the prop is a pixel sprite, and will be rendered without anti-aliasing.
|
||||
* If true, the note is a pixel sprite, and will be rendered without anti-aliasing.
|
||||
*/
|
||||
@:default(false)
|
||||
@:optional
|
||||
|
||||
@@ -7,7 +7,7 @@ import funkin.util.tools.ISingleton;
|
||||
import funkin.data.DefaultRegistryImpl;
|
||||
|
||||
@:nullSafety
|
||||
class NoteStyleRegistry extends BaseRegistry<NoteStyle, NoteStyleData> implements ISingleton implements DefaultRegistryImpl
|
||||
class NoteStyleRegistry extends BaseRegistry<NoteStyle, NoteStyleData, NoteStyleEntryParams> implements ISingleton implements DefaultRegistryImpl
|
||||
{
|
||||
/**
|
||||
* The current version string for the note style data format.
|
||||
@@ -30,3 +30,5 @@ class NoteStyleRegistry extends BaseRegistry<NoteStyle, NoteStyleData> implement
|
||||
return notestyle;
|
||||
}
|
||||
}
|
||||
|
||||
typedef NoteStyleEntryParams = {}
|
||||
|
||||
@@ -1117,6 +1117,23 @@ class SongNoteDataRaw implements ICloneable<SongNoteDataRaw>
|
||||
return 'SongNoteData(${this.time}ms, ' + (this.length > 0 ? '[${this.length}ms hold]' : '') + ' ${this.data}'
|
||||
+ (this.kind != '' ? ' [kind: ${this.kind}])' : ')');
|
||||
}
|
||||
|
||||
public function buildTooltip():String
|
||||
{
|
||||
if ((this.kind?.length ?? 0) == 0) return "";
|
||||
|
||||
var result:String = 'Kind: ${this.kind}';
|
||||
if (this.params.length == 0) return result;
|
||||
|
||||
result += "\nParams:";
|
||||
|
||||
for (param in params)
|
||||
{
|
||||
result += '\n- ${param.name}: ${param.value}';
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,8 +15,7 @@ import funkin.data.DefaultRegistryImpl;
|
||||
|
||||
using funkin.data.song.migrator.SongDataMigrator;
|
||||
|
||||
@:nullSafety
|
||||
class SongRegistry extends BaseRegistry<Song, SongMetadata> implements ISingleton implements DefaultRegistryImpl
|
||||
@:nullSafety class SongRegistry extends BaseRegistry<Song, SongMetadata, SongEntryParams> implements ISingleton implements DefaultRegistryImpl
|
||||
{
|
||||
/**
|
||||
* The current version string for the stage data format.
|
||||
@@ -37,6 +36,8 @@ class SongRegistry extends BaseRegistry<Song, SongMetadata> implements ISingleto
|
||||
|
||||
public static var DEFAULT_GENERATEDBY(get, never):String;
|
||||
|
||||
public var scriptedSongVariations:Map<String, Song> = new Map<String, Song>();
|
||||
|
||||
static function get_DEFAULT_GENERATEDBY():String
|
||||
{
|
||||
return '${Constants.TITLE} - ${Constants.VERSION}';
|
||||
@@ -63,9 +64,17 @@ class SongRegistry extends BaseRegistry<Song, SongMetadata> implements ISingleto
|
||||
|
||||
if (entry != null)
|
||||
{
|
||||
log('Successfully created scripted entry (${entryCls} = ${entry.id})');
|
||||
entries.set(entry.id, entry);
|
||||
scriptedEntryIds.set(entry.id, entryCls);
|
||||
if (entry.variation != null)
|
||||
{
|
||||
scriptedSongVariations.set('${entry.id}:${entry.variation}', entry);
|
||||
log('Successfully created scripted entry (${entryCls} = ${entry.id}, ${entry.variation})');
|
||||
}
|
||||
else
|
||||
{
|
||||
entries.set(entry.id, entry);
|
||||
scriptedEntryIds.set(entry.id, entryCls);
|
||||
log('Successfully created scripted entry (${entryCls} = ${entry.id})');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -120,6 +129,28 @@ class SongRegistry extends BaseRegistry<Song, SongMetadata> implements ISingleto
|
||||
return parseEntryMetadataRaw(contents);
|
||||
}
|
||||
|
||||
/**
|
||||
* We override `fetchEntry` to handle song variations!
|
||||
*/
|
||||
public override function fetchEntry(id:String, ?params:SongEntryParams):Null<Song>
|
||||
{
|
||||
var variation:String = params?.variation ?? Constants.DEFAULT_VARIATION;
|
||||
|
||||
if (variation != Constants.DEFAULT_VARIATION)
|
||||
{
|
||||
if (scriptedSongVariations.exists('${id}:${variation}'))
|
||||
{
|
||||
var variationSongScript:Null<Song> = scriptedSongVariations.get('${id}:${variation}');
|
||||
if (variationSongScript != null)
|
||||
{
|
||||
return variationSongScript;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.fetchEntry(id, params);
|
||||
}
|
||||
|
||||
public function parseEntryMetadata(id:String, ?variation:String):Null<SongMetadata>
|
||||
{
|
||||
variation = variation == null ? Constants.DEFAULT_VARIATION : variation;
|
||||
@@ -395,12 +426,13 @@ class SongRegistry extends BaseRegistry<Song, SongMetadata> implements ISingleto
|
||||
}
|
||||
}
|
||||
|
||||
public function parseEntryChartDataRawWithMigration(contents:String, ?fileName:String = 'raw', version:thx.semver.Version):Null<SongChartData>
|
||||
public function parseEntryChartDataRawWithMigration(contents:String, ?fileName:String = 'raw', version:thx.semver.Version,
|
||||
?variation:String):Null<SongChartData>
|
||||
{
|
||||
// If a version rule is not specified, do not check against it.
|
||||
if (SONG_CHART_DATA_VERSION_RULE == null || VersionUtil.validateVersion(version, SONG_CHART_DATA_VERSION_RULE))
|
||||
{
|
||||
return parseEntryChartDataRaw(contents, fileName);
|
||||
return parseEntryChartDataRaw(contents, fileName, variation);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -517,3 +549,11 @@ class SongRegistry extends BaseRegistry<Song, SongMetadata> implements ISingleto
|
||||
return allDifficulties;
|
||||
}
|
||||
}
|
||||
|
||||
typedef SongEntryParams =
|
||||
{
|
||||
/**
|
||||
* The variation ID for the song.
|
||||
*/
|
||||
var variation:String;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ class ChartManifestData
|
||||
*/
|
||||
public static final CHART_MANIFEST_DATA_VERSION:thx.semver.Version = "1.0.0";
|
||||
|
||||
public static final invalidIdRegex:EReg = ~/[\/\\:*?"<>|]/g;
|
||||
|
||||
@:default(funkin.data.song.importer.ChartManifestData.CHART_MANIFEST_DATA_VERSION)
|
||||
@:jcustomparse(funkin.data.DataParse.semverVersion)
|
||||
@:jcustomwrite(funkin.data.DataWrite.semverVersion)
|
||||
@@ -19,7 +21,11 @@ class ChartManifestData
|
||||
* The internal song ID for this chart.
|
||||
* The metadata and chart data file names are derived from this.
|
||||
*/
|
||||
public var songId:String;
|
||||
public var songId(default, set):String;
|
||||
public function set_songId(value:String):String
|
||||
{
|
||||
return songId = invalidIdRegex.replace(value.trim(), '');
|
||||
}
|
||||
|
||||
public function new(songId:String)
|
||||
{
|
||||
|
||||
@@ -120,6 +120,11 @@ class LegacyNote
|
||||
|
||||
public inline function getKind():String
|
||||
{
|
||||
return this.alt ? 'alt' : 'normal';
|
||||
return this.alt ? 'alt' : '';
|
||||
}
|
||||
|
||||
public function toString():String
|
||||
{
|
||||
return 'LegacyNote(${this.time}, ${this.data}, ${this.length}, ${this.alt})';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ class FNFLegacyImporter
|
||||
{
|
||||
trace('Migrating song metadata from FNF Legacy.');
|
||||
|
||||
var songMetadata:SongMetadata = new SongMetadata('Import', Constants.DEFAULT_ARTIST, 'default');
|
||||
var songMetadata:SongMetadata = new SongMetadata('Import', Constants.DEFAULT_ARTIST, Constants.DEFAULT_CHARTER, Constants.DEFAULT_VARIATION);
|
||||
|
||||
// Set generatedBy string for debugging.
|
||||
songMetadata.generatedBy = 'Chart Editor Import (FNF Legacy)';
|
||||
@@ -95,8 +95,8 @@ class FNFLegacyImporter
|
||||
switch (songData.song.speed)
|
||||
{
|
||||
case Left(speed):
|
||||
// All difficulties will use the one scroll speed.
|
||||
songChartData.scrollSpeed.set('default', speed);
|
||||
// Sets the scroll speed for the difficulty.
|
||||
songChartData.scrollSpeed.set(difficulty, speed);
|
||||
case Right(speeds):
|
||||
if (speeds.easy != null) songChartData.scrollSpeed.set('easy', speeds.easy);
|
||||
if (speeds.normal != null) songChartData.scrollSpeed.set('normal', speeds.normal);
|
||||
|
||||
@@ -24,7 +24,7 @@ class SongDataMigrator
|
||||
|
||||
public static function migrate_SongMetadata_v2_1_0(input:SongData_v2_1_0.SongMetadata_v2_1_0):SongMetadata
|
||||
{
|
||||
var result:SongMetadata = new SongMetadata(input.songName, input.artist, input.variation);
|
||||
var result:SongMetadata = new SongMetadata(input.songName, input.artist, Constants.DEFAULT_CHARTER, input.variation);
|
||||
result.version = SongRegistry.SONG_METADATA_VERSION;
|
||||
result.timeFormat = input.timeFormat;
|
||||
result.divisions = input.divisions;
|
||||
@@ -66,7 +66,7 @@ class SongDataMigrator
|
||||
|
||||
public static function migrate_SongMetadata_v2_0_0(input:SongData_v2_0_0.SongMetadata_v2_0_0):SongMetadata
|
||||
{
|
||||
var result:SongMetadata = new SongMetadata(input.songName, input.artist, input.variation);
|
||||
var result:SongMetadata = new SongMetadata(input.songName, input.artist, Constants.DEFAULT_CHARTER, input.variation);
|
||||
result.version = SongRegistry.SONG_METADATA_VERSION;
|
||||
result.timeFormat = input.timeFormat;
|
||||
result.divisions = input.divisions;
|
||||
|
||||
@@ -6,7 +6,7 @@ import funkin.util.tools.ISingleton;
|
||||
import funkin.data.DefaultRegistryImpl;
|
||||
|
||||
@:nullSafety
|
||||
class StageRegistry extends BaseRegistry<Stage, StageData> implements ISingleton implements DefaultRegistryImpl
|
||||
class StageRegistry extends BaseRegistry<Stage, StageData, StageEntryParams> implements ISingleton implements DefaultRegistryImpl
|
||||
{
|
||||
/**
|
||||
* The current version string for the stage data format.
|
||||
@@ -22,3 +22,5 @@ class StageRegistry extends BaseRegistry<Stage, StageData> implements ISingleton
|
||||
super('STAGE', 'stages', STAGE_DATA_VERSION_RULE);
|
||||
}
|
||||
}
|
||||
|
||||
typedef StageEntryParams = {}
|
||||
|
||||
@@ -5,7 +5,7 @@ import funkin.ui.transition.stickers.StickerPack;
|
||||
import funkin.ui.transition.stickers.ScriptedStickerPack;
|
||||
|
||||
@:nullSafety
|
||||
class StickerRegistry extends BaseRegistry<StickerPack, StickerData>
|
||||
class StickerRegistry extends BaseRegistry<StickerPack, StickerData, StickerEntryParams>
|
||||
{
|
||||
/**
|
||||
* The current version string for the sticker pack data format.
|
||||
@@ -90,3 +90,5 @@ class StickerRegistry extends BaseRegistry<StickerPack, StickerData>
|
||||
return ScriptedStickerPack.listScriptClasses();
|
||||
}
|
||||
}
|
||||
|
||||
typedef StickerEntryParams = {}
|
||||
|
||||
@@ -7,7 +7,7 @@ import funkin.util.tools.ISingleton;
|
||||
import funkin.data.DefaultRegistryImpl;
|
||||
|
||||
@:nullSafety
|
||||
class LevelRegistry extends BaseRegistry<Level, LevelData> implements ISingleton implements DefaultRegistryImpl
|
||||
class LevelRegistry extends BaseRegistry<Level, LevelData, LevelEntryParams> implements ISingleton implements DefaultRegistryImpl
|
||||
{
|
||||
/**
|
||||
* The current version string for the level data format.
|
||||
@@ -56,3 +56,5 @@ class LevelRegistry extends BaseRegistry<Level, LevelData> implements ISingleton
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
typedef LevelEntryParams = {}
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
package funkin.external.android;
|
||||
|
||||
#if android
|
||||
import lime.system.JNI;
|
||||
import flixel.util.FlxSignal;
|
||||
|
||||
/**
|
||||
* A Utility class to handle Android API level callbacks and events.
|
||||
*/
|
||||
@:unreflective
|
||||
class CallbackUtil
|
||||
{
|
||||
/**
|
||||
* The result code for `DATA_FOLDER_CLOSED` activity.
|
||||
*/
|
||||
public static var DATA_FOLDER_CLOSED(get, never):Int;
|
||||
|
||||
@:noCompletion
|
||||
static function get_DATA_FOLDER_CLOSED():Int
|
||||
{
|
||||
final field:Null<Dynamic> = JNIUtil.createStaticField('funkin/extensions/CallbackUtil', 'DATA_FOLDER_CLOSED', 'I');
|
||||
|
||||
return field != null ? field.get() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal triggered when an activity result is received.
|
||||
*
|
||||
* First argument is the request code, second is the result code.
|
||||
*/
|
||||
public static var onActivityResult:FlxTypedSignal<Int->Int->Void> = new FlxTypedSignal<Int->Int->Void>();
|
||||
|
||||
/**
|
||||
* Initializes the callback utility.
|
||||
*/
|
||||
public static function init():Void
|
||||
{
|
||||
final initCallBackJNI:Null<Dynamic> = JNIUtil.createStaticMethod('funkin/extensions/CallbackUtil', 'initCallBack', '(Lorg/haxe/lime/HaxeObject;)V');
|
||||
|
||||
if (initCallBackJNI != null)
|
||||
{
|
||||
initCallBackJNI(new CallbackHandler());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal class to handle native callback events.
|
||||
*/
|
||||
class CallbackHandler #if (lime >= "8.0.0") implements JNISafety #end
|
||||
{
|
||||
@:allow(funkin.external.android.CallbackUtil)
|
||||
function new():Void {}
|
||||
|
||||
/**
|
||||
* Handles the activity result callback from native code.
|
||||
*
|
||||
* @param requestCode The request code of the acitivty.
|
||||
* @param resultCode The result code of the acitivty.
|
||||
*/
|
||||
@:keep
|
||||
#if (lime >= "8.0.0")
|
||||
@:runOnMainThread
|
||||
#end
|
||||
public function onActivityResult(requestCode:Int, resultCode:Int):Void
|
||||
{
|
||||
if (CallbackUtil.onActivityResult != null) CallbackUtil.onActivityResult.dispatch(requestCode, resultCode);
|
||||
}
|
||||
}
|
||||
#end
|
||||
@@ -0,0 +1,23 @@
|
||||
package funkin.external.android;
|
||||
|
||||
#if android
|
||||
/**
|
||||
* A Utility class to manage the Application's Data folder on Android.
|
||||
*/
|
||||
@:unreflective
|
||||
class DataFolderUtil
|
||||
{
|
||||
/**
|
||||
* Opens the data folder on an Android device using JNI.
|
||||
*/
|
||||
public static function openDataFolder():Void
|
||||
{
|
||||
final openDataFolderJNI:Null<Dynamic> = JNIUtil.createStaticMethod('funkin/util/DataFolderUtil', 'openDataFolder', '(I)V');
|
||||
|
||||
if (openDataFolderJNI != null)
|
||||
{
|
||||
openDataFolderJNI(CallbackUtil.DATA_FOLDER_CLOSED);
|
||||
}
|
||||
}
|
||||
}
|
||||
#end
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
package funkin.external.android;
|
||||
|
||||
#if android
|
||||
import lime.system.JNI;
|
||||
|
||||
/**
|
||||
* A utility class for caching JNI method and field references.
|
||||
*/
|
||||
class JNIUtil
|
||||
{
|
||||
@:noCompletion
|
||||
private static var staticMethodCache:Map<String, Dynamic> = [];
|
||||
|
||||
@:noCompletion
|
||||
private static var memberMethodCache:Map<String, Dynamic> = [];
|
||||
|
||||
@:noCompletion
|
||||
private static var staticFieldCache:Map<String, JNIStaticField> = [];
|
||||
|
||||
@:noCompletion
|
||||
private static var memberFieldCache:Map<String, JNIMemberField> = [];
|
||||
|
||||
/**
|
||||
* Retrieves or creates a cached static method reference.
|
||||
*
|
||||
* @param className The name of the Java class containing the method.
|
||||
* @param methodName The name of the method.
|
||||
* @param signature The method signature in JNI format.
|
||||
* @param cache Whether to cache the result (default true).
|
||||
* @return A dynamic reference to the static method.
|
||||
*/
|
||||
public static function createStaticMethod(className:String, methodName:String, signature:String, cache:Bool = true):Null<Dynamic>
|
||||
{
|
||||
@:privateAccess
|
||||
className = JNI.transformClassName(className);
|
||||
|
||||
final key:String = '$className::$methodName::$signature';
|
||||
|
||||
if (cache && !staticMethodCache.exists(key)) staticMethodCache.set(key, JNI.createStaticMethod(className, methodName, signature));
|
||||
else if (!cache) return JNI.createStaticMethod(className, methodName, signature);
|
||||
|
||||
return staticMethodCache.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves or creates a cached member method reference.
|
||||
*
|
||||
* @param className The name of the Java class containing the method.
|
||||
* @param methodName The name of the method.
|
||||
* @param signature The method signature in JNI format.
|
||||
* @param cache Whether to cache the result (default true).
|
||||
* @return A dynamic reference to the member method.
|
||||
*/
|
||||
public static function createMemberMethod(className:String, methodName:String, signature:String, cache:Bool = true):Null<Dynamic>
|
||||
{
|
||||
@:privateAccess
|
||||
className = JNI.transformClassName(className);
|
||||
|
||||
final key:String = '$className::$methodName::$signature';
|
||||
|
||||
if (cache && !memberMethodCache.exists(key)) memberMethodCache.set(key, JNI.createMemberMethod(className, methodName, signature));
|
||||
else if (!cache) return JNI.createMemberMethod(className, methodName, signature);
|
||||
|
||||
return memberMethodCache.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves or creates a cached static field reference.
|
||||
*
|
||||
* @param className The name of the Java class containing the field.
|
||||
* @param fieldName The name of the field.
|
||||
* @param signature The field signature in JNI format.
|
||||
* @param cache Whether to cache the result (default true).
|
||||
* @return A reference to the static field.
|
||||
*/
|
||||
public static function createStaticField(className:String, fieldName:String, signature:String, cache:Bool = true):Null<JNIStaticField>
|
||||
{
|
||||
@:privateAccess
|
||||
className = JNI.transformClassName(className);
|
||||
|
||||
final key:String = '$className::$fieldName::$signature';
|
||||
|
||||
if (cache && !staticFieldCache.exists(key)) staticFieldCache.set(key, JNI.createStaticField(className, fieldName, signature));
|
||||
else if (!cache) return JNI.createStaticField(className, fieldName, signature);
|
||||
|
||||
return staticFieldCache.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves or creates a cached member field reference.
|
||||
*
|
||||
* @param className The name of the Java class containing the field.
|
||||
* @param fieldName The name of the field.
|
||||
* @param signature The field signature in JNI format.
|
||||
* @param cache Whether to cache the result (default true).
|
||||
* @return A reference to the member field.
|
||||
*/
|
||||
public static function createMemberField(className:String, fieldName:String, signature:String, cache:Bool = true):Null<JNIMemberField>
|
||||
{
|
||||
@:privateAccess
|
||||
className = JNI.transformClassName(className);
|
||||
|
||||
final key:String = '$className::$fieldName::$signature';
|
||||
|
||||
if (cache && !memberFieldCache.exists(key)) memberFieldCache.set(key, JNI.createMemberField(className, fieldName, signature));
|
||||
else if (!cache) return JNI.createMemberField(className, fieldName, signature);
|
||||
|
||||
return memberFieldCache.get(key);
|
||||
}
|
||||
}
|
||||
#end
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package funkin.external.android;
|
||||
|
||||
#if android
|
||||
import lime.math.Rectangle;
|
||||
import lime.system.JNI;
|
||||
|
||||
/**
|
||||
* A Utility class to get Android screen related informations.
|
||||
*/
|
||||
@:unreflective
|
||||
class ScreenUtil
|
||||
{
|
||||
/**
|
||||
* Retrieves the dimensions of display cutouts (such as notches) on Android devices.
|
||||
*
|
||||
* @return An array of `Rectangle` objects, each representing a display cutout's position and size.
|
||||
*/
|
||||
public static function getCutoutDimensions():Array<Rectangle>
|
||||
{
|
||||
final getCutoutDimensionsJNI:Null<Dynamic> = JNIUtil.createStaticMethod('funkin/util/ScreenUtil', 'getCutoutDimensions', '()[Landroid/graphics/Rect;');
|
||||
|
||||
if (getCutoutDimensionsJNI != null)
|
||||
{
|
||||
final rectangles:Array<Rectangle> = [];
|
||||
|
||||
for (rectangle in cast(getCutoutDimensionsJNI(), Array<Dynamic>))
|
||||
{
|
||||
if (rectangle == null) continue;
|
||||
|
||||
final topJNI:Null<JNIMemberField> = JNIUtil.createMemberField('android/graphics/Rect', 'top', 'I');
|
||||
final leftJNI:Null<JNIMemberField> = JNIUtil.createMemberField('android/graphics/Rect', 'left', 'I');
|
||||
final rightJNI:Null<JNIMemberField> = JNIUtil.createMemberField('android/graphics/Rect', 'right', 'I');
|
||||
final bottomJNI:Null<JNIMemberField> = JNIUtil.createMemberField('android/graphics/Rect', 'bottom', 'I');
|
||||
|
||||
if (topJNI != null && leftJNI != null && rightJNI != null && bottomJNI != null)
|
||||
{
|
||||
final top:Int = topJNI.get(rectangle);
|
||||
final left:Int = leftJNI.get(rectangle);
|
||||
final right:Int = rightJNI.get(rectangle);
|
||||
final bottom:Int = bottomJNI.get(rectangle);
|
||||
|
||||
rectangles.push(new Rectangle(left, top, right - left, bottom - top));
|
||||
}
|
||||
}
|
||||
|
||||
return rectangles;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
#end
|
||||
@@ -0,0 +1,36 @@
|
||||
package funkin.extensions;
|
||||
|
||||
import android.content.Intent;
|
||||
|
||||
import org.haxe.extension.Extension;
|
||||
|
||||
import org.haxe.lime.HaxeObject;
|
||||
|
||||
public class CallbackUtil extends Extension
|
||||
{
|
||||
/**
|
||||
* Constant representing the event when the data folder is closed.
|
||||
*/
|
||||
public static int DATA_FOLDER_CLOSED = 0x01;
|
||||
|
||||
private static HaxeObject haxeObject;
|
||||
|
||||
/**
|
||||
* Initializes the callback object for handling Haxe callbacks.
|
||||
*
|
||||
* @param haxeObject The HaxeObject instance to handle callbacks.
|
||||
*/
|
||||
public static void initCallBack(final HaxeObject haxeObject)
|
||||
{
|
||||
CallbackUtil.haxeObject = haxeObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActivityResult(int requestCode, int resultCode, Intent data)
|
||||
{
|
||||
if (haxeObject != null)
|
||||
haxeObject.call2("onActivityResult", requestCode, resultCode);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,346 @@
|
||||
package funkin.provider;
|
||||
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
import android.database.Cursor;
|
||||
import android.database.MatrixCursor;
|
||||
import android.graphics.Point;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.provider.DocumentsContract.Document;
|
||||
import android.provider.DocumentsContract.Root;
|
||||
import android.provider.DocumentsProvider;
|
||||
import android.webkit.MimeTypeMap;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
* @see https://github.com/termux/termux-app/blob/7bceab88e2272f961d1b94ef736f1a9e20173247/app/src/main/java/com/termux/filepicker/TermuxDocumentsProvider.java
|
||||
*/
|
||||
public class DataFolderProvider extends DocumentsProvider
|
||||
{
|
||||
private static File BASE_DIR;
|
||||
|
||||
private static String BASE_DIR_PATH;
|
||||
|
||||
private static final String[] DEFAULT_ROOT_PROJECTION = new String[] {
|
||||
Root.COLUMN_ROOT_ID,
|
||||
Root.COLUMN_MIME_TYPES,
|
||||
Root.COLUMN_FLAGS,
|
||||
Root.COLUMN_ICON,
|
||||
Root.COLUMN_TITLE,
|
||||
Root.COLUMN_SUMMARY,
|
||||
Root.COLUMN_DOCUMENT_ID,
|
||||
Root.COLUMN_AVAILABLE_BYTES
|
||||
};
|
||||
|
||||
private static final String[] DEFAULT_DOCUMENT_PROJECTION = new String[] {
|
||||
Document.COLUMN_DOCUMENT_ID,
|
||||
Document.COLUMN_MIME_TYPE,
|
||||
Document.COLUMN_DISPLAY_NAME,
|
||||
Document.COLUMN_LAST_MODIFIED,
|
||||
Document.COLUMN_FLAGS,
|
||||
Document.COLUMN_SIZE
|
||||
};
|
||||
|
||||
@Override
|
||||
public Cursor queryRoots(String[] projection)
|
||||
{
|
||||
final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_ROOT_PROJECTION);
|
||||
|
||||
if (BASE_DIR == null)
|
||||
return result;
|
||||
|
||||
final MatrixCursor.RowBuilder row = result.newRow();
|
||||
|
||||
row.add(Root.COLUMN_ROOT_ID, getDocIdForFile(BASE_DIR));
|
||||
row.add(Root.COLUMN_DOCUMENT_ID, getDocIdForFile(BASE_DIR));
|
||||
row.add(Root.COLUMN_SUMMARY, "Data Folder");
|
||||
row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE | Root.FLAG_SUPPORTS_SEARCH | Root.FLAG_SUPPORTS_IS_CHILD);
|
||||
row.add(Root.COLUMN_TITLE, "::APP_TITLE::");
|
||||
row.add(Root.COLUMN_MIME_TYPES, "*/*");
|
||||
row.add(Root.COLUMN_AVAILABLE_BYTES, BASE_DIR.getFreeSpace());
|
||||
::if (APP_PACKAGE != "")::
|
||||
row.add(Root.COLUMN_ICON, ::APP_PACKAGE::.R.mipmap.ic_launcher);
|
||||
::end::
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor queryDocument(String documentId, String[] projection) throws FileNotFoundException
|
||||
{
|
||||
final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION);
|
||||
includeFile(result, documentId, null);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor queryChildDocuments(String parentDocumentId, String[] projection, String sortOrder) throws FileNotFoundException
|
||||
{
|
||||
final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION);
|
||||
|
||||
File parent = getFileForDocId(parentDocumentId);
|
||||
|
||||
if (parent != null)
|
||||
{
|
||||
File[] children = null;
|
||||
|
||||
try {
|
||||
children = parent.listFiles();
|
||||
} catch (SecurityException e) {
|
||||
children = new File[0];
|
||||
}
|
||||
|
||||
if (children != null)
|
||||
{
|
||||
for (File file : children)
|
||||
includeFile(result, null, file);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParcelFileDescriptor openDocument(String documentId, String mode, CancellationSignal signal) throws FileNotFoundException
|
||||
{
|
||||
return ParcelFileDescriptor.open(getFileForDocId(documentId), ParcelFileDescriptor.parseMode(mode));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AssetFileDescriptor openDocumentThumbnail(String documentId, Point sizeHint, CancellationSignal signal) throws FileNotFoundException
|
||||
{
|
||||
final File file = getFileForDocId(documentId);
|
||||
final ParcelFileDescriptor pfd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
|
||||
return new AssetFileDescriptor(pfd, 0, file.length());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreate()
|
||||
{
|
||||
BASE_DIR = getContext().getExternalFilesDir(null);
|
||||
|
||||
if (BASE_DIR == null)
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
BASE_DIR_PATH = BASE_DIR.getCanonicalPath();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
BASE_DIR_PATH = BASE_DIR.getAbsolutePath();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createDocument(String parentDocumentId, String mimeType, String displayName) throws FileNotFoundException
|
||||
{
|
||||
File parentFile = getFileForDocId(parentDocumentId);
|
||||
|
||||
File newFile = new File(parentFile, displayName);
|
||||
|
||||
int noConflictId = 2;
|
||||
|
||||
while (newFile.exists())
|
||||
{
|
||||
newFile = new File(parentFile, displayName + " (" + noConflictId++ + ")");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
boolean succeeded;
|
||||
|
||||
if (Document.MIME_TYPE_DIR.equals(mimeType))
|
||||
succeeded = newFile.mkdir();
|
||||
else
|
||||
succeeded = newFile.createNewFile();
|
||||
|
||||
if (!succeeded)
|
||||
throw new FileNotFoundException("Failed to create document with id " + newFile.getPath());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new FileNotFoundException("Failed to create document with id " + newFile.getPath());
|
||||
}
|
||||
|
||||
return newFile.getPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteDocument(String documentId) throws FileNotFoundException
|
||||
{
|
||||
if (!deleteRecursive(getFileForDocId(documentId)))
|
||||
throw new FileNotFoundException("Failed to delete document with id " + documentId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDocumentType(String documentId) throws FileNotFoundException
|
||||
{
|
||||
return getMimeType(getFileForDocId(documentId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor querySearchDocuments(String rootId, String query, String[] projection) throws FileNotFoundException
|
||||
{
|
||||
final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION);
|
||||
|
||||
final LinkedList<File> pending = new LinkedList<>();
|
||||
|
||||
pending.add(getFileForDocId(rootId));
|
||||
|
||||
final int MAX_SEARCH_RESULTS = 50;
|
||||
|
||||
while (!pending.isEmpty() && result.getCount() < MAX_SEARCH_RESULTS)
|
||||
{
|
||||
final File file = pending.removeFirst();
|
||||
|
||||
boolean isInsideHome;
|
||||
|
||||
try
|
||||
{
|
||||
isInsideHome = file.getCanonicalPath().startsWith(BASE_DIR_PATH);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
isInsideHome = true;
|
||||
}
|
||||
|
||||
if (isInsideHome)
|
||||
{
|
||||
if (file.isDirectory())
|
||||
{
|
||||
try {
|
||||
Collections.addAll(pending, file.listFiles());
|
||||
} catch (SecurityException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
else if (file.getName().toLowerCase().contains(query))
|
||||
{
|
||||
includeFile(result, null, file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChildDocument(String parentDocumentId, String documentId)
|
||||
{
|
||||
try
|
||||
{
|
||||
File parent = getFileForDocId(parentDocumentId).getCanonicalFile();
|
||||
File child = getFileForDocId(documentId).getCanonicalFile();
|
||||
return child.getPath().startsWith(parent.getPath() + "/");
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean deleteRecursive(File file)
|
||||
{
|
||||
if (file.isDirectory())
|
||||
{
|
||||
File[] children = file.listFiles();
|
||||
|
||||
if (children != null)
|
||||
{
|
||||
for (File child : children)
|
||||
{
|
||||
if (!deleteRecursive(child))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return file.delete();
|
||||
}
|
||||
|
||||
private static String getDocIdForFile(File file)
|
||||
{
|
||||
return file.getAbsolutePath();
|
||||
}
|
||||
|
||||
private static File getFileForDocId(String docId) throws FileNotFoundException
|
||||
{
|
||||
if (BASE_DIR == null)
|
||||
throw new FileNotFoundException("Base directory not available");
|
||||
|
||||
final File f = (docId == null || docId.isEmpty()) ? BASE_DIR : new File(docId);
|
||||
|
||||
if (!f.exists())
|
||||
throw new FileNotFoundException(f.getAbsolutePath() + " not found");
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
private static String getMimeType(File file)
|
||||
{
|
||||
if (file == null || file.isDirectory())
|
||||
return Document.MIME_TYPE_DIR;
|
||||
|
||||
String name = file.getName();
|
||||
|
||||
int lastDot = name.lastIndexOf('.');
|
||||
|
||||
if (lastDot >= 0)
|
||||
{
|
||||
String extension = name.substring(lastDot + 1).toLowerCase();
|
||||
|
||||
String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
|
||||
|
||||
if (mime != null)
|
||||
return mime;
|
||||
}
|
||||
|
||||
return "application/octet-stream";
|
||||
}
|
||||
|
||||
private void includeFile(MatrixCursor result, String docId, File file) throws FileNotFoundException
|
||||
{
|
||||
if (docId == null)
|
||||
docId = getDocIdForFile(file);
|
||||
else
|
||||
file = getFileForDocId(docId);
|
||||
|
||||
int flags = 0;
|
||||
|
||||
if (file.isDirectory())
|
||||
{
|
||||
if (file.canWrite())
|
||||
flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
|
||||
}
|
||||
else if (file.canWrite())
|
||||
{
|
||||
flags |= Document.FLAG_SUPPORTS_WRITE;
|
||||
}
|
||||
|
||||
if (file.getParentFile() != null && file.getParentFile().canWrite())
|
||||
flags |= Document.FLAG_SUPPORTS_DELETE;
|
||||
|
||||
final String mimeType = getMimeType(file);
|
||||
|
||||
if (mimeType.startsWith("image/"))
|
||||
flags |= Document.FLAG_SUPPORTS_THUMBNAIL;
|
||||
|
||||
final MatrixCursor.RowBuilder row = result.newRow();
|
||||
row.add(Document.COLUMN_DOCUMENT_ID, docId);
|
||||
row.add(Document.COLUMN_DISPLAY_NAME, file.getName());
|
||||
row.add(Document.COLUMN_SIZE, file.length());
|
||||
row.add(Document.COLUMN_MIME_TYPE, mimeType);
|
||||
row.add(Document.COLUMN_LAST_MODIFIED, file.lastModified());
|
||||
row.add(Document.COLUMN_FLAGS, flags);
|
||||
::if (APP_PACKAGE != "")::
|
||||
row.add(Document.COLUMN_ICON, ::APP_PACKAGE::.R.mipmap.ic_launcher);
|
||||
::end::
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package funkin.util;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.ContentResolver;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.content.pm.PackageInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.haxe.extension.Extension;
|
||||
|
||||
public class DataFolderUtil
|
||||
{
|
||||
/**
|
||||
* A method that opens the Application's data folder for browsing through the Storage Access Framework.
|
||||
* It's highly based on some code borrowed from Mterial Files
|
||||
* https://github.com/zhanghai/MaterialFiles
|
||||
*/
|
||||
public static void openDataFolder(int requestCode)
|
||||
{
|
||||
::if (APP_PACKAGE != "")::
|
||||
if (Extension.mainActivity != null)
|
||||
{
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setDataAndType(DocumentsContract.buildRootUri("::APP_PACKAGE::.docprovider", ""), "vnd.android.document/directory");
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
Extension.mainActivity.startActivityForResult(intent, requestCode);
|
||||
}
|
||||
::end::
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package funkin.util;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.view.DisplayCutout;
|
||||
import android.view.WindowInsets;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.haxe.extension.Extension;
|
||||
|
||||
public class ScreenUtil
|
||||
{
|
||||
public static Rect[] getCutoutDimensions()
|
||||
{
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
|
||||
{
|
||||
if (Extension.mainActivity != null)
|
||||
{
|
||||
WindowInsets insets = Extension.mainActivity.getWindow().getDecorView().getRootWindowInsets();
|
||||
|
||||
if (insets != null)
|
||||
{
|
||||
DisplayCutout cutout = insets.getDisplayCutout();
|
||||
|
||||
if (cutout != null)
|
||||
{
|
||||
List<Rect> boundingRects = cutout.getBoundingRects();
|
||||
|
||||
if (boundingRects != null && !boundingRects.isEmpty())
|
||||
return boundingRects.toArray(new Rect[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Rect[0];
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package funkin.external.apple;
|
||||
|
||||
#if ((ios || macos) && cpp)
|
||||
/**
|
||||
* A utility class to manage the audio session on apple devices.
|
||||
*/
|
||||
@:build(funkin.util.macro.LinkerMacro.xml('project/Build.xml'))
|
||||
@:include('AudioSession.hpp')
|
||||
@:unreflective
|
||||
extern class AudioSession
|
||||
{
|
||||
/**
|
||||
* Initializes the audio session for playback.
|
||||
*
|
||||
* This function configures the shared AVAudioSession instance with the following settings:
|
||||
* - Sets the audio session category to Playback, allowing Bluetooth A2DP and mixing with spoken audio interruptions.
|
||||
* - For iOS 17.0 and above, disables interruption on route disconnect.
|
||||
* - For iOS 14.5 and above, prefers no interruptions from system alerts.
|
||||
*/
|
||||
@:native('Apple_AudioSession_Initialize')
|
||||
static function initialize():Void;
|
||||
|
||||
/**
|
||||
* Sets the active state of the shared AVAudioSession.
|
||||
*
|
||||
* @param active Whether to activate or deactivate the audio session.
|
||||
*/
|
||||
@:native('Apple_AudioSession_SetActive')
|
||||
static function setActive(active:Bool):Void;
|
||||
}
|
||||
#end
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package funkin.external.apple;
|
||||
|
||||
#if ((ios || macos) && cpp)
|
||||
/**
|
||||
* A utility class to get information about the mem usage.
|
||||
*/
|
||||
@:build(funkin.util.macro.LinkerMacro.xml('project/Build.xml'))
|
||||
@:include('MemoryUtil.hpp')
|
||||
@:unreflective
|
||||
extern class MemoryUtil
|
||||
{
|
||||
/**
|
||||
* Retrieves the current process's resident set size (RSS) in bytes on Apple platforms.
|
||||
*
|
||||
* @return The resident set size (RSS) in bytes if successful; otherwise, returns 0 on failure.
|
||||
*/
|
||||
@:native('Apple_MemoryUtil_GetCurrentProcessRss')
|
||||
static function getCurrentProcessRss():cpp.SizeT;
|
||||
}
|
||||
#end
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package funkin.external.apple;
|
||||
|
||||
#if ((ios || macos) && cpp)
|
||||
/**
|
||||
* A utility class to get screen related informations on apple devices.
|
||||
*/
|
||||
@:build(funkin.util.macro.LinkerMacro.xml('project/Build.xml'))
|
||||
@:include('ScreenUtil.hpp')
|
||||
@:unreflective
|
||||
extern class ScreenUtil
|
||||
{
|
||||
/**
|
||||
* Retrieves the safe area insets for the current screen on iOS devices.
|
||||
*
|
||||
* This function populates the provided pointers with the safe area insets (in pixels) for the top, bottom, left, and right edges of the screen.
|
||||
* On iOS 11 and later, it uses the main window's safeAreaInsets and converts them to pixel values using the screen scale.
|
||||
* On earlier iOS versions, all insets are set to 0.0.
|
||||
*
|
||||
* @param top Pointer to a double to receive the top safe area inset (in pixels).
|
||||
* @param bottom Pointer to a double to receive the bottom safe area inset (in pixels).
|
||||
* @param left Pointer to a double to receive the left safe area inset (in pixels).
|
||||
* @param right Pointer to a double to receive the right safe area inset (in pixels).
|
||||
*/
|
||||
@:native('Apple_ScreenUtil_GetSafeAreaInsets')
|
||||
static function getSafeAreaInsets(top:cpp.RawPointer<Float>, bottom:cpp.RawPointer<Float>, left:cpp.RawPointer<Float>, right:cpp.RawPointer<Float>):Void;
|
||||
|
||||
/**
|
||||
* Retrieves the size of the main screen in pixels.
|
||||
*
|
||||
* @param width Pointer to a double where the screen width (in pixels) will be stored.
|
||||
* @param height Pointer to a double where the screen height (in pixels) will be stored.
|
||||
*/
|
||||
@:native('Apple_ScreenUtil_GetScreenSize')
|
||||
static function getScreenSize(width:cpp.RawPointer<Float>, height:cpp.RawPointer<Float>):Void;
|
||||
}
|
||||
#end
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xml>
|
||||
<pragma once="true" />
|
||||
|
||||
<files id="haxe">
|
||||
<compilerflag value="-I${this_dir}/include" />
|
||||
</files>
|
||||
|
||||
<files id="__main__">
|
||||
<compilerflag value="-I${this_dir}/include" />
|
||||
</files>
|
||||
|
||||
<files id="external-apple">
|
||||
<compilerflag value="-I${this_dir}/include" />
|
||||
|
||||
<file name="${this_dir}/src/AudioSession.mm" />
|
||||
<file name="${this_dir}/src/MemoryUtil.mm" />
|
||||
<file name="${this_dir}/src/ScreenUtil.mm" />
|
||||
</files>
|
||||
|
||||
<target id="haxe">
|
||||
<vflag name="-framework" value="UIKit" unless="macos" />
|
||||
<vflag name="-framework" value="Foundation" />
|
||||
<vflag name="-framework" value="AVFAudio" />
|
||||
|
||||
<files id="external-apple" />
|
||||
</target>
|
||||
</xml>
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* Initializes the audio session for playback.
|
||||
*
|
||||
* This function configures the shared AVAudioSession instance with the following settings:
|
||||
* - Sets the audio session category to Playback, allowing Bluetooth A2DP and mixing with spoken audio interruptions.
|
||||
* - For iOS 17.0 and above, disables interruption on route disconnect.
|
||||
* - For iOS 14.5 and above, prefers no interruptions from system alerts.
|
||||
*/
|
||||
void Apple_AudioSession_Initialize();
|
||||
|
||||
/**
|
||||
* Sets the active state of the shared AVAudioSession.
|
||||
*
|
||||
* @param active Whether to activate or deactivate the audio session.
|
||||
*/
|
||||
void Apple_AudioSession_SetActive(bool active);
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
/**
|
||||
* Retrieves the current process's resident set size (RSS) in bytes on Apple platforms.
|
||||
*
|
||||
* @return The resident set size (RSS) in bytes if successful; otherwise, returns 0 on failure.
|
||||
*/
|
||||
size_t Apple_MemoryUtil_GetCurrentProcessRss();
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* Retrieves the safe area insets for the current screen on iOS devices.
|
||||
*
|
||||
* This function populates the provided pointers with the safe area insets (in pixels) for the top, bottom, left, and right edges of the screen.
|
||||
* On iOS 11 and later, it uses the main window's safeAreaInsets and converts them to pixel values using the screen scale.
|
||||
* On earlier iOS versions, all insets are set to 0.0.
|
||||
*
|
||||
* @param top Pointer to a double to receive the top safe area inset (in pixels).
|
||||
* @param bottom Pointer to a double to receive the bottom safe area inset (in pixels).
|
||||
* @param left Pointer to a double to receive the left safe area inset (in pixels).
|
||||
* @param right Pointer to a double to receive the right safe area inset (in pixels).
|
||||
*/
|
||||
void Apple_ScreenUtil_GetSafeAreaInsets(double* top, double* bottom, double* left, double* right);
|
||||
|
||||
/**
|
||||
* Retrieves the size of the main screen in pixels.
|
||||
*
|
||||
* @param width Pointer to a double where the screen width (in pixels) will be stored.
|
||||
* @param height Pointer to a double where the screen height (in pixels) will be stored.
|
||||
*/
|
||||
void Apple_ScreenUtil_GetScreenSize(double* width, double* height);
|
||||
@@ -0,0 +1,43 @@
|
||||
#import "AudioSession.hpp"
|
||||
|
||||
#import <TargetConditionals.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AVFAudio/AVFAudio.h>
|
||||
|
||||
void Apple_AudioSession_Initialize()
|
||||
{
|
||||
#if TARGET_OS_IOS
|
||||
AVAudioSession *session = [AVAudioSession sharedInstance];
|
||||
|
||||
NSError *error;
|
||||
|
||||
[session setCategory:AVAudioSessionCategoryPlayback mode:AVAudioSessionModeDefault options:AVAudioSessionCategoryOptionAllowBluetoothA2DP | AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers error:&error];
|
||||
|
||||
if (@available(iOS 17.0, *))
|
||||
{
|
||||
[session setPrefersInterruptionOnRouteDisconnect:false error:nil];
|
||||
}
|
||||
|
||||
if (@available(iOS 14.5, *))
|
||||
{
|
||||
[session setPrefersNoInterruptionsFromSystemAlerts:true error:nil];
|
||||
}
|
||||
|
||||
if (error)
|
||||
NSLog(@"Unable to set category of audio session: %@", error);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Apple_AudioSession_SetActive(bool active)
|
||||
{
|
||||
#if TARGET_OS_IOS
|
||||
AVAudioSession *session = [AVAudioSession sharedInstance];
|
||||
|
||||
NSError *error;
|
||||
|
||||
[session setActive:active error:&error];
|
||||
|
||||
if (error)
|
||||
NSLog(@"Unable to set active of audio session: %@", error);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#import "MemoryUtil.hpp"
|
||||
|
||||
#include <mach/mach.h>
|
||||
|
||||
size_t Apple_MemoryUtil_GetCurrentProcessRss()
|
||||
{
|
||||
struct task_basic_info info;
|
||||
|
||||
mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT;
|
||||
|
||||
if (task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &count) != KERN_SUCCESS)
|
||||
return 0;
|
||||
|
||||
return info.resident_size;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
#import "ScreenUtil.hpp"
|
||||
|
||||
#import <TargetConditionals.h>
|
||||
#if TARGET_OS_IOS
|
||||
#import <UIKit/UIKit.h>
|
||||
#endif
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
void Apple_ScreenUtil_GetSafeAreaInsets(double* top, double* bottom, double* left, double* right)
|
||||
{
|
||||
#if TARGET_OS_IOS
|
||||
if (@available(iOS 11, *))
|
||||
{
|
||||
UIWindow* window = [UIApplication sharedApplication].windows[0];
|
||||
UIEdgeInsets safeAreaInsets = window.safeAreaInsets;
|
||||
float scale = [UIScreen mainScreen].scale;
|
||||
|
||||
(*top) = safeAreaInsets.top * scale;
|
||||
(*bottom) = safeAreaInsets.bottom * scale;
|
||||
(*left) = safeAreaInsets.left * scale;
|
||||
(*right) = safeAreaInsets.right * scale;
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
(*top) = 0.0;
|
||||
(*bottom) = 0.0;
|
||||
(*left) = 0.0;
|
||||
(*right) = 0.0;
|
||||
}
|
||||
|
||||
void Apple_ScreenUtil_GetScreenSize(double* width, double* height)
|
||||
{
|
||||
#if TARGET_OS_IOS
|
||||
CGRect screenRect = [[UIScreen mainScreen] bounds];
|
||||
float scale = [UIScreen mainScreen].scale;
|
||||
|
||||
(*width) = (double)screenRect.size.width * scale;
|
||||
(*height) = (double)screenRect.size.height * scale;
|
||||
#else
|
||||
(*width) = 0.0;
|
||||
(*width) = 0.0;
|
||||
#endif
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
package funkin.external.windows;
|
||||
|
||||
#if (windows && cpp)
|
||||
/**
|
||||
* This class provides handling for Windows API-related functions.
|
||||
*/
|
||||
@:build(funkin.util.macro.LinkerMacro.xml('project/Build.xml'))
|
||||
@:include('winapi.hpp')
|
||||
extern class WinAPI
|
||||
{
|
||||
/**
|
||||
* Shows a message box with an error icon.
|
||||
*
|
||||
* @param message The message to display.
|
||||
* @param title The title of the message box.
|
||||
*/
|
||||
@:native('WINAPI_ShowError')
|
||||
static function showError(message:cpp.ConstCharStar, title:cpp.ConstCharStar):Void;
|
||||
|
||||
/**
|
||||
* Shows a message box with a warning icon.
|
||||
*
|
||||
* @param message The message to display.
|
||||
* @param title The title of the message box.
|
||||
*/
|
||||
@:native('WINAPI_ShowWarning')
|
||||
static function showWarning(message:cpp.ConstCharStar, title:cpp.ConstCharStar):Void;
|
||||
|
||||
/**
|
||||
* Shows a message box with an information icon.
|
||||
*
|
||||
* @param message The message to display.
|
||||
* @param title The title of the message box.
|
||||
*/
|
||||
@:native('WINAPI_ShowInformation')
|
||||
static function showInformation(message:cpp.ConstCharStar, title:cpp.ConstCharStar):Void;
|
||||
|
||||
/**
|
||||
* Shows a message box with a question icon.
|
||||
*
|
||||
* @param message The message to display.
|
||||
* @param title The title of the message box.
|
||||
*/
|
||||
@:native('WINAPI_ShowQuestion')
|
||||
static function showQuestion(message:cpp.ConstCharStar, title:cpp.ConstCharStar):Void;
|
||||
|
||||
/**
|
||||
* Disables the "Report to Microsoft" dialog that appears when the application crashes.
|
||||
*/
|
||||
@:native('WINAPI_DisableErrorReporting')
|
||||
static function disableErrorReporting():Void;
|
||||
|
||||
/**
|
||||
* Disables Windows ghosting, which prevents the system from marking unresponsive windows as "Not Responding."
|
||||
*/
|
||||
@:native('WINAPI_DisableWindowsGhosting')
|
||||
static function disableWindowsGhosting():Void;
|
||||
|
||||
/**
|
||||
* Retrieves the current working set size (in bytes) of the process.
|
||||
*
|
||||
* @return The size of the working set memory used by the process.
|
||||
*/
|
||||
@:native('WINAPI_GetProcessMemoryWorkingSetSize')
|
||||
static function getProcessMemoryWorkingSetSize():cpp.SizeT;
|
||||
|
||||
/**
|
||||
* Sets the dark mode for the active window.
|
||||
*
|
||||
* @param enable Whether to enable or disable dark mode.
|
||||
*/
|
||||
@:native('WINAPI_SetDarkMode')
|
||||
static function setDarkMode(enable:Bool):Void;
|
||||
|
||||
/**
|
||||
* Checks if the system is using dark mode.
|
||||
*
|
||||
* @return True if system is in dark mode, false otherwise.
|
||||
*/
|
||||
@:native('WINAPI_IsSystemDarkMode')
|
||||
static function isSystemDarkMode():Bool;
|
||||
}
|
||||
#end
|
||||
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xml>
|
||||
<pragma once="true" />
|
||||
|
||||
<files id="haxe">
|
||||
<compilerflag value="-I${this_dir}/include" />
|
||||
</files>
|
||||
|
||||
<files id="__main__">
|
||||
<compilerflag value="-I${this_dir}/include" />
|
||||
</files>
|
||||
|
||||
<files id="external-windows">
|
||||
<compilerflag value="-I${this_dir}/include" />
|
||||
|
||||
<file name="${this_dir}/src/winapi.cpp" />
|
||||
</files>
|
||||
|
||||
<target id="haxe">
|
||||
<section if="mingw">
|
||||
<lib name="-luser32" />
|
||||
<lib name="-lkernel32" />
|
||||
<lib name="-ldwmapi" />
|
||||
<lib name="-ladvapi32" />
|
||||
</section>
|
||||
|
||||
<section unless="mingw">
|
||||
<lib name="user32.lib" />
|
||||
<lib name="kernel32.lib" />
|
||||
<lib name="dwmapi.lib" />
|
||||
<lib name="advapi32.lib" />
|
||||
</section>
|
||||
|
||||
<files id="external-windows" />
|
||||
</target>
|
||||
</xml>
|
||||
@@ -0,0 +1,66 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* Shows an error message box.
|
||||
*
|
||||
* @param message The error message to display
|
||||
* @param title The title of the message box
|
||||
*/
|
||||
void WINAPI_ShowError(const char *message, const char *title);
|
||||
|
||||
/**
|
||||
* Shows a warning message box.
|
||||
*
|
||||
* @param message The warning message to display
|
||||
* @param title The title of the message box
|
||||
*/
|
||||
void WINAPI_ShowWarning(const char *message, const char *title);
|
||||
|
||||
/**
|
||||
* Shows an information message box.
|
||||
*
|
||||
* @param message The information message to display
|
||||
* @param title The title of the message box
|
||||
*/
|
||||
void WINAPI_ShowInformation(const char *message, const char *title);
|
||||
|
||||
/**
|
||||
* Shows a question message box with OK/Cancel buttons.
|
||||
*
|
||||
* @param message The question message to display
|
||||
* @param title The title of the message box
|
||||
*/
|
||||
void WINAPI_ShowQuestion(const char *message, const char *title);
|
||||
|
||||
/**
|
||||
* Disables Windows error reporting dialogs.
|
||||
*/
|
||||
void WINAPI_DisableErrorReporting();
|
||||
|
||||
/**
|
||||
* Disables Windows ghosting for the current process.
|
||||
*/
|
||||
void WINAPI_DisableWindowsGhosting();
|
||||
|
||||
/**
|
||||
* Retrieves the current working set size (in bytes) of the calling process.
|
||||
*
|
||||
* This function queries the operating system for the amount of physical memory currently allocated to the process (its working set).
|
||||
*
|
||||
* @return The working set size in bytes. Returns 0 if the query fails.
|
||||
*/
|
||||
size_t WINAPI_GetProcessMemoryWorkingSetSize();
|
||||
|
||||
/**
|
||||
* Sets dark mode for the active window.
|
||||
*
|
||||
* @param enable True to enable dark mode, false to disable
|
||||
*/
|
||||
void WINAPI_SetDarkMode(bool enable);
|
||||
|
||||
/**
|
||||
* Checks if the system is using dark mode.
|
||||
*
|
||||
* @return True if system is in dark mode, false otherwise
|
||||
*/
|
||||
bool WINAPI_IsSystemDarkMode();
|
||||
@@ -0,0 +1,85 @@
|
||||
#define WIN32_LEAN_AND_MEAN // Excludes rarely-used APIs like cryptography, DDE, RPC, and shell functions, reducing compile time and binary size.
|
||||
#define NOMINMAX // Prevents Windows from defining min() and max() macros, which can conflict with standard C++ functions.
|
||||
#define NOCRYPT // Excludes Cryptographic APIs, such as Encrypt/Decrypt functions.
|
||||
#define NOCOMM // Excludes serial communication APIs, such as COM port handling.
|
||||
#define NOKANJI // Excludes Kanji character set support (not needed unless working with Japanese text processing).
|
||||
#define NOHELP // Excludes Windows Help APIs, removing functions related to WinHelp and other help systems.
|
||||
|
||||
#include <windows.h>
|
||||
#include <psapi.h>
|
||||
#include <dwmapi.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void WINAPI_ShowError(const char *message, const char *title)
|
||||
{
|
||||
MessageBox(GetActiveWindow(), message, title, MB_OK | MB_ICONERROR);
|
||||
}
|
||||
|
||||
void WINAPI_ShowWarning(const char *message, const char *title)
|
||||
{
|
||||
MessageBox(GetActiveWindow(), message, title, MB_OK | MB_ICONWARNING);
|
||||
}
|
||||
|
||||
void WINAPI_ShowInformation(const char *message, const char *title)
|
||||
{
|
||||
MessageBox(GetActiveWindow(), message, title, MB_OK | MB_ICONINFORMATION);
|
||||
}
|
||||
|
||||
void WINAPI_ShowQuestion(const char *message, const char *title)
|
||||
{
|
||||
MessageBox(GetActiveWindow(), message, title, MB_OKCANCEL | MB_ICONQUESTION);
|
||||
}
|
||||
|
||||
void WINAPI_DisableErrorReporting()
|
||||
{
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
|
||||
}
|
||||
|
||||
void WINAPI_DisableWindowsGhosting()
|
||||
{
|
||||
DisableProcessWindowsGhosting();
|
||||
}
|
||||
|
||||
size_t WINAPI_GetProcessMemoryWorkingSetSize()
|
||||
{
|
||||
PROCESS_MEMORY_COUNTERS_EX pmc;
|
||||
|
||||
if (GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc)))
|
||||
return pmc.WorkingSetSize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WINAPI_SetDarkMode(bool enable)
|
||||
{
|
||||
HWND window = GetActiveWindow();
|
||||
|
||||
int darkMode = enable ? 1 : 0;
|
||||
|
||||
if (DwmSetWindowAttribute(window, 20, &darkMode, sizeof(darkMode)) != S_OK)
|
||||
DwmSetWindowAttribute(window, 19, &darkMode, sizeof(darkMode));
|
||||
|
||||
UpdateWindow(window);
|
||||
}
|
||||
|
||||
bool WINAPI_IsSystemDarkMode()
|
||||
{
|
||||
HKEY hKey;
|
||||
DWORD dwValue = 0;
|
||||
DWORD dwSize = sizeof(DWORD);
|
||||
DWORD dwType = REG_DWORD;
|
||||
|
||||
if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
if (RegQueryValueEx(hKey, "AppsUseLightTheme", NULL, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
{
|
||||
RegCloseKey(hKey);
|
||||
return dwValue == 0;
|
||||
}
|
||||
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import flixel.math.FlxPoint;
|
||||
import flixel.graphics.frames.FlxFrame.FlxFrameAngle;
|
||||
import flixel.FlxCamera;
|
||||
import openfl.system.System;
|
||||
import funkin.FunkinMemory;
|
||||
|
||||
using StringTools;
|
||||
|
||||
@@ -23,20 +24,6 @@ using StringTools;
|
||||
@:nullSafety
|
||||
class FunkinSprite extends FlxSprite
|
||||
{
|
||||
/**
|
||||
* An internal list of all the textures cached with `cacheTexture`.
|
||||
* This excludes any temporary textures like those from `FlxText` or `makeSolidColor`.
|
||||
*/
|
||||
static var currentCachedTextures:Map<String, FlxGraphic> = [];
|
||||
|
||||
/**
|
||||
* An internal list of textures that were cached in the previous state.
|
||||
* We don't know whether we want to keep them cached or not.
|
||||
*/
|
||||
static var previousCachedTextures:Map<String, FlxGraphic> = [];
|
||||
|
||||
static var permanentCachedTextures:Map<String, FlxGraphic> = [];
|
||||
|
||||
/**
|
||||
* @param x Starting X position
|
||||
* @param y Starting Y position
|
||||
@@ -216,122 +203,40 @@ class FunkinSprite extends FlxSprite
|
||||
return FlxG.bitmap.get(key) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the texture with the given key is cached.
|
||||
* @param key The key of the texture to cache.
|
||||
*/
|
||||
@:deprecated("Use FunkinMemory.cacheTexture() instead")
|
||||
public static function cacheTexture(key:String):Void
|
||||
{
|
||||
// We don't want to cache the same texture twice.
|
||||
if (currentCachedTextures.exists(key)) return;
|
||||
|
||||
if (previousCachedTextures.exists(key))
|
||||
{
|
||||
// Move the graphic from the previous cache to the current cache.
|
||||
var graphic = previousCachedTextures.get(key);
|
||||
previousCachedTextures.remove(key);
|
||||
if (graphic != null) currentCachedTextures.set(key, graphic);
|
||||
return;
|
||||
}
|
||||
|
||||
// Else, texture is currently uncached.
|
||||
var graphic:FlxGraphic = FlxGraphic.fromAssetKey(key, false, null, true);
|
||||
if (graphic == null)
|
||||
{
|
||||
FlxG.log.warn('Failed to cache graphic: $key');
|
||||
}
|
||||
else
|
||||
{
|
||||
trace('Successfully cached graphic: $key');
|
||||
graphic.persist = true;
|
||||
currentCachedTextures.set(key, graphic);
|
||||
}
|
||||
FunkinMemory.cacheTexture(Paths.image(key));
|
||||
}
|
||||
|
||||
@:deprecated("Use FunkinMemory.permanentCacheTexture() instead")
|
||||
public static function permanentCacheTexture(key:String):Void
|
||||
{
|
||||
// We don't want to cache the same texture twice.
|
||||
if (permanentCachedTextures.exists(key)) return;
|
||||
|
||||
// Else, texture is currently uncached.
|
||||
var graphic:FlxGraphic = FlxGraphic.fromAssetKey(key, false, null, true);
|
||||
if (graphic == null)
|
||||
{
|
||||
FlxG.log.warn('Failed to cache graphic: $key');
|
||||
}
|
||||
else
|
||||
{
|
||||
trace('Successfully cached graphic: $key');
|
||||
graphic.persist = true;
|
||||
permanentCachedTextures.set(key, graphic);
|
||||
}
|
||||
|
||||
currentCachedTextures = permanentCachedTextures;
|
||||
@:privateAccess FunkinMemory.permanentCacheTexture(Paths.image(key));
|
||||
}
|
||||
|
||||
@:deprecated("Use FunkinMemory.cacheTexture() instead")
|
||||
public static function cacheSparrow(key:String):Void
|
||||
{
|
||||
cacheTexture(Paths.image(key));
|
||||
FunkinMemory.cacheTexture(Paths.image(key));
|
||||
}
|
||||
|
||||
@:deprecated("Use FunkinMemory.cacheTexture() instead")
|
||||
public static function cachePacker(key:String):Void
|
||||
{
|
||||
cacheTexture(Paths.image(key));
|
||||
FunkinMemory.cacheTexture(Paths.image(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this, then `cacheTexture` to keep the textures we still need, then `purgeCache` to remove the textures that we won't be using anymore.
|
||||
*/
|
||||
@:deprecated("Use FunkinMemory.preparePurgeTextureCache() instead")
|
||||
public static function preparePurgeCache():Void
|
||||
{
|
||||
previousCachedTextures = currentCachedTextures;
|
||||
|
||||
for (graphicKey in previousCachedTextures.keys())
|
||||
{
|
||||
if (!permanentCachedTextures.exists(graphicKey)) continue;
|
||||
previousCachedTextures.remove(graphicKey);
|
||||
}
|
||||
|
||||
currentCachedTextures = permanentCachedTextures;
|
||||
FunkinMemory.preparePurgeTextureCache();
|
||||
}
|
||||
|
||||
@:deprecated("Use FunkinMemory.purgeCache() instead")
|
||||
public static function purgeCache():Void
|
||||
{
|
||||
// Everything that is in previousCachedTextures but not in currentCachedTextures should be destroyed.
|
||||
for (graphicKey in previousCachedTextures.keys())
|
||||
{
|
||||
var graphic = previousCachedTextures.get(graphicKey);
|
||||
if (graphic == null) continue;
|
||||
FlxG.bitmap.remove(graphic);
|
||||
graphic.destroy();
|
||||
previousCachedTextures.remove(graphicKey);
|
||||
}
|
||||
@:privateAccess
|
||||
if (FlxG.bitmap._cache == null)
|
||||
{
|
||||
@:privateAccess
|
||||
FlxG.bitmap._cache = new Map();
|
||||
System.gc();
|
||||
return;
|
||||
}
|
||||
|
||||
@:privateAccess
|
||||
for (key in FlxG.bitmap._cache.keys())
|
||||
{
|
||||
var obj:Null<FlxGraphic> = FlxG.bitmap.get(key);
|
||||
if (obj == null) continue;
|
||||
if (obj.persist) continue;
|
||||
if (permanentCachedTextures.exists(key)) continue;
|
||||
if (!(obj.useCount <= 0 || key.contains("characters") || key.contains("charSelect") || key.contains("results"))) continue;
|
||||
|
||||
FlxG.bitmap.removeKey(key);
|
||||
obj.destroy();
|
||||
}
|
||||
openfl.Assets.cache.clear("songs");
|
||||
openfl.Assets.cache.clear("sounds");
|
||||
openfl.Assets.cache.clear("music");
|
||||
|
||||
System.gc();
|
||||
FunkinMemory.purgeCache();
|
||||
}
|
||||
|
||||
static function isGraphicCached(graphic:FlxGraphic):Bool
|
||||
|
||||
@@ -71,7 +71,7 @@ class FlxAtlasSprite extends FlxAnimate
|
||||
onAnimationComplete.add(cleanupAnimation);
|
||||
|
||||
// This defaults the sprite to play the first animation in the atlas,
|
||||
// then pauses it. This ensures symbols are intialized properly.
|
||||
// then pauses it. This ensures symbols are initialized properly.
|
||||
this.anim.play('');
|
||||
this.anim.pause();
|
||||
|
||||
|
||||
@@ -136,6 +136,9 @@ class DropShadowScreenspace extends DropShadowShader
|
||||
// essentially just stole this from the AngleMask shader but repurposed it to smooth
|
||||
// the threshold because without any sort of smoothing it produces horrible edges
|
||||
float antialias(vec2 fragCoord, float curThreshold, bool useMask) {
|
||||
if (AA_STAGES == 0.0) {
|
||||
return intensityPass(fragCoord, curThreshold, useMask);
|
||||
}
|
||||
|
||||
// In GLSL 100, we need to use constant loop bounds
|
||||
// Well assume a reasonable maximum for AA_STAGES and use a fixed loop
|
||||
|
||||
@@ -362,6 +362,9 @@ class DropShadowShader extends FlxShader
|
||||
// essentially just stole this from the AngleMask shader but repurposed it to smooth
|
||||
// the threshold because without any sort of smoothing it produces horrible edges
|
||||
float antialias(vec2 fragCoord, float curThreshold, bool useMask) {
|
||||
if (AA_STAGES == 0.0) {
|
||||
return intensityPass(fragCoord, curThreshold, useMask);
|
||||
}
|
||||
|
||||
// In GLSL 100, we need to use constant loop bounds
|
||||
// Well assume a reasonable maximum for AA_STAGES and use a fixed loop
|
||||
|
||||
@@ -17,7 +17,7 @@ class PureColor extends FlxShader
|
||||
|
||||
function set_col(val:FlxColor):FlxColor
|
||||
{
|
||||
funnyColor.value = [val.red, val.green, val.blue, val.alpha];
|
||||
funnyColor.value = [val.redFloat, val.greenFloat, val.blueFloat, val.alphaFloat];
|
||||
|
||||
return val;
|
||||
}
|
||||
@@ -33,7 +33,7 @@ class PureColor extends FlxShader
|
||||
vec4 color = flixel_texture2D(bitmap, openfl_TextureCoordv);
|
||||
|
||||
if (color.a > 0.0 && colSet)
|
||||
color = vec4(funnyColor.r, funnyColor.g, funnyColor.b, color.a);
|
||||
color = funnyColor * color.a;
|
||||
|
||||
gl_FragColor = color;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package funkin.graphics.video;
|
||||
|
||||
/**
|
||||
* A script that can be tied to a FunkinVideoSprite.
|
||||
* Create a scripted class that extends FunkinVideoSprite to use this.
|
||||
*/
|
||||
#if hxvlc
|
||||
@:hscriptClass
|
||||
class ScriptedFunkinVideoSprite extends funkin.graphics.video.FunkinVideoSprite implements polymod.hscript.HScriptedClass {}
|
||||
#end
|
||||
@@ -324,7 +324,7 @@ class Controls extends FlxActionSet
|
||||
inline function get_VOLUME_MUTE()
|
||||
return _volume_mute.check();
|
||||
|
||||
public function new(name, scheme:KeyboardScheme = null)
|
||||
public function new(name, ?scheme:KeyboardScheme)
|
||||
{
|
||||
super(name);
|
||||
|
||||
@@ -372,7 +372,7 @@ class Controls extends FlxActionSet
|
||||
setKeyboardScheme(scheme, false);
|
||||
}
|
||||
|
||||
override function update()
|
||||
override function update():Void
|
||||
{
|
||||
super.update();
|
||||
}
|
||||
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
package funkin.mobile.external;
|
||||
|
||||
/**
|
||||
* A Utility class to manage iOS audio.
|
||||
*/
|
||||
@:build(funkin.mobile.macros.LinkerMacro.xml('project/Build.xml'))
|
||||
@:include('AudioSession.hpp')
|
||||
@:unreflective
|
||||
extern class AudioSession
|
||||
{
|
||||
@:native('initialize')
|
||||
static function initialize():Void;
|
||||
@:native('setActive')
|
||||
static function setActive(active:Bool):Void;
|
||||
}
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
package funkin.mobile.external;
|
||||
|
||||
/**
|
||||
* A Utility class to get iOS screen related informations.
|
||||
*/
|
||||
@:build(funkin.mobile.macros.LinkerMacro.xml('project/Build.xml'))
|
||||
@:include('ScreenUtils.hpp')
|
||||
@:unreflective
|
||||
extern class ScreenUtils
|
||||
{
|
||||
@:native('getSafeAreaInsets')
|
||||
static function getSafeAreaInsets(top:cpp.RawPointer<Float>, bottom:cpp.RawPointer<Float>, left:cpp.RawPointer<Float>, right:cpp.RawPointer<Float>):Void;
|
||||
@:native('getScreenSize')
|
||||
static function getScreenSize(width:cpp.RawPointer<Float>, height:cpp.RawPointer<Float>):Void;
|
||||
}
|
||||
-29
@@ -1,29 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xml>
|
||||
<pragma once="true" />
|
||||
|
||||
<files id="haxe">
|
||||
<compilerflag value="-I${this_dir}/ios/include" if="iphoneos || iphonesim" />
|
||||
</files>
|
||||
|
||||
<files id="__main__">
|
||||
<compilerflag value="-I${this_dir}/ios/include" if="iphoneos || iphonesim" />
|
||||
</files>
|
||||
|
||||
<files id="external-ios" dir="${this_dir}/ios" if="iphoneos || iphonesim">
|
||||
<compilerflag value="-I${this_dir}/ios/include" />
|
||||
|
||||
<file name="src/ScreenUtils.mm" />
|
||||
<file name="src/AudioSession.mm" />
|
||||
</files>
|
||||
|
||||
<target id="haxe">
|
||||
<section if="iphoneos || iphonesim">
|
||||
<vflag name="-framework" value="UIKit" />
|
||||
<vflag name="-framework" value="Foundation" />
|
||||
<vflag name="-framework" value="AVFAudio" />
|
||||
</section>
|
||||
|
||||
<files id="external-ios" if="iphoneos || iphonesim" />
|
||||
</target>
|
||||
</xml>
|
||||
@@ -1,4 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
void initialize();
|
||||
void setActive(bool active);
|
||||
@@ -1,4 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
void getSafeAreaInsets(double* top, double* bottom, double* left, double* right);
|
||||
void getScreenSize(double* width, double* height);
|
||||
@@ -1,41 +0,0 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AVFAudio/AVFAudio.h>
|
||||
|
||||
void initialize()
|
||||
{
|
||||
AVAudioSession *session = [AVAudioSession sharedInstance];
|
||||
|
||||
NSError *error;
|
||||
[session setCategory:AVAudioSessionCategoryPlayback
|
||||
mode:AVAudioSessionModeDefault
|
||||
options:AVAudioSessionCategoryOptionAllowBluetoothA2DP|AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers
|
||||
error:&error];
|
||||
|
||||
if (@available(iOS 17.0, *))
|
||||
{
|
||||
[session setPrefersInterruptionOnRouteDisconnect:false error:nil];
|
||||
}
|
||||
|
||||
if (@available(iOS 14.5, *))
|
||||
{
|
||||
[session setPrefersNoInterruptionsFromSystemAlerts:true error:nil];
|
||||
}
|
||||
|
||||
if (error)
|
||||
{
|
||||
NSLog(@"Unable to set category of audio session: %@", error);
|
||||
}
|
||||
}
|
||||
|
||||
void setActive(bool active)
|
||||
{
|
||||
AVAudioSession *session = [AVAudioSession sharedInstance];
|
||||
NSError *error;
|
||||
|
||||
[session setActive:YES error:&error];
|
||||
|
||||
if (error)
|
||||
{
|
||||
NSLog(@"Unable to set active of audio session: %@", error);
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
#import "ScreenUtils.hpp"
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
void getSafeAreaInsets(double* top, double* bottom, double* left, double* right)
|
||||
{
|
||||
if (@available(iOS 11, *))
|
||||
{
|
||||
UIWindow* window = [UIApplication sharedApplication].windows[0];
|
||||
UIEdgeInsets safeAreaInsets = window.safeAreaInsets;
|
||||
|
||||
float scale = [UIScreen mainScreen].scale;
|
||||
|
||||
(*top) = safeAreaInsets.top * scale;
|
||||
(*bottom) = safeAreaInsets.bottom * scale;
|
||||
(*left) = safeAreaInsets.left * scale;
|
||||
(*right) = safeAreaInsets.right * scale;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
(*top) = 0.0;
|
||||
(*bottom) = 0.0;
|
||||
(*left) = 0.0;
|
||||
(*right) = 0.0;
|
||||
}
|
||||
|
||||
void getScreenSize(double* width, double* height)
|
||||
{
|
||||
CGRect screenRect = [[UIScreen mainScreen] bounds];
|
||||
float scale = [UIScreen mainScreen].scale;
|
||||
|
||||
(*width) = (double)screenRect.size.width * scale;
|
||||
(*height) = (double)screenRect.size.height * scale;
|
||||
}
|
||||
@@ -125,7 +125,7 @@ class ControlsHandler
|
||||
@:noCompletion
|
||||
private static function get_hasExternalInputDevice():Bool
|
||||
{
|
||||
return FlxG.gamepads.numActiveGamepads > 0;
|
||||
return FlxG.gamepads.numActiveGamepads > 0 #if android || extension.androidtools.Tools.isChromebook() #end;
|
||||
}
|
||||
|
||||
@:noCompletion
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
package funkin.mobile.macros;
|
||||
|
||||
import haxe.macro.Context;
|
||||
import haxe.macro.Expr;
|
||||
import haxe.xml.Printer;
|
||||
import sys.FileSystem;
|
||||
|
||||
using haxe.io.Path;
|
||||
|
||||
/**
|
||||
* This class provides a macro to include an XML build file in the metadata of a Haxe class.
|
||||
* The file must be located relative to the directory of the Haxe class that uses this macro.
|
||||
*/
|
||||
@:nullSafety
|
||||
class LinkerMacro
|
||||
{
|
||||
/**
|
||||
* Adds an XML `<include>` element to the class's metadata, pointing to a specified build file.
|
||||
* @param file_name The name of the XML file to include. Defaults to `Build.xml` if not provided.
|
||||
* @return An array of fields that are processed during the build.
|
||||
*/
|
||||
public static macro function xml(?file_name:String = 'Build.xml'):Array<Field>
|
||||
{
|
||||
final pos:Position = Context.currentPos();
|
||||
final sourcePath:String = FileSystem.absolutePath(Context.getPosInfos(pos).file.directory()).removeTrailingSlashes();
|
||||
final fileToInclude:String = Path.join([sourcePath, file_name?.length > 0 ? file_name : 'Build.xml']);
|
||||
|
||||
if (!FileSystem.exists(fileToInclude)) Context.error('The specified file "$fileToInclude" could not be found at "$sourcePath".', pos);
|
||||
|
||||
final includeElement:Xml = Xml.createElement('include');
|
||||
includeElement.set('name', fileToInclude);
|
||||
Context.getLocalClass().get().meta.add(':buildXml', [
|
||||
{expr: EConst(CString(Printer.print(includeElement, true))), pos: pos}], pos);
|
||||
|
||||
return Context.getBuildFields();
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user