Compare commits
1197 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c2da48c49f | |||
| ca5cbf05be | |||
| dc6410e7b8 | |||
| e1572a2a5c | |||
| a3dddbfa24 | |||
| d88b93d56b | |||
| bd0bc42adc | |||
| 04ef3c60d5 | |||
| a14de5e255 | |||
| 90f377fa83 | |||
| c79952a4d6 | |||
| d7dc0b76e5 | |||
| 27b3538b2f | |||
| 74ca6b2c51 | |||
| d49def6f7e | |||
| 72d1d8f085 | |||
| d31fc32399 | |||
| 615ec636d4 | |||
| 5ee7b0d939 | |||
| 9f7ae5bb58 | |||
| 5f756a6ceb | |||
| 5d9e6b7364 | |||
| 9db3439d0d | |||
| 544eb03f7e | |||
| 9d640656e6 | |||
| 9a1fd12a85 | |||
| aaf349170c | |||
| 422f2323d2 | |||
| 10d9d53e47 | |||
| 94e5a8b7bc | |||
| bda94834f7 | |||
| df3969dae1 | |||
| 789dfac27c | |||
| 4f78f79201 | |||
| 28335478bd | |||
| 58618bd402 | |||
| 0ee6aad3ec | |||
| 9205352f94 | |||
| 5079ddd20a | |||
| 2bd2bd5081 | |||
| d5100373be | |||
| 8c006f6e11 | |||
| 804826fbc7 | |||
| 0498f1488e | |||
| 96589557b3 | |||
| 3119c50789 | |||
| 04c1cf469d | |||
| 70ab159dd4 | |||
| ac54838eea | |||
| 5e5ee8e039 | |||
| bb9711277a | |||
| 96a1f20bee | |||
| 32629b7a44 | |||
| 1b46c0921f | |||
| b581ec837c | |||
| c0a5417108 | |||
| 45a1d33689 | |||
| bb3cefbe54 | |||
| e7b62ad1c3 | |||
| 7997d2bc4e | |||
| c44e97c8bc | |||
| f7deac4b63 | |||
| 70136509a9 | |||
| 38451f7dce | |||
| 63a70758f2 | |||
| 890248edf2 | |||
| 9536c37623 | |||
| bf6daed6d2 | |||
| 864f5f77f5 | |||
| b16a6199d0 | |||
| 093928f2f9 | |||
| d3b96742e7 | |||
| fb6bc75e3a | |||
| 61bb41c878 | |||
| c52c23013c | |||
| 17aa4ea60d | |||
| 76e4e1b8d4 | |||
| fe8260fe14 | |||
| 90f9754781 | |||
| 75d5023354 | |||
| 0711710544 | |||
| 23a6a8b69f | |||
| 020b0a90d7 | |||
| 6013705988 | |||
| 65397621e9 | |||
| cbd1e5c837 | |||
| 9282bcfbbf | |||
| 1d8ae580b7 | |||
| 694f8fbaf3 | |||
| 623752e69b | |||
| 420525f688 | |||
| 9b570a46d2 | |||
| b8ee20c7dc | |||
| 4696ed4f8a | |||
| c37aee0a27 | |||
| 7b34ddc089 | |||
| 028ccfca2e | |||
| 072d70722c | |||
| 875dd30d57 | |||
| 9c2a04aa21 | |||
| 83485d2f52 | |||
| 74760a7661 | |||
| 2a109e50fb | |||
| 67dad80e15 | |||
| 64a7985376 | |||
| d3073f5251 | |||
| 62047d2d4c | |||
| 2020b8b011 | |||
| 87e96a9017 | |||
| 0e5335a806 | |||
| e8b07e1588 | |||
| 1c4901305c | |||
| 7106d958d7 | |||
| cd7ad4e5f8 | |||
| c0ba3b0edb | |||
| b82f19a0df | |||
| 6f487bcab5 | |||
| f7e3480d79 | |||
| 7ff3b565e5 | |||
| cc6f5f83ac | |||
| c38a2870dc | |||
| 287c9432b7 | |||
| 0e95700349 | |||
| a99282f86d | |||
| e17eed7029 | |||
| 46c406cc9e | |||
| 6a1552505e | |||
| 2190031ccf | |||
| 228ef4e130 | |||
| dd8817582a | |||
| 3b642c0370 | |||
| 16159a9d98 | |||
| c87b315fef | |||
| b07528d9ce | |||
| 9e2e6759bd | |||
| 2485987901 | |||
| 1a6e706e57 | |||
| 21a3081b9f | |||
| 8f9989dc65 | |||
| a3e3ee396a | |||
| cd68f2463b | |||
| d1f11bbdb2 | |||
| 3b6100837f | |||
| cc85450ed5 | |||
| 70470bc421 | |||
| f995d12686 | |||
| 3645377b15 | |||
| 1e804a0a81 | |||
| fadc5beb1c | |||
| 5f019dc79f | |||
| b57a3165fa | |||
| b13139c6cc | |||
| fea4b3fcba | |||
| 329a6ce0ef | |||
| 53587ad162 | |||
| 086e4c9835 | |||
| ee9627bc15 | |||
| 9de5ee5615 | |||
| 125591dc71 | |||
| b0134ab1ce | |||
| 9f313491b8 | |||
| 8f7da81621 | |||
| 55971167c8 | |||
| 9f50146e68 | |||
| bda71c067b | |||
| cc1e5873a6 | |||
| c652bab9b2 | |||
| 13b1c16213 | |||
| f1c98320fc | |||
| bdb65857bc | |||
| 164670cceb | |||
| d7ddb2ef6f | |||
| 326b6f000a | |||
| 7cc2c143ab | |||
| 37bf4bb34f | |||
| 534d2388f5 | |||
| d5cb34f1b4 | |||
| 6b8d8b7913 | |||
| 14d12418b6 | |||
| 979168e82c | |||
| 7140c4a2d8 | |||
| 5f8e5d44dc | |||
| 31c9b85a3f | |||
| 958c7b2181 | |||
| 652f8ccb8d | |||
| 26f4574358 | |||
| 0eadf2de1e | |||
| ec67d04a0a | |||
| 2df931e090 | |||
| f552dd0c28 | |||
| 8cf10bf71d | |||
| 621d408078 | |||
| 1fdc91255b | |||
| 524b55b6c1 | |||
| 5e07a42417 | |||
| ea4f97aad8 | |||
| e7804f9d02 | |||
| 092df84170 | |||
| 22288b0561 | |||
| 43c1e40461 | |||
| 8f76fe4049 | |||
| 60ddf0ea89 | |||
| b299ed3246 | |||
| 7c55d50507 | |||
| d798b10d4c | |||
| a6430692d2 | |||
| 3bbfe9de8a | |||
| 94abdfd734 | |||
| a0d6f3c22b | |||
| bbdc2bc876 | |||
| 9bda3aa52a | |||
| 9faf9e43fb | |||
| e5f3329e88 | |||
| a8cf4e95c5 | |||
| f345e0dffc | |||
| 26e09aebe3 | |||
| 892e091643 | |||
| ef823c0646 | |||
| c043e64b6b | |||
| 2382e2cbbc | |||
| 2a28126700 | |||
| f9251e41a4 | |||
| 1f11f287ec | |||
| 0476251638 | |||
| d71f89718b | |||
| 55f76999b4 | |||
| 393514c13d | |||
| 126ea687e6 | |||
| d83dcdebf3 | |||
| 248f78ed56 | |||
| ee7f2b3724 | |||
| 0b8c06b149 | |||
| 8b0dd039ca | |||
| f28a3572bb | |||
| 31c3171b72 | |||
| e000acd6fc | |||
| 8c0c6c0142 | |||
| c22eae0e2d | |||
| e32f4d5f8c | |||
| eda4def35b | |||
| ac0cf01404 | |||
| 50639e2378 | |||
| 88a5e07f2e | |||
| 9c93828976 | |||
| fcbe624f7c | |||
| efed1f5b1d | |||
| 4849a49ba4 | |||
| 424e832ec7 | |||
| dae05e0549 | |||
| 007edb4651 | |||
| 3953e6ddc0 | |||
| 40f5032898 | |||
| a2e2ef51be | |||
| c46f78885e | |||
| 5c67c4f5d4 | |||
| 70cb4d3cd9 | |||
| 5416d385d3 | |||
| 2c809389ad | |||
| 8bd4ad03de | |||
| 01688bc050 | |||
| d5c89cb3de | |||
| 9e07e80fa1 | |||
| 3e848d93da | |||
| d0bf176178 | |||
| fce41b95f6 | |||
| fb6a9728a3 | |||
| 6a482c987c | |||
| f60007da83 | |||
| 2149995116 | |||
| 44036a26d0 | |||
| f2ecefb7ee | |||
| 6b4340ce24 | |||
| e0d97486ec | |||
| b65c84c02e | |||
| 5a45ccf70d | |||
| f3393c46a5 | |||
| 587578ccfb | |||
| 522015c2d7 | |||
| 81ae687238 | |||
| 311637616b | |||
| 1cf97186dd | |||
| 62946f6359 | |||
| 9cdd1cbc45 | |||
| 482d516c2e | |||
| 3e906686db | |||
| b219aaf708 | |||
| b6f8876315 | |||
| 583a5d9223 | |||
| d42b9321f2 | |||
| 997dc53a49 | |||
| 95d89382c9 | |||
| ecc6f83130 | |||
| 7ac23e35f8 | |||
| eeb543c653 | |||
| bb567cafde | |||
| d71a9efd92 | |||
| a4d7693a2f | |||
| 42dbd8db0a | |||
| c9d48d00e7 | |||
| a21abaac84 | |||
| bca5e908f1 | |||
| 4e683dcc15 | |||
| bdf6a11491 | |||
| 91fdd60b07 | |||
| 9572073eda | |||
| 75f1c8baaa | |||
| e9250ab365 | |||
| a45f067719 | |||
| ad1c573678 | |||
| c2cd3b64ff | |||
| 48b18bf84e | |||
| 694980160b | |||
| 90d633fb2d | |||
| e10aa1ff58 | |||
| 7efb3e3f3d | |||
| 982639f215 | |||
| 9986d62a28 | |||
| 2c1f6e561a | |||
| c4f57d19db | |||
| 1a6e4bf14b | |||
| 47f9bc2017 | |||
| eb2fc0f02f | |||
| 8ba17f1026 | |||
| 914f7b842e | |||
| 4879b9bd90 | |||
| f5adbc08fa | |||
| 2881ca17a0 | |||
| 1b8b585367 | |||
| 2ae20c5fc4 | |||
| c92a3e566e | |||
| d5fcdf6edb | |||
| 3afec6c897 | |||
| ee83c19c7b | |||
| 144b72109b | |||
| 7b8c013918 | |||
| 3e792e6cd7 | |||
| ed70eb24c7 | |||
| f46d1a4aba | |||
| 306cedeb39 | |||
| 66f66c5481 | |||
| 8c20ba83de | |||
| cdee91f258 | |||
| 8f6ceece10 | |||
| f5d3e30972 | |||
| 408d620b17 | |||
| 1d079842f6 | |||
| b6395cf6f1 | |||
| d0f5d3270f | |||
| 6e6a427488 | |||
| 48f890dd80 | |||
| d4bd2d372c | |||
| 7a6c1b8b86 | |||
| 0d3bae3761 | |||
| 3e073c45ba | |||
| fc5ff3feb7 | |||
| 01365f995d | |||
| 712eaebb25 | |||
| 90603792d7 | |||
| 04d61eba3c | |||
| 24396031a7 | |||
| b244ffedd2 | |||
| ff3bc557b2 | |||
| f0564e0b06 | |||
| 31fb25a43d | |||
| a870513086 | |||
| 5cf3803860 | |||
| e045f096a9 | |||
| 70593177c7 | |||
| 953ae3e9bb | |||
| 64f3f1e9bc | |||
| 3fa9f9e9cf | |||
| 80511d5a19 | |||
| 4482fc0bcf | |||
| 73ee5676c6 | |||
| a3ab7cd14e | |||
| 818ee98b27 | |||
| 2a7a07d2fc | |||
| 4a165d0661 | |||
| 226b1307c0 | |||
| 1dd8aa3db8 | |||
| 1af69421fa | |||
| b43196cd1a | |||
| aab48f1cc1 | |||
| b402603b1d | |||
| 1195572318 | |||
| a2113d4acc | |||
| b57018f55c | |||
| eab14e28da | |||
| a8f670a9c9 | |||
| 2e5d89c8cd | |||
| cde4415052 | |||
| b5117af4b8 | |||
| d7327d62e2 | |||
| b1b1b88982 | |||
| 17b95e3ee5 | |||
| 3d36d1ce71 | |||
| 92b155dbb3 | |||
| 42c042c249 | |||
| 5c6de69e0e | |||
| b30f845924 | |||
| b8ed115f63 | |||
| cbe07b842f | |||
| de7c6483e0 | |||
| f94ae3f3fd | |||
| 4b4bf833a9 | |||
| d5237715a5 | |||
| 395a72b7d4 | |||
| f80ded2057 | |||
| a2d4207504 | |||
| 627b1cee10 | |||
| eb75f8a8ad | |||
| 5bc76de7d6 | |||
| 4e78b49cac | |||
| 637850d06c | |||
| 4144c22dc4 | |||
| 2ce727d994 | |||
| 1855ff133e | |||
| 51004bbd9d | |||
| 873d42344b | |||
| 27b6ba83a6 | |||
| eeaf7eb733 | |||
| 2b59cbf0f1 | |||
| ab2cfe89ce | |||
| aab3d494ff | |||
| fe4e8f3dd2 | |||
| 0c2c643ea8 | |||
| 3bff65d6b6 | |||
| 1069ff0c60 | |||
| 03ab243f9b | |||
| b9d8e2b336 | |||
| ac67813198 | |||
| 6c2ba51926 | |||
| c73897ce7f | |||
| 32bab1e7bf | |||
| e26d793976 | |||
| 9e3c0f5e26 | |||
| b14f5f5cd6 | |||
| 59c54db275 | |||
| 1ebf4d49e5 | |||
| c73ab05d70 | |||
| d29c2fc5af | |||
| ec04e858ef | |||
| 421db7fee2 | |||
| 3bf9c1cc10 | |||
| e68807d574 | |||
| e03516e22e | |||
| a403c4d9ee | |||
| d13c722ce3 | |||
| 2cf70453f8 | |||
| da149d32cf | |||
| 66de1e744a | |||
| cae07f3623 | |||
| c1fa9e595c | |||
| 80e6853f44 | |||
| ec60c90963 | |||
| 8edc154501 | |||
| 86d0ccb210 | |||
| 74af2e53a8 | |||
| 3ea771fe22 | |||
| ec6e459aa7 | |||
| 959fa185c3 | |||
| fa2171503b | |||
| 2c2b403da1 | |||
| 69cdb1268a | |||
| a5afa04f8f | |||
| aeda759086 | |||
| 0508d5a987 | |||
| 31a000b2b6 | |||
| 95daff3e96 | |||
| 04439d9dec | |||
| 681564189f | |||
| f6ee5123d7 | |||
| 296ac0b940 | |||
| 141555377b | |||
| c0428c3316 | |||
| e7249d9d94 | |||
| f3d7ad0aa9 | |||
| 5a66e90b56 | |||
| cffc3f7f5d | |||
| 0a5d37fd9b | |||
| 531d005169 | |||
| c717a102fc | |||
| 4c906f4040 | |||
| 159fb8f5ee | |||
| 0c3d1e3ec6 | |||
| dd7dc28828 | |||
| a99f792979 | |||
| 713cf0d4b2 | |||
| 10541ac743 | |||
| 7c6148dfd8 | |||
| fae6a1ebe9 | |||
| bc1cb402ab | |||
| e973c3ee67 | |||
| bcbbd98898 | |||
| 4131e15f0e | |||
| e8ec5794d2 | |||
| a9f1163743 | |||
| 4be02f5832 | |||
| efab20e335 | |||
| c47907c0c3 | |||
| 7faa9aa23a | |||
| 64515404e9 | |||
| db14c8a0a6 | |||
| 10bab59acc | |||
| 2affebd375 | |||
| 3f2f567364 | |||
| dee445c32c | |||
| d65fe3bae3 | |||
| 04daf10a92 | |||
| 1a3c6bfc73 | |||
| b797d3b0f0 | |||
| bcefaea416 | |||
| 12a2a69ad7 | |||
| 68151592a4 | |||
| 5d2a3482c7 | |||
| e93eb6aae6 | |||
| b7f269f9bd | |||
| bb4c459296 | |||
| 404340b02e | |||
| 50c6b23e35 | |||
| 95d798f49e | |||
| 42a9eaf72e | |||
| 86044fcc05 | |||
| 285a824858 | |||
| 37e8fa7b76 | |||
| 315df12fbe | |||
| 3a3e8e2ad5 | |||
| ec2226f06e | |||
| 22239bc2d1 | |||
| 238526bdc4 | |||
| b1988776ab | |||
| de1ba2de6f | |||
| 65a68131cc | |||
| c6ecf12c32 | |||
| 177d48acb5 | |||
| 695b630e79 | |||
| ea1b2ada50 | |||
| 912d1503e5 | |||
| 9c9bb7ca53 | |||
| c665cc99b9 | |||
| bd43ca236b | |||
| 9e7fb79859 | |||
| 9cd8a74bba | |||
| daa06cb320 | |||
| bc1da787de | |||
| 11a8bb59ce | |||
| a324e05e8f | |||
| 747abba4f7 | |||
| e9eb9890a0 | |||
| deaab07793 | |||
| 5e31a678bd | |||
| f0176c3520 | |||
| 142202f519 | |||
| 634053432e | |||
| 17fbfc969b | |||
| e8e3d5dfa6 | |||
| f82e4b332d | |||
| 433a398b45 | |||
| ca9d98f466 | |||
| e97653d3f3 | |||
| b98d3ae572 | |||
| 53223bb2ab | |||
| 848ab51753 | |||
| d56f7a211f | |||
| 98a5985ce9 | |||
| 71a5d56105 | |||
| c91bc0d8c6 | |||
| 57052b3b14 | |||
| a889d888ff | |||
| 2b2b4f6b6f | |||
| 273b6c0228 | |||
| 1c12e3d530 | |||
| 05ffaf7cef | |||
| 144287ba1c | |||
| f0da221621 | |||
| 518ce457df | |||
| 5efbfc86ad | |||
| 36a9ffe3aa | |||
| 65b63da93a | |||
| c900b6525d | |||
| 176f95fbbc | |||
| cfefe7a24c | |||
| 299ca398fa | |||
| bc9c9d2e72 | |||
| 6d7e23f254 | |||
| b89d32ce2b | |||
| 3136079ca3 | |||
| 7f741c04ed | |||
| 5a2831d0cb | |||
| 896f75b789 | |||
| ba319d8499 | |||
| 320955f8b7 | |||
| 6378f62acd | |||
| 7c0d1ab977 | |||
| 4d1ac04e5c | |||
| 385ef7361c | |||
| b6ceed5c6d | |||
| 6fd636b421 | |||
| 1978cb6df9 | |||
| 8de2e6a424 | |||
| 915f6a719d | |||
| 12f5157bfb | |||
| 968e1328dc | |||
| 6aaa5832a8 | |||
| cf6b9b7ab5 | |||
| 5b50562a9f | |||
| 89d34650c0 | |||
| 39b89ada6c | |||
| 698a9f1938 | |||
| c920b75142 | |||
| 5178caeda6 | |||
| 7158cfb5bf | |||
| 2c9541f6a0 | |||
| 0b3259fcc3 | |||
| 309302c212 | |||
| ce1b47979e | |||
| 85cfc73bbf | |||
| 65e477cfd0 | |||
| 107bea9c2e | |||
| 918140bc6d | |||
| 390460907d | |||
| 73ff053470 | |||
| 9377466ec8 | |||
| 37032810c9 | |||
| 9e222d222c | |||
| 55621054d8 | |||
| 8d057f5b8e | |||
| f04d723b29 | |||
| 2bd66cf625 | |||
| c9a2a17166 | |||
| c5b7d2fe8a | |||
| 978b3f835a | |||
| 765cd7a0f0 | |||
| f19e0628c5 | |||
| 2090cba743 | |||
| 8d0cfcf05d | |||
| 97e2e9a61d | |||
| a1f225d2ef | |||
| c93b41a88d | |||
| 3e8a29cdd5 | |||
| 3d16f97e4c | |||
| 2afa287b67 | |||
| 8457687025 | |||
| 76c6696ead | |||
| 5a94116c9b | |||
| eb613d3e8a | |||
| c8dc8396f9 | |||
| 8cfc14f4b1 | |||
| 1ffe8a7b60 | |||
| 094a3cfe5a | |||
| 8c638e7947 | |||
| d719ef8d03 | |||
| 6ec35e5175 | |||
| dd9fa6e949 | |||
| be204fd2f5 | |||
| 787414451e | |||
| 552ce3e495 | |||
| 29f5556634 | |||
| 1e1c296300 | |||
| 1b278f5c56 | |||
| c2117f0254 | |||
| 648520a6dc | |||
| 42c657cb58 | |||
| b6a46a5ec2 | |||
| 6fef9b09fa | |||
| 941237342d | |||
| 9501d23f35 | |||
| 0a13e01d95 | |||
| 1f2260048a | |||
| 44d78dccbb | |||
| 5eb888868f | |||
| 38b1203bb2 | |||
| 627de10e72 | |||
| 644eb35b97 | |||
| ca48d60627 | |||
| a500f88b4c | |||
| 808c741ed7 | |||
| 9eaef3447c | |||
| 364676ceae | |||
| e21756d685 | |||
| 7df206f533 | |||
| e3ceaa3f9a | |||
| 8b2d3db3f1 | |||
| 589941d6b2 | |||
| f046642ba7 | |||
| 3792aa1984 | |||
| 024dd74ae1 | |||
| cdc8e4adb8 | |||
| 8c02dfbb3f | |||
| 9a84f9e4ac | |||
| 9322a2006a | |||
| 67b373c6df | |||
| 0842a95dd6 | |||
| c3ef9f993b | |||
| 378e48e7aa | |||
| 7ad497ca3b | |||
| 0e3dedbc5b | |||
| 414bce38bb | |||
| 67da36a611 | |||
| dc32386590 | |||
| e9bdc8b319 | |||
| 4449f1ddcf | |||
| 6562a8769e | |||
| fcb71134c2 | |||
| b7dcf9576e | |||
| 2eea7abc27 | |||
| 71b5b528fd | |||
| d5b8e44572 | |||
| b85184eee0 | |||
| 2e1691c2f1 | |||
| c3cc78b7c2 | |||
| 297b4f2a81 | |||
| e1ea6a0676 | |||
| 4378b9e455 | |||
| f843b3858a | |||
| f5c9dce34a | |||
| 8a80a26523 | |||
| 2e22abaff9 | |||
| d38badb54b | |||
| 17aca44a3b | |||
| dbd5c71344 | |||
| 49e05bc206 | |||
| 2d51332bf7 | |||
| e4804db160 | |||
| 4e5795ab91 | |||
| acecda482d | |||
| da85771472 | |||
| e8aa2f922b | |||
| 62a335fab0 | |||
| d813078e91 | |||
| 685a68b7b8 | |||
| c420318267 | |||
| a52b352bd9 | |||
| b4d20e128b | |||
| 89704bebe9 | |||
| 62fdfe2519 | |||
| 7a01ccb5fb | |||
| 2c653f8c92 | |||
| e5f4a52be1 | |||
| 924ee9085f | |||
| 4bdeb26e74 | |||
| 91c017713c | |||
| a379c551cb | |||
| 8a44ea5a99 | |||
| f8bfc3520b | |||
| 31c35a7dd9 | |||
| a11ffb5ea5 | |||
| 01ced1cacd | |||
| 09ebd7462a | |||
| 0281c6dcde | |||
| 048c1f6985 | |||
| a9a7bc0b70 | |||
| 898a5c4561 | |||
| b0966c9114 | |||
| cffa9aa58e | |||
| 0652a1c367 | |||
| c5491eea97 | |||
| cf397e1cc7 | |||
| d9855f2ed6 | |||
| 047eb2eddf | |||
| 8c94b56080 | |||
| bedb056645 | |||
| e6de28bb6a | |||
| 2e5adca99a | |||
| 9e5a48af4b | |||
| abf68328e6 | |||
| 609217a3bb | |||
| f8cf82a005 | |||
| 3c1622fbfd | |||
| 0bea917ef1 | |||
| 4de3512e12 | |||
| b747031e2f | |||
| 66a140f402 | |||
| b40384c329 | |||
| 7c39e5726d | |||
| 338e3bbd42 | |||
| 99566a0f0f | |||
| 1a604e24a0 | |||
| 9ecfe90708 | |||
| f9e8ad7c12 | |||
| 68c6a01805 | |||
| 96609815ec | |||
| 558a7d99ff | |||
| e186adc90e | |||
| 7df5a7c646 | |||
| 06ba894e39 | |||
| 7b3152885d | |||
| a82856176e | |||
| 4e3d5ad11c | |||
| 133e192b98 | |||
| aa64da9869 | |||
| 92520a3c17 | |||
| 0c167f38b7 | |||
| f4e62afe8a | |||
| a9b706becf | |||
| 09bd7c696b | |||
| 2475706df4 | |||
| 8719bfe820 | |||
| cd2669230e | |||
| d8f996ddc7 | |||
| 1093818381 | |||
| 067ae8fc8e | |||
| f721284f70 | |||
| f930c9b5dc | |||
| bb7ca521c4 | |||
| 6c8b5e5e8a | |||
| ce45c92dae | |||
| 7de30bef7c | |||
| a8c6b2b619 | |||
| a236bc0b81 | |||
| 58d0ed18e6 | |||
| 0df9f5c797 | |||
| 0c4a608b65 | |||
| e48e15f02f | |||
| eda07ac57b | |||
| 820c18968a | |||
| be7da82cfc | |||
| bb84a51478 | |||
| 03b16875c7 | |||
| 84bb56d68b | |||
| d28be9cf44 | |||
| 58e5c988af | |||
| e995736012 | |||
| 493f3430bc | |||
| 350112a0d7 | |||
| 5ca6dae8c3 | |||
| 21f419dd4b | |||
| 0d082f5773 | |||
| a3517b273c | |||
| e1a0e51bc7 | |||
| 12f4dc74d2 | |||
| 2196a3d791 | |||
| c505561118 | |||
| 809a1041b3 | |||
| 29d0281932 | |||
| e562a7d72c | |||
| 7bec45dacf | |||
| 5a96c0e717 | |||
| a7c9c6142c | |||
| dfca248ebd | |||
| 4cc0807384 | |||
| 7cbafcd86b | |||
| 20ce4642ea | |||
| 4528cce71c | |||
| aeb0bf700f | |||
| bb27f85951 | |||
| 94e7531109 | |||
| fd23a61846 | |||
| de566a361a | |||
| d925c8dab8 | |||
| a25eae5d10 | |||
| 6f7b138488 | |||
| 52fb941237 | |||
| 0694f87b0d | |||
| ed13de2d5b | |||
| 8d7225c056 | |||
| 4755c42d70 | |||
| 510fc443e8 | |||
| 27ab8ea404 | |||
| eed2cdfe04 | |||
| 4c4a559125 | |||
| 4c1519ba1b | |||
| 2253b5713b | |||
| 7d4bf8356e | |||
| c31e4023c4 | |||
| 3bbc7faf11 | |||
| 497aca829d | |||
| 7e28db91c2 | |||
| c71a34a1e9 | |||
| 30e825db75 | |||
| ad536a945e | |||
| 5dbc5f42d2 | |||
| 154076a5d0 | |||
| d719c534d4 | |||
| d63c21ec41 | |||
| 1fa7397b32 | |||
| 5bf645252f | |||
| 9568237c8e | |||
| 0232197cdc | |||
| 773047dc69 | |||
| 98ebbf8b99 | |||
| 1a2eb48705 | |||
| c615ad18a8 | |||
| 0ba261d338 | |||
| dc29ee180e | |||
| 8d16fb21b9 | |||
| 33ac9c8811 | |||
| 4f10f852c7 | |||
| e11587e72e | |||
| 16131b2858 | |||
| e878f5be15 | |||
| 19d77f0d81 | |||
| 2f9e72e03e | |||
| 47e2c82551 | |||
| 9e4fd9fadb | |||
| edd4e37111 | |||
| 01d5c6a25b | |||
| 31a6c052f3 | |||
| 74758f5380 | |||
| b7a3b10498 | |||
| dad41d9e0e | |||
| 1c27674fd5 | |||
| c39242ecba | |||
| 9614110f10 | |||
| 39c3b760ac | |||
| 72659a481e | |||
| 55a439645c | |||
| eece05c118 | |||
| 7950c0d9d7 | |||
| 7cdd35cc8d | |||
| 6f304040b0 | |||
| d2a0438b71 | |||
| dea3319b9d | |||
| 58fab97447 | |||
| a41ad511f0 | |||
| 44b45faa9a | |||
| e747a345d8 | |||
| dadb9207b9 | |||
| 086c2f155d | |||
| cfa7cac149 | |||
| 95748744a4 | |||
| 34629d46f3 | |||
| af54b907d7 | |||
| 2930b0ad67 | |||
| e00bf92f05 | |||
| c1dcc52a6a | |||
| c351e58c6e | |||
| c60b2cb4d7 | |||
| 2c70b74814 | |||
| e83b8afdd3 | |||
| 4cf20efe2e | |||
| b7d4758dde | |||
| 559aef2ee3 | |||
| 7fce25a2e4 | |||
| aaaf7c5c37 | |||
| 4265ba12d7 | |||
| 85c5c7f309 | |||
| c838a800b6 | |||
| 22af41193e | |||
| b450c65c93 | |||
| 4ce89f56cc | |||
| 57014851a7 | |||
| e6b0cd69ae | |||
| 70e9410da0 | |||
| 38c027704e | |||
| 31411e334b | |||
| 987e680908 | |||
| d5df227df5 | |||
| 60f21d1a92 | |||
| a26d0d03eb | |||
| a7c5397641 | |||
| 0112f70c05 | |||
| 1647fff024 | |||
| 9fe54dc02c | |||
| 6691aaca1e | |||
| 82a22b2a87 | |||
| 2016297fce | |||
| fa6b621368 | |||
| a17981bc87 | |||
| f88dd50098 | |||
| fb06fa2c8b | |||
| ad4c2484f3 | |||
| 3be4e50b78 | |||
| 499df770cc | |||
| 6f9f40192e | |||
| 64752781ed | |||
| 87e9046e41 | |||
| 1c74e89f0d | |||
| 272ffe2ea2 | |||
| d7e24f0168 | |||
| 0cf40729fa | |||
| c00769e2b8 | |||
| 1096daaeb7 | |||
| 9560bbe23e | |||
| 0d78a6ba67 | |||
| e07a07f13e | |||
| 2c1409c2a4 | |||
| b44c7ab32c | |||
| c18cefbb0b | |||
| 5b23a4b318 | |||
| 91247cc080 | |||
| 30fa911832 | |||
| c4b7f50609 | |||
| 7ccc0b83ff | |||
| 45a0b25ee4 | |||
| ac59cc4633 | |||
| cdc5106ef9 | |||
| dff13626c4 | |||
| 436d55932d | |||
| 2a6fb3ba81 | |||
| ea9dd48da9 | |||
| 547f4d1180 | |||
| 1ff49e1faf | |||
| 64f7c6bf64 | |||
| 0270772463 | |||
| f3b2011fef | |||
| dbee9f6816 | |||
| 2d98a46d94 | |||
| baf6048377 | |||
| 02c6354003 | |||
| 641e746ee1 | |||
| 9f7df23788 | |||
| c42ae97bb2 | |||
| e6e34a7baf | |||
| 1a4113009a | |||
| bc85c1b421 | |||
| f6aea86aeb | |||
| 86c5f3675b | |||
| 4f71976958 | |||
| 2fd251e7b1 | |||
| 08ae1917e8 | |||
| e779c3ca17 | |||
| 173f4e8092 | |||
| de7edf9e78 | |||
| 6b6f1eeb9b | |||
| 0847ccc360 | |||
| f5a37ec3b4 | |||
| acb1cef19d | |||
| 20c32ea6ed | |||
| 35ea0b5447 | |||
| e818d37dd6 | |||
| 048a4ac1e3 | |||
| f665642e71 | |||
| 6fb604a9a0 | |||
| 02e3697817 | |||
| 1c72798229 | |||
| 761d3735a7 | |||
| 71c2770df0 | |||
| c6be71c4ff | |||
| 754ccaa9b4 | |||
| 798b950046 | |||
| c9c35eb74e | |||
| f1f5dacb6f | |||
| 405ae519dd | |||
| f3366178ea | |||
| 38fcfee9a4 | |||
| 25811ed6d4 | |||
| 3ca0ea2e50 | |||
| a917567e92 | |||
| a633aa69c3 | |||
| 32440d6993 | |||
| 7b20bc38a4 | |||
| be720257ca | |||
| 5e9d153c6a | |||
| 1a1fadcc2f | |||
| abdc257332 | |||
| 59ba9102a6 | |||
| daa92db25c | |||
| 3df10d1d0a | |||
| 824ce1cacf | |||
| 4a8f336118 | |||
| 6ec6f9501b | |||
| b1ecb2f0eb | |||
| 474ce10e7e | |||
| 3c40c22049 | |||
| 9281db73a7 | |||
| 45a557f9c0 | |||
| 7698e79143 | |||
| 1c584e937a | |||
| 6ef5c76e1a | |||
| eebc4951de | |||
| 7048281931 | |||
| 9f76e9e230 | |||
| 4e4f4e700b | |||
| bf60955e5e | |||
| c53af39c92 | |||
| d034874fb7 | |||
| 5ec9716eac | |||
| 8896ebadda | |||
| a6050e6f27 | |||
| 1e046c0033 | |||
| 34cc546f00 | |||
| b21aeedae2 | |||
| 0872002dae | |||
| c4e4e38c4f | |||
| 63d3c9b1e0 | |||
| ccd919d4d6 | |||
| 88bd5b2534 | |||
| 0b8d4850f0 | |||
| 26f8e5aa9e | |||
| 06b2bf0094 | |||
| e596d48729 | |||
| ceacdc8d08 | |||
| 6a2c5169a9 | |||
| dea307179f | |||
| 0ab6e29792 | |||
| e718766073 | |||
| d3cdca6b33 | |||
| e48b642101 | |||
| 9acb597d5d | |||
| 00d960d61e | |||
| 5b4e209816 | |||
| 21c67b4777 | |||
| 2f507091b2 | |||
| 8b80f73641 | |||
| 6a8483a898 | |||
| 71e2cbe856 | |||
| af7b53814d | |||
| 147cadee16 | |||
| 77478f9515 | |||
| 64809f553b | |||
| 78a2f2e8f0 | |||
| 28da925c52 | |||
| 9083f511b5 | |||
| c2bb717a69 | |||
| 2408aa48c1 | |||
| 45286468c9 | |||
| 6f8c007a66 | |||
| c48a81a068 | |||
| aa0208072c | |||
| d3e02e23e5 | |||
| f12475ea99 | |||
| d966519d95 | |||
| 3f14d4bf64 | |||
| dfc69c9c8e | |||
| 53de6d018b | |||
| 3e8e839cd1 | |||
| c53bf2b7e3 | |||
| 219ad40088 | |||
| d9042b3db2 | |||
| c59586a934 | |||
| 7440cb0963 | |||
| d8805dc801 | |||
| 45b0bb24c4 | |||
| 759a9bd365 | |||
| 48214f925b | |||
| 2c0e9faa32 | |||
| 80c3056daf | |||
| 61bd491969 | |||
| fd64a33d3e | |||
| 2e502ce82a | |||
| 3c79be2910 | |||
| e03a819176 | |||
| 6a41ab0b6d | |||
| 22b4e25c02 | |||
| e71e6835de | |||
| b449353d2f | |||
| 94c5211ee6 | |||
| 75130fcca3 | |||
| 3f172442be | |||
| b049688d31 | |||
| 04799c89dc | |||
| ac99dc0ac4 | |||
| 8dc5c4e00b | |||
| edac611444 | |||
| 37a8380521 | |||
| 60a1de42a2 | |||
| b2beeb653b | |||
| 6ff5dcfa50 | |||
| 9a5c105db9 | |||
| aea28ce499 | |||
| c8cc899128 | |||
| 55747edaae | |||
| 15af6502a0 | |||
| 8c4771a738 | |||
| 2fee75517d | |||
| 580f4120dc | |||
| f874a0ad57 | |||
| a56090e70f | |||
| f0d0e0637c | |||
| eae38fa0c6 | |||
| 93f0b0e2e8 | |||
| 979f8bcfee | |||
| b9f11298e8 | |||
| 84f8e3a4b4 | |||
| 551c58db4f | |||
| ff438a6219 | |||
| 84a68c5977 | |||
| 889eb7d846 | |||
| 6eaecc8793 | |||
| df6bf1e04d | |||
| ff1ccdb7ee | |||
| d7fc221a6b | |||
| fcd1366d26 | |||
| 8cd90280c1 | |||
| 4e4fb91a6f | |||
| 55e287c890 | |||
| cc7655d804 | |||
| 676d87129c | |||
| 4a1c1ebe3a | |||
| bf190810dd | |||
| 2227642c13 | |||
| 76ee695a59 | |||
| 0d68e90b59 | |||
| 3b80a01813 | |||
| 89ac54520a | |||
| dc08f49bbe | |||
| 9fb0b00e75 | |||
| 96dc279ebd | |||
| fe943ca010 | |||
| 3396e10613 | |||
| 6bfb0205fd | |||
| c4be764f61 | |||
| cb09fb570d | |||
| 7e80a4fe0f | |||
| 44d1527759 | |||
| 5e6fcc9669 |
+1
-1
@@ -1,5 +1,5 @@
|
||||
# Set the default behavior, in case people don't have core.autocrlf set.
|
||||
* text=auto
|
||||
* text=auto eol=lf
|
||||
|
||||
# Explicitly declare text files you want to always be normalized and converted to native line endings on checkout.
|
||||
*.c text diff=cpp
|
||||
|
||||
@@ -1,21 +1,36 @@
|
||||
name: Build Android
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
DOTNET_NOLOGO: true
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: false
|
||||
|
||||
jobs:
|
||||
|
||||
# Game
|
||||
game-windows:
|
||||
name: Game (Android, Release ARM64)
|
||||
runs-on: "windows-2019"
|
||||
runs-on: "windows-2022"
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Setup .NET Workload
|
||||
run: |
|
||||
dotnet workload install android
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -arch=ARM64 -platform=Android -configuration=Release -buildtargets=FlaxGame
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -printSDKs -arch=ARM64 -platform=Android -configuration=Release -buildtargets=FlaxGame
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
name: Build iOS
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
DOTNET_NOLOGO: true
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: false
|
||||
|
||||
jobs:
|
||||
|
||||
# Game
|
||||
game-windows:
|
||||
name: Game (iOS, Release ARM64)
|
||||
runs-on: "macos-latest"
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Setup .NET Workload
|
||||
run: |
|
||||
dotnet workload install ios
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
./Development/Scripts/Mac/CallBuildTool.sh -build -log -arch=ARM64 -platform=iOS -configuration=Release -buildtargets=FlaxGame
|
||||
@@ -1,6 +1,10 @@
|
||||
name: Build Linux
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
DOTNET_NOLOGO: true
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: false
|
||||
|
||||
jobs:
|
||||
|
||||
# Editor
|
||||
@@ -18,13 +22,21 @@ jobs:
|
||||
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
./Development/Scripts/Linux/CallBuildTool.sh -build -log -arch=x64 -platform=Linux -configuration=Development -buildtargets=FlaxEditor
|
||||
./Development/Scripts/Linux/CallBuildTool.sh -build -log -printSDKs -arch=x64 -platform=Linux -configuration=Development -buildtargets=FlaxEditor
|
||||
|
||||
# Game
|
||||
game-linux:
|
||||
@@ -38,10 +50,18 @@ jobs:
|
||||
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
./Development/Scripts/Linux/CallBuildTool.sh -build -log -arch=x64 -platform=Linux -configuration=Release -buildtargets=FlaxGame
|
||||
./Development/Scripts/Linux/CallBuildTool.sh -build -log -printSDKs -arch=x64 -platform=Linux -configuration=Release -buildtargets=FlaxGame
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
name: Build macOS
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
DOTNET_NOLOGO: true
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: false
|
||||
|
||||
jobs:
|
||||
|
||||
# Editor
|
||||
@@ -12,13 +16,21 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
./Development/Scripts/Mac/CallBuildTool.sh -build -log -arch=x64 -platform=Mac -configuration=Development -buildtargets=FlaxEditor
|
||||
./Development/Scripts/Mac/CallBuildTool.sh -build -log -printSDKs -arch=x64 -platform=Mac -configuration=Development -buildtargets=FlaxEditor
|
||||
|
||||
# Game
|
||||
game-mac:
|
||||
@@ -29,10 +41,18 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
./Development/Scripts/Mac/CallBuildTool.sh -build -log -arch=x64 -platform=Mac -configuration=Release -buildtargets=FlaxGame
|
||||
./Development/Scripts/Mac/CallBuildTool.sh -build -log -printSDKs -arch=x64 -platform=Mac -configuration=Release -buildtargets=FlaxGame
|
||||
|
||||
@@ -1,38 +1,58 @@
|
||||
name: Build Windows
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
DOTNET_NOLOGO: true
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: false
|
||||
|
||||
jobs:
|
||||
|
||||
# Editor
|
||||
editor-windows:
|
||||
name: Editor (Windows, Development x64)
|
||||
runs-on: "windows-2019"
|
||||
runs-on: "windows-2022"
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -arch=x64 -platform=Windows -configuration=Development -buildtargets=FlaxEditor
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -printSDKs -arch=x64 -platform=Windows -configuration=Development -buildtargets=FlaxEditor
|
||||
|
||||
# Game
|
||||
game-windows:
|
||||
name: Game (Windows, Release x64)
|
||||
runs-on: "windows-2019"
|
||||
runs-on: "windows-2022"
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -arch=x64 -platform=Windows -configuration=Release -buildtargets=FlaxGame
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -printSDKs -arch=x64 -platform=Windows -configuration=Release -buildtargets=FlaxGame
|
||||
|
||||
@@ -4,12 +4,16 @@ on:
|
||||
- cron: '15 4 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
DOTNET_NOLOGO: true
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: false
|
||||
|
||||
jobs:
|
||||
|
||||
# Windows
|
||||
package-windows-editor:
|
||||
name: Editor (Windows)
|
||||
runs-on: "windows-2019"
|
||||
runs-on: "windows-2022"
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
@@ -19,6 +23,14 @@ jobs:
|
||||
git lfs pull
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Build
|
||||
run: |
|
||||
.\PackageEditor.bat -arch=x64 -platform=Windows -deployOutput=Output
|
||||
@@ -34,7 +46,7 @@ jobs:
|
||||
path: Output/EditorDebugSymbols.zip
|
||||
package-windows-game:
|
||||
name: Game (Windows)
|
||||
runs-on: "windows-2019"
|
||||
runs-on: "windows-2022"
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
@@ -44,6 +56,14 @@ jobs:
|
||||
git lfs pull
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Build
|
||||
run: |
|
||||
.\PackagePlatforms.bat -arch=x64 -platform=Windows -deployOutput=Output
|
||||
@@ -72,6 +92,14 @@ jobs:
|
||||
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Build
|
||||
run: |
|
||||
./PackageEditor.sh -arch=x64 -platform=Linux -deployOutput=Output
|
||||
@@ -98,6 +126,14 @@ jobs:
|
||||
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Build
|
||||
run: |
|
||||
./PackagePlatforms.sh -arch=x64 -platform=Linux -deployOutput=Output
|
||||
@@ -120,6 +156,14 @@ jobs:
|
||||
git lfs pull
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Build
|
||||
run: |
|
||||
./PackageEditor.command -arch=x64 -platform=Mac -deployOutput=Output
|
||||
@@ -140,6 +184,14 @@ jobs:
|
||||
git lfs pull
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Build
|
||||
run: |
|
||||
./PackagePlatforms.command -arch=x64 -platform=Mac -deployOutput=Output
|
||||
|
||||
+39
-16
@@ -1,6 +1,10 @@
|
||||
name: Tests
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
DOTNET_NOLOGO: true
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: false
|
||||
|
||||
jobs:
|
||||
|
||||
# Tests on Linux
|
||||
@@ -10,6 +14,14 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
@@ -22,41 +34,52 @@ jobs:
|
||||
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
|
||||
- name: Build
|
||||
run: |
|
||||
./GenerateProjectFiles.sh -vs2019
|
||||
./GenerateProjectFiles.sh -vs2022 -log -verbose -printSDKs
|
||||
./Development/Scripts/Linux/CallBuildTool.sh -build -log -arch=x64 -platform=Linux -configuration=Development -buildtargets=FlaxTestsTarget
|
||||
./Development/Scripts/Linux/CallBuildTool.sh -build -log -arch=x64 -platform=Linux -configuration=Debug -buildtargets=FlaxEditor -BuildBindingsOnly
|
||||
./Development/Scripts/Linux/CallBuildTool.sh -build -log -arch=x64 -platform=Linux -configuration=Debug -buildtargets="FlaxEngine.Tests"
|
||||
./Development/Scripts/Linux/CallBuildTool.sh -build -log -arch=x64 -platform=Linux -configuration=Debug -buildtargets="Flax.Build.Tests"
|
||||
dotnet msbuild Source/Tools/Flax.Build.Tests/Flax.Build.Tests.csproj /m /t:Restore,Build /p:Configuration=Debug /p:Platform=AnyCPU /nologo
|
||||
dotnet msbuild Source/Tools/Flax.Build.Tests/Flax.Build.Tests.csproj /m /t:Restore,Build /p:Configuration=Debug /p:Platform=AnyCPU /nologo
|
||||
- name: Test
|
||||
run: |
|
||||
Binaries/Editor/Linux/Development/FlaxTests
|
||||
mono Source/Platforms/DotNet/NUnit/nunit3-console.exe Binaries/Tools/FlaxEngine.Tests.dll --framework=mono-4.0
|
||||
mono Source/Platforms/DotNet/NUnit/nunit3-console.exe Binaries/Tools/Flax.Build.Tests.dll --framework=mono-4.0
|
||||
${GITHUB_WORKSPACE}/Binaries/Editor/Linux/Development/FlaxTests
|
||||
dotnet test -f net7.0 Binaries/Tests/Flax.Build.Tests.dll
|
||||
cp Binaries/Editor/Linux/Development/FlaxEngine.CSharp.dll Binaries/Tests
|
||||
cp Binaries/Editor/Linux/Development/FlaxEngine.CSharp.runtimeconfig.json Binaries/Tests
|
||||
cp Binaries/Editor/Linux/Development/Newtonsoft.Json.dll Binaries/Tests
|
||||
dotnet test -f net7.0 Binaries/Tests/FlaxEngine.CSharp.dll
|
||||
- name: Test UseLargeWorlds
|
||||
run: |
|
||||
./Development/Scripts/Linux/CallBuildTool.sh -build -log -arch=x64 -platform=Linux -configuration=Development -buildtargets=FlaxTestsTarget -UseLargeWorlds=true
|
||||
Binaries/Editor/Linux/Development/FlaxTests
|
||||
${GITHUB_WORKSPACE}/Binaries/Editor/Linux/Development/FlaxTests
|
||||
|
||||
# Tests on Windows
|
||||
tests-windows:
|
||||
name: Tests (Windows)
|
||||
runs-on: "windows-2019"
|
||||
runs-on: "windows-2022"
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
.\GenerateProjectFiles.bat -vs2019
|
||||
.\GenerateProjectFiles.bat -vs2022 -log -verbose -printSDKs
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -arch=x64 -platform=Windows -configuration=Development -buildtargets=FlaxTestsTarget
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -arch=x64 -platform=Windows -configuration=Debug -buildtargets=FlaxEditor -BuildBindingsOnly
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -arch=x64 -platform=Windows -configuration=Debug -buildtargets="FlaxEngine.Tests"
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -arch=x64 -platform=Windows -configuration=Debug -buildtargets="Flax.Build.Tests"
|
||||
dotnet msbuild Source\Tools\Flax.Build.Tests\Flax.Build.Tests.csproj /m /t:Restore,Build /p:Configuration=Debug /p:Platform=AnyCPU /nologo
|
||||
- name: Test
|
||||
run: |
|
||||
Binaries\Editor\Win64\Development\FlaxTests.exe
|
||||
Source\Platforms\DotNet\NUnit\nunit3-console.exe Binaries\Tools\FlaxEngine.Tests.dll --framework=net-4.5.2
|
||||
Source\Platforms\DotNet\NUnit\nunit3-console.exe Binaries\Tools\Flax.Build.Tests.dll --framework=net-4.5.2
|
||||
.\Binaries\Editor\Win64\Development\FlaxTests.exe
|
||||
dotnet test -f net7.0 Binaries\Tests\Flax.Build.Tests.dll
|
||||
xcopy /y Binaries\Editor\Win64\Development\FlaxEngine.CSharp.dll Binaries\Tests
|
||||
xcopy /y Binaries\Editor\Win64\Development\FlaxEngine.CSharp.runtimeconfig.json Binaries\Tests
|
||||
xcopy /y Binaries\Editor\Win64\Development\Newtonsoft.Json.dll Binaries\Tests
|
||||
dotnet test -f net7.0 Binaries\Tests\FlaxEngine.CSharp.dll
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
obj/
|
||||
Cache/
|
||||
Binaries/
|
||||
Output/
|
||||
Logs/
|
||||
Source/*.Gen.*
|
||||
Source/*.csproj
|
||||
/Package_*/
|
||||
!Source/Engine/Debug
|
||||
@@ -23,6 +25,7 @@ PackagePlatforms_Cert.bat
|
||||
*.opendb
|
||||
*.DS_Store
|
||||
*.xcodeproj
|
||||
launchSettings.json
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
@0// Deferred Shading: Defines
|
||||
@1// Deferred Shading: Includes
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
@0// Distortion: Defines
|
||||
@1// Distortion: Includes
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
@0// Forward Shading: Defines
|
||||
#define MAX_LOCAL_LIGHTS 4
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
@0// Global Illumination: Defines
|
||||
#define USE_GI 1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
@0// Lightmap: Defines
|
||||
#define CAN_USE_LIGHTMAP 1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
@0// Motion Vectors: Defines
|
||||
@1// Motion Vectors: Includes
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
@0// Tessellation: Defines
|
||||
#define TessalationProjectOntoPlane(planeNormal, planePosition, pointToProject) pointToProject - dot(pointToProject - planePosition, planeNormal) * planeNormal
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
@@ -10,8 +10,7 @@ if [ $testfilesize -le 1000 ]; then
|
||||
fi
|
||||
|
||||
# Compile the build tool.
|
||||
xbuild /nologo /verbosity:quiet "Source/Tools/Flax.Build/Flax.Build.csproj" /property:Configuration=Release /property:Platform=AnyCPU /target:Build
|
||||
dotnet msbuild /nologo /verbosity:quiet "Source/Tools/Flax.Build/Flax.Build.csproj" /property:Configuration=Release /target:Restore,Build /property:RestorePackagesConfig=True /p:RuntimeIdentifiers=linux-x64
|
||||
|
||||
# Run the build tool using the provided arguments.
|
||||
#mono --debug --debugger-agent=transport=dt_socket,server=y,address=127.0.0.1:55555 Binaries/Tools/Flax.Build.exe "$@"
|
||||
mono Binaries/Tools/Flax.Build.exe "$@"
|
||||
Binaries/Tools/Flax.Build "$@"
|
||||
|
||||
@@ -10,8 +10,7 @@ if [ $testfilesize -le 1000 ]; then
|
||||
fi
|
||||
|
||||
# Compile the build tool.
|
||||
xbuild /nologo /verbosity:quiet "Source/Tools/Flax.Build/Flax.Build.csproj" /property:Configuration=Release /property:Platform=AnyCPU /target:Build
|
||||
dotnet msbuild /nologo /verbosity:quiet "Source/Tools/Flax.Build/Flax.Build.csproj" /property:Configuration=Release /target:Restore,Build /property:RestorePackagesConfig=True /p:RuntimeIdentifiers=osx-x64
|
||||
|
||||
# Run the build tool using the provided arguments.
|
||||
#mono --debug --debugger-agent=transport=dt_socket,server=y,address=127.0.0.1:55555 Binaries/Tools/Flax.Build.exe "$@"
|
||||
mono Binaries/Tools/Flax.Build.exe "$@"
|
||||
Binaries/Tools/Flax.Build "$@"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Copyright (c) 2012-2023 Wojciech Figat. All rights reserved
|
||||
|
||||
# Fix mono bin to be in a path
|
||||
export PATH=/Library/Frameworks/Mono.framework/Versions/Current/Commands:$PATH
|
||||
#export PATH=/Library/Frameworks/Mono.framework/Versions/Current/Commands:$PATH
|
||||
|
||||
echo "Running Flax.Build $*"
|
||||
mono Binaries/Tools/Flax.Build.exe "$@"
|
||||
Binaries/Tools/Flax.Build "$@"
|
||||
|
||||
@@ -28,9 +28,9 @@ fc /b Cache\Intermediate\Build\Flax.Build.Files.txt Cache\Intermediate\Build\Fla
|
||||
if not errorlevel 1 goto SkipClean
|
||||
|
||||
copy /y Cache\Intermediate\Build\Flax.Build.Files.txt Cache\Intermediate\Build\Flax.Build.PrevFiles.txt >nul
|
||||
%MSBUILD_PATH% /nologo /verbosity:quiet Source\Tools\Flax.Build\Flax.Build.csproj /property:Configuration=Release /property:Platform=AnyCPU /target:Clean
|
||||
%MSBUILD_PATH% /nologo /verbosity:quiet Source\Tools\Flax.Build\Flax.Build.csproj /property:Configuration=Release /target:Restore,Clean /property:RestorePackagesConfig=True /p:RuntimeIdentifiers=win-x64
|
||||
:SkipClean
|
||||
%MSBUILD_PATH% /nologo /verbosity:quiet Source\Tools\Flax.Build\Flax.Build.csproj /property:Configuration=Release /property:Platform=AnyCPU /target:Build
|
||||
%MSBUILD_PATH% /nologo /verbosity:quiet Source\Tools\Flax.Build\Flax.Build.csproj /property:Configuration=Release /target:Build /property:SelfContained=False /property:RuntimeIdentifiers=win-x64
|
||||
if errorlevel 1 goto Error_CompilationFailed
|
||||
|
||||
Binaries\Tools\Flax.Build.exe %*
|
||||
|
||||
+4
-3
@@ -2,8 +2,8 @@
|
||||
"Name": "Flax",
|
||||
"Version": {
|
||||
"Major": 1,
|
||||
"Minor": 5,
|
||||
"Build": 6339
|
||||
"Minor": 6,
|
||||
"Build": 6344
|
||||
},
|
||||
"Company": "Flax",
|
||||
"Copyright": "Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.",
|
||||
@@ -11,6 +11,7 @@
|
||||
"EditorTarget": "FlaxEditor",
|
||||
"Configuration": {
|
||||
"UseCSharp": true,
|
||||
"UseLargeWorlds": false
|
||||
"UseLargeWorlds": false,
|
||||
"UseDotNet": true
|
||||
}
|
||||
}
|
||||
@@ -278,6 +278,7 @@
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=heightfield/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Heightmap/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=HLSL/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=HRTF/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Inlines/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Inscattering/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Interpolants/@EntryIndexedValue">True</s:Boolean>
|
||||
@@ -305,6 +306,7 @@
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=occluder/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=offseted/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=offsetted/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=opcode/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Perlin/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=phong/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=preload/@EntryIndexedValue">True</s:Boolean>
|
||||
@@ -320,6 +322,9 @@
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Reimports/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=reimported/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=renderable/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=retarget/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=retargeting/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=retargets/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=reverb/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=rigidbodies/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=rigidbody/@EntryIndexedValue">True</s:Boolean>
|
||||
@@ -334,6 +339,7 @@
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Skybox/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Skyboxes/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=slerp/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Spatialization/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=splatmap/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=splatmaps/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=SRGB/@EntryIndexedValue">True</s:Boolean>
|
||||
|
||||
@@ -26,16 +26,12 @@ This repository contains full source code of the Flax Engine (excluding NDA-prot
|
||||
|
||||
Follow the instructions below to compile and run the engine from source.
|
||||
|
||||
## Flax plugin for Visual Studio
|
||||
|
||||
Flax Visual Studio extension provides better programming workflow, C# scripts debugging functionality and allows to attach to running engine instance to debug C# source. This extension is available to download [here](https://marketplace.visualstudio.com/items?itemName=Flax.FlaxVS).
|
||||
|
||||
## Windows
|
||||
|
||||
* Install Visual Studio 2015 or newer
|
||||
* Install Visual Studio 2022 or newer
|
||||
* Install Windows 8.1 SDK or newer (via Visual Studio Installer)
|
||||
* Install Microsoft Visual C++ 2015 v140 toolset or newer (via Visual Studio Installer)
|
||||
* Install .Net Framework 4.5.2 SDK/Targeting Pack (via Visual Studio Installer)
|
||||
* Install .Net 7 SDK (via Visual Studio Installer or [from web](https://dotnet.microsoft.com/en-us/download/dotnet/7.0))
|
||||
* Install Git with LFS
|
||||
* Clone repo (with LFS)
|
||||
* Run **GenerateProjectFiles.bat**
|
||||
@@ -44,16 +40,13 @@ Flax Visual Studio extension provides better programming workflow, C# scripts de
|
||||
* Compile Flax project (hit F7 or CTRL+Shift+B)
|
||||
* Run Flax (hit F5 key)
|
||||
|
||||
> When building on Windows to support Vulkan rendering, first install the Vulkan SDK then set an environment variable to provide the path to the SDK prior to running GenerateProjectFiles.bat: `set VULKAN_SDK=%sdk_path%`
|
||||
|
||||
## Linux
|
||||
|
||||
* Install Visual Studio Code
|
||||
* Install Mono
|
||||
* Ubuntu: see the instructions here: ([https://www.mono-project.com/download/stable](https://www.mono-project.com/download/stable))
|
||||
* Arch: `sudo pacman -S mono`
|
||||
* Install Vulkan SDK
|
||||
* Ubuntu: see the instructions here: ([https://vulkan.lunarg.com/](https://vulkan.lunarg.com/))
|
||||
* Install .Net 7 SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/7.0](https://dotnet.microsoft.com/en-us/download/dotnet/7.0))
|
||||
* Ubuntu: `sudo apt install dotnet-sdk-7.0`
|
||||
* Install Vulkan SDK ([https://vulkan.lunarg.com/](https://vulkan.lunarg.com/))
|
||||
* Ubuntu: `sudo apt install vulkan-sdk`
|
||||
* Arch: `sudo pacman -S spirv-tools vulkan-headers vulkan-tools vulkan-validation-layers`
|
||||
* Install Git with LFS
|
||||
* Ubuntu: `sudo apt-get install git git-lfs`
|
||||
@@ -73,13 +66,31 @@ Flax Visual Studio extension provides better programming workflow, C# scripts de
|
||||
## Mac
|
||||
|
||||
* Install XCode
|
||||
* Install Mono ([https://www.mono-project.com/download/stable](https://www.mono-project.com/download/stable))
|
||||
* Install .Net 7 SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/7.0](https://dotnet.microsoft.com/en-us/download/dotnet/7.0))
|
||||
* Install Vulkan SDK ([https://vulkan.lunarg.com/](https://vulkan.lunarg.com/))
|
||||
* Clone repo (with LFS)
|
||||
* Run `GenerateProjectFiles.command`
|
||||
* Open workspace with XCode or Visual Studio Code
|
||||
* Build and run (configuration `Editor.Mac.Development`)
|
||||
|
||||
#### Troubleshooting
|
||||
|
||||
* `Could not execute because the specified command or file was not found.`
|
||||
|
||||
Restart PC - ensure DotNet is added to PATH for command line tools execution.
|
||||
|
||||
* `Microsoft.NET.TargetFrameworkInference.targets(141,5): error NETSDK1045: The current .NET SDK does not support targeting .NET 7.0. Either target .NET 5.0 or lower, or use a version of the .NET SDK that supports .NET 7.0`
|
||||
|
||||
Use Visual Studio 2022, older versions are not supported by .NET SDK 7.
|
||||
|
||||
* `Building for Windows without Vulkan rendering backend (Vulkan SDK is missing)`
|
||||
|
||||
Install the Vulkan SDK then set an environment variable to provide the path to the SDK prior to running GenerateProjectFiles.bat: `set VULKAN_SDK=%sdk_path%`.
|
||||
|
||||
* `The NuGetSdkResolver did not resolve this SDK`
|
||||
|
||||
Install `.NET SDK`, `NuGet package manager` and `NuGet targets and build tasks` in Visual Studio components.
|
||||
|
||||
## Workspace directory
|
||||
|
||||
- **Binaries/** - executable files
|
||||
@@ -93,7 +104,6 @@ Flax Visual Studio extension provides better programming workflow, C# scripts de
|
||||
- **Content/** - assets and binary files used by the engine and editor
|
||||
- **Development/** - engine development files
|
||||
- **Scripts/** - utility scripts
|
||||
- **packages/** - NuGet packages cache location
|
||||
- **Source/** - source code location
|
||||
- **Editor/** - Flax Editor source code
|
||||
- **Engine/** - Flax Engine source code
|
||||
@@ -103,7 +113,6 @@ Flax Visual Studio extension provides better programming workflow, C# scripts de
|
||||
- ***PlatformName*/** - per-platform files
|
||||
- **Binaries/** - per-platform binaries
|
||||
- **Game/** - Flax Game binaries
|
||||
- **Mono/** - Mono runtime files and data
|
||||
- **ThirdParty/** - prebuilt 3rd Party binaries
|
||||
- **Shaders/** - shaders source code
|
||||
- **ThirdParty/** - 3rd Party source code
|
||||
|
||||
@@ -1,49 +1,103 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "EditorAnalytics.h"
|
||||
#include "EditorAnalyticsController.h"
|
||||
#include "Editor/Editor.h"
|
||||
#include "Editor/ProjectInfo.h"
|
||||
#include "Editor/Cooker/GameCooker.h"
|
||||
#include "Engine/Threading/Task.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Engine/Platform/MemoryStats.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Math/Vector2.h"
|
||||
#include "Engine/Core/Types/DateTime.h"
|
||||
#include "Engine/Core/Types/TimeSpan.h"
|
||||
#include "Editor/Editor.h"
|
||||
#include "Editor/ProjectInfo.h"
|
||||
#include "Engine/Engine/EngineService.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Engine/Graphics/GPUDevice.h"
|
||||
#include "Engine/Utilities/StringConverter.h"
|
||||
#include "Engine/Utilities/TextWriter.h"
|
||||
#include "Engine/ShadowsOfMordor/Builder.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "FlaxEngine.Gen.h"
|
||||
#include <ThirdParty/UniversalAnalytics/universal-analytics.h>
|
||||
#include <ThirdParty/UniversalAnalytics/http.h>
|
||||
|
||||
#define FLAX_EDITOR_GOOGLE_ID "UA-88357703-3"
|
||||
// Docs:
|
||||
// https://developers.google.com/analytics/devguides/collection/ga4
|
||||
// https://developers.google.com/analytics/devguides/collection/protocol/ga4
|
||||
|
||||
// Helper doc: https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters
|
||||
// [GA4] Flax Editor
|
||||
#define GA_MEASUREMENT_ID "G-2SNY6RW6VX"
|
||||
#define GA_API_SECRET "wFlau4khTPGFRnx-AIZ1zg"
|
||||
#define GA_DEBUG 0
|
||||
#if GA_DEBUG
|
||||
#define GA_URL "https://www.google-analytics.com/debug/mp/collect"
|
||||
#else
|
||||
#define GA_URL "https://www.google-analytics.com/mp/collect"
|
||||
#endif
|
||||
|
||||
namespace EditorAnalyticsImpl
|
||||
namespace
|
||||
{
|
||||
UATracker Tracker = nullptr;
|
||||
|
||||
StringAnsi Url;
|
||||
StringAnsi ClientId;
|
||||
StringAnsi ProjectName;
|
||||
StringAnsi ScreenResolution;
|
||||
StringAnsi UserLanguage;
|
||||
StringAnsi GPU;
|
||||
DateTime SessionStartTime;
|
||||
|
||||
CriticalSection Locker;
|
||||
bool IsSessionActive = false;
|
||||
EditorAnalyticsController Controller;
|
||||
Array<char> TmpBuffer;
|
||||
TextWriterANSI JsonBuffer;
|
||||
curl_slist* CurlHttpHeadersList = nullptr;
|
||||
}
|
||||
|
||||
using namespace EditorAnalyticsImpl;
|
||||
size_t curl_null_data_handler(char* ptr, size_t size, size_t nmemb, void* userdata)
|
||||
{
|
||||
return nmemb * size;
|
||||
}
|
||||
|
||||
void RegisterGameCookingStart(GameCooker::EventType type)
|
||||
{
|
||||
if (type == GameCooker::EventType::BuildStarted)
|
||||
{
|
||||
auto& data = *GameCooker::GetCurrentData();
|
||||
StringAnsi name = "Build " + StringAnsi(ToString(data.Platform));
|
||||
const Pair<const char*, const char*> params[1] = { { "GameCooker", name.Get() } };
|
||||
EditorAnalytics::SendEvent("Actions", ToSpan(params, ARRAY_COUNT(params)));
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterLightmapsBuildingStart()
|
||||
{
|
||||
const Pair<const char*, const char*> params[1] = { { "ShadowsOfMordor", "Build" }, };
|
||||
EditorAnalytics::SendEvent("Actions", ToSpan(params, ARRAY_COUNT(params)));
|
||||
}
|
||||
|
||||
void RegisterError(LogType type, const StringView& msg)
|
||||
{
|
||||
if (type == LogType::Error && false)
|
||||
{
|
||||
StringAnsi value(msg);
|
||||
const int32 MaxLength = 300;
|
||||
if (msg.Length() > MaxLength)
|
||||
value = value.Substring(0, MaxLength);
|
||||
value.Replace('\n', ' ');
|
||||
value.Replace('\r', ' ');
|
||||
const Pair<const char*, const char*> params[1] = { { "Error", value.Get() }, };
|
||||
EditorAnalytics::SendEvent("Errors", ToSpan(params, ARRAY_COUNT(params)));
|
||||
}
|
||||
else if (type == LogType::Fatal)
|
||||
{
|
||||
StringAnsi value(msg);
|
||||
const int32 MaxLength = 300;
|
||||
if (msg.Length() > MaxLength)
|
||||
value = value.Substring(0, MaxLength);
|
||||
value.Replace('\n', ' ');
|
||||
value.Replace('\r', ' ');
|
||||
const Pair<const char*, const char*> params[1] = { { "Fatal", value.Get() }, };
|
||||
EditorAnalytics::SendEvent("Errors", ToSpan(params, ARRAY_COUNT(params)));
|
||||
}
|
||||
}
|
||||
|
||||
class EditorAnalyticsService : public EngineService
|
||||
{
|
||||
public:
|
||||
|
||||
EditorAnalyticsService()
|
||||
: EngineService(TEXT("Editor Analytics"))
|
||||
{
|
||||
@@ -57,192 +111,141 @@ EditorAnalyticsService EditorAnalyticsServiceInstance;
|
||||
|
||||
bool EditorAnalytics::IsSessionActive()
|
||||
{
|
||||
return EditorAnalyticsImpl::IsSessionActive;
|
||||
return ::IsSessionActive;
|
||||
}
|
||||
|
||||
void EditorAnalytics::StartSession()
|
||||
{
|
||||
ScopeLock lock(Locker);
|
||||
|
||||
if (EditorAnalyticsImpl::IsSessionActive)
|
||||
if (::IsSessionActive)
|
||||
return;
|
||||
PROFILE_CPU();
|
||||
|
||||
// Prepare client metadata
|
||||
if (ClientId.IsEmpty())
|
||||
{
|
||||
ClientId = Platform::GetUniqueDeviceId().ToString(Guid::FormatType::N).ToStringAnsi();
|
||||
}
|
||||
if (ScreenResolution.IsEmpty())
|
||||
{
|
||||
const auto desktopSize = Platform::GetDesktopSize();
|
||||
ScreenResolution = StringAnsi(StringUtils::ToString((int32)desktopSize.X)) + "x" + StringAnsi(StringUtils::ToString((int32)desktopSize.Y));
|
||||
}
|
||||
if (UserLanguage.IsEmpty())
|
||||
{
|
||||
UserLanguage = Platform::GetUserLocaleName().ToStringAnsi();
|
||||
}
|
||||
if (GPU.IsEmpty())
|
||||
{
|
||||
const auto gpu = GPUDevice::Instance;
|
||||
if (gpu && gpu->GetState() == GPUDevice::DeviceState::Ready)
|
||||
GPU = StringAsANSI<>(gpu->GetAdapter()->GetDescription().GetText()).Get();
|
||||
}
|
||||
if (ProjectName.IsEmpty())
|
||||
{
|
||||
ProjectName = Editor::Project->Name.ToStringAnsi();
|
||||
}
|
||||
ClientId = Platform::GetUniqueDeviceId().ToString(Guid::FormatType::N).ToStringAnsi();
|
||||
StringAnsi ProjectName = Editor::Project->Name.ToStringAnsi();
|
||||
const auto desktopSize = Platform::GetDesktopSize();
|
||||
StringAnsi ScreenResolution = StringAnsi::Format("{0}x{1}", (int32)desktopSize.X, (int32)desktopSize.Y);
|
||||
const auto memoryStats = Platform::GetMemoryStats();
|
||||
StringAnsi Memory = StringAnsi::Format("{0} GB", (int32)(memoryStats.TotalPhysicalMemory / 1024 / 1024 / 1000));
|
||||
StringAnsi UserLocale = Platform::GetUserLocaleName().ToStringAnsi();
|
||||
StringAnsi GPU;
|
||||
if (GPUDevice::Instance && GPUDevice::Instance->GetState() == GPUDevice::DeviceState::Ready)
|
||||
GPU = StringAsANSI<>(GPUDevice::Instance->GetAdapter()->GetDescription().GetText()).Get();
|
||||
SessionStartTime = DateTime::Now();
|
||||
|
||||
// Initialize the analytics tracker
|
||||
Tracker = createTracker(FLAX_EDITOR_GOOGLE_ID, ClientId.Get(), nullptr);
|
||||
Tracker->user_agent = "Flax Editor";
|
||||
|
||||
// Store these options permanently (for the lifetime of the tracker)
|
||||
setTrackerOption(Tracker, UA_OPTION_QUEUE, 1);
|
||||
UASettings GlobalSettings =
|
||||
{
|
||||
{
|
||||
{ UA_DOCUMENT_PATH, 0, "Flax Editor" },
|
||||
{ UA_DOCUMENT_TITLE, 0, "Flax Editor" },
|
||||
StringAnsiView EngineVersion = FLAXENGINE_VERSION_TEXT;
|
||||
#if PLATFORM_WINDOWS
|
||||
{ UA_USER_AGENT, 0, "Windows " FLAXENGINE_VERSION_TEXT },
|
||||
StringAnsiView PlatformName = "Windows";
|
||||
#elif PLATFORM_LINUX
|
||||
{ UA_USER_AGENT, 0, "Linux " FLAXENGINE_VERSION_TEXT },
|
||||
StringAnsiView PlatformName = "Linux";
|
||||
#elif PLATFORM_MAC
|
||||
{ UA_USER_AGENT, 0, "Mac " FLAXENGINE_VERSION_TEXT },
|
||||
StringAnsiView PlatformName = "Mac";
|
||||
#else
|
||||
#error "Unknown platform"
|
||||
#endif
|
||||
{ UA_ANONYMIZE_IP, 0, "0" },
|
||||
{ UA_APP_ID, 0, "Flax Editor " FLAXENGINE_VERSION_TEXT },
|
||||
{ UA_APP_INSTALLER_ID, 0, "Flax Editor" },
|
||||
{ UA_APP_NAME, 0, "Flax Editor" },
|
||||
{ UA_APP_VERSION, 0, FLAXENGINE_VERSION_TEXT },
|
||||
{ UA_SCREEN_NAME, 0, "Flax Editor " FLAXENGINE_VERSION_TEXT },
|
||||
{ UA_SCREEN_RESOLUTION, 0, ScreenResolution.Get() },
|
||||
{ UA_USER_LANGUAGE, 0, UserLanguage.Get() },
|
||||
}
|
||||
};
|
||||
setParameters(Tracker, &GlobalSettings);
|
||||
|
||||
// Send the initial session event
|
||||
UAOptions sessionViewOptions =
|
||||
// Initialize HTTP
|
||||
Url = StringAnsi::Format("{0}?measurement_id={1}&api_secret={2}", GA_URL, GA_MEASUREMENT_ID, GA_API_SECRET);
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
CurlHttpHeadersList = curl_slist_append(nullptr, "Content-Type: application/json");
|
||||
::IsSessionActive = true;
|
||||
|
||||
// Start session
|
||||
{
|
||||
{
|
||||
{ UA_EVENT_CATEGORY, 0, "Session" },
|
||||
{ UA_EVENT_ACTION, 0, "Start Editor" },
|
||||
{ UA_EVENT_LABEL, 0, "Start Editor" },
|
||||
{ UA_SESSION_CONTROL, 0, "start" },
|
||||
{ UA_DOCUMENT_TITLE, 0, ProjectName.Get() },
|
||||
}
|
||||
};
|
||||
sendTracking(Tracker, UA_SCREENVIEW, &sessionViewOptions);
|
||||
|
||||
EditorAnalyticsImpl::IsSessionActive = true;
|
||||
|
||||
Controller.Init();
|
||||
|
||||
// Report GPU model
|
||||
if (GPU.HasChars())
|
||||
{
|
||||
SendEvent("Telemetry", "GPU.Model", GPU.Get());
|
||||
const Pair<const char*, const char*> params[1] = { { "Project", ProjectName.Get() }, };
|
||||
SendEvent("Session", ToSpan(params, ARRAY_COUNT(params)));
|
||||
}
|
||||
|
||||
// Report telemetry stats
|
||||
#define SEND_TELEMETRY(name, value) \
|
||||
if (value.HasChars()) \
|
||||
{ \
|
||||
const Pair<const char*, const char*> params[1] = { { name, value.Get() } }; \
|
||||
SendEvent("Telemetry", ToSpan(params, ARRAY_COUNT(params))); \
|
||||
}
|
||||
SEND_TELEMETRY("Platform", PlatformName);
|
||||
SEND_TELEMETRY("GPU", GPU);
|
||||
SEND_TELEMETRY("Memory", Memory);
|
||||
SEND_TELEMETRY("Locale", UserLocale);
|
||||
SEND_TELEMETRY("Screen", ScreenResolution);
|
||||
SEND_TELEMETRY("Version", EngineVersion);
|
||||
#undef SEND_TELEMETRY
|
||||
|
||||
// Bind events
|
||||
GameCooker::OnEvent.Bind<RegisterGameCookingStart>();
|
||||
ShadowsOfMordor::Builder::Instance()->OnBuildStarted.Bind<RegisterLightmapsBuildingStart>();
|
||||
Log::Logger::OnError.Bind<RegisterError>();
|
||||
}
|
||||
|
||||
void EditorAnalytics::EndSession()
|
||||
{
|
||||
ScopeLock lock(Locker);
|
||||
|
||||
if (!EditorAnalyticsImpl::IsSessionActive)
|
||||
if (!::IsSessionActive)
|
||||
return;
|
||||
PROFILE_CPU();
|
||||
|
||||
Controller.Cleanup();
|
||||
// Unbind events
|
||||
GameCooker::OnEvent.Unbind<RegisterGameCookingStart>();
|
||||
ShadowsOfMordor::Builder::Instance()->OnBuildStarted.Unbind<RegisterLightmapsBuildingStart>();
|
||||
Log::Logger::OnError.Unbind<RegisterError>();
|
||||
|
||||
StringAnsi sessionLength = StringAnsi::Format("{0}", (int32)(DateTime::Now() - SessionStartTime).GetTotalSeconds());
|
||||
|
||||
// Send the end session event
|
||||
UAOptions sessionEventOptions =
|
||||
// End session
|
||||
{
|
||||
StringAnsi sessionLength = StringAnsi::Format("{}", (int32)(DateTime::Now() - SessionStartTime).GetTotalSeconds());
|
||||
const Pair<const char*, const char*> params[1] =
|
||||
{
|
||||
{ UA_EVENT_CATEGORY, 0, "Session" },
|
||||
{ UA_EVENT_ACTION, 0, "Session Length" },
|
||||
{ UA_EVENT_LABEL, 0, "Session Length" },
|
||||
{ UA_EVENT_VALUE, 0, sessionLength.Get() },
|
||||
{ UA_CUSTOM_DIMENSION, 1, "Session Length" },
|
||||
{ UA_CUSTOM_METRIC, 1, sessionLength.Get() },
|
||||
}
|
||||
};
|
||||
sendTracking(Tracker, UA_EVENT, &sessionEventOptions);
|
||||
|
||||
// Send the end session event
|
||||
UAOptions sessionViewOptions =
|
||||
{
|
||||
{
|
||||
{ UA_EVENT_CATEGORY, 0, "Session" },
|
||||
{ UA_EVENT_ACTION, 0, "End Editor" },
|
||||
{ UA_EVENT_LABEL, 0, "End Editor" },
|
||||
{ UA_EVENT_VALUE, 0, sessionLength.Get() },
|
||||
{ UA_SESSION_CONTROL, 0, "end" },
|
||||
}
|
||||
};
|
||||
sendTracking(Tracker, UA_SCREENVIEW, &sessionViewOptions);
|
||||
{ "Duration", sessionLength.Get() },
|
||||
};
|
||||
SendEvent("Session", ToSpan(params, ARRAY_COUNT(params)));
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
removeTracker(Tracker);
|
||||
Tracker = nullptr;
|
||||
|
||||
EditorAnalyticsImpl::IsSessionActive = false;
|
||||
curl_slist_free_all(CurlHttpHeadersList);
|
||||
CurlHttpHeadersList = nullptr;
|
||||
curl_global_cleanup();
|
||||
::IsSessionActive = false;
|
||||
}
|
||||
|
||||
void EditorAnalytics::SendEvent(const char* category, const char* name, const char* label)
|
||||
void EditorAnalytics::SendEvent(const char* name, Span<Pair<const char*, const char*>> parameters)
|
||||
{
|
||||
ScopeLock lock(Locker);
|
||||
|
||||
if (!EditorAnalyticsImpl::IsSessionActive)
|
||||
if (!::IsSessionActive)
|
||||
return;
|
||||
PROFILE_CPU();
|
||||
|
||||
UAOptions opts =
|
||||
// Create Json request contents
|
||||
JsonBuffer.Clear();
|
||||
JsonBuffer.Write("{ \"client_id\": \"");
|
||||
JsonBuffer.Write(ClientId);
|
||||
JsonBuffer.Write("\", \"events\": [ { \"name\": \"");
|
||||
JsonBuffer.Write(name);
|
||||
JsonBuffer.Write("\", \"params\": {");
|
||||
for (int32 i = 0; i < parameters.Length(); i++)
|
||||
{
|
||||
{
|
||||
{ UA_EVENT_CATEGORY, 0, (char*)category },
|
||||
{ UA_EVENT_ACTION, 0, (char*)name },
|
||||
{ UA_EVENT_LABEL, 0, (char*)label },
|
||||
}
|
||||
};
|
||||
if (i != 0)
|
||||
JsonBuffer.Write(",");
|
||||
const auto& e = parameters[i];
|
||||
JsonBuffer.Write("\"");
|
||||
JsonBuffer.Write(e.First);
|
||||
JsonBuffer.Write("\":\"");
|
||||
JsonBuffer.Write(e.Second);
|
||||
JsonBuffer.Write("\"");
|
||||
}
|
||||
JsonBuffer.Write("}}]}");
|
||||
const StringAnsiView json((const char*)JsonBuffer.GetBuffer()->GetHandle(), (int32)JsonBuffer.GetBuffer()->GetPosition());
|
||||
|
||||
sendTracking(Tracker, UA_EVENT, &opts);
|
||||
}
|
||||
|
||||
void EditorAnalytics::SendEvent(const char* category, const char* name, const StringView& label)
|
||||
{
|
||||
SendEvent(category, name, label.Get());
|
||||
}
|
||||
|
||||
void EditorAnalytics::SendEvent(const char* category, const char* name, const Char* label)
|
||||
{
|
||||
ScopeLock lock(Locker);
|
||||
|
||||
if (!EditorAnalyticsImpl::IsSessionActive)
|
||||
return;
|
||||
|
||||
ASSERT(category && name && label);
|
||||
|
||||
const int32 labelLength = StringUtils::Length(label);
|
||||
TmpBuffer.Clear();
|
||||
TmpBuffer.Resize(labelLength + 1);
|
||||
StringUtils::ConvertUTF162ANSI(label, TmpBuffer.Get(), labelLength);
|
||||
TmpBuffer[labelLength] = 0;
|
||||
|
||||
UAOptions opts =
|
||||
{
|
||||
{
|
||||
{ UA_EVENT_CATEGORY, 0, (char*)category },
|
||||
{ UA_EVENT_ACTION, 0, (char*)name },
|
||||
{ UA_EVENT_LABEL, 0, (char*)TmpBuffer.Get() },
|
||||
}
|
||||
};
|
||||
|
||||
sendTracking(Tracker, UA_EVENT, &opts);
|
||||
// Send HTTP request
|
||||
CURL* curl = curl_easy_init();
|
||||
curl_easy_setopt(curl, CURLOPT_POST, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, Url.Get());
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, CurlHttpHeadersList);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json.Get());
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, json.Length());
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, "Flax Editor");
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, curl);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_null_data_handler);
|
||||
CURLcode res = curl_easy_perform(curl);
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
|
||||
bool EditorAnalyticsService::Init()
|
||||
@@ -265,8 +268,7 @@ bool EditorAnalyticsService::Init()
|
||||
}
|
||||
|
||||
LOG(Info, "Editor analytics service is enabled. Curl version: {0}", TEXT(LIBCURL_VERSION));
|
||||
|
||||
EditorAnalytics::StartSession();
|
||||
Task::StartNew(EditorAnalytics::StartSession);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -10,11 +10,9 @@
|
||||
class EditorAnalytics
|
||||
{
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether analytics session is active.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if there is active analytics session running; otherwise, <c>false</c>.</returns>
|
||||
static bool IsSessionActive();
|
||||
|
||||
/// <summary>
|
||||
@@ -30,24 +28,7 @@ public:
|
||||
/// <summary>
|
||||
/// Sends the custom event.
|
||||
/// </summary>
|
||||
/// <param name="category">The event category name.</param>
|
||||
/// <param name="name">The event name.</param>
|
||||
/// <param name="label">The event label.</param>
|
||||
static void SendEvent(const char* category, const char* name, const char* label = nullptr);
|
||||
|
||||
/// <summary>
|
||||
/// Sends the custom event.
|
||||
/// </summary>
|
||||
/// <param name="category">The event category name.</param>
|
||||
/// <param name="name">The event name.</param>
|
||||
/// <param name="label">The event label.</param>
|
||||
static void SendEvent(const char* category, const char* name, const StringView& label);
|
||||
|
||||
/// <summary>
|
||||
/// Sends the custom event.
|
||||
/// </summary>
|
||||
/// <param name="category">The event category name.</param>
|
||||
/// <param name="name">The event name.</param>
|
||||
/// <param name="label">The event label.</param>
|
||||
static void SendEvent(const char* category, const char* name, const Char* label);
|
||||
/// <param name="parameters">The event parameters (key and value pairs).</param>
|
||||
static void SendEvent(const char* name, Span<Pair<const char*, const char*>> parameters);
|
||||
};
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "EditorAnalyticsController.h"
|
||||
#include "Editor/Cooker/GameCooker.h"
|
||||
#include "EditorAnalytics.h"
|
||||
#include "Engine/ShadowsOfMordor/Builder.h"
|
||||
|
||||
void RegisterGameCookingStart(GameCooker::EventType type)
|
||||
{
|
||||
auto& data = *GameCooker::GetCurrentData();
|
||||
auto platform = ToString(data.Platform);
|
||||
if (type == GameCooker::EventType::BuildStarted)
|
||||
{
|
||||
EditorAnalytics::SendEvent("Actions", "GameCooker.Start", platform);
|
||||
}
|
||||
else if (type == GameCooker::EventType::BuildFailed)
|
||||
{
|
||||
EditorAnalytics::SendEvent("Actions", "GameCooker.Failed", platform);
|
||||
}
|
||||
else if (type == GameCooker::EventType::BuildDone)
|
||||
{
|
||||
EditorAnalytics::SendEvent("Actions", "GameCooker.End", platform);
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterLightmapsBuildingStart()
|
||||
{
|
||||
EditorAnalytics::SendEvent("Actions", "ShadowsOfMordor.Build", "ShadowsOfMordor.Build");
|
||||
}
|
||||
|
||||
void RegisterError(LogType type, const StringView& msg)
|
||||
{
|
||||
if (type == LogType::Error && false)
|
||||
{
|
||||
String value = msg.ToString();
|
||||
const int32 MaxLength = 300;
|
||||
if (msg.Length() > MaxLength)
|
||||
value = value.Substring(0, MaxLength);
|
||||
value.Replace('\n', ' ');
|
||||
value.Replace('\r', ' ');
|
||||
|
||||
EditorAnalytics::SendEvent("Errors", "Log.Error", value);
|
||||
}
|
||||
else if (type == LogType::Fatal)
|
||||
{
|
||||
String value = msg.ToString();
|
||||
const int32 MaxLength = 300;
|
||||
if (msg.Length() > MaxLength)
|
||||
value = value.Substring(0, MaxLength);
|
||||
value.Replace('\n', ' ');
|
||||
value.Replace('\r', ' ');
|
||||
|
||||
EditorAnalytics::SendEvent("Errors", "Log.Fatal", value);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorAnalyticsController::Init()
|
||||
{
|
||||
GameCooker::OnEvent.Bind<RegisterGameCookingStart>();
|
||||
ShadowsOfMordor::Builder::Instance()->OnBuildStarted.Bind<RegisterLightmapsBuildingStart>();
|
||||
Log::Logger::OnError.Bind<RegisterError>();
|
||||
}
|
||||
|
||||
void EditorAnalyticsController::Cleanup()
|
||||
{
|
||||
GameCooker::OnEvent.Unbind<RegisterGameCookingStart>();
|
||||
ShadowsOfMordor::Builder::Instance()->OnBuildStarted.Unbind<RegisterLightmapsBuildingStart>();
|
||||
Log::Logger::OnError.Unbind<RegisterError>();
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
/// <summary>
|
||||
/// The controller object for the tracking events for the editor analytics.
|
||||
/// </summary>
|
||||
class EditorAnalyticsController
|
||||
{
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Starts the service (registers to event handlers).
|
||||
/// </summary>
|
||||
void Init();
|
||||
|
||||
/// <summary>
|
||||
/// Ends the service (unregisters to event handlers).
|
||||
/// </summary>
|
||||
void Cleanup();
|
||||
};
|
||||
@@ -692,10 +692,13 @@ namespace FlaxEditor.Content.GUI
|
||||
c = char.ToLowerInvariant(c);
|
||||
for (int i = 0; i < _items.Count; i++)
|
||||
{
|
||||
var name = _items[i].ShortName;
|
||||
var item = _items[i];
|
||||
var name = item.ShortName;
|
||||
if (!string.IsNullOrEmpty(name) && char.ToLowerInvariant(name[0]) == c)
|
||||
{
|
||||
Select(_items[i]);
|
||||
Select(item);
|
||||
if (Parent is Panel panel)
|
||||
panel.ScrollViewTo(item, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Interop;
|
||||
|
||||
namespace FlaxEditor.Content.Import
|
||||
{
|
||||
@@ -93,6 +93,7 @@ namespace FlaxEditor.Content.Import
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct InternalOptions
|
||||
{
|
||||
[MarshalAs(UnmanagedType.I1)]
|
||||
public AudioFormat Format;
|
||||
public byte DisableStreaming;
|
||||
public byte Is3D;
|
||||
@@ -144,7 +145,7 @@ namespace FlaxEditor.Content.Import
|
||||
/// Audio asset import entry.
|
||||
/// </summary>
|
||||
/// <seealso cref="AssetImportEntry" />
|
||||
public class AudioImportEntry : AssetImportEntry
|
||||
public partial class AudioImportEntry : AssetImportEntry
|
||||
{
|
||||
private AudioImportSettings _settings = new AudioImportSettings();
|
||||
|
||||
@@ -182,8 +183,9 @@ namespace FlaxEditor.Content.Import
|
||||
|
||||
#region Internal Calls
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_GetAudioImportOptions(string path, out AudioImportSettings.InternalOptions result);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "AudioImportEntryInternal_GetAudioImportOptions", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_GetAudioImportOptions(string path, out AudioImportSettings.InternalOptions result);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -1,88 +1,47 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Collections.Generic;
|
||||
using FlaxEditor.CustomEditors.Editors;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Tools;
|
||||
|
||||
namespace FlaxEngine.Tools
|
||||
{
|
||||
partial class ModelTool
|
||||
{
|
||||
partial struct Options
|
||||
{
|
||||
private bool ShowGeometry => Type == ModelTool.ModelType.Model || Type == ModelTool.ModelType.SkinnedModel;
|
||||
private bool ShowModel => Type == ModelTool.ModelType.Model;
|
||||
private bool ShowSkinnedModel => Type == ModelTool.ModelType.SkinnedModel;
|
||||
private bool ShowAnimation => Type == ModelTool.ModelType.Animation;
|
||||
private bool ShowSmoothingNormalsAngle => ShowGeometry && CalculateNormals;
|
||||
private bool ShowSmoothingTangentsAngle => ShowGeometry && CalculateTangents;
|
||||
private bool ShowFramesRange => ShowAnimation && Duration == ModelTool.AnimationDuration.Custom;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom editor for <see cref="FlaxEngine.Tools.ModelTool.Options"/>.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(FlaxEngine.Tools.ModelTool.Options)), DefaultEditor]
|
||||
public class ModelToolOptionsEditor : GenericEditor
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override List<ItemInfo> GetItemsForType(ScriptType type)
|
||||
{
|
||||
// Show both fields and properties
|
||||
return GetItemsForType(type, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace FlaxEditor.Content.Import
|
||||
{
|
||||
/// <summary>
|
||||
/// Importing model lightmap UVs source
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
public enum ModelLightmapUVsSource : int
|
||||
{
|
||||
/// <summary>
|
||||
/// No lightmap UVs.
|
||||
/// </summary>
|
||||
Disable = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Generate lightmap UVs from model geometry.
|
||||
/// </summary>
|
||||
Generate = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The texcoords channel 0.
|
||||
/// </summary>
|
||||
Channel0 = 2,
|
||||
|
||||
/// <summary>
|
||||
/// The texcoords channel 1.
|
||||
/// </summary>
|
||||
Channel1 = 3,
|
||||
|
||||
/// <summary>
|
||||
/// The texcoords channel 2.
|
||||
/// </summary>
|
||||
Channel2 = 4,
|
||||
|
||||
/// <summary>
|
||||
/// The texcoords channel 3.
|
||||
/// </summary>
|
||||
Channel3 = 5
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Declares the imported data type.
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
public enum ModelType : int
|
||||
{
|
||||
/// <summary>
|
||||
/// The model asset.
|
||||
/// </summary>
|
||||
Model = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The skinned model asset.
|
||||
/// </summary>
|
||||
SkinnedModel = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The animation asset.
|
||||
/// </summary>
|
||||
Animation = 2,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Declares the imported animation clip duration.
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
public enum AnimationDuration : int
|
||||
{
|
||||
/// <summary>
|
||||
/// The imported duration.
|
||||
/// </summary>
|
||||
Imported = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The custom duration specified via keyframes range.
|
||||
/// </summary>
|
||||
Custom = 1,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Proxy object to present model import settings in <see cref="ImportFilesDialog"/>.
|
||||
/// </summary>
|
||||
@@ -90,431 +49,10 @@ namespace FlaxEditor.Content.Import
|
||||
public class ModelImportSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Type of the imported asset.
|
||||
/// The settings data.
|
||||
/// </summary>
|
||||
[EditorOrder(0)]
|
||||
public ModelType Type { get; set; } = ModelType.Model;
|
||||
|
||||
/// <summary>
|
||||
/// Enable model normal vectors recalculating.
|
||||
/// </summary>
|
||||
[EditorDisplay("Geometry"), VisibleIf(nameof(ShowGeometry))]
|
||||
[EditorOrder(20), DefaultValue(false)]
|
||||
public bool CalculateNormals { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the maximum angle (in degrees) that may be between two face normals at the same vertex position that their are smoothed together. The default value is 175.
|
||||
/// </summary>
|
||||
[EditorDisplay("Geometry"), VisibleIf(nameof(ShowSmoothingNormalsAngle))]
|
||||
[EditorOrder(30), DefaultValue(175.0f), Limit(0, 175, 0.1f)]
|
||||
public float SmoothingNormalsAngle { get; set; } = 175.0f;
|
||||
|
||||
private bool ShowSmoothingNormalsAngle => ShowGeometry && CalculateNormals;
|
||||
|
||||
/// <summary>
|
||||
/// If checked, the imported normal vectors of the mesh will be flipped (scaled by -1).
|
||||
/// </summary>
|
||||
[EditorDisplay("Geometry"), VisibleIf(nameof(ShowGeometry))]
|
||||
[EditorOrder(35), DefaultValue(false)]
|
||||
public bool FlipNormals { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Enable model tangent vectors recalculating.
|
||||
/// </summary>
|
||||
[EditorDisplay("Geometry"), VisibleIf(nameof(ShowGeometry))]
|
||||
[EditorOrder(40), DefaultValue(false)]
|
||||
public bool CalculateTangents { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the maximum angle (in degrees) that may be between two vertex tangents that their tangents and bi-tangents are smoothed. The default value is 45.
|
||||
/// </summary>
|
||||
[EditorDisplay("Geometry"), VisibleIf(nameof(ShowSmoothingTangentsAngle))]
|
||||
[EditorOrder(45), DefaultValue(45.0f), Limit(0, 45, 0.1f)]
|
||||
public float SmoothingTangentsAngle { get; set; } = 45.0f;
|
||||
|
||||
private bool ShowSmoothingTangentsAngle => ShowGeometry && CalculateTangents;
|
||||
|
||||
/// <summary>
|
||||
/// Enable/disable meshes geometry optimization.
|
||||
/// </summary>
|
||||
[EditorDisplay("Geometry"), VisibleIf(nameof(ShowGeometry))]
|
||||
[EditorOrder(50), DefaultValue(true)]
|
||||
public bool OptimizeMeshes { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Enable/disable geometry merge for meshes with the same materials.
|
||||
/// </summary>
|
||||
[EditorDisplay("Geometry"), VisibleIf(nameof(ShowGeometry))]
|
||||
[EditorOrder(60), DefaultValue(true)]
|
||||
public bool MergeMeshes { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Enable/disable importing meshes Level of Details.
|
||||
/// </summary>
|
||||
[EditorDisplay("Geometry", "Import LODs"), VisibleIf(nameof(ShowGeometry))]
|
||||
[EditorOrder(70), DefaultValue(true)]
|
||||
public bool ImportLODs { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Enable/disable importing vertex colors (channel 0 only).
|
||||
/// </summary>
|
||||
[EditorDisplay("Geometry"), VisibleIf(nameof(ShowModel))]
|
||||
[EditorOrder(80), DefaultValue(true)]
|
||||
public bool ImportVertexColors { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Enable/disable importing blend shapes (morph targets).
|
||||
/// </summary>
|
||||
[EditorDisplay("Geometry"), VisibleIf(nameof(ShowSkinnedModel))]
|
||||
[EditorOrder(85), DefaultValue(false)]
|
||||
public bool ImportBlendShapes { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// The lightmap UVs source.
|
||||
/// </summary>
|
||||
[EditorDisplay("Geometry", "Lightmap UVs Source"), VisibleIf(nameof(ShowModel))]
|
||||
[EditorOrder(90), DefaultValue(ModelLightmapUVsSource.Disable)]
|
||||
public ModelLightmapUVsSource LightmapUVsSource { get; set; } = ModelLightmapUVsSource.Disable;
|
||||
|
||||
/// <summary>
|
||||
/// If specified, all meshes which name starts with this prefix will be imported as a separate collision data (excluded used for rendering).
|
||||
/// </summary>
|
||||
[EditorDisplay("Geometry"), VisibleIf(nameof(ShowGeometry))]
|
||||
[EditorOrder(100), DefaultValue("")]
|
||||
public string CollisionMeshesPrefix { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Custom uniform import scale.
|
||||
/// </summary>
|
||||
[EditorOrder(500), DefaultValue(1.0f), EditorDisplay("Transform")]
|
||||
public float Scale { get; set; } = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Custom import geometry rotation.
|
||||
/// </summary>
|
||||
[DefaultValue(typeof(Quaternion), "0,0,0,1")]
|
||||
[EditorOrder(510), EditorDisplay("Transform")]
|
||||
public Quaternion Rotation { get; set; } = Quaternion.Identity;
|
||||
|
||||
/// <summary>
|
||||
/// Custom import geometry offset.
|
||||
/// </summary>
|
||||
[DefaultValue(typeof(Float3), "0,0,0")]
|
||||
[EditorOrder(520), EditorDisplay("Transform")]
|
||||
public Float3 Translation { get; set; } = Float3.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// If checked, the imported geometry will be shifted to the center of mass.
|
||||
/// </summary>
|
||||
[EditorOrder(530), DefaultValue(false), EditorDisplay("Transform")]
|
||||
public bool CenterGeometry { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Imported animation duration mode. Can use the original value or overriden by settings.
|
||||
/// </summary>
|
||||
[EditorDisplay("Animation"), VisibleIf(nameof(ShowAnimation))]
|
||||
[EditorOrder(1000), DefaultValue(AnimationDuration.Imported)]
|
||||
public AnimationDuration Duration { get; set; } = AnimationDuration.Imported;
|
||||
|
||||
/// <summary>
|
||||
/// Imported animation first frame index. Used only if Duration mode is set to Custom.
|
||||
/// </summary>
|
||||
[EditorDisplay("Animation"), VisibleIf(nameof(ShowFramesRange))]
|
||||
[EditorOrder(1010), DefaultValue(0.0f), Limit(0)]
|
||||
public float FramesRangeStart { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Imported animation last frame index. Used only if Duration mode is set to Custom.
|
||||
/// </summary>
|
||||
[EditorDisplay("Animation"), VisibleIf(nameof(ShowFramesRange))]
|
||||
[EditorOrder(1020), DefaultValue(0.0f), Limit(0)]
|
||||
public float FramesRangeEnd { get; set; } = 0;
|
||||
|
||||
private bool ShowFramesRange => ShowAnimation && Duration == AnimationDuration.Custom;
|
||||
|
||||
/// <summary>
|
||||
/// The imported animation default frame rate. Can specify the default frames per second amount for imported animation. If value is 0 then the original animation frame rate will be used.
|
||||
/// </summary>
|
||||
[EditorDisplay("Animation"), VisibleIf(nameof(ShowAnimation))]
|
||||
[EditorOrder(1025), DefaultValue(0.0f), Limit(0, 1000, 0.01f)]
|
||||
public float DefaultFrameRate { get; set; } = 0.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The imported animation sampling rate. If value is 0 then the original animation speed will be used.
|
||||
/// </summary>
|
||||
[EditorDisplay("Animation"), VisibleIf(nameof(ShowAnimation))]
|
||||
[EditorOrder(1030), DefaultValue(0.0f), Limit(0, 1000, 0.01f)]
|
||||
public float SamplingRate { get; set; } = 0.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The imported animation will have removed tracks with no keyframes or unspecified data.
|
||||
/// </summary>
|
||||
[EditorDisplay("Animation"), VisibleIf(nameof(ShowAnimation))]
|
||||
[EditorOrder(1040), DefaultValue(true)]
|
||||
public bool SkipEmptyCurves { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// The imported animation channels will be optimized to remove redundant keyframes.
|
||||
/// </summary>
|
||||
[EditorDisplay("Animation"), VisibleIf(nameof(ShowAnimation))]
|
||||
[EditorOrder(1050), DefaultValue(true)]
|
||||
public bool OptimizeKeyframes { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// If checked, the importer will import scale animation tracks (otherwise scale animation will be ignored).
|
||||
/// </summary>
|
||||
[EditorDisplay("Animation"), VisibleIf(nameof(ShowAnimation))]
|
||||
[EditorOrder(1055), DefaultValue(false)]
|
||||
public bool ImportScaleTracks { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Enables root motion extraction support from this animation.
|
||||
/// </summary>
|
||||
[EditorDisplay("Animation"), VisibleIf(nameof(ShowAnimation))]
|
||||
[EditorOrder(1060), DefaultValue(false)]
|
||||
public bool EnableRootMotion { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// The custom node name to be used as a root motion source. If not specified the actual root node will be used.
|
||||
/// </summary>
|
||||
[EditorDisplay("Animation"), VisibleIf(nameof(ShowAnimation))]
|
||||
[EditorOrder(1070), DefaultValue(typeof(string), "")]
|
||||
public string RootNodeName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If checked, the importer will generate a sequence of LODs based on the base LOD index.
|
||||
/// </summary>
|
||||
[EditorDisplay("Level Of Detail", "Generate LODs"), VisibleIf(nameof(ShowGeometry))]
|
||||
[EditorOrder(1100), DefaultValue(false)]
|
||||
public bool GenerateLODs { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// The index of the LOD from the source model data to use as a reference for following LODs generation.
|
||||
/// </summary>
|
||||
[EditorDisplay("Level Of Detail", "Base LOD"), VisibleIf(nameof(ShowGeometry))]
|
||||
[EditorOrder(1110), DefaultValue(0), Limit(0, Model.MaxLODs - 1)]
|
||||
public int BaseLOD { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The amount of LODs to include in the model (all remaining ones starting from Base LOD will be generated).
|
||||
/// </summary>
|
||||
[EditorDisplay("Level Of Detail", "LOD Count"), VisibleIf(nameof(ShowGeometry))]
|
||||
[EditorOrder(1120), DefaultValue(4), Limit(1, Model.MaxLODs)]
|
||||
public int LODCount { get; set; } = 4;
|
||||
|
||||
/// <summary>
|
||||
/// The target amount of triangles for the generated LOD (based on the higher LOD). Normalized to range 0-1. For instance 0.4 cuts the triangle count to 40%.
|
||||
/// </summary>
|
||||
[EditorDisplay("Level Of Detail"), VisibleIf(nameof(ShowGeometry))]
|
||||
[EditorOrder(1130), DefaultValue(0.5f), Limit(0, 1, 0.001f)]
|
||||
public float TriangleReduction { get; set; } = 0.5f;
|
||||
|
||||
/// <summary>
|
||||
/// If checked, the importer will create materials for model meshes as specified in the file.
|
||||
/// </summary>
|
||||
[EditorDisplay("Materials"), VisibleIf(nameof(ShowGeometry))]
|
||||
[EditorOrder(400), DefaultValue(true)]
|
||||
public bool ImportMaterials { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// If checked, the importer will import texture files used by the model and any embedded texture resources.
|
||||
/// </summary>
|
||||
[EditorDisplay("Materials"), VisibleIf(nameof(ShowGeometry))]
|
||||
[EditorOrder(410), DefaultValue(true)]
|
||||
public bool ImportTextures { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// If checked, the importer will try to restore the model material slots.
|
||||
/// </summary>
|
||||
[EditorDisplay("Materials", "Restore Materials On Reimport"), VisibleIf(nameof(ShowGeometry))]
|
||||
[EditorOrder(420), DefaultValue(true)]
|
||||
public bool RestoreMaterialsOnReimport { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// If checked, enables generation of Signed Distance Field (SDF).
|
||||
/// </summary>
|
||||
[EditorDisplay("SDF"), VisibleIf(nameof(ShowModel))]
|
||||
[EditorOrder(1500), DefaultValue(false)]
|
||||
public bool GenerateSDF { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Resolution scale for generated Signed Distance Field (SDF) texture. Higher values improve accuracy but increase memory usage and reduce performance.
|
||||
/// </summary>
|
||||
[EditorDisplay("SDF"), VisibleIf(nameof(ShowModel))]
|
||||
[EditorOrder(1510), DefaultValue(1.0f), Limit(0.0001f, 100.0f)]
|
||||
public float SDFResolution { get; set; } = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// If checked, the imported mesh/animations are splitted into separate assets. Used if ObjectIndex is set to -1.
|
||||
/// </summary>
|
||||
[EditorOrder(2000), DefaultValue(false), EditorDisplay("Splitting")]
|
||||
public bool SplitObjects { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// The zero-based index for the mesh/animation clip to import. If the source file has more than one mesh/animation it can be used to pick a desire object. Default -1 imports all objects.
|
||||
/// </summary>
|
||||
[EditorOrder(2010), DefaultValue(-1), EditorDisplay("Splitting")]
|
||||
public int ObjectIndex { get; set; } = -1;
|
||||
|
||||
private bool ShowGeometry => Type == ModelType.Model || Type == ModelType.SkinnedModel;
|
||||
private bool ShowModel => Type == ModelType.Model;
|
||||
private bool ShowSkinnedModel => Type == ModelType.SkinnedModel;
|
||||
private bool ShowAnimation => Type == ModelType.Animation;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct InternalOptions
|
||||
{
|
||||
public ModelType Type;
|
||||
|
||||
// Geometry
|
||||
public byte CalculateNormals;
|
||||
public float SmoothingNormalsAngle;
|
||||
public byte FlipNormals;
|
||||
public float SmoothingTangentsAngle;
|
||||
public byte CalculateTangents;
|
||||
public byte OptimizeMeshes;
|
||||
public byte MergeMeshes;
|
||||
public byte ImportLODs;
|
||||
public byte ImportVertexColors;
|
||||
public byte ImportBlendShapes;
|
||||
public ModelLightmapUVsSource LightmapUVsSource;
|
||||
public string CollisionMeshesPrefix;
|
||||
|
||||
// Transform
|
||||
public float Scale;
|
||||
public Quaternion Rotation;
|
||||
public Float3 Translation;
|
||||
public byte CenterGeometry;
|
||||
|
||||
// Animation
|
||||
public AnimationDuration Duration;
|
||||
public float FramesRangeStart;
|
||||
public float FramesRangeEnd;
|
||||
public float DefaultFrameRate;
|
||||
public float SamplingRate;
|
||||
public byte SkipEmptyCurves;
|
||||
public byte OptimizeKeyframes;
|
||||
public byte ImportScaleTracks;
|
||||
public byte EnableRootMotion;
|
||||
public string RootNodeName;
|
||||
|
||||
// Level Of Detail
|
||||
public byte GenerateLODs;
|
||||
public int BaseLOD;
|
||||
public int LODCount;
|
||||
public float TriangleReduction;
|
||||
|
||||
// Misc
|
||||
public byte ImportMaterials;
|
||||
public byte ImportTextures;
|
||||
public byte RestoreMaterialsOnReimport;
|
||||
|
||||
// SDF
|
||||
public byte GenerateSDF;
|
||||
public float SDFResolution;
|
||||
|
||||
// Splitting
|
||||
public byte SplitObjects;
|
||||
public int ObjectIndex;
|
||||
}
|
||||
|
||||
internal void ToInternal(out InternalOptions options)
|
||||
{
|
||||
options = new InternalOptions
|
||||
{
|
||||
Type = Type,
|
||||
CalculateNormals = (byte)(CalculateNormals ? 1 : 0),
|
||||
SmoothingNormalsAngle = SmoothingNormalsAngle,
|
||||
FlipNormals = (byte)(FlipNormals ? 1 : 0),
|
||||
SmoothingTangentsAngle = SmoothingTangentsAngle,
|
||||
CalculateTangents = (byte)(CalculateTangents ? 1 : 0),
|
||||
OptimizeMeshes = (byte)(OptimizeMeshes ? 1 : 0),
|
||||
MergeMeshes = (byte)(MergeMeshes ? 1 : 0),
|
||||
ImportLODs = (byte)(ImportLODs ? 1 : 0),
|
||||
ImportVertexColors = (byte)(ImportVertexColors ? 1 : 0),
|
||||
ImportBlendShapes = (byte)(ImportBlendShapes ? 1 : 0),
|
||||
LightmapUVsSource = LightmapUVsSource,
|
||||
CollisionMeshesPrefix = CollisionMeshesPrefix,
|
||||
Scale = Scale,
|
||||
Rotation = Rotation,
|
||||
Translation = Translation,
|
||||
CenterGeometry = (byte)(CenterGeometry ? 1 : 0),
|
||||
Duration = Duration,
|
||||
FramesRangeStart = FramesRangeStart,
|
||||
FramesRangeEnd = FramesRangeEnd,
|
||||
DefaultFrameRate = DefaultFrameRate,
|
||||
SamplingRate = SamplingRate,
|
||||
SkipEmptyCurves = (byte)(SkipEmptyCurves ? 1 : 0),
|
||||
OptimizeKeyframes = (byte)(OptimizeKeyframes ? 1 : 0),
|
||||
ImportScaleTracks = (byte)(ImportScaleTracks ? 1 : 0),
|
||||
EnableRootMotion = (byte)(EnableRootMotion ? 1 : 0),
|
||||
RootNodeName = RootNodeName,
|
||||
GenerateLODs = (byte)(GenerateLODs ? 1 : 0),
|
||||
BaseLOD = BaseLOD,
|
||||
LODCount = LODCount,
|
||||
TriangleReduction = TriangleReduction,
|
||||
ImportMaterials = (byte)(ImportMaterials ? 1 : 0),
|
||||
ImportTextures = (byte)(ImportTextures ? 1 : 0),
|
||||
RestoreMaterialsOnReimport = (byte)(RestoreMaterialsOnReimport ? 1 : 0),
|
||||
GenerateSDF = (byte)(GenerateSDF ? 1 : 0),
|
||||
SDFResolution = SDFResolution,
|
||||
SplitObjects = (byte)(SplitObjects ? 1 : 0),
|
||||
ObjectIndex = ObjectIndex,
|
||||
};
|
||||
}
|
||||
|
||||
internal void FromInternal(ref InternalOptions options)
|
||||
{
|
||||
Type = options.Type;
|
||||
CalculateNormals = options.CalculateNormals != 0;
|
||||
SmoothingNormalsAngle = options.SmoothingNormalsAngle;
|
||||
FlipNormals = options.FlipNormals != 0;
|
||||
SmoothingTangentsAngle = options.SmoothingTangentsAngle;
|
||||
CalculateTangents = options.CalculateTangents != 0;
|
||||
OptimizeMeshes = options.OptimizeMeshes != 0;
|
||||
MergeMeshes = options.MergeMeshes != 0;
|
||||
ImportLODs = options.ImportLODs != 0;
|
||||
ImportVertexColors = options.ImportVertexColors != 0;
|
||||
ImportBlendShapes = options.ImportBlendShapes != 0;
|
||||
LightmapUVsSource = options.LightmapUVsSource;
|
||||
CollisionMeshesPrefix = options.CollisionMeshesPrefix;
|
||||
Scale = options.Scale;
|
||||
Rotation = options.Rotation;
|
||||
Translation = options.Translation;
|
||||
CenterGeometry = options.CenterGeometry != 0;
|
||||
FramesRangeStart = options.FramesRangeStart;
|
||||
FramesRangeEnd = options.FramesRangeEnd;
|
||||
DefaultFrameRate = options.DefaultFrameRate;
|
||||
SamplingRate = options.SamplingRate;
|
||||
SkipEmptyCurves = options.SkipEmptyCurves != 0;
|
||||
OptimizeKeyframes = options.OptimizeKeyframes != 0;
|
||||
ImportScaleTracks = options.ImportScaleTracks != 0;
|
||||
EnableRootMotion = options.EnableRootMotion != 0;
|
||||
RootNodeName = options.RootNodeName;
|
||||
GenerateLODs = options.GenerateLODs != 0;
|
||||
BaseLOD = options.BaseLOD;
|
||||
LODCount = options.LODCount;
|
||||
TriangleReduction = options.TriangleReduction;
|
||||
ImportMaterials = options.ImportMaterials != 0;
|
||||
ImportTextures = options.ImportTextures != 0;
|
||||
RestoreMaterialsOnReimport = options.RestoreMaterialsOnReimport != 0;
|
||||
GenerateSDF = options.GenerateSDF != 0;
|
||||
SDFResolution = options.SDFResolution;
|
||||
SplitObjects = options.SplitObjects != 0;
|
||||
ObjectIndex = options.ObjectIndex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries the restore the asset import options from the target resource file. Applies the project default options too.
|
||||
/// </summary>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <param name="assetPath">The asset path.</param>
|
||||
/// <returns>True settings has been restored, otherwise false.</returns>
|
||||
public static void TryRestore(ref ModelImportSettings options, string assetPath)
|
||||
{
|
||||
ModelImportEntry.Internal_GetModelImportOptions(assetPath, out var internalOptions);
|
||||
options.FromInternal(ref internalOptions);
|
||||
}
|
||||
[EditorDisplay(null, EditorDisplayAttribute.InlineStyle)]
|
||||
public ModelTool.Options Settings = ModelTool.Options.Default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -523,7 +61,7 @@ namespace FlaxEditor.Content.Import
|
||||
/// <seealso cref="AssetImportEntry" />
|
||||
public class ModelImportEntry : AssetImportEntry
|
||||
{
|
||||
private ModelImportSettings _settings = new ModelImportSettings();
|
||||
private ModelImportSettings _settings = new();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ModelImportEntry"/> class.
|
||||
@@ -533,7 +71,7 @@ namespace FlaxEditor.Content.Import
|
||||
: base(ref request)
|
||||
{
|
||||
// Try to restore target asset model import options (useful for fast reimport)
|
||||
ModelImportSettings.TryRestore(ref _settings, ResultUrl);
|
||||
Editor.TryRestoreImportOptions(ref _settings.Settings, ResultUrl);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -542,9 +80,14 @@ namespace FlaxEditor.Content.Import
|
||||
/// <inheritdoc />
|
||||
public override bool TryOverrideSettings(object settings)
|
||||
{
|
||||
if (settings is ModelImportSettings o)
|
||||
if (settings is ModelImportSettings s)
|
||||
{
|
||||
_settings = o;
|
||||
_settings.Settings = s.Settings;
|
||||
return true;
|
||||
}
|
||||
if (settings is ModelTool.Options o)
|
||||
{
|
||||
_settings.Settings = o;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -553,14 +96,7 @@ namespace FlaxEditor.Content.Import
|
||||
/// <inheritdoc />
|
||||
public override bool Import()
|
||||
{
|
||||
return Editor.Import(SourceUrl, ResultUrl, _settings);
|
||||
return Editor.Import(SourceUrl, ResultUrl, _settings.Settings);
|
||||
}
|
||||
|
||||
#region Internal Calls
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_GetModelImportOptions(string path, out ModelImportSettings.InternalOptions result);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,56 +3,94 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using FlaxEditor.CustomEditors.Editors;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Tools;
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
namespace FlaxEngine.Tools
|
||||
{
|
||||
partial class TextureTool
|
||||
{
|
||||
partial struct Options
|
||||
{
|
||||
#pragma warning disable CS1591
|
||||
public enum CustomMaxSizes
|
||||
{
|
||||
_32 = 32,
|
||||
_64 = 64,
|
||||
_128 = 128,
|
||||
_256 = 256,
|
||||
_512 = 512,
|
||||
_1024 = 1024,
|
||||
_2048 = 2048,
|
||||
_4096 = 4096,
|
||||
_8192 = 8192,
|
||||
_16384 = 16384,
|
||||
}
|
||||
#pragma warning restore CS1591
|
||||
|
||||
/// <summary>
|
||||
/// The size of the imported texture. If Resize property is set to true then texture will be resized during the import to this value. Otherwise it will be ignored.
|
||||
/// </summary>
|
||||
[EditorOrder(110), VisibleIf(nameof(Resize)), DefaultValue(typeof(Int2), "1024,1024")]
|
||||
public Int2 Size
|
||||
{
|
||||
get => new Int2(SizeX, SizeY);
|
||||
set
|
||||
{
|
||||
SizeX = value.X;
|
||||
SizeY = value.Y;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maximum size of the texture (for both width and height). Higher resolution textures will be resized during importing process.
|
||||
/// </summary>
|
||||
[EditorOrder(90), DefaultValue(CustomMaxSizes._8192), EditorDisplay(null, "Max Size")]
|
||||
public CustomMaxSizes CustomMaxSize
|
||||
{
|
||||
get
|
||||
{
|
||||
var value = MaxSize;
|
||||
if (!Mathf.IsPowerOfTwo(value))
|
||||
value = Mathf.NextPowerOfTwo(value);
|
||||
FieldInfo[] fields = typeof(CustomMaxSizes).GetFields();
|
||||
for (int i = 0; i < fields.Length; i++)
|
||||
{
|
||||
var field = fields[i];
|
||||
if (field.Name.Equals("value__"))
|
||||
continue;
|
||||
if (value == (int)field.GetRawConstantValue())
|
||||
return (CustomMaxSizes)value;
|
||||
}
|
||||
return CustomMaxSizes._8192;
|
||||
}
|
||||
set => MaxSize = (int)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom editor for <see cref="FlaxEngine.Tools.TextureTool.Options"/>.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(FlaxEngine.Tools.TextureTool.Options)), DefaultEditor]
|
||||
public class TextureToolOptionsEditor : GenericEditor
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override List<ItemInfo> GetItemsForType(ScriptType type)
|
||||
{
|
||||
// Show both fields and properties
|
||||
return GetItemsForType(type, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace FlaxEditor.Content.Import
|
||||
{
|
||||
/// <summary>
|
||||
/// Texture format types.
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
public enum TextureFormatType : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// The unknown.
|
||||
/// </summary>
|
||||
Unknown = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The color with RGB channels.
|
||||
/// </summary>
|
||||
ColorRGB = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The color with RGBA channels.
|
||||
/// </summary>
|
||||
ColorRGBA = 2,
|
||||
|
||||
/// <summary>
|
||||
/// The normal map (packed and compressed).
|
||||
/// </summary>
|
||||
NormalMap = 3,
|
||||
|
||||
/// <summary>
|
||||
/// The gray scale (R channel).
|
||||
/// </summary>
|
||||
GrayScale = 4,
|
||||
|
||||
/// <summary>
|
||||
/// The HDR color (RGBA channels).
|
||||
/// </summary>
|
||||
HdrRGBA = 5,
|
||||
|
||||
/// <summary>
|
||||
/// The HDR color (RGB channels).
|
||||
/// </summary>
|
||||
HdrRGB = 6
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Proxy object to present texture import settings in <see cref="ImportFilesDialog"/>.
|
||||
/// </summary>
|
||||
@@ -60,346 +98,10 @@ namespace FlaxEditor.Content.Import
|
||||
public class TextureImportSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// A custom version of <see cref="TextureFormatType"/> for GUI.
|
||||
/// The settings data.
|
||||
/// </summary>
|
||||
public enum CustomTextureFormatType
|
||||
{
|
||||
/// <summary>
|
||||
/// The color with RGB channels.
|
||||
/// </summary>
|
||||
ColorRGB = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The color with RGBA channels.
|
||||
/// </summary>
|
||||
ColorRGBA = 2,
|
||||
|
||||
/// <summary>
|
||||
/// The normal map (packed and compressed).
|
||||
/// </summary>
|
||||
NormalMap = 3,
|
||||
|
||||
/// <summary>
|
||||
/// The gray scale (R channel).
|
||||
/// </summary>
|
||||
GrayScale = 4,
|
||||
|
||||
/// <summary>
|
||||
/// The HDR color (RGBA channels).
|
||||
/// </summary>
|
||||
HdrRGBA = 5,
|
||||
|
||||
/// <summary>
|
||||
/// The HDR color (RGB channels).
|
||||
/// </summary>
|
||||
HdrRGB = 6
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A custom set of max texture import sizes.
|
||||
/// </summary>
|
||||
public enum CustomMaxSizeType
|
||||
{
|
||||
/// <summary>
|
||||
/// The 32.
|
||||
/// </summary>
|
||||
_32 = 32,
|
||||
|
||||
/// <summary>
|
||||
/// The 64.
|
||||
/// </summary>
|
||||
_64 = 64,
|
||||
|
||||
/// <summary>
|
||||
/// The 128.
|
||||
/// </summary>
|
||||
_128 = 128,
|
||||
|
||||
/// <summary>
|
||||
/// The 256.
|
||||
/// </summary>
|
||||
_256 = 256,
|
||||
|
||||
/// <summary>
|
||||
/// The 512.
|
||||
/// </summary>
|
||||
_512 = 512,
|
||||
|
||||
/// <summary>
|
||||
/// The 1024.
|
||||
/// </summary>
|
||||
_1024 = 1024,
|
||||
|
||||
/// <summary>
|
||||
/// The 2048.
|
||||
/// </summary>
|
||||
_2048 = 2048,
|
||||
|
||||
/// <summary>
|
||||
/// The 4096.
|
||||
/// </summary>
|
||||
_4096 = 4096,
|
||||
|
||||
/// <summary>
|
||||
/// The 8192.
|
||||
/// </summary>
|
||||
_8192 = 8192,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the maximum size to enum.
|
||||
/// </summary>
|
||||
/// <param name="f">The max size.</param>
|
||||
/// <returns>The converted enum.</returns>
|
||||
public static CustomMaxSizeType ConvertMaxSize(int f)
|
||||
{
|
||||
if (!Mathf.IsPowerOfTwo(f))
|
||||
f = Mathf.NextPowerOfTwo(f);
|
||||
|
||||
FieldInfo[] fields = typeof(CustomMaxSizeType).GetFields();
|
||||
for (int i = 0; i < fields.Length; i++)
|
||||
{
|
||||
var field = fields[i];
|
||||
if (field.Name.Equals("value__"))
|
||||
continue;
|
||||
|
||||
if (f == (int)field.GetRawConstantValue())
|
||||
return (CustomMaxSizeType)f;
|
||||
}
|
||||
|
||||
return CustomMaxSizeType._8192;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The sprite info.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SpriteInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// The sprite area.
|
||||
/// </summary>
|
||||
public Rectangle Area;
|
||||
|
||||
/// <summary>
|
||||
/// The sprite name.
|
||||
/// </summary>
|
||||
public string Name;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SpriteInfo"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="area">The area.</param>
|
||||
/// <param name="name">The name.</param>
|
||||
public SpriteInfo(Rectangle area, string name)
|
||||
{
|
||||
Area = area;
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Texture format type
|
||||
/// </summary>
|
||||
[EditorOrder(0), DefaultValue(CustomTextureFormatType.ColorRGB), Tooltip("Texture import format type")]
|
||||
public CustomTextureFormatType Type { get; set; } = CustomTextureFormatType.ColorRGB;
|
||||
|
||||
/// <summary>
|
||||
/// True if texture should be imported as a texture atlas resource
|
||||
/// </summary>
|
||||
[EditorOrder(10), DefaultValue(false), Tooltip("True if texture should be imported as a texture atlas (with sprites)")]
|
||||
public bool IsAtlas { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if disable dynamic texture streaming
|
||||
/// </summary>
|
||||
[EditorOrder(20), DefaultValue(false), Tooltip("True if disable dynamic texture streaming")]
|
||||
public bool NeverStream { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enables/disables texture data compression.
|
||||
/// </summary>
|
||||
[EditorOrder(30), DefaultValue(true), Tooltip("True if compress texture data")]
|
||||
public bool Compress { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// True if texture channels have independent data
|
||||
/// </summary>
|
||||
[EditorOrder(40), DefaultValue(false), Tooltip("True if texture channels have independent data (for compression methods)")]
|
||||
public bool IndependentChannels { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if use sRGB format for texture data. Recommended for color maps and diffuse color textures.
|
||||
/// </summary>
|
||||
[EditorOrder(50), DefaultValue(false), EditorDisplay(null, "sRGB"), Tooltip("True if use sRGB format for texture data. Recommended for color maps and diffuse color textures.")]
|
||||
public bool sRGB { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if generate mip maps chain for the texture.
|
||||
/// </summary>
|
||||
[EditorOrder(60), DefaultValue(true), Tooltip("True if generate mip maps chain for the texture")]
|
||||
public bool GenerateMipMaps { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// True if flip Y coordinate of the texture.
|
||||
/// </summary>
|
||||
[EditorOrder(65), DefaultValue(false), EditorDisplay(null, "Flip Y"), Tooltip("True if flip Y coordinate of the texture.")]
|
||||
public bool FlipY { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// The import texture scale.
|
||||
/// </summary>
|
||||
[EditorOrder(70), DefaultValue(1.0f), Tooltip("Texture scale. Default is 1.")]
|
||||
public float Scale { get; set; } = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum size of the texture (for both width and height).
|
||||
/// Higher resolution textures will be resized during importing process.
|
||||
/// </summary>
|
||||
[EditorOrder(80), DefaultValue(CustomMaxSizeType._8192), Tooltip("Maximum texture size (will be resized if need to)")]
|
||||
public CustomMaxSizeType MaxSize { get; set; } = CustomMaxSizeType._8192;
|
||||
|
||||
/// <summary>
|
||||
/// True if resize texture on import. Use Size property to define texture width and height. Texture scale property will be ignored.
|
||||
/// </summary>
|
||||
[EditorOrder(90), DefaultValue(false), Tooltip("True if resize texture on import. Use Size property to define texture width and height. Texture scale property will be ignored.")]
|
||||
public bool Resize { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the size of the imported texture. If Resize property is set to true then texture will be resized during the import to this value. Otherwise it will be ignored.
|
||||
/// </summary>
|
||||
[EditorOrder(100), VisibleIf("Resize"), DefaultValue(typeof(Int2), "1024,1024"), Tooltip("The size of the imported texture. If Resize property is set to true then texture will be resized during the import to this value. Otherwise it will be ignored.")]
|
||||
public Int2 Size { get; set; } = new Int2(1024, 1024);
|
||||
|
||||
/// <summary>
|
||||
/// True if preserve alpha coverage in generated mips for alpha test reference. Scales mipmap alpha values to preserve alpha coverage based on an alpha test reference value.
|
||||
/// </summary>
|
||||
[EditorOrder(240), DefaultValue(false), Tooltip("Check to preserve alpha coverage in generated mips for alpha test reference. Scales mipmap alpha values to preserve alpha coverage based on an alpha test reference value.")]
|
||||
public bool PreserveAlphaCoverage { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// The reference value for the alpha coverage preserving.
|
||||
/// </summary>
|
||||
[EditorOrder(250), VisibleIf("PreserveAlphaCoverage"), DefaultValue(0.5f), Tooltip("The reference value for the alpha coverage preserving.")]
|
||||
public float PreserveAlphaCoverageReference { get; set; } = 0.5f;
|
||||
|
||||
/// <summary>
|
||||
/// Texture group for streaming (negative if unused). See Streaming Settings.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(CustomEditors.Dedicated.TextureGroupEditor))]
|
||||
[EditorOrder(300), Tooltip("Texture group for streaming (negative if unused). See Streaming Settings.")]
|
||||
public int TextureGroup = -1;
|
||||
|
||||
/// <summary>
|
||||
/// The sprites. Used to keep created sprites on sprite atlas reimport.
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
public List<SpriteInfo> Sprites = new List<SpriteInfo>();
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct InternalOptions
|
||||
{
|
||||
public TextureFormatType Type;
|
||||
public byte IsAtlas;
|
||||
public byte NeverStream;
|
||||
public byte Compress;
|
||||
public byte IndependentChannels;
|
||||
public byte sRGB;
|
||||
public byte GenerateMipMaps;
|
||||
public byte FlipY;
|
||||
public byte Resize;
|
||||
public byte PreserveAlphaCoverage;
|
||||
public float PreserveAlphaCoverageReference;
|
||||
public float Scale;
|
||||
public int MaxSize;
|
||||
public int TextureGroup;
|
||||
public Int2 Size;
|
||||
public Rectangle[] SpriteAreas;
|
||||
public string[] SpriteNames;
|
||||
}
|
||||
|
||||
internal void ToInternal(out InternalOptions options)
|
||||
{
|
||||
options = new InternalOptions
|
||||
{
|
||||
Type = (TextureFormatType)(int)Type,
|
||||
IsAtlas = (byte)(IsAtlas ? 1 : 0),
|
||||
NeverStream = (byte)(NeverStream ? 1 : 0),
|
||||
Compress = (byte)(Compress ? 1 : 0),
|
||||
IndependentChannels = (byte)(IndependentChannels ? 1 : 0),
|
||||
sRGB = (byte)(sRGB ? 1 : 0),
|
||||
GenerateMipMaps = (byte)(GenerateMipMaps ? 1 : 0),
|
||||
FlipY = (byte)(FlipY ? 1 : 0),
|
||||
Resize = (byte)(Resize ? 1 : 0),
|
||||
PreserveAlphaCoverage = (byte)(PreserveAlphaCoverage ? 1 : 0),
|
||||
PreserveAlphaCoverageReference = PreserveAlphaCoverageReference,
|
||||
Scale = Scale,
|
||||
Size = Size,
|
||||
MaxSize = (int)MaxSize,
|
||||
TextureGroup = TextureGroup,
|
||||
};
|
||||
if (Sprites != null && Sprites.Count > 0)
|
||||
{
|
||||
int count = Sprites.Count;
|
||||
options.SpriteAreas = new Rectangle[count];
|
||||
options.SpriteNames = new string[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
options.SpriteAreas[i] = Sprites[i].Area;
|
||||
options.SpriteNames[i] = Sprites[i].Name;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
options.SpriteAreas = null;
|
||||
options.SpriteNames = null;
|
||||
}
|
||||
}
|
||||
|
||||
internal void FromInternal(ref InternalOptions options)
|
||||
{
|
||||
Type = (CustomTextureFormatType)(int)options.Type;
|
||||
IsAtlas = options.IsAtlas != 0;
|
||||
NeverStream = options.NeverStream != 0;
|
||||
Compress = options.Compress != 0;
|
||||
IndependentChannels = options.IndependentChannels != 0;
|
||||
sRGB = options.sRGB != 0;
|
||||
GenerateMipMaps = options.GenerateMipMaps != 0;
|
||||
FlipY = options.FlipY != 0;
|
||||
Resize = options.Resize != 0;
|
||||
PreserveAlphaCoverage = options.PreserveAlphaCoverage != 0;
|
||||
PreserveAlphaCoverageReference = options.PreserveAlphaCoverageReference;
|
||||
Scale = options.Scale;
|
||||
MaxSize = ConvertMaxSize(options.MaxSize);
|
||||
TextureGroup = options.TextureGroup;
|
||||
Size = options.Size;
|
||||
if (options.SpriteAreas != null)
|
||||
{
|
||||
int spritesCount = options.SpriteAreas.Length;
|
||||
Sprites.Capacity = spritesCount;
|
||||
for (int i = 0; i < spritesCount; i++)
|
||||
{
|
||||
Sprites.Add(new SpriteInfo(options.SpriteAreas[i], options.SpriteNames[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries the restore the asset import options from the target resource file.
|
||||
/// </summary>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <param name="assetPath">The asset path.</param>
|
||||
/// <returns>True settings has been restored, otherwise false.</returns>
|
||||
public static bool TryRestore(ref TextureImportSettings options, string assetPath)
|
||||
{
|
||||
if (TextureImportEntry.Internal_GetTextureImportOptions(assetPath, out var internalOptions))
|
||||
{
|
||||
// Restore settings
|
||||
options.FromInternal(ref internalOptions);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
[EditorDisplay(null, EditorDisplayAttribute.InlineStyle)]
|
||||
public TextureTool.Options Settings = TextureTool.Options.Default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -408,7 +110,7 @@ namespace FlaxEditor.Content.Import
|
||||
/// <seealso cref="AssetImportEntry" />
|
||||
public class TextureImportEntry : AssetImportEntry
|
||||
{
|
||||
private TextureImportSettings _settings = new TextureImportSettings();
|
||||
private TextureImportSettings _settings = new();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TextureImportEntry"/> class.
|
||||
@@ -423,15 +125,15 @@ namespace FlaxEditor.Content.Import
|
||||
if (extension == ".raw")
|
||||
{
|
||||
// Raw image data in 16bit gray-scale, preserve the quality
|
||||
_settings.Type = TextureImportSettings.CustomTextureFormatType.HdrRGBA;
|
||||
_settings.Compress = false;
|
||||
_settings.Settings.Type = TextureFormatType.HdrRGBA;
|
||||
_settings.Settings.Compress = false;
|
||||
}
|
||||
else if (extension == ".hdr")
|
||||
{
|
||||
// HDR sky texture
|
||||
_settings.Type = TextureImportSettings.CustomTextureFormatType.HdrRGB;
|
||||
_settings.Settings.Type = TextureFormatType.HdrRGB;
|
||||
}
|
||||
else if (_settings.Type != TextureImportSettings.CustomTextureFormatType.ColorRGB)
|
||||
else if (_settings.Settings.Type != TextureFormatType.ColorRGB)
|
||||
{
|
||||
// Skip checking
|
||||
}
|
||||
@@ -443,7 +145,7 @@ namespace FlaxEditor.Content.Import
|
||||
|| snl.EndsWith("normals"))
|
||||
{
|
||||
// Normal map
|
||||
_settings.Type = TextureImportSettings.CustomTextureFormatType.NormalMap;
|
||||
_settings.Settings.Type = TextureFormatType.NormalMap;
|
||||
}
|
||||
else if (snl.EndsWith("_d")
|
||||
|| snl.Contains("diffuse")
|
||||
@@ -454,8 +156,8 @@ namespace FlaxEditor.Content.Import
|
||||
|| snl.Contains("albedo"))
|
||||
{
|
||||
// Albedo or diffuse map
|
||||
_settings.Type = TextureImportSettings.CustomTextureFormatType.ColorRGB;
|
||||
_settings.sRGB = true;
|
||||
_settings.Settings.Type = TextureFormatType.ColorRGB;
|
||||
_settings.Settings.sRGB = true;
|
||||
}
|
||||
else if (snl.EndsWith("ao")
|
||||
|| snl.EndsWith("ambientocclusion")
|
||||
@@ -478,11 +180,11 @@ namespace FlaxEditor.Content.Import
|
||||
|| snl.EndsWith("metallic"))
|
||||
{
|
||||
// Glossiness, metalness, ambient occlusion, displacement, height, cavity or specular
|
||||
_settings.Type = TextureImportSettings.CustomTextureFormatType.GrayScale;
|
||||
_settings.Settings.Type = TextureFormatType.GrayScale;
|
||||
}
|
||||
|
||||
// Try to restore target asset texture import options (useful for fast reimport)
|
||||
TextureImportSettings.TryRestore(ref _settings, ResultUrl);
|
||||
Editor.TryRestoreImportOptions(ref _settings.Settings, ResultUrl);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -491,11 +193,18 @@ namespace FlaxEditor.Content.Import
|
||||
/// <inheritdoc />
|
||||
public override bool TryOverrideSettings(object settings)
|
||||
{
|
||||
if (settings is TextureImportSettings o)
|
||||
if (settings is TextureImportSettings s)
|
||||
{
|
||||
var sprites = o.Sprites ?? _settings.Sprites; // Preserve sprites if not specified to override
|
||||
_settings = o;
|
||||
_settings.Sprites = sprites;
|
||||
var sprites = s.Settings.Sprites ?? _settings.Settings.Sprites; // Preserve sprites if not specified to override
|
||||
_settings.Settings = s.Settings;
|
||||
_settings.Settings.Sprites = sprites;
|
||||
return true;
|
||||
}
|
||||
if (settings is TextureTool.Options o)
|
||||
{
|
||||
var sprites = o.Sprites ?? _settings.Settings.Sprites; // Preserve sprites if not specified to override
|
||||
_settings.Settings = o;
|
||||
_settings.Settings.Sprites = sprites;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -504,14 +213,7 @@ namespace FlaxEditor.Content.Import
|
||||
/// <inheritdoc />
|
||||
public override bool Import()
|
||||
{
|
||||
return Editor.Import(SourceUrl, ResultUrl, _settings);
|
||||
return Editor.Import(SourceUrl, ResultUrl, _settings.Settings);
|
||||
}
|
||||
|
||||
#region Internal Calls
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_GetTextureImportOptions(string path, out TextureImportSettings.InternalOptions result);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
@@ -25,6 +23,11 @@ namespace FlaxEditor.Content
|
||||
/// </summary>
|
||||
public string TypeName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if asset is now loaded.
|
||||
/// </summary>
|
||||
public bool IsLoaded => FlaxEngine.Content.GetAsset(ID)?.IsLoaded ?? false;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AssetItem"/> class.
|
||||
/// </summary>
|
||||
@@ -38,14 +41,6 @@ namespace FlaxEditor.Content
|
||||
ID = id;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void UpdateTooltipText()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
OnBuildTooltipText(sb);
|
||||
TooltipText = sb.ToString();
|
||||
}
|
||||
|
||||
private sealed class TooltipDoubleClickHook : Control
|
||||
{
|
||||
public AssetItem Item;
|
||||
@@ -74,20 +69,46 @@ namespace FlaxEditor.Content
|
||||
hook.Item = this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when building tooltip text.
|
||||
/// </summary>
|
||||
/// <param name="sb">The String Builder.</param>
|
||||
protected virtual void OnBuildTooltipText(StringBuilder sb)
|
||||
{
|
||||
sb.Append("Type: ").Append(TypeName).AppendLine();
|
||||
sb.Append("Size: ").Append(Utilities.Utils.FormatBytesCount((int)new FileInfo(Path).Length)).AppendLine();
|
||||
sb.Append("Path: ").Append(Path).AppendLine();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ContentItemType ItemType => ContentItemType.Asset;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string TypeDescription
|
||||
{
|
||||
get
|
||||
{
|
||||
// Translate asset type name
|
||||
var typeName = TypeName;
|
||||
string[] typeNamespaces = typeName.Split('.');
|
||||
if (typeNamespaces.Length != 0 && typeNamespaces.Length != 0)
|
||||
{
|
||||
typeName = Utilities.Utils.GetPropertyNameUI(typeNamespaces[typeNamespaces.Length - 1]);
|
||||
}
|
||||
return typeName;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the asset.
|
||||
/// </summary>
|
||||
/// <returns>The asset object.</returns>
|
||||
public Asset LoadAsync()
|
||||
{
|
||||
return FlaxEngine.Content.LoadAsync<Asset>(ID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reloads the asset (if it's loaded).
|
||||
/// </summary>
|
||||
public void Reload()
|
||||
{
|
||||
var asset = FlaxEngine.Content.GetAsset(ID);
|
||||
if (asset != null && asset.IsLoaded)
|
||||
{
|
||||
asset.Reload();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether asset is of the specified type (included inheritance checks).
|
||||
/// </summary>
|
||||
|
||||
@@ -19,6 +19,9 @@ namespace FlaxEditor.Content
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string TypeDescription => "C# Source Code";
|
||||
|
||||
/// <inheritdoc />
|
||||
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.CSharpScript128;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using FlaxEditor.GUI.Drag;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
@@ -112,7 +113,15 @@ namespace FlaxEditor.Content
|
||||
public override ContentItemSearchFilter SearchFilter => ContentItemSearchFilter.Other;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanRename => ParentFolder != null; // Deny rename action for root folders
|
||||
public override bool CanRename
|
||||
{
|
||||
get
|
||||
{
|
||||
var hasParentFolder = ParentFolder != null;
|
||||
var isContentFolder = Node is MainContentTreeNode;
|
||||
return hasParentFolder && !isContentFolder;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanDrag => ParentFolder != null; // Deny rename action for root folders
|
||||
@@ -120,6 +129,9 @@ namespace FlaxEditor.Content
|
||||
/// <inheritdoc />
|
||||
public override bool Exists => Directory.Exists(Path);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string TypeDescription => "Folder";
|
||||
|
||||
/// <inheritdoc />
|
||||
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Folder128;
|
||||
|
||||
@@ -135,9 +147,10 @@ namespace FlaxEditor.Content
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void UpdateTooltipText()
|
||||
protected override void OnBuildTooltipText(StringBuilder sb)
|
||||
{
|
||||
TooltipText = Path;
|
||||
sb.Append("Type: ").Append(TypeDescription).AppendLine();
|
||||
sb.Append("Path: ").Append(Utilities.Utils.GetAssetNamePathWithExt(Path)).AppendLine();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using FlaxEditor.Content.GUI;
|
||||
using FlaxEditor.GUI.Drag;
|
||||
using FlaxEngine;
|
||||
@@ -222,7 +224,7 @@ namespace FlaxEditor.Content
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this item can be dragged and dropped.
|
||||
/// </summary>
|
||||
public virtual bool CanDrag => true;
|
||||
public virtual bool CanDrag => Root != null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this <see cref="ContentItem"/> exists on drive.
|
||||
@@ -273,6 +275,11 @@ namespace FlaxEditor.Content
|
||||
/// </summary>
|
||||
public string NamePath => FlaxEditor.Utilities.Utils.GetAssetNamePath(Path);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content item type description (for UI).
|
||||
/// </summary>
|
||||
public abstract string TypeDescription { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default name of the content item thumbnail. Returns null if not used.
|
||||
/// </summary>
|
||||
@@ -357,7 +364,29 @@ namespace FlaxEditor.Content
|
||||
/// </summary>
|
||||
public virtual void UpdateTooltipText()
|
||||
{
|
||||
TooltipText = "Path: " + Path;
|
||||
var sb = new StringBuilder();
|
||||
OnBuildTooltipText(sb);
|
||||
if (sb.Length != 0 && sb[sb.Length - 1] == '\n')
|
||||
{
|
||||
// Remove new-line from end
|
||||
int sub = 1;
|
||||
if (sb.Length != 1 && sb[sb.Length - 2] == '\r')
|
||||
sub = 2;
|
||||
sb.Length -= sub;
|
||||
}
|
||||
TooltipText = sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when building tooltip text.
|
||||
/// </summary>
|
||||
/// <param name="sb">The output string builder.</param>
|
||||
protected virtual void OnBuildTooltipText(StringBuilder sb)
|
||||
{
|
||||
sb.Append("Type: ").Append(TypeDescription).AppendLine();
|
||||
if (File.Exists(Path))
|
||||
sb.Append("Size: ").Append(Utilities.Utils.FormatBytesCount((int)new FileInfo(Path).Length)).AppendLine();
|
||||
sb.Append("Path: ").Append(Utilities.Utils.GetAssetNamePathWithExt(Path)).AppendLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -690,7 +719,7 @@ namespace FlaxEditor.Content
|
||||
public override bool OnMouseDoubleClick(Float2 location, MouseButton button)
|
||||
{
|
||||
Focus();
|
||||
|
||||
|
||||
// Open
|
||||
(Parent as ContentView).OnItemDoubleClick(this);
|
||||
|
||||
|
||||
@@ -19,6 +19,9 @@ namespace FlaxEditor.Content
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string TypeDescription => Path.EndsWith(".h") ? "C++ Header File" : "C++ Source Code";
|
||||
|
||||
/// <inheritdoc />
|
||||
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.CPPScript128;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,9 @@ namespace FlaxEditor.Content
|
||||
/// <inheritdoc />
|
||||
public override ContentItemSearchFilter SearchFilter => ContentItemSearchFilter.Other;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string TypeDescription => "File";
|
||||
|
||||
/// <inheritdoc />
|
||||
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Document128;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System.Text;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Content
|
||||
@@ -39,10 +40,19 @@ namespace FlaxEditor.Content
|
||||
/// <inheritdoc />
|
||||
public override ContentItemSearchFilter SearchFilter => ContentItemSearchFilter.Other;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string TypeDescription => "New";
|
||||
|
||||
/// <inheritdoc />
|
||||
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Document128;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool DrawShadow => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void UpdateTooltipText()
|
||||
{
|
||||
TooltipText = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,9 @@ namespace FlaxEditor.Content
|
||||
/// <inheritdoc />
|
||||
public override ContentItemSearchFilter SearchFilter => ContentItemSearchFilter.Scene;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string TypeDescription => "Scene";
|
||||
|
||||
/// <inheritdoc />
|
||||
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Scene128;
|
||||
|
||||
|
||||
@@ -26,6 +26,9 @@ namespace FlaxEditor.Content
|
||||
/// <inheritdoc />
|
||||
public override ContentItemSearchFilter SearchFilter => ContentItemSearchFilter.Shader;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string TypeDescription => "Shader Source Code";
|
||||
|
||||
/// <inheritdoc />
|
||||
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Document128;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ using System.Reflection;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Json;
|
||||
using FlaxEngine.Utilities;
|
||||
using Object = FlaxEngine.Object;
|
||||
|
||||
namespace FlaxEditor.Content
|
||||
@@ -134,7 +135,7 @@ namespace FlaxEditor.Content
|
||||
_index = index;
|
||||
type.Asset.GetMethodSignature(index, out _name, out _flags, out var returnTypeName, out var paramNames, out var paramTypeNames, out var paramOuts);
|
||||
_returnType = TypeUtils.GetType(returnTypeName);
|
||||
if (paramNames.Length != 0)
|
||||
if (paramNames != null && paramNames.Length != 0)
|
||||
{
|
||||
_parameters = new ScriptMemberInfo.Parameter[paramNames.Length];
|
||||
for (int i = 0; i < _parameters.Length; i++)
|
||||
@@ -310,7 +311,10 @@ namespace FlaxEditor.Content
|
||||
|
||||
internal void Dispose()
|
||||
{
|
||||
OnAssetReloading(_asset);
|
||||
if (_parameters != null)
|
||||
{
|
||||
OnAssetReloading(_asset);
|
||||
}
|
||||
_asset = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
using System;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.Content
|
||||
{
|
||||
@@ -42,7 +43,7 @@ namespace FlaxEditor.Content
|
||||
/// <inheritdoc />
|
||||
public override AssetItem ConstructItem(string path, string typeName, ref Guid id)
|
||||
{
|
||||
var type = Scripting.TypeUtils.GetType(typeName).Type;
|
||||
var type = TypeUtils.GetType(typeName).Type;
|
||||
|
||||
if (typeof(TextureBase).IsAssignableFrom(type))
|
||||
return new TextureAssetItem(path, ref id, typeName, type);
|
||||
|
||||
@@ -80,7 +80,8 @@ namespace FlaxEditor.Content
|
||||
/// </summary>
|
||||
/// <param name="model">The associated model.</param>
|
||||
/// <param name="created">The action to call once the collision data gets created (or reused from existing).</param>
|
||||
public void CreateCollisionDataFromModel(Model model, Action<CollisionData> created = null)
|
||||
/// <param name="withRenaming">True if start initial item renaming by user, or tru to skip it.</param>
|
||||
public void CreateCollisionDataFromModel(Model model, Action<CollisionData> created = null, bool withRenaming = true)
|
||||
{
|
||||
// Check if there already is collision data for that model to reuse
|
||||
var modelItem = (AssetItem)Editor.Instance.ContentDatabase.Find(model.ID);
|
||||
@@ -140,7 +141,7 @@ namespace FlaxEditor.Content
|
||||
});
|
||||
};
|
||||
var initialName = (modelItem?.ShortName ?? Path.GetFileNameWithoutExtension(model.Path)) + " Collision";
|
||||
Editor.Instance.Windows.ContentWin.NewItem(this, null, create, initialName);
|
||||
Editor.Instance.Windows.ContentWin.NewItem(this, null, create, initialName, withRenaming);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ namespace FlaxEditor.Content
|
||||
/// Json assets proxy.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.JsonAssetBaseProxy" />
|
||||
[ContentContextMenu("New/Json Asset")]
|
||||
public abstract class JsonAssetProxy : JsonAssetBaseProxy
|
||||
{
|
||||
/// <summary>
|
||||
@@ -127,6 +126,7 @@ namespace FlaxEditor.Content
|
||||
/// Generic Json assets proxy (supports all json assets that don't have dedicated proxy).
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.JsonAssetBaseProxy" />
|
||||
[ContentContextMenu("New/Json Asset")]
|
||||
public class GenericJsonAssetProxy : JsonAssetProxy
|
||||
{
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -72,11 +72,9 @@ namespace FlaxEditor.Content
|
||||
/// <param name="materialItem">The material item to use as a base material.</param>
|
||||
public static void CreateMaterialInstance(BinaryAssetItem materialItem)
|
||||
{
|
||||
if (materialItem == null)
|
||||
throw new ArgumentNullException();
|
||||
|
||||
var materialInstanceName = materialItem.ShortName + " Instance";
|
||||
var materialInstanceProxy = Editor.Instance.ContentDatabase.GetProxy<MaterialInstance>();
|
||||
Editor.Instance.Windows.ContentWin.NewItem(materialInstanceProxy, null, item => OnMaterialInstanceCreated(item, materialItem));
|
||||
Editor.Instance.Windows.ContentWin.NewItem(materialInstanceProxy, null, item => OnMaterialInstanceCreated(item, materialItem), materialInstanceName);
|
||||
}
|
||||
|
||||
private static void OnMaterialInstanceCreated(ContentItem item, BinaryAssetItem materialItem)
|
||||
|
||||
@@ -47,9 +47,23 @@ namespace FlaxEditor.Content
|
||||
|
||||
menu.AddButton("Create collision data", () =>
|
||||
{
|
||||
var model = FlaxEngine.Content.LoadAsync<Model>(((ModelItem)item).ID);
|
||||
var collisionDataProxy = (CollisionDataProxy)Editor.Instance.ContentDatabase.GetProxy<CollisionData>();
|
||||
collisionDataProxy.CreateCollisionDataFromModel(model);
|
||||
var selection = Editor.Instance.Windows.ContentWin.View.Selection;
|
||||
if (selection.Count > 1)
|
||||
{
|
||||
// Batch action
|
||||
var items = selection.ToArray(); // Clone to prevent issue when iterating over and content window changes the selection
|
||||
foreach (var contentItem in items)
|
||||
{
|
||||
if (contentItem is ModelItem modelItem)
|
||||
collisionDataProxy.CreateCollisionDataFromModel(FlaxEngine.Content.LoadAsync<Model>(modelItem.ID), null, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var model = FlaxEngine.Content.LoadAsync<Model>(((ModelItem)item).ID);
|
||||
collisionDataProxy.CreateCollisionDataFromModel(model);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace FlaxEditor.Content
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string NewItemName => "Script";
|
||||
public override string NewItemName => "MyScript";
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanCreate(ContentFolder targetLocation)
|
||||
@@ -72,6 +72,8 @@ namespace FlaxEditor.Content
|
||||
// Scripts cannot start with digit.
|
||||
if (Char.IsDigit(filename[0]))
|
||||
return false;
|
||||
if (filename.Equals("Script"))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,10 @@ namespace FlaxEditor.Content
|
||||
|
||||
// Check if asset is streamed enough
|
||||
var asset = (SkinnedModel)request.Asset;
|
||||
return asset.LoadedLODs >= Mathf.Max(1, (int)(asset.LODs.Length * ThumbnailsModule.MinimumRequiredResourcesQuality));
|
||||
var lods = asset.LODs.Length;
|
||||
if (asset.IsLoaded && lods == 0)
|
||||
return true; // Skeleton-only model
|
||||
return asset.LoadedLODs >= Mathf.Max(1, (int)(lods * ThumbnailsModule.MinimumRequiredResourcesQuality));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -8,6 +8,7 @@ using FlaxEditor.Windows;
|
||||
using FlaxEditor.Windows.Assets;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Json;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.Content
|
||||
{
|
||||
|
||||
@@ -242,21 +242,36 @@ namespace FlaxEditor.Content.Thumbnails
|
||||
if (!atlas.IsReady)
|
||||
return;
|
||||
|
||||
// Setup
|
||||
_guiRoot.RemoveChildren();
|
||||
_guiRoot.AccentColor = request.Proxy.AccentColor;
|
||||
try
|
||||
{
|
||||
// Setup
|
||||
_guiRoot.RemoveChildren();
|
||||
_guiRoot.AccentColor = request.Proxy.AccentColor;
|
||||
|
||||
// Call proxy to prepare for thumbnail rendering
|
||||
request.Proxy.OnThumbnailDrawBegin(request, _guiRoot, context);
|
||||
_guiRoot.UnlockChildrenRecursive();
|
||||
// Call proxy to prepare for thumbnail rendering
|
||||
request.Proxy.OnThumbnailDrawBegin(request, _guiRoot, context);
|
||||
_guiRoot.UnlockChildrenRecursive();
|
||||
|
||||
// Draw preview
|
||||
context.Clear(_output.View(), Color.Black);
|
||||
Render2D.CallDrawing(_guiRoot, context, _output);
|
||||
// Draw preview
|
||||
context.Clear(_output.View(), Color.Black);
|
||||
Render2D.CallDrawing(_guiRoot, context, _output);
|
||||
|
||||
// Call proxy and cleanup UI (delete create controls, shared controls should be unlinked during OnThumbnailDrawEnd event)
|
||||
request.Proxy.OnThumbnailDrawEnd(request, _guiRoot);
|
||||
_guiRoot.DisposeChildren();
|
||||
// Call proxy and cleanup UI (delete create controls, shared controls should be unlinked during OnThumbnailDrawEnd event)
|
||||
request.Proxy.OnThumbnailDrawEnd(request, _guiRoot);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Handle internal errors gracefully (eg. when asset is corrupted and proxy fails)
|
||||
Editor.LogError("Failed to render thumbnail icon for asset: " + request.Item);
|
||||
Editor.LogWarning(ex);
|
||||
request.FinishRender(ref SpriteHandle.Invalid);
|
||||
RemoveRequest(request);
|
||||
return;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_guiRoot.DisposeChildren();
|
||||
}
|
||||
|
||||
// Copy backbuffer with rendered preview into atlas
|
||||
SpriteHandle icon = atlas.OccupySlot(_output, request.Item.ID);
|
||||
|
||||
@@ -115,9 +115,19 @@ API_ENUM() enum class BuildPlatform
|
||||
/// </summary>
|
||||
API_ENUM(Attributes="EditorDisplay(null, \"Mac x64\")")
|
||||
MacOSx64 = 12,
|
||||
};
|
||||
|
||||
extern FLAXENGINE_API const Char* ToString(const BuildPlatform platform);
|
||||
/// <summary>
|
||||
/// MacOS (ARM64 Apple Silicon)
|
||||
/// </summary>
|
||||
API_ENUM(Attributes="EditorDisplay(null, \"Mac ARM64\")")
|
||||
MacOSARM64 = 13,
|
||||
|
||||
/// <summary>
|
||||
/// iOS (ARM64)
|
||||
/// </summary>
|
||||
API_ENUM(Attributes="EditorDisplay(null, \"iOS ARM64\")")
|
||||
iOSARM64 = 14,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Game build configuration modes.
|
||||
@@ -140,7 +150,35 @@ API_ENUM() enum class BuildConfiguration
|
||||
Release = 2,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// .NET Ahead of Time Compilation (AOT) modes.
|
||||
/// </summary>
|
||||
enum class DotNetAOTModes
|
||||
{
|
||||
/// <summary>
|
||||
/// AOT is not used.
|
||||
/// </summary>
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// Use .NET Native IL Compiler (shorten as ILC) to convert all C# assemblies in native platform executable binary.
|
||||
/// </summary>
|
||||
ILC,
|
||||
|
||||
/// <summary>
|
||||
/// Use Mono AOT to cross-compile all used C# assemblies into native platform shared libraries.
|
||||
/// </summary>
|
||||
MonoAOTDynamic,
|
||||
|
||||
/// <summary>
|
||||
/// Use Mono AOT to cross-compile all used C# assemblies into native platform static libraries which can be linked into a single shared library.
|
||||
/// </summary>
|
||||
MonoAOTStatic,
|
||||
};
|
||||
|
||||
extern FLAXENGINE_API const Char* ToString(const BuildPlatform platform);
|
||||
extern FLAXENGINE_API const Char* ToString(const BuildConfiguration configuration);
|
||||
extern FLAXENGINE_API const Char* ToString(const DotNetAOTModes mode);
|
||||
|
||||
#define BUILD_STEP_CANCEL_CHECK if (GameCooker::IsCancelRequested()) return true
|
||||
|
||||
@@ -188,7 +226,7 @@ public:
|
||||
API_FIELD(ReadOnly) String OriginalOutputPath;
|
||||
|
||||
/// <summary>
|
||||
/// The output path for data files (Content, Mono, etc.).
|
||||
/// The output path for data files (Content, Dotnet, Mono, etc.).
|
||||
/// </summary>
|
||||
API_FIELD(ReadOnly) String DataOutputPath;
|
||||
|
||||
@@ -300,15 +338,18 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the absolute path to the Platform Data folder that contains the binary files used by the current build configuration.
|
||||
/// </summary>
|
||||
/// <returns>The platform data folder path.</returns>
|
||||
String GetGameBinariesPath() const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the absolute path to the platform folder that contains the dependency files used by the current build configuration.
|
||||
/// </summary>
|
||||
/// <returns>The platform deps folder path.</returns>
|
||||
String GetPlatformBinariesRoot() const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the platform and architecture for the current BuildPlatform.
|
||||
/// </summary>
|
||||
void GetBuildPlatformName(const Char*& platform, const Char*& architecture) const;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
@@ -368,17 +409,15 @@ public:
|
||||
|
||||
public:
|
||||
|
||||
void Error(const String& msg);
|
||||
void Error(const StringView& msg);
|
||||
|
||||
void Error(const String& msg)
|
||||
{
|
||||
Error(StringView(msg));
|
||||
}
|
||||
|
||||
void Error(const Char* msg)
|
||||
{
|
||||
Error(String(msg));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void Error(const Char* format, const Args& ... args)
|
||||
{
|
||||
const String msg = String::Format(format, args...);
|
||||
Error(msg);
|
||||
Error(StringView(msg));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
#include "GameCooker.h"
|
||||
#include "PlatformTools.h"
|
||||
#include "FlaxEngine.Gen.h"
|
||||
#include "Engine/Scripting/MainThreadManagedInvokeAction.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MTypes.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MClass.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MException.h"
|
||||
#include "Engine/Scripting/Internal/MainThreadManagedInvokeAction.h"
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
#include "Engine/Scripting/ScriptingType.h"
|
||||
#include "Engine/Scripting/BinaryModule.h"
|
||||
@@ -23,12 +24,12 @@
|
||||
#include "Steps/CookAssetsStep.h"
|
||||
#include "Steps/PostProcessStep.h"
|
||||
#include "Engine/Platform/ConditionVariable.h"
|
||||
#include "Engine/Platform/CreateProcessSettings.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MDomain.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MCore.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MAssembly.h"
|
||||
#include "Engine/Content/JsonAsset.h"
|
||||
#include "Engine/Content/AssetReference.h"
|
||||
#include "Engine/Scripting/MException.h"
|
||||
#if PLATFORM_TOOLS_WINDOWS
|
||||
#include "Platform/Windows/WindowsPlatformTools.h"
|
||||
#include "Engine/Platform/Windows/WindowsPlatformSettings.h"
|
||||
@@ -63,6 +64,10 @@
|
||||
#include "Platform/Mac/MacPlatformTools.h"
|
||||
#include "Engine/Platform/Mac/MacPlatformSettings.h"
|
||||
#endif
|
||||
#if PLATFORM_TOOLS_IOS
|
||||
#include "Platform/iOS/iOSPlatformTools.h"
|
||||
#include "Engine/Platform/iOS/iOSPlatformSettings.h"
|
||||
#endif
|
||||
|
||||
namespace GameCookerImpl
|
||||
{
|
||||
@@ -139,8 +144,12 @@ const Char* ToString(const BuildPlatform platform)
|
||||
return TEXT("PlayStation 5");
|
||||
case BuildPlatform::MacOSx64:
|
||||
return TEXT("Mac x64");
|
||||
case BuildPlatform::MacOSARM64:
|
||||
return TEXT("Mac ARM64");
|
||||
case BuildPlatform::iOSARM64:
|
||||
return TEXT("iOS ARM64");
|
||||
default:
|
||||
return TEXT("?");
|
||||
return TEXT("");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,10 +164,37 @@ const Char* ToString(const BuildConfiguration configuration)
|
||||
case BuildConfiguration::Release:
|
||||
return TEXT("Release");
|
||||
default:
|
||||
return TEXT("?");
|
||||
return TEXT("");
|
||||
}
|
||||
}
|
||||
|
||||
const Char* ToString(const DotNetAOTModes mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case DotNetAOTModes::None:
|
||||
return TEXT("None");
|
||||
case DotNetAOTModes::ILC:
|
||||
return TEXT("ILC");
|
||||
case DotNetAOTModes::MonoAOTDynamic:
|
||||
return TEXT("MonoAOTDynamic");
|
||||
case DotNetAOTModes::MonoAOTStatic:
|
||||
return TEXT("MonoAOTStatic");
|
||||
default:
|
||||
return TEXT("");
|
||||
}
|
||||
}
|
||||
|
||||
bool PlatformTools::IsNativeCodeFile(CookingData& data, const String& file)
|
||||
{
|
||||
const String filename = StringUtils::GetFileName(file);
|
||||
if (filename.Contains(TEXT(".CSharp")) ||
|
||||
filename.Contains(TEXT("Newtonsoft.Json")))
|
||||
return false;
|
||||
// TODO: maybe use Mono.Cecil via Flax.Build to read assembly image metadata and check if it contains C#?
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CookingData::AssetTypeStatistics::operator<(const AssetTypeStatistics& other) const
|
||||
{
|
||||
if (ContentSize != other.ContentSize)
|
||||
@@ -211,6 +247,71 @@ String CookingData::GetPlatformBinariesRoot() const
|
||||
return Globals::StartupFolder / TEXT("Source/Platforms") / Tools->GetName() / TEXT("Binaries");
|
||||
}
|
||||
|
||||
void CookingData::GetBuildPlatformName(const Char*& platform, const Char*& architecture) const
|
||||
{
|
||||
switch (Platform)
|
||||
{
|
||||
case BuildPlatform::Windows32:
|
||||
platform = TEXT("Windows");
|
||||
architecture = TEXT("x86");
|
||||
break;
|
||||
case BuildPlatform::Windows64:
|
||||
platform = TEXT("Windows");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::UWPx86:
|
||||
platform = TEXT("UWP");
|
||||
architecture = TEXT("x86");
|
||||
break;
|
||||
case BuildPlatform::UWPx64:
|
||||
platform = TEXT("UWP");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::XboxOne:
|
||||
platform = TEXT("XboxOne");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::LinuxX64:
|
||||
platform = TEXT("Linux");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::PS4:
|
||||
platform = TEXT("PS4");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::XboxScarlett:
|
||||
platform = TEXT("XboxScarlett");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::AndroidARM64:
|
||||
platform = TEXT("Android");
|
||||
architecture = TEXT("ARM64");
|
||||
break;
|
||||
case BuildPlatform::Switch:
|
||||
platform = TEXT("Switch");
|
||||
architecture = TEXT("ARM64");
|
||||
break;
|
||||
case BuildPlatform::PS5:
|
||||
platform = TEXT("PS5");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::MacOSx64:
|
||||
platform = TEXT("Mac");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::MacOSARM64:
|
||||
platform = TEXT("Mac");
|
||||
architecture = TEXT("ARM64");
|
||||
break;
|
||||
case BuildPlatform::iOSARM64:
|
||||
platform = TEXT("iOS");
|
||||
architecture = TEXT("ARM64");
|
||||
break;
|
||||
default:
|
||||
LOG(Fatal, "Unknown or unsupported build platform.");
|
||||
}
|
||||
}
|
||||
|
||||
void CookingData::StepProgress(const String& info, const float stepProgress) const
|
||||
{
|
||||
const float singleStepProgress = 1.0f / (StepsCount + 1);
|
||||
@@ -242,7 +343,7 @@ void CookingData::AddRootEngineAsset(const String& internalPath)
|
||||
}
|
||||
}
|
||||
|
||||
void CookingData::Error(const String& msg)
|
||||
void CookingData::Error(const StringView& msg)
|
||||
{
|
||||
LOG_STR(Error, msg);
|
||||
}
|
||||
@@ -340,6 +441,14 @@ PlatformTools* GameCooker::GetTools(BuildPlatform platform)
|
||||
case BuildPlatform::MacOSx64:
|
||||
result = New<MacPlatformTools>(ArchitectureType::x64);
|
||||
break;
|
||||
case BuildPlatform::MacOSARM64:
|
||||
result = New<MacPlatformTools>(ArchitectureType::ARM64);
|
||||
break;
|
||||
#endif
|
||||
#if PLATFORM_TOOLS_IOS
|
||||
case BuildPlatform::iOSARM64:
|
||||
result = New<iOSPlatformTools>();
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
Tools.Add(platform, result);
|
||||
@@ -470,7 +579,10 @@ void GameCooker::GetCurrentPlatform(PlatformType& platform, BuildPlatform& build
|
||||
buildPlatform = BuildPlatform::PS5;
|
||||
break;
|
||||
case PlatformType::Mac:
|
||||
buildPlatform = BuildPlatform::MacOSx64;
|
||||
buildPlatform = PLATFORM_ARCH_ARM || PLATFORM_ARCH_ARM64 ? BuildPlatform::MacOSARM64 : BuildPlatform::MacOSx64;
|
||||
break;
|
||||
case PlatformType::iOS:
|
||||
buildPlatform = BuildPlatform::iOSARM64;
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
@@ -511,9 +623,9 @@ void GameCookerImpl::OnCollectAssets(HashSet<Guid>& assets)
|
||||
ASSERT(GameCookerImpl::Internal_OnCollectAssets);
|
||||
}
|
||||
|
||||
MCore::AttachThread();
|
||||
MCore::Thread::Attach();
|
||||
MObject* exception = nullptr;
|
||||
auto list = (MonoArray*)Internal_OnCollectAssets->Invoke(nullptr, nullptr, &exception);
|
||||
auto list = (MArray*)Internal_OnCollectAssets->Invoke(nullptr, nullptr, &exception);
|
||||
if (exception)
|
||||
{
|
||||
MException ex(exception);
|
||||
@@ -547,13 +659,13 @@ bool GameCookerImpl::Build()
|
||||
Steps.Add(New<PostProcessStep>());
|
||||
}
|
||||
|
||||
MCore::AttachThread();
|
||||
MCore::Thread::Attach();
|
||||
|
||||
// Build Started
|
||||
CallEvent(GameCooker::EventType::BuildStarted);
|
||||
data.Tools->OnBuildStarted(data);
|
||||
for (int32 stepIndex = 0; stepIndex < Steps.Count(); stepIndex++)
|
||||
Steps[stepIndex]->OnBuildStarted(data);
|
||||
data.Tools->OnBuildStarted(data);
|
||||
data.InitProgress(Steps.Count());
|
||||
|
||||
// Execute all steps in a sequence
|
||||
@@ -602,7 +714,15 @@ bool GameCookerImpl::Build()
|
||||
const String commandLine = commandLineFormat.HasChars() ? String::Format(*commandLineFormat, gameArgs) : gameArgs;
|
||||
if (workingDir.IsEmpty())
|
||||
workingDir = data.NativeCodeOutputPath;
|
||||
Platform::StartProcess(executableFile, commandLine, workingDir);
|
||||
CreateProcessSettings procSettings;
|
||||
procSettings.FileName = executableFile;
|
||||
procSettings.Arguments = commandLine;
|
||||
procSettings.WorkingDirectory = workingDir;
|
||||
procSettings.HiddenWindow = false;
|
||||
procSettings.WaitForEnd = false;
|
||||
procSettings.LogOutput = false;
|
||||
procSettings.ShellExecute = true;
|
||||
Platform::CreateProcess(procSettings);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -612,9 +732,9 @@ bool GameCookerImpl::Build()
|
||||
}
|
||||
IsRunning = false;
|
||||
CancelFlag = 0;
|
||||
data.Tools->OnBuildEnded(data, failed);
|
||||
for (int32 stepIndex = 0; stepIndex < Steps.Count(); stepIndex++)
|
||||
Steps[stepIndex]->OnBuildEnded(data, failed);
|
||||
data.Tools->OnBuildEnded(data, failed);
|
||||
CallEvent(failed ? GameCooker::EventType::BuildFailed : GameCooker::EventType::BuildDone);
|
||||
Delete(Data);
|
||||
Data = nullptr;
|
||||
@@ -667,7 +787,7 @@ void GameCookerService::Update()
|
||||
}
|
||||
|
||||
MainThreadManagedInvokeAction::ParamsBuilder params;
|
||||
params.AddParam(ProgressMsg, Scripting::GetScriptsDomain()->GetNative());
|
||||
params.AddParam(ProgressMsg, Scripting::GetScriptsDomain());
|
||||
params.AddParam(ProgressValue);
|
||||
MainThreadManagedInvokeAction::Invoke(Internal_OnProgress, params);
|
||||
GameCooker::OnProgress(ProgressMsg, ProgressValue);
|
||||
|
||||
@@ -103,7 +103,9 @@ namespace FlaxEditor
|
||||
case BuildPlatform.AndroidARM64: return PlatformType.Android;
|
||||
case BuildPlatform.XboxScarlett: return PlatformType.XboxScarlett;
|
||||
case BuildPlatform.Switch: return PlatformType.Switch;
|
||||
case BuildPlatform.MacOSARM64:
|
||||
case BuildPlatform.MacOSx64: return PlatformType.Mac;
|
||||
case BuildPlatform.iOSARM64: return PlatformType.iOS;
|
||||
default: throw new ArgumentOutOfRangeException(nameof(buildPlatform), buildPlatform, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "Editor/Utilities/EditorUtilities.h"
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Engine/Platform/CreateProcessSettings.h"
|
||||
#include "Engine/Platform/Android/AndroidPlatformSettings.h"
|
||||
#include "Engine/Graphics/PixelFormatExtensions.h"
|
||||
#include "Engine/Graphics/Textures/TextureData.h"
|
||||
@@ -115,8 +116,6 @@ void AndroidPlatformTools::OnBuildStarted(CookingData& data)
|
||||
data.DataOutputPath /= TEXT("app/assets");
|
||||
data.NativeCodeOutputPath /= TEXT("app/assets");
|
||||
data.ManagedCodeOutputPath /= TEXT("app/assets");
|
||||
|
||||
PlatformTools::OnBuildStarted(data);
|
||||
}
|
||||
|
||||
bool AndroidPlatformTools::OnPostProcess(CookingData& data)
|
||||
@@ -140,33 +139,8 @@ bool AndroidPlatformTools::OnPostProcess(CookingData& data)
|
||||
|
||||
// Setup package name (eg. com.company.project)
|
||||
String packageName = platformSettings->PackageName;
|
||||
{
|
||||
String productName = gameSettings->ProductName;
|
||||
productName.Replace(TEXT(" "), TEXT(""));
|
||||
productName.Replace(TEXT("."), TEXT(""));
|
||||
productName.Replace(TEXT("-"), TEXT(""));
|
||||
String companyName = gameSettings->CompanyName;
|
||||
companyName.Replace(TEXT(" "), TEXT(""));
|
||||
companyName.Replace(TEXT("."), TEXT(""));
|
||||
companyName.Replace(TEXT("-"), TEXT(""));
|
||||
packageName.Replace(TEXT("${PROJECT_NAME}"), *productName, StringSearchCase::IgnoreCase);
|
||||
packageName.Replace(TEXT("${COMPANY_NAME}"), *companyName, StringSearchCase::IgnoreCase);
|
||||
packageName = packageName.ToLower();
|
||||
for (int32 i = 0; i < packageName.Length(); i++)
|
||||
{
|
||||
const auto c = packageName[i];
|
||||
if (c != '_' && c != '.' && !StringUtils::IsAlnum(c))
|
||||
{
|
||||
LOG(Error, "Android Package Name \'{0}\' contains invalid character. Only letters, numbers, dots and underscore characters are allowed.", packageName);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (packageName.IsEmpty())
|
||||
{
|
||||
LOG(Error, "Android Package Name is empty.", packageName);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (EditorUtilities::FormatAppPackageName(packageName))
|
||||
return true;
|
||||
|
||||
// Setup Android application permissions
|
||||
HashSet<String> permissionsList;
|
||||
@@ -267,7 +241,7 @@ bool AndroidPlatformTools::OnPostProcess(CookingData& data)
|
||||
}
|
||||
}
|
||||
|
||||
// Generate Mono files hash id used to skip deploying Mono files if already extracted on device (Mono cannot access files packed into .apk via unix file access)
|
||||
// Generate Dotnet files hash id used to skip deploying Dotnet files if already extracted on device (Dotnet cannot access files packed into .apk via unix file access)
|
||||
File::WriteAllText(assetsPath / TEXT("hash.txt"), Guid::New().ToString(), Encoding::ANSI);
|
||||
|
||||
// TODO: expose event to inject custom gradle and manifest options or custom binaries into app
|
||||
@@ -309,11 +283,13 @@ bool AndroidPlatformTools::OnPostProcess(CookingData& data)
|
||||
Platform::RunProcess(String::Format(TEXT("chmod +x \"{0}/gradlew\""), data.OriginalOutputPath), data.OriginalOutputPath, Dictionary<String, String>(), true);
|
||||
#endif
|
||||
const bool distributionPackage = buildSettings->ForDistribution;
|
||||
const String gradleCommand = String::Format(TEXT("\"{0}\" {1}"), data.OriginalOutputPath / gradlew, distributionPackage ? TEXT("assemble") : TEXT("assembleDebug"));
|
||||
const int32 result = Platform::RunProcess(gradleCommand, data.OriginalOutputPath, Dictionary<String, String>(), true);
|
||||
CreateProcessSettings procSettings;
|
||||
procSettings.FileName = String::Format(TEXT("\"{0}\" {1}"), data.OriginalOutputPath / gradlew, distributionPackage ? TEXT("assemble") : TEXT("assembleDebug"));
|
||||
procSettings.WorkingDirectory = data.OriginalOutputPath;
|
||||
const int32 result = Platform::CreateProcess(procSettings);
|
||||
if (result != 0)
|
||||
{
|
||||
data.Error(TEXT("Failed to build Gradle project into package (result code: {0}). See log for more info."), result);
|
||||
data.Error(String::Format(TEXT("Failed to build Gradle project into package (result code: {0}). See log for more info."), result));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2019 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "GDKPlatformTools.h"
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Engine/Platform/CreateProcessSettings.h"
|
||||
#include "Engine/Platform/GDK/GDKPlatformSettings.h"
|
||||
#include "Engine/Core/Types/StringBuilder.h"
|
||||
#include "Engine/Core/Collections/Sorting.h"
|
||||
@@ -36,24 +37,9 @@ GDKPlatformTools::GDKPlatformTools()
|
||||
}
|
||||
}
|
||||
|
||||
bool GDKPlatformTools::UseAOT() const
|
||||
DotNetAOTModes GDKPlatformTools::UseAOT() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GDKPlatformTools::OnScriptsStepDone(CookingData& data)
|
||||
{
|
||||
// Override Newtonsoft.Json.dll for some platforms (that don't support runtime code generation)
|
||||
const String customBinPath = data.GetPlatformBinariesRoot() / TEXT("Newtonsoft.Json.dll");
|
||||
const String assembliesPath = data.ManagedCodeOutputPath;
|
||||
if (FileSystem::CopyFile(assembliesPath / TEXT("Newtonsoft.Json.dll"), customBinPath))
|
||||
{
|
||||
data.Error(TEXT("Failed to copy deloy custom assembly."));
|
||||
return true;
|
||||
}
|
||||
FileSystem::DeleteFile(assembliesPath / TEXT("Newtonsoft.Json.pdb"));
|
||||
|
||||
return false;
|
||||
return DotNetAOTModes::MonoAOTDynamic;
|
||||
}
|
||||
|
||||
bool GDKPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
@@ -66,7 +52,7 @@ bool GDKPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
files.Add(binPath / executableFilename);
|
||||
if (!FileSystem::FileExists(files[0]))
|
||||
{
|
||||
data.Error(TEXT("Missing executable file ({0})."), files[0]);
|
||||
data.Error(String::Format(TEXT("Missing executable file ({0})."), files[0]));
|
||||
return true;
|
||||
}
|
||||
FileSystem::DirectoryGetFiles(files, binPath, TEXT("*.dll"), DirectorySearchOption::TopDirectoryOnly);
|
||||
@@ -74,7 +60,7 @@ bool GDKPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
{
|
||||
if (FileSystem::CopyFile(data.NativeCodeOutputPath / StringUtils::GetFileName(files[i]), files[i]))
|
||||
{
|
||||
data.Error(TEXT("Failed to setup output directory (file {0})."), files[i]);
|
||||
data.Error(String::Format(TEXT("Failed to setup output directory (file {0})."), files[i]));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -82,85 +68,6 @@ bool GDKPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
return false;
|
||||
}
|
||||
|
||||
void GDKPlatformTools::OnConfigureAOT(CookingData& data, AotConfig& config)
|
||||
{
|
||||
const auto platformDataPath = data.GetPlatformBinariesRoot();
|
||||
const bool useInterpreter = true; // TODO: use Full AOT on GDK
|
||||
const bool enableDebug = data.Configuration != BuildConfiguration::Release;
|
||||
const Char* aotMode = useInterpreter ? TEXT("full,interp") : TEXT("full");
|
||||
const Char* debugMode = enableDebug ? TEXT("soft-debug") : TEXT("nodebug");
|
||||
config.AotCompilerArgs = String::Format(TEXT("--aot={0},verbose,stats,print-skipped,{1} -O=all"), aotMode, debugMode);
|
||||
if (enableDebug)
|
||||
config.AotCompilerArgs = TEXT("--debug ") + config.AotCompilerArgs;
|
||||
config.AotCompilerPath = platformDataPath / TEXT("Tools/mono.exe");
|
||||
}
|
||||
|
||||
bool GDKPlatformTools::OnPerformAOT(CookingData& data, AotConfig& config, const String& assemblyPath)
|
||||
{
|
||||
// Skip .dll.dll which could be a false result from the previous AOT which could fail
|
||||
if (assemblyPath.EndsWith(TEXT(".dll.dll")))
|
||||
{
|
||||
LOG(Warning, "Skip AOT for file '{0}' as it can be a result from the previous task", assemblyPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if skip this assembly (could be already processed)
|
||||
const String filename = StringUtils::GetFileName(assemblyPath);
|
||||
const String outputPath = config.AotCachePath / filename + TEXT(".dll");
|
||||
if (FileSystem::FileExists(outputPath) && FileSystem::GetFileLastEditTime(assemblyPath) < FileSystem::GetFileLastEditTime(outputPath))
|
||||
return false;
|
||||
LOG(Info, "Calling AOT tool for \"{0}\"", assemblyPath);
|
||||
|
||||
// Cleanup temporary results (fromm the previous AT that fail or sth)
|
||||
const String resultPath = assemblyPath + TEXT(".dll");
|
||||
const String resultPathExp = resultPath + TEXT(".exp");
|
||||
const String resultPathLib = resultPath + TEXT(".lib");
|
||||
const String resultPathPdb = resultPath + TEXT(".pdb");
|
||||
if (FileSystem::FileExists(resultPath))
|
||||
FileSystem::DeleteFile(resultPath);
|
||||
if (FileSystem::FileExists(resultPathExp))
|
||||
FileSystem::DeleteFile(resultPathExp);
|
||||
if (FileSystem::FileExists(resultPathLib))
|
||||
FileSystem::DeleteFile(resultPathLib);
|
||||
if (FileSystem::FileExists(resultPathPdb))
|
||||
FileSystem::DeleteFile(resultPathPdb);
|
||||
|
||||
// Call tool
|
||||
const String workingDir = StringUtils::GetDirectoryName(config.AotCompilerPath);
|
||||
const String command = String::Format(TEXT("\"{0}\" {1} \"{2}\""), config.AotCompilerPath, config.AotCompilerArgs, assemblyPath);
|
||||
const int32 result = Platform::RunProcess(command, workingDir, config.EnvVars);
|
||||
if (result != 0)
|
||||
{
|
||||
data.Error(TEXT("AOT tool execution failed with result code {1} for assembly \"{0}\". See log for more info."), assemblyPath, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Copy result
|
||||
if (FileSystem::CopyFile(outputPath, resultPath))
|
||||
{
|
||||
data.Error(TEXT("Failed to copy the AOT tool result file. It can be missing."));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Copy pdb file if exists
|
||||
if (data.Configuration != BuildConfiguration::Release && FileSystem::FileExists(resultPathPdb))
|
||||
{
|
||||
FileSystem::CopyFile(config.AotCachePath / StringUtils::GetFileName(resultPathPdb), resultPathPdb);
|
||||
}
|
||||
|
||||
// Clean intermediate results
|
||||
if (FileSystem::DeleteFile(resultPath)
|
||||
|| (FileSystem::FileExists(resultPathExp) && FileSystem::DeleteFile(resultPathExp))
|
||||
|| (FileSystem::FileExists(resultPathLib) && FileSystem::DeleteFile(resultPathLib))
|
||||
|| (FileSystem::FileExists(resultPathPdb) && FileSystem::DeleteFile(resultPathPdb))
|
||||
)
|
||||
{
|
||||
LOG(Warning, "Failed to remove the AOT tool result file(s).");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GDKPlatformTools::OnPostProcess(CookingData& data, GDKPlatformSettings* platformSettings)
|
||||
{
|
||||
// Configuration
|
||||
@@ -275,8 +182,10 @@ bool GDKPlatformTools::OnPostProcess(CookingData& data, GDKPlatformSettings* pla
|
||||
data.StepProgress(TEXT("Generating package layout"), 0.3f);
|
||||
const String gdkBinPath = _gdkPath / TEXT("../bin");
|
||||
const String makePkgPath = gdkBinPath / TEXT("MakePkg.exe");
|
||||
const String command = String::Format(TEXT("\"{0}\" genmap /f layout.xml /d \"{1}\""), makePkgPath, data.DataOutputPath);
|
||||
const int32 result = Platform::RunProcess(command, data.DataOutputPath);
|
||||
CreateProcessSettings procSettings;
|
||||
procSettings.FileName = String::Format(TEXT("\"{0}\" genmap /f layout.xml /d \"{1}\""), makePkgPath, data.DataOutputPath);
|
||||
procSettings.WorkingDirectory = data.DataOutputPath;
|
||||
const int32 result = Platform::CreateProcess(procSettings);
|
||||
if (result != 0)
|
||||
{
|
||||
data.Error(TEXT("Failed to generate package layout."));
|
||||
|
||||
@@ -26,11 +26,8 @@ public:
|
||||
public:
|
||||
|
||||
// [PlatformTools]
|
||||
bool UseAOT() const override;
|
||||
bool OnScriptsStepDone(CookingData& data) override;
|
||||
DotNetAOTModes UseAOT() const override;
|
||||
bool OnDeployBinaries(CookingData& data) override;
|
||||
void OnConfigureAOT(CookingData& data, AotConfig& config) override;
|
||||
bool OnPerformAOT(CookingData& data, AotConfig& config, const String& assemblyPath) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2019 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#if PLATFORM_TOOLS_LINUX
|
||||
|
||||
@@ -34,6 +34,11 @@ ArchitectureType LinuxPlatformTools::GetArchitecture() const
|
||||
return ArchitectureType::x64;
|
||||
}
|
||||
|
||||
bool LinuxPlatformTools::UseSystemDotnet() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LinuxPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
{
|
||||
const auto gameSettings = GameSettings::Get();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2019 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -18,6 +18,7 @@ public:
|
||||
const Char* GetName() const override;
|
||||
PlatformType GetPlatform() const override;
|
||||
ArchitectureType GetArchitecture() const override;
|
||||
bool UseSystemDotnet() const override;
|
||||
bool OnDeployBinaries(CookingData& data) override;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2019 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#if PLATFORM_TOOLS_MAC
|
||||
|
||||
@@ -59,6 +59,11 @@ ArchitectureType MacPlatformTools::GetArchitecture() const
|
||||
return _arch;
|
||||
}
|
||||
|
||||
bool MacPlatformTools::UseSystemDotnet() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacPlatformTools::IsNativeCodeFile(CookingData& data, const String& file)
|
||||
{
|
||||
String extension = FileSystem::GetExtension(file);
|
||||
@@ -87,33 +92,8 @@ bool MacPlatformTools::OnPostProcess(CookingData& data)
|
||||
|
||||
// Setup package name (eg. com.company.project)
|
||||
String appIdentifier = platformSettings->AppIdentifier;
|
||||
{
|
||||
String productName = gameSettings->ProductName;
|
||||
productName.Replace(TEXT(" "), TEXT(""));
|
||||
productName.Replace(TEXT("."), TEXT(""));
|
||||
productName.Replace(TEXT("-"), TEXT(""));
|
||||
String companyName = gameSettings->CompanyName;
|
||||
companyName.Replace(TEXT(" "), TEXT(""));
|
||||
companyName.Replace(TEXT("."), TEXT(""));
|
||||
companyName.Replace(TEXT("-"), TEXT(""));
|
||||
appIdentifier.Replace(TEXT("${PROJECT_NAME}"), *productName, StringSearchCase::IgnoreCase);
|
||||
appIdentifier.Replace(TEXT("${COMPANY_NAME}"), *companyName, StringSearchCase::IgnoreCase);
|
||||
appIdentifier = appIdentifier.ToLower();
|
||||
for (int32 i = 0; i < appIdentifier.Length(); i++)
|
||||
{
|
||||
const auto c = appIdentifier[i];
|
||||
if (c != '_' && c != '.' && !StringUtils::IsAlnum(c))
|
||||
{
|
||||
LOG(Error, "Apple app identifier \'{0}\' contains invalid character. Only letters, numbers, dots and underscore characters are allowed.", appIdentifier);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (appIdentifier.IsEmpty())
|
||||
{
|
||||
LOG(Error, "Apple app identifier is empty.", appIdentifier);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (EditorUtilities::FormatAppPackageName(appIdentifier))
|
||||
return true;
|
||||
|
||||
// Find executable
|
||||
String executableName;
|
||||
@@ -187,7 +167,7 @@ bool MacPlatformTools::OnPostProcess(CookingData& data)
|
||||
ADD_ENTRY("CFBundlePackageType", "APPL");
|
||||
ADD_ENTRY("NSPrincipalClass", "NSApplication");
|
||||
ADD_ENTRY("LSApplicationCategoryType", "public.app-category.games");
|
||||
ADD_ENTRY("LSMinimumSystemVersion", "10.14");
|
||||
ADD_ENTRY("LSMinimumSystemVersion", "10.15");
|
||||
ADD_ENTRY("CFBundleIconFile", "icon.icns");
|
||||
ADD_ENTRY_STR("CFBundleExecutable", executableName);
|
||||
ADD_ENTRY_STR("CFBundleIdentifier", appIdentifier);
|
||||
@@ -201,10 +181,19 @@ bool MacPlatformTools::OnPostProcess(CookingData& data)
|
||||
|
||||
dict.append_child(PUGIXML_TEXT("key")).set_child_value(PUGIXML_TEXT("LSMinimumSystemVersionByArchitecture"));
|
||||
xml_node LSMinimumSystemVersionByArchitecture = dict.append_child(PUGIXML_TEXT("dict"));
|
||||
LSMinimumSystemVersionByArchitecture.append_child(PUGIXML_TEXT("key")).set_child_value(PUGIXML_TEXT("x86_64"));
|
||||
LSMinimumSystemVersionByArchitecture.append_child(PUGIXML_TEXT("string")).set_child_value(PUGIXML_TEXT("10.14"));
|
||||
switch (_arch)
|
||||
{
|
||||
case ArchitectureType::x64:
|
||||
LSMinimumSystemVersionByArchitecture.append_child(PUGIXML_TEXT("key")).set_child_value(PUGIXML_TEXT("x86_64"));
|
||||
break;
|
||||
case ArchitectureType::ARM64:
|
||||
LSMinimumSystemVersionByArchitecture.append_child(PUGIXML_TEXT("key")).set_child_value(PUGIXML_TEXT("arm64"));
|
||||
break;
|
||||
}
|
||||
LSMinimumSystemVersionByArchitecture.append_child(PUGIXML_TEXT("string")).set_child_value(PUGIXML_TEXT("10.15"));
|
||||
|
||||
#undef ADD_ENTRY
|
||||
#undef ADD_ENTRY_STR
|
||||
|
||||
if (!doc.save_file(*StringAnsi(plistPath)))
|
||||
{
|
||||
@@ -215,8 +204,6 @@ bool MacPlatformTools::OnPostProcess(CookingData& data)
|
||||
|
||||
// TODO: sign binaries
|
||||
|
||||
// TODO: expose event to inject custom post-processing before app packaging (eg. third-party plugins)
|
||||
|
||||
// Package application
|
||||
const auto buildSettings = BuildSettings::Get();
|
||||
if (buildSettings->SkipPackaging)
|
||||
@@ -228,7 +215,7 @@ bool MacPlatformTools::OnPostProcess(CookingData& data)
|
||||
const int32 result = Platform::RunProcess(dmgCommand, data.OriginalOutputPath);
|
||||
if (result != 0)
|
||||
{
|
||||
data.Error(TEXT("Failed to package app (result code: {0}). See log for more info."), result);
|
||||
data.Error(String::Format(TEXT("Failed to package app (result code: {0}). See log for more info."), result));
|
||||
return true;
|
||||
}
|
||||
// TODO: sign dmg
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2019 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -23,6 +23,7 @@ public:
|
||||
const Char* GetName() const override;
|
||||
PlatformType GetPlatform() const override;
|
||||
ArchitectureType GetArchitecture() const override;
|
||||
bool UseSystemDotnet() const override;
|
||||
bool IsNativeCodeFile(CookingData& data, const String& file) override;
|
||||
void OnBuildStarted(CookingData& data) override;
|
||||
bool OnPostProcess(CookingData& data) override;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
// Copyright (c) 2012-2019 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#if PLATFORM_TOOLS_UWP
|
||||
|
||||
#include "UWPPlatformTools.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Platform/CreateProcessSettings.h"
|
||||
#include "Engine/Platform/UWP/UWPPlatformSettings.h"
|
||||
#include "Engine/Core/Config/GameSettings.h"
|
||||
#include "Engine/Core/Types/StringBuilder.h"
|
||||
@@ -36,24 +37,9 @@ ArchitectureType UWPPlatformTools::GetArchitecture() const
|
||||
return _arch;
|
||||
}
|
||||
|
||||
bool UWPPlatformTools::UseAOT() const
|
||||
DotNetAOTModes UWPPlatformTools::UseAOT() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UWPPlatformTools::OnScriptsStepDone(CookingData& data)
|
||||
{
|
||||
// Override Newtonsoft.Json.dll for some platforms (that don't support runtime code generation)
|
||||
const String customBinPath = data.GetPlatformBinariesRoot() / TEXT("Newtonsoft.Json.dll");
|
||||
const String assembliesPath = data.ManagedCodeOutputPath;
|
||||
if (FileSystem::CopyFile(assembliesPath / TEXT("Newtonsoft.Json.dll"), customBinPath))
|
||||
{
|
||||
data.Error(TEXT("Failed to copy deploy custom assembly."));
|
||||
return true;
|
||||
}
|
||||
FileSystem::DeleteFile(assembliesPath / TEXT("Newtonsoft.Json.pdb"));
|
||||
|
||||
return false;
|
||||
return DotNetAOTModes::MonoAOTDynamic;
|
||||
}
|
||||
|
||||
bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
@@ -79,7 +65,7 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
{
|
||||
if (!FileSystem::FileExists(files[i]))
|
||||
{
|
||||
data.Error(TEXT("Missing source file {0}."), files[i]);
|
||||
data.Error(String::Format(TEXT("Missing source file {0}."), files[i]));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -414,90 +400,9 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
return false;
|
||||
}
|
||||
|
||||
void UWPPlatformTools::OnConfigureAOT(CookingData& data, AotConfig& config)
|
||||
{
|
||||
const auto platformDataPath = data.GetPlatformBinariesRoot();
|
||||
const bool useInterpreter = true; // TODO: support using Full AOT instead of interpreter
|
||||
const bool enableDebug = data.Configuration != BuildConfiguration::Release;
|
||||
const Char* aotMode = useInterpreter ? TEXT("full,interp") : TEXT("full");
|
||||
const Char* debugMode = enableDebug ? TEXT("soft-debug") : TEXT("nodebug");
|
||||
config.AotCompilerArgs = String::Format(TEXT("--aot={0},verbose,stats,print-skipped,{1} -O=all"),
|
||||
aotMode,
|
||||
debugMode);
|
||||
if (enableDebug)
|
||||
config.AotCompilerArgs = TEXT("--debug ") + config.AotCompilerArgs;
|
||||
config.AotCompilerPath = platformDataPath / TEXT("Tools/mono.exe");
|
||||
}
|
||||
|
||||
bool UWPPlatformTools::OnPerformAOT(CookingData& data, AotConfig& config, const String& assemblyPath)
|
||||
{
|
||||
// Skip .dll.dll which could be a false result from the previous AOT which could fail
|
||||
if (assemblyPath.EndsWith(TEXT(".dll.dll")))
|
||||
{
|
||||
LOG(Warning, "Skip AOT for file '{0}' as it can be a result from the previous task", assemblyPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if skip this assembly (could be already processed)
|
||||
const String filename = StringUtils::GetFileName(assemblyPath);
|
||||
const String outputPath = config.AotCachePath / filename + TEXT(".dll");
|
||||
if (FileSystem::FileExists(outputPath) && FileSystem::GetFileLastEditTime(assemblyPath) < FileSystem::GetFileLastEditTime(outputPath))
|
||||
return false;
|
||||
LOG(Info, "Calling AOT tool for \"{0}\"", assemblyPath);
|
||||
|
||||
// Cleanup temporary results (fromm the previous AT that fail or sth)
|
||||
const String resultPath = assemblyPath + TEXT(".dll");
|
||||
const String resultPathExp = resultPath + TEXT(".exp");
|
||||
const String resultPathLib = resultPath + TEXT(".lib");
|
||||
const String resultPathPdb = resultPath + TEXT(".pdb");
|
||||
if (FileSystem::FileExists(resultPath))
|
||||
FileSystem::DeleteFile(resultPath);
|
||||
if (FileSystem::FileExists(resultPathExp))
|
||||
FileSystem::DeleteFile(resultPathExp);
|
||||
if (FileSystem::FileExists(resultPathLib))
|
||||
FileSystem::DeleteFile(resultPathLib);
|
||||
if (FileSystem::FileExists(resultPathPdb))
|
||||
FileSystem::DeleteFile(resultPathPdb);
|
||||
|
||||
// Call tool
|
||||
String workingDir = StringUtils::GetDirectoryName(config.AotCompilerPath);
|
||||
String command = String::Format(TEXT("\"{0}\" {1} \"{2}\""), config.AotCompilerPath, config.AotCompilerArgs, assemblyPath);
|
||||
const int32 result = Platform::RunProcess(command, workingDir, config.EnvVars);
|
||||
if (result != 0)
|
||||
{
|
||||
data.Error(TEXT("AOT tool execution failed with result code {1} for assembly \"{0}\". See log for more info."), assemblyPath, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Copy result
|
||||
if (FileSystem::CopyFile(outputPath, resultPath))
|
||||
{
|
||||
data.Error(TEXT("Failed to copy the AOT tool result file. It can be missing."));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Copy pdb file if exists
|
||||
if (data.Configuration != BuildConfiguration::Release && FileSystem::FileExists(resultPathPdb))
|
||||
{
|
||||
FileSystem::CopyFile(config.AotCachePath / StringUtils::GetFileName(resultPathPdb), resultPathPdb);
|
||||
}
|
||||
|
||||
// Clean intermediate results
|
||||
if (FileSystem::DeleteFile(resultPath)
|
||||
|| (FileSystem::FileExists(resultPathExp) && FileSystem::DeleteFile(resultPathExp))
|
||||
|| (FileSystem::FileExists(resultPathLib) && FileSystem::DeleteFile(resultPathLib))
|
||||
|| (FileSystem::FileExists(resultPathPdb) && FileSystem::DeleteFile(resultPathPdb))
|
||||
)
|
||||
{
|
||||
LOG(Warning, "Failed to remove the AOT tool result file(s).");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UWPPlatformTools::OnPostProcess(CookingData& data)
|
||||
{
|
||||
LOG(Error, "UWP (Windows Store) platform has been deprecated and soon will be removed!");
|
||||
LOG(Error, "UWP (Windows Store) platform has been deprecated and is no longer supported");
|
||||
|
||||
// Special case for UWP
|
||||
// FlaxEngine.dll cannot be added to the solution as `Content` item (due to conflicts with C++ /CX FlaxEngine.dll)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2019 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -29,11 +29,8 @@ public:
|
||||
const Char* GetName() const override;
|
||||
PlatformType GetPlatform() const override;
|
||||
ArchitectureType GetArchitecture() const override;
|
||||
bool UseAOT() const override;
|
||||
bool OnScriptsStepDone(CookingData& data) override;
|
||||
DotNetAOTModes UseAOT() const override;
|
||||
bool OnDeployBinaries(CookingData& data) override;
|
||||
void OnConfigureAOT(CookingData& data, AotConfig& config) override;
|
||||
bool OnPerformAOT(CookingData& data, AotConfig& config, const String& assemblyPath) override;
|
||||
bool OnPostProcess(CookingData& data) override;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2019 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#if PLATFORM_TOOLS_WINDOWS
|
||||
|
||||
@@ -33,6 +33,11 @@ ArchitectureType WindowsPlatformTools::GetArchitecture() const
|
||||
return _arch;
|
||||
}
|
||||
|
||||
bool WindowsPlatformTools::UseSystemDotnet() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WindowsPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
{
|
||||
const auto platformSettings = WindowsPlatformSettings::Get();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2019 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -29,6 +29,7 @@ public:
|
||||
const Char* GetName() const override;
|
||||
PlatformType GetPlatform() const override;
|
||||
ArchitectureType GetArchitecture() const override;
|
||||
bool UseSystemDotnet() const override;
|
||||
bool OnDeployBinaries(CookingData& data) override;
|
||||
void OnRun(CookingData& data, String& executableFile, String& commandLineFormat, String& workingDir) override;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,284 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#if PLATFORM_TOOLS_IOS
|
||||
|
||||
#include "iOSPlatformTools.h"
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Engine/Platform/CreateProcessSettings.h"
|
||||
#include "Engine/Platform/iOS/iOSPlatformSettings.h"
|
||||
#include "Engine/Core/Config/GameSettings.h"
|
||||
#include "Engine/Core/Config/BuildSettings.h"
|
||||
#include "Engine/Core/Collections/Dictionary.h"
|
||||
#include "Engine/Graphics/Textures/TextureData.h"
|
||||
#include "Engine/Graphics/PixelFormatExtensions.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Content/JsonAsset.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Editor/Editor.h"
|
||||
#include "Editor/ProjectInfo.h"
|
||||
#include "Editor/Cooker/GameCooker.h"
|
||||
#include "Editor/Utilities/EditorUtilities.h"
|
||||
|
||||
IMPLEMENT_SETTINGS_GETTER(iOSPlatformSettings, iOSPlatform);
|
||||
|
||||
namespace
|
||||
{
|
||||
String GetAppName()
|
||||
{
|
||||
const auto gameSettings = GameSettings::Get();
|
||||
String productName = gameSettings->ProductName;
|
||||
productName.Replace(TEXT(" "), TEXT(""));
|
||||
productName.Replace(TEXT("."), TEXT(""));
|
||||
productName.Replace(TEXT("-"), TEXT(""));
|
||||
return productName;
|
||||
}
|
||||
|
||||
const Char* GetExportMethod(iOSPlatformSettings::ExportMethods method)
|
||||
{
|
||||
switch (method)
|
||||
{
|
||||
case iOSPlatformSettings::ExportMethods::AppStore: return TEXT("app-store");
|
||||
case iOSPlatformSettings::ExportMethods::Development: return TEXT("development");
|
||||
case iOSPlatformSettings::ExportMethods::AdHoc: return TEXT("ad-hoc");
|
||||
case iOSPlatformSettings::ExportMethods::Enterprise: return TEXT("enterprise");
|
||||
default: return TEXT("");
|
||||
}
|
||||
}
|
||||
|
||||
String GetUIInterfaceOrientation(iOSPlatformSettings::UIInterfaceOrientations orientations)
|
||||
{
|
||||
String result;
|
||||
if (EnumHasAnyFlags(orientations, iOSPlatformSettings::UIInterfaceOrientations::Portrait))
|
||||
result += TEXT("UIInterfaceOrientationPortrait ");
|
||||
if (EnumHasAnyFlags(orientations, iOSPlatformSettings::UIInterfaceOrientations::PortraitUpsideDown))
|
||||
result += TEXT("UIInterfaceOrientationPortraitUpsideDown ");
|
||||
if (EnumHasAnyFlags(orientations, iOSPlatformSettings::UIInterfaceOrientations::LandscapeLeft))
|
||||
result += TEXT("UIInterfaceOrientationLandscapeLeft ");
|
||||
if (EnumHasAnyFlags(orientations, iOSPlatformSettings::UIInterfaceOrientations::LandscapeRight))
|
||||
result += TEXT("UIInterfaceOrientationLandscapeRight ");
|
||||
result = result.TrimTrailing();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
const Char* iOSPlatformTools::GetDisplayName() const
|
||||
{
|
||||
return TEXT("iOS");
|
||||
}
|
||||
|
||||
const Char* iOSPlatformTools::GetName() const
|
||||
{
|
||||
return TEXT("iOS");
|
||||
}
|
||||
|
||||
PlatformType iOSPlatformTools::GetPlatform() const
|
||||
{
|
||||
return PlatformType::iOS;
|
||||
}
|
||||
|
||||
ArchitectureType iOSPlatformTools::GetArchitecture() const
|
||||
{
|
||||
return ArchitectureType::ARM64;
|
||||
}
|
||||
|
||||
DotNetAOTModes iOSPlatformTools::UseAOT() const
|
||||
{
|
||||
return DotNetAOTModes::MonoAOTDynamic;
|
||||
}
|
||||
|
||||
PixelFormat iOSPlatformTools::GetTextureFormat(CookingData& data, TextureBase* texture, PixelFormat format)
|
||||
{
|
||||
// TODO: add ETC compression support for iOS
|
||||
// TODO: add ASTC compression support for iOS
|
||||
|
||||
if (PixelFormatExtensions::IsCompressedBC(format))
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case PixelFormat::BC1_Typeless:
|
||||
case PixelFormat::BC2_Typeless:
|
||||
case PixelFormat::BC3_Typeless:
|
||||
return PixelFormat::R8G8B8A8_Typeless;
|
||||
case PixelFormat::BC1_UNorm:
|
||||
case PixelFormat::BC2_UNorm:
|
||||
case PixelFormat::BC3_UNorm:
|
||||
return PixelFormat::R8G8B8A8_UNorm;
|
||||
case PixelFormat::BC1_UNorm_sRGB:
|
||||
case PixelFormat::BC2_UNorm_sRGB:
|
||||
case PixelFormat::BC3_UNorm_sRGB:
|
||||
return PixelFormat::R8G8B8A8_UNorm_sRGB;
|
||||
case PixelFormat::BC4_Typeless:
|
||||
return PixelFormat::R8_Typeless;
|
||||
case PixelFormat::BC4_UNorm:
|
||||
return PixelFormat::R8_UNorm;
|
||||
case PixelFormat::BC4_SNorm:
|
||||
return PixelFormat::R8_SNorm;
|
||||
case PixelFormat::BC5_Typeless:
|
||||
return PixelFormat::R16G16_Typeless;
|
||||
case PixelFormat::BC5_UNorm:
|
||||
return PixelFormat::R16G16_UNorm;
|
||||
case PixelFormat::BC5_SNorm:
|
||||
return PixelFormat::R16G16_SNorm;
|
||||
case PixelFormat::BC7_Typeless:
|
||||
case PixelFormat::BC6H_Typeless:
|
||||
return PixelFormat::R16G16B16A16_Typeless;
|
||||
case PixelFormat::BC7_UNorm:
|
||||
case PixelFormat::BC6H_Uf16:
|
||||
case PixelFormat::BC6H_Sf16:
|
||||
return PixelFormat::R16G16B16A16_Float;
|
||||
case PixelFormat::BC7_UNorm_sRGB:
|
||||
return PixelFormat::R16G16B16A16_UNorm;
|
||||
default:
|
||||
return format;
|
||||
}
|
||||
}
|
||||
|
||||
return format;
|
||||
}
|
||||
|
||||
bool iOSPlatformTools::IsNativeCodeFile(CookingData& data, const String& file)
|
||||
{
|
||||
String extension = FileSystem::GetExtension(file);
|
||||
return extension.IsEmpty() || extension == TEXT("dylib");
|
||||
}
|
||||
|
||||
void iOSPlatformTools::OnBuildStarted(CookingData& data)
|
||||
{
|
||||
// Adjust the cooking output folders for packaging app
|
||||
const Char* subDir = TEXT("FlaxGame/Data");
|
||||
data.DataOutputPath /= subDir;
|
||||
data.NativeCodeOutputPath /= subDir;
|
||||
data.ManagedCodeOutputPath /= subDir;
|
||||
|
||||
PlatformTools::OnBuildStarted(data);
|
||||
}
|
||||
|
||||
bool iOSPlatformTools::OnPostProcess(CookingData& data)
|
||||
{
|
||||
const auto gameSettings = GameSettings::Get();
|
||||
const auto platformSettings = iOSPlatformSettings::Get();
|
||||
const auto platformDataPath = data.GetPlatformBinariesRoot();
|
||||
const auto projectVersion = Editor::Project->Version.ToString();
|
||||
const auto appName = GetAppName();
|
||||
|
||||
// Setup package name (eg. com.company.project)
|
||||
String appIdentifier = platformSettings->AppIdentifier;
|
||||
if (EditorUtilities::FormatAppPackageName(appIdentifier))
|
||||
return true;
|
||||
|
||||
// Copy fresh Gradle project template
|
||||
if (FileSystem::CopyDirectory(data.OriginalOutputPath, platformDataPath / TEXT("Project"), true))
|
||||
{
|
||||
LOG(Error, "Failed to deploy XCode project to {0} from {1}", data.OriginalOutputPath, platformDataPath);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Format project template files
|
||||
Dictionary<String, String> configReplaceMap;
|
||||
configReplaceMap[TEXT("${AppName}")] = appName;
|
||||
configReplaceMap[TEXT("${AppIdentifier}")] = appIdentifier;
|
||||
configReplaceMap[TEXT("${AppTeamId}")] = platformSettings->AppTeamId;
|
||||
configReplaceMap[TEXT("${AppVersion}")] = platformSettings->AppVersion;
|
||||
configReplaceMap[TEXT("${ProjectName}")] = gameSettings->ProductName;
|
||||
configReplaceMap[TEXT("${ProjectVersion}")] = projectVersion;
|
||||
configReplaceMap[TEXT("${HeaderSearchPaths}")] = Globals::StartupFolder;
|
||||
configReplaceMap[TEXT("${ExportMethod}")] = GetExportMethod(platformSettings->ExportMethod);
|
||||
configReplaceMap[TEXT("${UISupportedInterfaceOrientations_iPhone}")] = GetUIInterfaceOrientation(platformSettings->SupportedInterfaceOrientationsiPhone);
|
||||
configReplaceMap[TEXT("${UISupportedInterfaceOrientations_iPad}")] = GetUIInterfaceOrientation(platformSettings->SupportedInterfaceOrientationsiPad);
|
||||
{
|
||||
// Initialize auto-generated areas as empty
|
||||
configReplaceMap[TEXT("${PBXBuildFile}")] = String::Empty;
|
||||
configReplaceMap[TEXT("${PBXCopyFilesBuildPhaseFiles}")] = String::Empty;
|
||||
configReplaceMap[TEXT("${PBXFileReference}")] = String::Empty;
|
||||
configReplaceMap[TEXT("${PBXFrameworksBuildPhase}")] = String::Empty;
|
||||
configReplaceMap[TEXT("${PBXFrameworksGroup}")] = String::Empty;
|
||||
configReplaceMap[TEXT("${PBXFilesGroup}")] = String::Empty;
|
||||
configReplaceMap[TEXT("${PBXResourcesGroup}")] = String::Empty;
|
||||
}
|
||||
{
|
||||
// Rename dotnet license files to not mislead the actual game licensing
|
||||
FileSystem::MoveFile(data.DataOutputPath / TEXT("Dotnet/DOTNET-LICENSE.TXT"), data.DataOutputPath / TEXT("Dotnet/LICENSE.TXT"), true);
|
||||
FileSystem::MoveFile(data.DataOutputPath / TEXT("Dotnet/DOTNET-THIRD-PARTY-NOTICES.TXT"), data.DataOutputPath / TEXT("Dotnet/THIRD-PARTY-NOTICES.TXT"), true);
|
||||
}
|
||||
Array<String> files;
|
||||
FileSystem::DirectoryGetFiles(files, data.DataOutputPath, TEXT("*"), DirectorySearchOption::AllDirectories);
|
||||
for (const String& file : files)
|
||||
{
|
||||
String name = StringUtils::GetFileName(file);
|
||||
if (name == TEXT(".DS_Store") || name == TEXT("FlaxGame"))
|
||||
continue;
|
||||
String fileId = Guid::New().ToString(Guid::FormatType::N).Left(24);
|
||||
String projectPath = FileSystem::ConvertAbsolutePathToRelative(data.DataOutputPath, file);
|
||||
if (name.EndsWith(TEXT(".dylib")))
|
||||
{
|
||||
String frameworkId = Guid::New().ToString(Guid::FormatType::N).Left(24);
|
||||
String frameworkEmbedId = Guid::New().ToString(Guid::FormatType::N).Left(24);
|
||||
configReplaceMap[TEXT("${PBXBuildFile}")] += String::Format(TEXT("\t\t{0} /* {1} in Frameworks */ = {{isa = PBXBuildFile; fileRef = {2} /* {1} */; }};\n"), frameworkId, name, fileId);
|
||||
configReplaceMap[TEXT("${PBXBuildFile}")] += String::Format(TEXT("\t\t{0} /* {1} in Embed Frameworks */ = {{isa = PBXBuildFile; fileRef = {2} /* {1} */; settings = {{ATTRIBUTES = (CodeSignOnCopy, ); }}; }};\n"), frameworkEmbedId, name, fileId);
|
||||
configReplaceMap[TEXT("${PBXCopyFilesBuildPhaseFiles}")] += String::Format(TEXT("\t\t\t\t{0} /* {1} in Embed Frameworks */,\n"), frameworkEmbedId, name);
|
||||
configReplaceMap[TEXT("${PBXFileReference}")] += String::Format(TEXT("\t\t{0} /* {1} */ = {{isa = PBXFileReference; lastKnownFileType = \"compiled.mach-o.dylib\"; name = \"{1}\"; path = \"FlaxGame/Data/{2}\"; sourceTree = \"<group>\"; }};\n"), fileId, name, projectPath);
|
||||
configReplaceMap[TEXT("${PBXFrameworksBuildPhase}")] += String::Format(TEXT("\t\t\t\t{0} /* {1} in Frameworks */,\n"), frameworkId, name);
|
||||
configReplaceMap[TEXT("${PBXFrameworksGroup}")] += String::Format(TEXT("\t\t\t\t{0} /* {1} */,\n"), fileId, name);
|
||||
}
|
||||
else
|
||||
{
|
||||
String fileRefId = Guid::New().ToString(Guid::FormatType::N).Left(24);
|
||||
configReplaceMap[TEXT("${PBXBuildFile}")] += String::Format(TEXT("\t\t{0} /* {1} in Resources */ = {{isa = PBXBuildFile; fileRef = {2} /* {1} */; }};\n"), fileRefId, name, fileId);
|
||||
configReplaceMap[TEXT("${PBXFileReference}")] += String::Format(TEXT("\t\t{0} /* {1} */ = {{isa = PBXFileReference; lastKnownFileType = file; name = \"{1}\"; path = \"Data/{2}\"; sourceTree = \"<group>\"; }};\n"), fileId, name, projectPath);
|
||||
configReplaceMap[TEXT("${PBXFilesGroup}")] += String::Format(TEXT("\t\t\t\t{0} /* {1} */,\n"), fileId, name);
|
||||
configReplaceMap[TEXT("${PBXResourcesGroup}")] += String::Format(TEXT("\t\t\t\t{0} /* {1} in Resources */,\n"), fileRefId, name);
|
||||
}
|
||||
}
|
||||
bool failed = false;
|
||||
failed |= EditorUtilities::ReplaceInFile(data.OriginalOutputPath / TEXT("FlaxGame.xcodeproj/project.pbxproj"), configReplaceMap);
|
||||
failed |= EditorUtilities::ReplaceInFile(data.OriginalOutputPath / TEXT("ExportOptions.plist"), configReplaceMap);
|
||||
if (failed)
|
||||
{
|
||||
LOG(Error, "Failed to format XCode project");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Export images
|
||||
// TODO: provide per-device icons (eg. iPad 1x, iPad 2x) instead of a single icon size
|
||||
TextureData iconData;
|
||||
if (!EditorUtilities::GetApplicationImage(platformSettings->OverrideIcon, iconData))
|
||||
{
|
||||
String outputPath = data.OriginalOutputPath / TEXT("FlaxGame/Assets.xcassets/AppIcon.appiconset/ios_store_icon.png");
|
||||
if (EditorUtilities::ExportApplicationImage(iconData, 1024, 1024, PixelFormat::R8G8B8A8_UNorm, outputPath))
|
||||
{
|
||||
LOG(Error, "Failed to export application icon.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Package application
|
||||
const auto buildSettings = BuildSettings::Get();
|
||||
if (buildSettings->SkipPackaging)
|
||||
return false;
|
||||
GameCooker::PackageFiles();
|
||||
{
|
||||
LOG(Info, "Building app package...");
|
||||
const Char* configuration = data.Configuration == BuildConfiguration::Release ? TEXT("Release") : TEXT("Debug");
|
||||
String command = String::Format(TEXT("xcodebuild -project FlaxGame.xcodeproj -configuration {} -scheme FlaxGame -archivePath FlaxGame.xcarchive archive"), configuration);
|
||||
int32 result = Platform::RunProcess(command, data.OriginalOutputPath);
|
||||
if (result != 0)
|
||||
{
|
||||
data.Error(String::Format(TEXT("Failed to package app (result code: {0}). See log for more info."), result));
|
||||
return true;
|
||||
}
|
||||
command = TEXT("xcodebuild -exportArchive -archivePath FlaxGame.xcarchive -allowProvisioningUpdates -exportPath . -exportOptionsPlist ExportOptions.plist");
|
||||
result = Platform::RunProcess(command, data.OriginalOutputPath);
|
||||
if (result != 0)
|
||||
{
|
||||
data.Error(String::Format(TEXT("Failed to package app (result code: {0}). See log for more info."), result));
|
||||
return true;
|
||||
}
|
||||
const String ipaPath = data.OriginalOutputPath / TEXT("FlaxGame.ipa");
|
||||
LOG(Info, "Output application package: {0} (size: {1} MB)", ipaPath, FileSystem::GetFileSize(ipaPath) / 1024 / 1024);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if PLATFORM_TOOLS_IOS
|
||||
|
||||
#include "../../PlatformTools.h"
|
||||
|
||||
/// <summary>
|
||||
/// The iOS platform support tools.
|
||||
/// </summary>
|
||||
class iOSPlatformTools : public PlatformTools
|
||||
{
|
||||
public:
|
||||
// [PlatformTools]
|
||||
const Char* GetDisplayName() const override;
|
||||
const Char* GetName() const override;
|
||||
PlatformType GetPlatform() const override;
|
||||
ArchitectureType GetArchitecture() const override;
|
||||
DotNetAOTModes UseAOT() const override;
|
||||
PixelFormat GetTextureFormat(CookingData& data, TextureBase* texture, PixelFormat format) override;
|
||||
bool IsNativeCodeFile(CookingData& data, const String& file) override;
|
||||
void OnBuildStarted(CookingData& data) override;
|
||||
bool OnPostProcess(CookingData& data) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright (c) 2012-2019 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CookingData.h"
|
||||
#include "Engine/Core/Collections/Dictionary.h"
|
||||
#include "Editor/Scripting/ScriptsBuilder.h"
|
||||
#include "Engine/Graphics/PixelFormat.h"
|
||||
|
||||
@@ -15,7 +14,6 @@ class TextureBase;
|
||||
class FLAXENGINE_API PlatformTools
|
||||
{
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes an instance of the <see cref="PlatformTools"/> class.
|
||||
/// </summary>
|
||||
@@ -24,32 +22,35 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the name of the platform for UI and logging.
|
||||
/// </summary>
|
||||
/// <returns>The name.</returns>
|
||||
virtual const Char* GetDisplayName() const = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the platform for filesystem cache directories, deps folder.
|
||||
/// </summary>
|
||||
/// <returns>The name.</returns>
|
||||
virtual const Char* GetName() const = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of the platform.
|
||||
/// </summary>
|
||||
/// <returns>The platform type.</returns>
|
||||
virtual PlatformType GetPlatform() const = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the architecture of the platform.
|
||||
/// </summary>
|
||||
/// <returns>The architecture type.</returns>
|
||||
virtual ArchitectureType GetArchitecture() const = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value indicating whenever platform requires AOT.
|
||||
/// Gets the value indicating whenever platform requires AOT (needs C# assemblies to be precompiled).
|
||||
/// </summary>
|
||||
/// <returns>True if platform uses AOT and needs C# assemblies to be precompiled, otherwise false.</returns>
|
||||
virtual bool UseAOT() const
|
||||
virtual DotNetAOTModes UseAOT() const
|
||||
{
|
||||
return DotNetAOTModes::None;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value indicating whenever platform supports using system-installed .Net Runtime.
|
||||
/// </summary>
|
||||
virtual bool UseSystemDotnet() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -72,13 +73,9 @@ public:
|
||||
/// <param name="data">The cooking data.</param>
|
||||
/// <param name="file">The file path.</param>
|
||||
/// <returns>True if it's a native file, otherwise false.<returns>
|
||||
virtual bool IsNativeCodeFile(CookingData& data, const String& file)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
virtual bool IsNativeCodeFile(CookingData& data, const String& file);
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Called when game building starts.
|
||||
/// </summary>
|
||||
@@ -136,64 +133,6 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The C# scripts AOT configuration options.
|
||||
/// </summary>
|
||||
struct AotConfig
|
||||
{
|
||||
String AotCompilerPath;
|
||||
String AotCompilerArgs;
|
||||
String AssemblerPath;
|
||||
String AssemblerArgs;
|
||||
String ArchiverPath;
|
||||
String ArchiverArgs;
|
||||
String AuxToolPath;
|
||||
String AuxToolArgs;
|
||||
String AotCachePath;
|
||||
Dictionary<String, String> EnvVars;
|
||||
Array<String> AssembliesSearchDirs;
|
||||
Array<String> Assemblies;
|
||||
|
||||
AotConfig(CookingData& data)
|
||||
{
|
||||
Platform::GetEnvironmentVariables(EnvVars);
|
||||
EnvVars[TEXT("MONO_PATH")] = data.DataOutputPath / TEXT("Mono/lib/mono/4.5");
|
||||
AssembliesSearchDirs.Add(data.DataOutputPath / TEXT("Mono/lib/mono/4.5"));
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Called to configure AOT options.
|
||||
/// </summary>
|
||||
/// <param name="data">The cooking data.</param>
|
||||
/// <param name="config">The configuration.</param>
|
||||
virtual void OnConfigureAOT(CookingData& data, AotConfig& config)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called to execute AOT for the given assembly.
|
||||
/// </summary>
|
||||
/// <param name="data">The cooking data.</param>
|
||||
/// <param name="config">The configuration.</param>
|
||||
/// <param name="assemblyPath">The input managed library file path.</param>
|
||||
/// <returns>True if failed, otherwise false.<returns>
|
||||
virtual bool OnPerformAOT(CookingData& data, AotConfig& config, const String& assemblyPath)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called after AOT execution for the assemblies.
|
||||
/// </summary>
|
||||
/// <param name="data">The cooking data.</param>
|
||||
/// <param name="config">The configuration.</param>
|
||||
/// <returns>True if failed, otherwise false.<returns>
|
||||
virtual bool OnPostProcessAOT(CookingData& data, AotConfig& config)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called during staged build post-processing.
|
||||
/// </summary>
|
||||
|
||||
@@ -95,8 +95,8 @@ bool CompileScriptsStep::DeployBinaries(CookingData& data, const String& path, c
|
||||
Scripting::ProcessBuildInfoPath(e.NativePath, projectFolderPath);
|
||||
Scripting::ProcessBuildInfoPath(e.ManagedPath, projectFolderPath);
|
||||
|
||||
e.NativePath = StringUtils::GetFileName(e.NativePath);
|
||||
e.ManagedPath = StringUtils::GetFileName(e.ManagedPath);
|
||||
e.NativePath = String(StringUtils::GetFileName(e.NativePath));
|
||||
e.ManagedPath = String(StringUtils::GetFileName(e.ManagedPath));
|
||||
|
||||
LOG(Info, "Collecting binary module {0}", e.Name);
|
||||
}
|
||||
@@ -129,7 +129,7 @@ bool CompileScriptsStep::DeployBinaries(CookingData& data, const String& path, c
|
||||
continue;
|
||||
if (FileSystem::CopyFile(dst, file))
|
||||
{
|
||||
data.Error(TEXT("Failed to copy file from {0} to {1}."), file, dst);
|
||||
data.Error(String::Format(TEXT("Failed to copy file from {0} to {1}."), file, dst));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -154,60 +154,7 @@ bool CompileScriptsStep::Perform(CookingData& data)
|
||||
String target = project->GameTarget;
|
||||
StringView workingDir;
|
||||
const Char *platform, *architecture, *configuration = ::ToString(data.Configuration);
|
||||
switch (data.Platform)
|
||||
{
|
||||
case BuildPlatform::Windows32:
|
||||
platform = TEXT("Windows");
|
||||
architecture = TEXT("x86");
|
||||
break;
|
||||
case BuildPlatform::Windows64:
|
||||
platform = TEXT("Windows");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::UWPx86:
|
||||
platform = TEXT("UWP");
|
||||
architecture = TEXT("x86");
|
||||
break;
|
||||
case BuildPlatform::UWPx64:
|
||||
platform = TEXT("UWP");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::XboxOne:
|
||||
platform = TEXT("XboxOne");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::LinuxX64:
|
||||
platform = TEXT("Linux");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::PS4:
|
||||
platform = TEXT("PS4");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::XboxScarlett:
|
||||
platform = TEXT("XboxScarlett");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::AndroidARM64:
|
||||
platform = TEXT("Android");
|
||||
architecture = TEXT("ARM64");
|
||||
break;
|
||||
case BuildPlatform::Switch:
|
||||
platform = TEXT("Switch");
|
||||
architecture = TEXT("ARM64");
|
||||
break;
|
||||
case BuildPlatform::PS5:
|
||||
platform = TEXT("PS5");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::MacOSx64:
|
||||
platform = TEXT("Mac");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
default:
|
||||
LOG(Error, "Unknown or unsupported build platform.");
|
||||
return true;
|
||||
}
|
||||
data.GetBuildPlatformName(platform, architecture);
|
||||
String targetBuildInfo = project->ProjectFolderPath / TEXT("Binaries") / target / platform / architecture / configuration / target + TEXT(".Build.json");
|
||||
if (target.IsEmpty())
|
||||
{
|
||||
@@ -241,8 +188,8 @@ bool CompileScriptsStep::Perform(CookingData& data)
|
||||
LOG(Info, "Starting scripts compilation for game...");
|
||||
const String logFile = data.CacheDirectory / TEXT("CompileLog.txt");
|
||||
auto args = String::Format(
|
||||
TEXT("-log -logfile=\"{4}\" -build -mutex -buildtargets={0} -platform={1} -arch={2} -configuration={3}"),
|
||||
target, platform, architecture, configuration, logFile);
|
||||
TEXT("-log -logfile=\"{4}\" -build -mutex -buildtargets={0} -platform={1} -arch={2} -configuration={3} -aotMode={5}"),
|
||||
target, platform, architecture, configuration, logFile, ToString(data.Tools->UseAOT()));
|
||||
#if PLATFORM_WINDOWS
|
||||
if (data.Platform == BuildPlatform::LinuxX64)
|
||||
#elif PLATFORM_LINUX
|
||||
@@ -257,7 +204,7 @@ bool CompileScriptsStep::Perform(CookingData& data)
|
||||
// Assume FlaxGame was prebuilt for target platform
|
||||
args += TEXT(" -SkipTargets=FlaxGame");
|
||||
}
|
||||
for (auto& define : data.CustomDefines)
|
||||
for (const String& define : data.CustomDefines)
|
||||
{
|
||||
args += TEXT(" -D");
|
||||
args += define;
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "Engine/Engine/Base/GameBase.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Engine/Tools/TextureTool/TextureTool.h"
|
||||
#include "Engine/Scripting/Enums.h"
|
||||
#if PLATFORM_TOOLS_WINDOWS
|
||||
#include "Engine/Platform/Windows/WindowsPlatformSettings.h"
|
||||
#endif
|
||||
@@ -327,8 +328,8 @@ bool CookAssetsStep::ProcessDefaultAsset(AssetCookData& options)
|
||||
{
|
||||
// Use compact json
|
||||
rapidjson_flax::StringBuffer buffer;
|
||||
rapidjson_flax::Writer<rapidjson_flax::StringBuffer> writer(buffer);
|
||||
asJsonAsset->Document.Accept(writer);
|
||||
CompactJsonWriter writerObj(buffer);
|
||||
asJsonAsset->Save(writerObj);
|
||||
|
||||
// Store json data in the first chunk
|
||||
auto chunk = New<FlaxChunk>();
|
||||
@@ -409,7 +410,7 @@ bool ProcessShaderBase(CookAssetsStep::AssetCookData& data, ShaderAssetBase* ass
|
||||
assetBase->InitCompilationOptions(options); \
|
||||
if (ShadersCompilation::Compile(options)) \
|
||||
{ \
|
||||
data.Data.Error(TEXT("Failed to compile shader '{0}' (profile: {1})."), asset->ToString(), ::ToString(options.Profile)); \
|
||||
data.Data.Error(String::Format(TEXT("Failed to compile shader '{0}' (profile: {1})."), asset->ToString(), ::ToString(options.Profile))); \
|
||||
return true; \
|
||||
} \
|
||||
includes.Clear(); \
|
||||
@@ -528,11 +529,20 @@ bool ProcessShaderBase(CookAssetsStep::AssetCookData& data, ShaderAssetBase* ass
|
||||
#endif
|
||||
#if PLATFORM_TOOLS_MAC
|
||||
case BuildPlatform::MacOSx64:
|
||||
case BuildPlatform::MacOSARM64:
|
||||
{
|
||||
const char* platformDefineName = "PLATFORM_MAC";
|
||||
COMPILE_PROFILE(Vulkan_SM5, SHADER_FILE_CHUNK_INTERNAL_VULKAN_SM5_CACHE);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if PLATFORM_TOOLS_IOS
|
||||
case BuildPlatform::iOSARM64:
|
||||
{
|
||||
const char* platformDefineName = "PLATFORM_IOS";
|
||||
COMPILE_PROFILE(Vulkan_SM5, SHADER_FILE_CHUNK_INTERNAL_VULKAN_SM5_CACHE);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
{
|
||||
@@ -647,7 +657,7 @@ bool ProcessTextureBase(CookAssetsStep::AssetCookData& data)
|
||||
// Convert texture data to the target format
|
||||
if (TextureTool::Convert(textureDataTmp1, *textureData, targetFormat))
|
||||
{
|
||||
LOG(Error, "Failed to convert texture {0} from format {1} to {2}", asset->ToString(), (int32)format, (int32)targetFormat);
|
||||
LOG(Error, "Failed to convert texture {0} from format {1} to {2}", asset->ToString(), ScriptingEnum::ToString(format), ScriptingEnum::ToString(targetFormat));
|
||||
return true;
|
||||
}
|
||||
textureData = &textureDataTmp1;
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "DeployDataStep.h"
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Editor/Cooker/PlatformTools.h"
|
||||
#include "Engine/Core/Collections/Sorting.h"
|
||||
#include "Engine/Core/Config/BuildSettings.h"
|
||||
#include "Engine/Core/Config/GameSettings.h"
|
||||
#include "Engine/Renderer/ReflectionsPass.h"
|
||||
#include "Engine/Renderer/AntiAliasing/SMAA.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Editor/Cooker/PlatformTools.h"
|
||||
#include "Editor/Utilities/EditorUtilities.h"
|
||||
|
||||
bool DeployDataStep::Perform(CookingData& data)
|
||||
{
|
||||
data.StepProgress(TEXT("Deploying engine data"), 0);
|
||||
const String depsRoot = data.GetPlatformBinariesRoot();
|
||||
const auto gameSettings = GameSettings::Get();
|
||||
const auto& gameSettings = *GameSettings::Get();
|
||||
const auto& buildSettings = *BuildSettings::Get();
|
||||
|
||||
// Setup output folders and copy required data
|
||||
const auto contentDir = data.DataOutputPath / TEXT("Content");
|
||||
@@ -26,22 +30,275 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
Platform::Sleep(10);
|
||||
}
|
||||
FileSystem::CreateDirectory(contentDir);
|
||||
const auto srcMono = depsRoot / TEXT("Mono");
|
||||
const auto dstMono = data.DataOutputPath / TEXT("Mono");
|
||||
const String dstMono = data.DataOutputPath / TEXT("Mono");
|
||||
#if USE_NETCORE
|
||||
{
|
||||
// Remove old Mono files
|
||||
FileSystem::DeleteDirectory(dstMono);
|
||||
FileSystem::DeleteFile(data.DataOutputPath / TEXT("MonoPosixHelper.dll"));
|
||||
}
|
||||
String dstDotnet = data.DataOutputPath / TEXT("Dotnet");
|
||||
const DotNetAOTModes aotMode = data.Tools->UseAOT();
|
||||
const bool usAOT = aotMode != DotNetAOTModes::None;
|
||||
if (usAOT)
|
||||
{
|
||||
// Deploy Dotnet files into intermediate cooking directory for AOT
|
||||
FileSystem::DeleteDirectory(dstDotnet);
|
||||
dstDotnet = data.ManagedCodeOutputPath;
|
||||
}
|
||||
if (buildSettings.SkipDotnetPackaging && data.Tools->UseSystemDotnet())
|
||||
{
|
||||
// Use system-installed .Net Runtime
|
||||
FileSystem::DeleteDirectory(dstDotnet);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Deploy .Net Runtime files
|
||||
FileSystem::CreateDirectory(dstDotnet);
|
||||
String srcDotnet = depsRoot / TEXT("Dotnet");
|
||||
if (FileSystem::DirectoryExists(srcDotnet))
|
||||
{
|
||||
// Use prebuilt .Net installation for that platform
|
||||
LOG(Info, "Using .Net Runtime {} at {}", data.Tools->GetName(), srcDotnet);
|
||||
if (EditorUtilities::CopyDirectoryIfNewer(dstDotnet, srcDotnet, true))
|
||||
{
|
||||
data.Error(TEXT("Failed to copy .Net runtime data files."));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool canUseSystemDotnet = false;
|
||||
switch (data.Platform)
|
||||
{
|
||||
case BuildPlatform::Windows32:
|
||||
case BuildPlatform::Windows64:
|
||||
canUseSystemDotnet = PLATFORM_TYPE == PlatformType::Windows;
|
||||
break;
|
||||
case BuildPlatform::LinuxX64:
|
||||
canUseSystemDotnet = PLATFORM_TYPE == PlatformType::Linux;
|
||||
break;
|
||||
case BuildPlatform::MacOSx64:
|
||||
case BuildPlatform::MacOSARM64:
|
||||
canUseSystemDotnet = PLATFORM_TYPE == PlatformType::Mac;
|
||||
break;
|
||||
}
|
||||
if (canUseSystemDotnet && (aotMode == DotNetAOTModes::None || aotMode == DotNetAOTModes::ILC))
|
||||
{
|
||||
// Ask Flax.Build to provide .Net SDK location for the current platform
|
||||
String sdks;
|
||||
bool failed = ScriptsBuilder::RunBuildTool(TEXT("-log -logMessagesOnly -logFileWithConsole -logfile=SDKs.txt -printSDKs"), data.CacheDirectory);
|
||||
failed |= File::ReadAllText(data.CacheDirectory / TEXT("SDKs.txt"), sdks);
|
||||
int32 idx = sdks.Find(TEXT("DotNetSdk, "), StringSearchCase::CaseSensitive);
|
||||
if (idx != -1)
|
||||
{
|
||||
idx = sdks.Find(TEXT(", "), StringSearchCase::CaseSensitive, idx + 12);
|
||||
idx += 2;
|
||||
int32 end = sdks.Find(TEXT("\n"), StringSearchCase::CaseSensitive, idx);
|
||||
if (sdks[end] == '\r')
|
||||
end--;
|
||||
srcDotnet = String(sdks.Get() + idx, end - idx).TrimTrailing();
|
||||
}
|
||||
if (failed || !FileSystem::DirectoryExists(srcDotnet))
|
||||
{
|
||||
data.Error(TEXT("Failed to get .Net SDK location for a current platform."));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Select version to use
|
||||
Array<String> versions;
|
||||
FileSystem::GetChildDirectories(versions, srcDotnet / TEXT("host/fxr"));
|
||||
if (versions.Count() == 0)
|
||||
{
|
||||
data.Error(TEXT("Failed to get .Net SDK location for a current platform."));
|
||||
return true;
|
||||
}
|
||||
for (String& version : versions)
|
||||
{
|
||||
version = String(StringUtils::GetFileName(version));
|
||||
if (!version.StartsWith(TEXT("7.")))
|
||||
version.Clear();
|
||||
}
|
||||
Sorting::QuickSort(versions.Get(), versions.Count());
|
||||
const String version = versions.Last();
|
||||
FileSystem::NormalizePath(srcDotnet);
|
||||
LOG(Info, "Using .Net Runtime {} at {}", version, srcDotnet);
|
||||
|
||||
// Check if previously deployed files are valid (eg. system-installed .NET was updated from version 7.0.3 to 7.0.5)
|
||||
{
|
||||
const String dotnetCacheFilePath = data.CacheDirectory / TEXT("SystemDotnetInfo.txt");
|
||||
String dotnetCachedValue = String::Format(TEXT("{};{}"), version, srcDotnet);
|
||||
if (FileSystem::DirectoryExists(dstDotnet))
|
||||
{
|
||||
String cachedData;
|
||||
File::ReadAllText(dotnetCacheFilePath, cachedData);
|
||||
if (cachedData != dotnetCachedValue)
|
||||
{
|
||||
FileSystem::DeleteDirectory(dstDotnet);
|
||||
FileSystem::CreateDirectory(dstDotnet);
|
||||
}
|
||||
}
|
||||
File::WriteAllText(dotnetCacheFilePath, dotnetCachedValue, Encoding::ANSI);
|
||||
}
|
||||
|
||||
// Deploy runtime files
|
||||
FileSystem::CopyFile(dstDotnet / TEXT("LICENSE.TXT"), srcDotnet / TEXT("LICENSE.txt"));
|
||||
FileSystem::CopyFile(dstDotnet / TEXT("LICENSE.TXT"), srcDotnet / TEXT("LICENSE.TXT"));
|
||||
FileSystem::CopyFile(dstDotnet / TEXT("THIRD-PARTY-NOTICES.TXT"), srcDotnet / TEXT("ThirdPartyNotices.txt"));
|
||||
FileSystem::CopyFile(dstDotnet / TEXT("THIRD-PARTY-NOTICES.TXT"), srcDotnet / TEXT("THIRD-PARTY-NOTICES.TXT"));
|
||||
if (usAOT)
|
||||
{
|
||||
failed |= EditorUtilities::CopyDirectoryIfNewer(dstDotnet, srcDotnet / TEXT("shared/Microsoft.NETCore.App") / version, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
failed |= EditorUtilities::CopyDirectoryIfNewer(dstDotnet / TEXT("host/fxr") / version, srcDotnet / TEXT("host/fxr") / version, true);
|
||||
failed |= EditorUtilities::CopyDirectoryIfNewer(dstDotnet / TEXT("shared/Microsoft.NETCore.App") / version, srcDotnet / TEXT("shared/Microsoft.NETCore.App") / version, true);
|
||||
}
|
||||
if (failed)
|
||||
{
|
||||
data.Error(TEXT("Failed to copy .Net runtime data files."));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ask Flax.Build to provide .Net Host Runtime location for the target platform
|
||||
String sdks;
|
||||
const Char *platformName, *archName;
|
||||
data.GetBuildPlatformName(platformName, archName);
|
||||
String args = String::Format(TEXT("-log -logMessagesOnly -logFileWithConsole -logfile=SDKs.txt -printDotNetRuntime -platform={} -arch={}"), platformName, archName);
|
||||
bool failed = ScriptsBuilder::RunBuildTool(args, data.CacheDirectory);
|
||||
failed |= File::ReadAllText(data.CacheDirectory / TEXT("SDKs.txt"), sdks);
|
||||
Array<String> parts;
|
||||
sdks.Split(',', parts);
|
||||
failed |= parts.Count() != 3;
|
||||
if (!failed)
|
||||
{
|
||||
srcDotnet = parts[2].TrimTrailing();
|
||||
}
|
||||
if (failed || !FileSystem::DirectoryExists(srcDotnet))
|
||||
{
|
||||
data.Error(TEXT("Failed to get .Net SDK location for a current platform."));
|
||||
return true;
|
||||
}
|
||||
FileSystem::NormalizePath(srcDotnet);
|
||||
LOG(Info, "Using .Net Runtime {} at {}", TEXT("Host"), srcDotnet);
|
||||
|
||||
// Deploy runtime files
|
||||
const Char* corlibPrivateName = TEXT("System.Private.CoreLib.dll");
|
||||
const bool srcDotnetFromEngine = srcDotnet.Contains(TEXT("Source/Platforms"));
|
||||
String packFolder = srcDotnet / TEXT("../../../");
|
||||
String dstDotnetLibs = dstDotnet, srcDotnetLibs = srcDotnet;
|
||||
StringUtils::PathRemoveRelativeParts(packFolder);
|
||||
if (usAOT)
|
||||
{
|
||||
if (srcDotnetFromEngine)
|
||||
{
|
||||
// AOT runtime files inside Engine Platform folder
|
||||
packFolder /= TEXT("Dotnet");
|
||||
dstDotnetLibs /= TEXT("lib/net7.0");
|
||||
srcDotnetLibs = packFolder / TEXT("lib/net7.0");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Runtime files inside Dotnet SDK folder but placed for AOT
|
||||
dstDotnetLibs /= TEXT("lib/net7.0");
|
||||
srcDotnetLibs /= TEXT("../lib/net7.0");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (srcDotnetFromEngine)
|
||||
{
|
||||
// Runtime files inside Engine Platform folder
|
||||
dstDotnetLibs /= TEXT("lib/net7.0");
|
||||
srcDotnetLibs /= TEXT("lib/net7.0");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Runtime files inside Dotnet SDK folder
|
||||
dstDotnetLibs /= TEXT("shared/Microsoft.NETCore.App");
|
||||
srcDotnetLibs /= TEXT("../lib/net7.0");
|
||||
}
|
||||
}
|
||||
FileSystem::CopyFile(dstDotnet / TEXT("LICENSE.TXT"), packFolder / TEXT("LICENSE.txt"));
|
||||
FileSystem::CopyFile(dstDotnet / TEXT("LICENSE.TXT"), packFolder / TEXT("LICENSE.TXT"));
|
||||
FileSystem::CopyFile(dstDotnet / TEXT("THIRD-PARTY-NOTICES.TXT"), packFolder / TEXT("ThirdPartyNotices.txt"));
|
||||
FileSystem::CopyFile(dstDotnet / TEXT("THIRD-PARTY-NOTICES.TXT"), packFolder / TEXT("THIRD-PARTY-NOTICES.TXT"));
|
||||
failed |= EditorUtilities::CopyDirectoryIfNewer(dstDotnetLibs, srcDotnetLibs, true);
|
||||
if (FileSystem::FileExists(srcDotnet / corlibPrivateName))
|
||||
failed |= EditorUtilities::CopyFileIfNewer(dstDotnetLibs / corlibPrivateName, srcDotnet / corlibPrivateName);
|
||||
switch (data.Platform)
|
||||
{
|
||||
#define DEPLOY_NATIVE_FILE(filename) failed |= FileSystem::CopyFile(data.NativeCodeOutputPath / TEXT(filename), srcDotnet / TEXT(filename));
|
||||
case BuildPlatform::AndroidARM64:
|
||||
if (data.Configuration != BuildConfiguration::Release)
|
||||
{
|
||||
DEPLOY_NATIVE_FILE("libmono-component-debugger.so");
|
||||
DEPLOY_NATIVE_FILE("libmono-component-diagnostics_tracing.so");
|
||||
DEPLOY_NATIVE_FILE("libmono-component-hot_reload.so");
|
||||
}
|
||||
DEPLOY_NATIVE_FILE("libmonosgen-2.0.so");
|
||||
DEPLOY_NATIVE_FILE("libSystem.IO.Compression.Native.so");
|
||||
DEPLOY_NATIVE_FILE("libSystem.Native.so");
|
||||
DEPLOY_NATIVE_FILE("libSystem.Security.Cryptography.Native.Android.so");
|
||||
break;
|
||||
case BuildPlatform::iOSARM64:
|
||||
DEPLOY_NATIVE_FILE("libmonosgen-2.0.dylib");
|
||||
DEPLOY_NATIVE_FILE("libSystem.IO.Compression.Native.dylib");
|
||||
DEPLOY_NATIVE_FILE("libSystem.Native.dylib");
|
||||
DEPLOY_NATIVE_FILE("libSystem.Net.Security.Native.dylib");
|
||||
DEPLOY_NATIVE_FILE("libSystem.Security.Cryptography.Native.Apple.dylib");
|
||||
break;
|
||||
#undef DEPLOY_NATIVE_FILE
|
||||
default: ;
|
||||
}
|
||||
if (failed)
|
||||
{
|
||||
data.Error(TEXT("Failed to copy .Net runtime data files."));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Optimize deployed C# class library (remove DLLs unused by scripts)
|
||||
if (aotMode == DotNetAOTModes::None && buildSettings.SkipUnusedDotnetLibsPackaging)
|
||||
{
|
||||
LOG(Info, "Optimizing .NET class library size to include only used assemblies");
|
||||
const String logFile = data.CacheDirectory / TEXT("StripDotnetLibs.txt");
|
||||
String args = String::Format(
|
||||
TEXT("-log -logfile=\"{}\" -runDotNetClassLibStripping -mutex -binaries=\"{}\""),
|
||||
logFile, data.DataOutputPath);
|
||||
for (const String& define : data.CustomDefines)
|
||||
{
|
||||
args += TEXT(" -D");
|
||||
args += define;
|
||||
}
|
||||
if (ScriptsBuilder::RunBuildTool(args))
|
||||
{
|
||||
data.Error(TEXT("Failed to optimize .Net class library."));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (!FileSystem::DirectoryExists(dstMono))
|
||||
{
|
||||
// Deploy Mono files (from platform data folder)
|
||||
const String srcMono = depsRoot / TEXT("Mono");
|
||||
if (!FileSystem::DirectoryExists(srcMono))
|
||||
{
|
||||
data.Error(TEXT("Missing Mono runtime data files."));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (FileSystem::CopyDirectory(dstMono, srcMono, true))
|
||||
{
|
||||
data.Error(TEXT("Failed to copy Mono runtime data files."));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Deploy engine data for the target platform
|
||||
if (data.Tools->OnDeployBinaries(data))
|
||||
@@ -82,7 +339,7 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
data.AddRootEngineAsset(TEXT("Engine/DefaultMaterial"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/DefaultDeformableMaterial"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/DefaultTerrainMaterial"));
|
||||
if (!gameSettings->NoSplashScreen && !gameSettings->SplashScreen.IsValid())
|
||||
if (!gameSettings.NoSplashScreen && !gameSettings.SplashScreen.IsValid())
|
||||
data.AddRootEngineAsset(TEXT("Engine/Textures/Logo"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/Textures/NormalTexture"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/Textures/BlackTexture"));
|
||||
@@ -112,7 +369,6 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
|
||||
// Register game assets
|
||||
data.StepProgress(TEXT("Deploying game data"), 50);
|
||||
auto& buildSettings = *BuildSettings::Get();
|
||||
for (auto& e : buildSettings.AdditionalAssets)
|
||||
data.AddRootAsset(e.GetID());
|
||||
for (auto& e : buildSettings.AdditionalScenes)
|
||||
|
||||
@@ -2,9 +2,20 @@
|
||||
|
||||
#include "PostProcessStep.h"
|
||||
#include "Editor/Cooker/PlatformTools.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
|
||||
bool PostProcessStep::Perform(CookingData& data)
|
||||
{
|
||||
// Print .NET stats
|
||||
const DotNetAOTModes aotMode = data.Tools->UseAOT();
|
||||
uint64 outputSize = FileSystem::GetDirectorySize(data.DataOutputPath / TEXT("Dotnet"));
|
||||
if (aotMode == DotNetAOTModes::None)
|
||||
{
|
||||
for (auto& binaryModule : data.BinaryModules)
|
||||
outputSize += FileSystem::GetFileSize(data.DataOutputPath / binaryModule.ManagedPath);
|
||||
}
|
||||
LOG(Info, "Output .NET files size: {0} MB", (uint32)(outputSize / (1024ull * 1024)));
|
||||
|
||||
GameCooker::PostProcessFiles();
|
||||
return data.Tools->OnPostProcess(data);
|
||||
}
|
||||
|
||||
@@ -1,78 +1,86 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "PrecompileAssembliesStep.h"
|
||||
#include "Editor/Scripting/ScriptsBuilder.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Core/Config/BuildSettings.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Editor/Scripting/ScriptsBuilder.h"
|
||||
#include "Editor/Cooker/PlatformTools.h"
|
||||
#include "Editor/Utilities/EditorUtilities.h"
|
||||
|
||||
void PrecompileAssembliesStep::OnBuildStarted(CookingData& data)
|
||||
{
|
||||
const DotNetAOTModes aotMode = data.Tools->UseAOT();
|
||||
if (aotMode == DotNetAOTModes::None)
|
||||
return;
|
||||
const auto& buildSettings = *BuildSettings::Get();
|
||||
|
||||
// Redirect C# assemblies to intermediate cooking directory (processed by ILC)
|
||||
data.ManagedCodeOutputPath = data.CacheDirectory / TEXT("AOTAssemblies");
|
||||
|
||||
// Reset any AOT cache from previous run if the AOT mode has changed (eg. Mono AOT -> ILC on Desktop)
|
||||
const String aotModeCacheFilePath = data.ManagedCodeOutputPath / TEXT("AOTMode.txt");
|
||||
String aotModeCacheValue = String::Format(TEXT("{};{};{};{}"),
|
||||
(int32)aotMode,
|
||||
(int32)data.Configuration,
|
||||
(int32)buildSettings.SkipUnusedDotnetLibsPackaging,
|
||||
FileSystem::GetFileLastEditTime(ScriptsBuilder::GetBuildToolPath()).Ticks);
|
||||
for (const String& define : data.CustomDefines)
|
||||
aotModeCacheValue += define;
|
||||
if (FileSystem::DirectoryExists(data.ManagedCodeOutputPath))
|
||||
{
|
||||
String cachedData;
|
||||
File::ReadAllText(aotModeCacheFilePath, cachedData);
|
||||
if (cachedData != aotModeCacheValue)
|
||||
{
|
||||
LOG(Info, "AOT cache invalidation");
|
||||
FileSystem::DeleteDirectory(data.ManagedCodeOutputPath);
|
||||
}
|
||||
}
|
||||
if (!FileSystem::DirectoryExists(data.ManagedCodeOutputPath))
|
||||
{
|
||||
FileSystem::CreateDirectory(data.ManagedCodeOutputPath);
|
||||
File::WriteAllText(aotModeCacheFilePath, aotModeCacheValue, Encoding::ANSI);
|
||||
}
|
||||
}
|
||||
|
||||
bool PrecompileAssembliesStep::Perform(CookingData& data)
|
||||
{
|
||||
// Skip for some platforms
|
||||
if (!data.Tools->UseAOT())
|
||||
const DotNetAOTModes aotMode = data.Tools->UseAOT();
|
||||
if (aotMode == DotNetAOTModes::None)
|
||||
return false;
|
||||
const auto& buildSettings = *BuildSettings::Get();
|
||||
if (buildSettings.SkipDotnetPackaging && data.Tools->UseSystemDotnet())
|
||||
return false;
|
||||
LOG(Info, "Using AOT...");
|
||||
|
||||
// Useful references about AOT:
|
||||
// http://www.mono-project.com/docs/advanced/runtime/docs/aot/
|
||||
// http://www.mono-project.com/docs/advanced/aot/
|
||||
|
||||
const String infoMsg = TEXT("Running AOT");
|
||||
data.StepProgress(infoMsg, 0);
|
||||
|
||||
// Setup
|
||||
PlatformTools::AotConfig config(data);
|
||||
data.Tools->OnConfigureAOT(data, config);
|
||||
// Override Newtonsoft.Json with AOT-version (one that doesn't use System.Reflection.Emit)
|
||||
EditorUtilities::CopyFileIfNewer(data.ManagedCodeOutputPath / TEXT("Newtonsoft.Json.dll"), Globals::StartupFolder / TEXT("Source/Platforms/DotNet/AOT/Newtonsoft.Json.dll"));
|
||||
FileSystem::DeleteFile(data.ManagedCodeOutputPath / TEXT("Newtonsoft.Json.xml"));
|
||||
FileSystem::DeleteFile(data.ManagedCodeOutputPath / TEXT("Newtonsoft.Json.pdb"));
|
||||
|
||||
// Prepare output directory
|
||||
config.AotCachePath = data.DataOutputPath / TEXT("Mono/lib/mono/aot-cache");
|
||||
switch (data.Tools->GetArchitecture())
|
||||
// Run AOT by Flax.Build (see DotNetAOT)
|
||||
const Char *platform, *architecture, *configuration = ::ToString(data.Configuration);
|
||||
data.GetBuildPlatformName(platform, architecture);
|
||||
const String logFile = data.CacheDirectory / TEXT("AOTLog.txt");
|
||||
String args = String::Format(
|
||||
TEXT("-log -logfile=\"{}\" -runDotNetAOT -mutex -platform={} -arch={} -configuration={} -aotMode={} -binaries=\"{}\" -intermediate=\"{}\""),
|
||||
logFile, platform, architecture, configuration, ToString(aotMode), data.DataOutputPath, data.ManagedCodeOutputPath);
|
||||
if (!buildSettings.SkipUnusedDotnetLibsPackaging)
|
||||
args += TEXT(" -skipUnusedDotnetLibs=false"); // Run AOT on whole class library (not just used libs)
|
||||
for (const String& define : data.CustomDefines)
|
||||
{
|
||||
case ArchitectureType::x86:
|
||||
config.AotCachePath /= TEXT("x86");
|
||||
break;
|
||||
case ArchitectureType::x64:
|
||||
config.AotCachePath /= TEXT("amd64");
|
||||
break;
|
||||
default:
|
||||
data.Error(TEXT("Not supported AOT architecture"));
|
||||
args += TEXT(" -D");
|
||||
args += define;
|
||||
}
|
||||
if (ScriptsBuilder::RunBuildTool(args))
|
||||
{
|
||||
data.Error(TEXT("Failed to precompile game scripts."));
|
||||
return true;
|
||||
}
|
||||
if (!FileSystem::DirectoryExists(config.AotCachePath))
|
||||
{
|
||||
if (FileSystem::CreateDirectory(config.AotCachePath))
|
||||
{
|
||||
data.Error(TEXT("Failed to setup AOT output directory."));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Collect assemblies for AOT
|
||||
// TODO: don't perform AOT on all assemblies but only ones used by the game and engine assemblies
|
||||
for (auto& dir : config.AssembliesSearchDirs)
|
||||
FileSystem::DirectoryGetFiles(config.Assemblies, dir, TEXT("*.dll"), DirectorySearchOption::TopDirectoryOnly);
|
||||
for (auto& binaryModule : data.BinaryModules)
|
||||
if (binaryModule.ManagedPath.HasChars())
|
||||
config.Assemblies.Add(data.ManagedCodeOutputPath / binaryModule.ManagedPath);
|
||||
// TODO: move AOT to Flax.Build and perform it on all C# assemblies used in target build
|
||||
config.Assemblies.Add(data.ManagedCodeOutputPath / TEXT("Newtonsoft.Json.dll"));
|
||||
|
||||
// Perform AOT for the assemblies
|
||||
for (int32 i = 0; i < config.Assemblies.Count(); i++)
|
||||
{
|
||||
BUILD_STEP_CANCEL_CHECK;
|
||||
|
||||
if (data.Tools->OnPerformAOT(data, config, config.Assemblies[i]))
|
||||
return true;
|
||||
|
||||
data.StepProgress(infoMsg, static_cast<float>(i) / config.Assemblies.Count());
|
||||
}
|
||||
|
||||
BUILD_STEP_CANCEL_CHECK;
|
||||
|
||||
if (data.Tools->OnPostProcessAOT(data, config))
|
||||
return true;
|
||||
|
||||
// TODO: maybe remove GAC/assemblies? aot-cache could be only used in the build game
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
#include "Editor/Cooker/GameCooker.h"
|
||||
|
||||
/// <summary>
|
||||
/// Optional step used only on selected platform that precompiles C# script assemblies.
|
||||
/// Uses Mono Ahead of Time Compilation (AOT) feature.
|
||||
/// Optional step used only on selected platform that precompiles C# script assemblies. Uses Ahead of Time Compilation (AOT) feature.
|
||||
/// </summary>
|
||||
/// <seealso cref="GameCooker::BuildStep" />
|
||||
class PrecompileAssembliesStep : public GameCooker::BuildStep
|
||||
@@ -14,5 +13,6 @@ class PrecompileAssembliesStep : public GameCooker::BuildStep
|
||||
public:
|
||||
|
||||
// [BuildStep]
|
||||
void OnBuildStarted(CookingData& data) override;
|
||||
bool Perform(CookingData& data) override;
|
||||
};
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
using FlaxEditor.CustomEditors;
|
||||
using FlaxEditor.Windows;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine;
|
||||
using DockState = FlaxEditor.GUI.Docking.DockState;
|
||||
|
||||
namespace FlaxEditor
|
||||
@@ -86,8 +85,12 @@ namespace FlaxEditor
|
||||
if (!FlaxEngine.Scripting.IsTypeFromGameScripts(type))
|
||||
return;
|
||||
|
||||
Editor.Instance.Windows.AddToRestore(this);
|
||||
if (!Window.IsHidden)
|
||||
{
|
||||
Editor.Instance.Windows.AddToRestore(this);
|
||||
}
|
||||
Window.Close();
|
||||
Window.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -7,6 +7,7 @@ using FlaxEditor.CustomEditors.GUI;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
using Newtonsoft.Json;
|
||||
using JsonSerializer = FlaxEngine.Json.JsonSerializer;
|
||||
|
||||
@@ -147,7 +148,7 @@ namespace FlaxEditor.CustomEditors
|
||||
return;
|
||||
|
||||
// Special case for root objects to run normal layout build
|
||||
if (_presenter.Selection == Values)
|
||||
if (_presenter != null && _presenter.Selection == Values)
|
||||
{
|
||||
_presenter.BuildLayout();
|
||||
return;
|
||||
@@ -158,7 +159,7 @@ namespace FlaxEditor.CustomEditors
|
||||
var layout = _layout;
|
||||
var control = layout.ContainerControl;
|
||||
var parent = _parent;
|
||||
var parentScrollV = (_presenter.Panel.Parent as Panel)?.VScrollBar?.Value ?? -1;
|
||||
var parentScrollV = (_presenter?.Panel.Parent as Panel)?.VScrollBar?.Value ?? -1;
|
||||
|
||||
control.IsLayoutLocked = true;
|
||||
control.DisposeChildren();
|
||||
@@ -248,6 +249,28 @@ namespace FlaxEditor.CustomEditors
|
||||
|
||||
internal virtual void RefreshRootChild()
|
||||
{
|
||||
// Check if need to update value
|
||||
if (_hasValueDirty)
|
||||
{
|
||||
IsSettingValue = true;
|
||||
try
|
||||
{
|
||||
// Cleanup (won't retry update in case of exception)
|
||||
object val = _valueToSet;
|
||||
_hasValueDirty = false;
|
||||
_valueToSet = null;
|
||||
|
||||
// Assign value
|
||||
for (int i = 0; i < _values.Count; i++)
|
||||
_values[i] = val;
|
||||
}
|
||||
finally
|
||||
{
|
||||
OnUnDirty();
|
||||
IsSettingValue = false;
|
||||
}
|
||||
}
|
||||
|
||||
Refresh();
|
||||
|
||||
for (int i = 0; i < _children.Count; i++)
|
||||
@@ -603,9 +626,7 @@ namespace FlaxEditor.CustomEditors
|
||||
JsonSerializer.Deserialize(obj, text);
|
||||
}
|
||||
}
|
||||
#pragma warning disable 618
|
||||
else if (Newtonsoft.Json.Schema.JsonSchema.Parse(text) == null)
|
||||
#pragma warning restore 618
|
||||
else if (!text.StartsWith("{") || !text.EndsWith("}"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -628,7 +649,14 @@ namespace FlaxEditor.CustomEditors
|
||||
else
|
||||
{
|
||||
// Default
|
||||
obj = JsonConvert.DeserializeObject(text, TypeUtils.GetType(Values.Type), JsonSerializer.Settings);
|
||||
try
|
||||
{
|
||||
obj = JsonConvert.DeserializeObject(text, TypeUtils.GetType(Values.Type), JsonSerializer.Settings);
|
||||
}
|
||||
catch
|
||||
{
|
||||
obj = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (obj == null || Values.Type.IsInstanceOfType(obj))
|
||||
@@ -795,6 +823,8 @@ namespace FlaxEditor.CustomEditors
|
||||
/// <returns>True if allow to handle this event, otherwise false.</returns>
|
||||
protected virtual bool OnDirty(CustomEditor editor, object value, object token = null)
|
||||
{
|
||||
if (ParentEditor == null)
|
||||
return false;
|
||||
return ParentEditor.OnDirty(editor, value, token);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Linq;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.CustomEditors
|
||||
{
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include "Engine/Scripting/ManagedCLR/MClass.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MUtils.h"
|
||||
#include "FlaxEngine.Gen.h"
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/reflection.h>
|
||||
|
||||
#define TRACK_ASSEMBLY(assembly) \
|
||||
if (assembly->IsLoaded()) \
|
||||
@@ -49,24 +48,24 @@ struct Entry
|
||||
}
|
||||
};
|
||||
|
||||
Dictionary<MonoType*, Entry> Cache(512);
|
||||
Dictionary<MType*, Entry> Cache(512);
|
||||
|
||||
void OnAssemblyLoaded(MAssembly* assembly);
|
||||
void OnAssemblyUnloading(MAssembly* assembly);
|
||||
void OnBinaryModuleLoaded(BinaryModule* module);
|
||||
|
||||
MonoReflectionType* CustomEditorsUtil::GetCustomEditor(MonoReflectionType* refType)
|
||||
MTypeObject* CustomEditorsUtil::GetCustomEditor(MTypeObject* refType)
|
||||
{
|
||||
if (!refType)
|
||||
return nullptr;
|
||||
MonoType* type = mono_reflection_type_get_type(refType);
|
||||
MType* type = INTERNAL_TYPE_OBJECT_GET(refType);
|
||||
Entry result;
|
||||
if (Cache.TryGet(type, result))
|
||||
{
|
||||
const auto editor = result.CustomEditor ? result.CustomEditor : result.DefaultEditor;
|
||||
MClass* editor = result.CustomEditor ? result.CustomEditor : result.DefaultEditor;
|
||||
if (editor)
|
||||
{
|
||||
return MUtils::GetType(editor->GetNative());
|
||||
return MUtils::GetType(editor);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
@@ -123,19 +122,19 @@ void OnAssemblyLoaded(MAssembly* assembly)
|
||||
continue;
|
||||
|
||||
const auto attribute = mclass->GetAttribute(customEditorAttribute);
|
||||
if (attribute == nullptr || mono_object_get_class(attribute) != customEditorAttribute->GetNative())
|
||||
if (attribute == nullptr || MCore::Object::GetClass(attribute) != customEditorAttribute)
|
||||
continue;
|
||||
|
||||
// Check if attribute references a valid class
|
||||
MonoReflectionType* refType = nullptr;
|
||||
MTypeObject* refType = nullptr;
|
||||
customEditorTypeField->GetValue(attribute, &refType);
|
||||
if (refType == nullptr)
|
||||
continue;
|
||||
|
||||
MonoType* type = mono_reflection_type_get_type(refType);
|
||||
MType* type = INTERNAL_TYPE_OBJECT_GET(refType);
|
||||
if (type == nullptr)
|
||||
continue;
|
||||
MonoClass* typeClass = mono_type_get_class(type);
|
||||
MClass* typeClass = MCore::Type::GetClass(type);
|
||||
|
||||
// Check if it's a custom editor class
|
||||
if (mclass->IsSubClassOf(customEditor))
|
||||
@@ -152,18 +151,14 @@ void OnAssemblyLoaded(MAssembly* assembly)
|
||||
entry.CustomEditor = mclass;
|
||||
}
|
||||
|
||||
//LOG(Info, "Custom Editor {0} for type {1} (default: {2})", String(mclass->GetFullName()), String(mono_type_get_name(type)), isDefault);
|
||||
//LOG(Info, "Custom Editor {0} for type {1} (default: {2})", String(mclass->GetFullName()), MCore::Type::ToString(type), isDefault);
|
||||
}
|
||||
else if (typeClass)
|
||||
{
|
||||
MClass* referencedClass = Scripting::FindClass(typeClass);
|
||||
if (referencedClass)
|
||||
{
|
||||
auto& entry = Cache[mono_class_get_type(mclass->GetNative())];
|
||||
entry.CustomEditor = referencedClass;
|
||||
auto& entry = Cache[mclass->GetType()];
|
||||
entry.CustomEditor = typeClass;
|
||||
|
||||
//LOG(Info, "Custom Editor {0} for type {1}", String(referencedClass->GetFullName()), String(mclass->GetFullName()));
|
||||
}
|
||||
//LOG(Info, "Custom Editor {0} for type {1}", String(typeClass->GetFullName()), String(mclass->GetFullName()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,17 +178,16 @@ void OnAssemblyUnloading(MAssembly* assembly)
|
||||
// Remove entries with user classes
|
||||
for (auto i = Cache.Begin(); i.IsNotEnd(); ++i)
|
||||
{
|
||||
MonoClass* monoClass = (MonoClass*)(void*)i->Key;
|
||||
|
||||
if (assembly->GetClass(monoClass))
|
||||
MClass* mClass = MCore::Type::GetClass(i->Key);
|
||||
if (mClass && mClass->GetAssembly() == assembly)
|
||||
{
|
||||
Cache.Remove(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i->Value.DefaultEditor && assembly->GetClass(i->Value.DefaultEditor->GetNative()))
|
||||
if (i->Value.DefaultEditor && i->Value.DefaultEditor->GetAssembly() == assembly)
|
||||
i->Value.DefaultEditor = nullptr;
|
||||
if (i->Value.CustomEditor && assembly->GetClass(i->Value.CustomEditor->GetNative()))
|
||||
if (i->Value.CustomEditor && i->Value.CustomEditor->GetAssembly() == assembly)
|
||||
i->Value.CustomEditor = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,14 +3,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
using FlaxEditor.CustomEditors.Dedicated;
|
||||
using FlaxEditor.CustomEditors.Editors;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Interop;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.CustomEditors
|
||||
{
|
||||
internal static class CustomEditorsUtil
|
||||
internal static partial class CustomEditorsUtil
|
||||
{
|
||||
internal static readonly Dictionary<Type, string> InBuildTypeNames = new Dictionary<Type, string>()
|
||||
{
|
||||
@@ -107,7 +111,7 @@ namespace FlaxEditor.CustomEditors
|
||||
// Select default editor (based on type)
|
||||
if (targetType.IsEnum)
|
||||
return new EnumEditor();
|
||||
if (targetType.IsGenericType)
|
||||
if (targetType.IsGenericType)
|
||||
{
|
||||
if (targetTypeType.GetGenericTypeDefinition() == typeof(Dictionary<,>))
|
||||
return new DictionaryEditor();
|
||||
@@ -118,12 +122,15 @@ namespace FlaxEditor.CustomEditors
|
||||
if (customEditorType != null)
|
||||
return (CustomEditor)Activator.CreateInstance(customEditorType);
|
||||
}
|
||||
if (typeof(FlaxEngine.Object).IsAssignableFrom(targetTypeType))
|
||||
return new ScriptingObjectEditor();
|
||||
|
||||
// The most generic editor
|
||||
return new GenericEditor();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern Type Internal_GetCustomEditor(Type targetType);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "CustomEditorsUtilInternal_GetCustomEditor", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
[return: MarshalUsing(typeof(SystemTypeMarshaller))]
|
||||
internal static partial Type Internal_GetCustomEditor([MarshalUsing(typeof(SystemTypeMarshaller))] Type targetType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ class CustomEditorsUtil
|
||||
{
|
||||
public:
|
||||
|
||||
#if USE_MONO
|
||||
static MonoReflectionType* GetCustomEditor(MonoReflectionType* refType);
|
||||
#if USE_CSHARP
|
||||
static MTypeObject* GetCustomEditor(MTypeObject* refType);
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -12,6 +12,7 @@ using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Json;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
@@ -20,7 +21,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.CustomEditors.Editors.GenericEditor" />
|
||||
[CustomEditor(typeof(Actor)), DefaultEditor]
|
||||
public class ActorEditor : GenericEditor
|
||||
public class ActorEditor : ScriptingObjectEditor
|
||||
{
|
||||
private Guid _linkedPrefabId;
|
||||
|
||||
@@ -94,19 +95,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
if (actor != null)
|
||||
group.Panel.TooltipText = Surface.SurfaceUtils.GetVisualScriptTypeDescription(TypeUtils.GetObjectType(actor));
|
||||
float settingsButtonSize = group.Panel.HeaderHeight;
|
||||
var settingsButton = new Image
|
||||
{
|
||||
TooltipText = "Settings",
|
||||
AutoFocus = true,
|
||||
AnchorPreset = AnchorPresets.TopRight,
|
||||
Parent = group.Panel,
|
||||
Bounds = new Rectangle(group.Panel.Width - settingsButtonSize, 0, settingsButtonSize, settingsButtonSize),
|
||||
IsScrollable = false,
|
||||
Color = FlaxEngine.GUI.Style.Current.ForegroundGrey,
|
||||
Margin = new Margin(1),
|
||||
Brush = new SpriteBrush(FlaxEngine.GUI.Style.Current.Settings),
|
||||
};
|
||||
var settingsButton = group.AddSettingsButton();
|
||||
settingsButton.Clicked += OnSettingsButtonClicked;
|
||||
break;
|
||||
}
|
||||
@@ -218,7 +207,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
node.Text = Utilities.Utils.GetPropertyNameUI(sceneObject.GetType().Name);
|
||||
}
|
||||
// Array Item
|
||||
else if (editor.ParentEditor?.Values?.Type.IsArray ?? false)
|
||||
else if (editor.ParentEditor is CollectionEditor)
|
||||
{
|
||||
node.Text = "Element " + editor.ParentEditor.ChildrenEditors.IndexOf(editor);
|
||||
}
|
||||
@@ -261,16 +250,14 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
}
|
||||
|
||||
// Skip if no change detected
|
||||
if (!editor.Values.IsReferenceValueModified && skipIfNotModified)
|
||||
var isRefEdited = editor.Values.IsReferenceValueModified;
|
||||
if (!isRefEdited && skipIfNotModified)
|
||||
return null;
|
||||
|
||||
TreeNode result = null;
|
||||
|
||||
if (editor.ChildrenEditors.Count == 0)
|
||||
if (editor.ChildrenEditors.Count == 0 || (isRefEdited && editor is CollectionEditor))
|
||||
result = CreateDiffNode(editor);
|
||||
|
||||
bool isScriptEditorWithRefValue = editor is ScriptsEditor && editor.Values.HasReferenceValue;
|
||||
|
||||
for (int i = 0; i < editor.ChildrenEditors.Count; i++)
|
||||
{
|
||||
var child = ProcessDiff(editor.ChildrenEditors[i], !isScriptEditorWithRefValue);
|
||||
@@ -278,7 +265,6 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
if (result == null)
|
||||
result = CreateDiffNode(editor);
|
||||
|
||||
result.AddChild(child);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom editor for <see cref="AudioSource"/>.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(AudioSource)), DefaultEditor]
|
||||
public class AudioSourceEditor : ActorEditor
|
||||
{
|
||||
private Label _infoLabel;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
base.Initialize(layout);
|
||||
|
||||
// Show playback options during simulation
|
||||
if (Editor.IsPlayMode)
|
||||
{
|
||||
var playbackGroup = layout.Group("Playback");
|
||||
playbackGroup.Panel.Open();
|
||||
|
||||
_infoLabel = playbackGroup.Label(string.Empty).Label;
|
||||
_infoLabel.AutoHeight = true;
|
||||
|
||||
var grid = playbackGroup.CustomContainer<UniformGridPanel>();
|
||||
var gridControl = grid.CustomControl;
|
||||
gridControl.ClipChildren = false;
|
||||
gridControl.Height = Button.DefaultHeight;
|
||||
gridControl.SlotsHorizontally = 3;
|
||||
gridControl.SlotsVertically = 1;
|
||||
grid.Button("Play").Button.Clicked += () => Foreach(x => x.Play());
|
||||
grid.Button("Pause").Button.Clicked += () => Foreach(x => x.Pause());
|
||||
grid.Button("Stop").Button.Clicked += () => Foreach(x => x.Stop());
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Refresh()
|
||||
{
|
||||
base.Refresh();
|
||||
|
||||
if (_infoLabel != null)
|
||||
{
|
||||
var text = string.Empty;
|
||||
foreach (var value in Values)
|
||||
{
|
||||
if (value is AudioSource audioSource && audioSource.Clip)
|
||||
text += $"Time: {audioSource.Time:##0.0}s / {audioSource.Clip.Length:##0.0}s\n";
|
||||
}
|
||||
_infoLabel.Text = text;
|
||||
}
|
||||
}
|
||||
|
||||
private void Foreach(Action<AudioSource> func)
|
||||
{
|
||||
foreach (var value in Values)
|
||||
{
|
||||
if (value is AudioSource audioSource)
|
||||
func(audioSource);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
var upperRightCell = new VerticalPanel
|
||||
{
|
||||
ClipChildren = false,
|
||||
Pivot = new Float2(0.0f, 0.0f),
|
||||
Pivot = new Float2(0.00001f, 0.0f),
|
||||
Offset = new Float2(-labelsWidth, 0),
|
||||
Rotation = -90,
|
||||
Spacing = 0,
|
||||
|
||||
@@ -145,7 +145,10 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
else
|
||||
{
|
||||
// No localization so initialize with empty table
|
||||
var path = Path.Combine(Path.Combine(Path.GetDirectoryName(GameSettings.Load().Localization.Path), "Localization", culture.Name + ".json"));
|
||||
var folder = Path.Combine(Path.GetDirectoryName(GameSettings.Load().Localization.Path), "Localization");
|
||||
if (!Directory.Exists(folder))
|
||||
Directory.CreateDirectory(folder);
|
||||
var path = Path.Combine(Path.Combine(folder, culture.Name + ".json"));
|
||||
var table = FlaxEngine.Content.CreateVirtualAsset<LocalizedStringTable>();
|
||||
table.Locale = culture.Name;
|
||||
if (!table.Save(path))
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using FlaxEditor.Surface;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
@@ -13,6 +15,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
[CustomEditor(typeof(ParticleEffect)), DefaultEditor]
|
||||
public class ParticleEffectEditor : ActorEditor
|
||||
{
|
||||
private Label _infoLabel;
|
||||
private bool _isValid;
|
||||
private bool _isActive;
|
||||
private uint _parametersVersion;
|
||||
@@ -48,6 +51,15 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
return null;
|
||||
}
|
||||
|
||||
private void Foreach(Action<ParticleEffect> func)
|
||||
{
|
||||
foreach (var value in Values)
|
||||
{
|
||||
if (value is ParticleEffect player)
|
||||
func(player);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
@@ -60,6 +72,26 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
_parametersVersion = effect.ParametersVersion;
|
||||
_isActive = effect.IsActive;
|
||||
|
||||
// Show playback options during simulation
|
||||
if (Editor.IsPlayMode)
|
||||
{
|
||||
var playbackGroup = layout.Group("Playback");
|
||||
playbackGroup.Panel.Open();
|
||||
|
||||
_infoLabel = playbackGroup.Label(string.Empty).Label;
|
||||
_infoLabel.AutoHeight = true;
|
||||
|
||||
var grid = playbackGroup.CustomContainer<UniformGridPanel>();
|
||||
var gridControl = grid.CustomControl;
|
||||
gridControl.ClipChildren = false;
|
||||
gridControl.Height = Button.DefaultHeight;
|
||||
gridControl.SlotsHorizontally = 3;
|
||||
gridControl.SlotsVertically = 1;
|
||||
grid.Button("Play").Button.Clicked += () => Foreach(x => x.Play());
|
||||
grid.Button("Pause").Button.Clicked += () => Foreach(x => x.Pause());
|
||||
grid.Button("Stop").Button.Clicked += () => Foreach(x => x.Stop());
|
||||
}
|
||||
|
||||
// Show all effect parameters grouped by the emitter track name
|
||||
var groups = layout.Group("Parameters");
|
||||
groups.Panel.Open();
|
||||
@@ -99,7 +131,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
base.RefreshRootChild();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < ChildrenEditors.Count; i++)
|
||||
{
|
||||
if (_isActive != effect.IsActive || _parametersVersion != effect.ParametersVersion)
|
||||
|
||||
@@ -167,7 +167,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
Presenter.Undo?.AddAction(new MultiUndoAction(actions));
|
||||
|
||||
// Build ragdoll
|
||||
SceneGraph.Actors.AnimatedModelNode.BuildRagdoll(animatedModel, options, ragdoll);
|
||||
AnimatedModelNode.BuildRagdoll(animatedModel, options, ragdoll);
|
||||
}
|
||||
|
||||
private void OnRebuildBone(Button button)
|
||||
@@ -191,7 +191,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
}
|
||||
|
||||
// Build ragdoll
|
||||
SceneGraph.Actors.AnimatedModelNode.BuildRagdoll(animatedModel, new AnimatedModelNode.RebuildOptions(), ragdoll, name);
|
||||
AnimatedModelNode.BuildRagdoll(animatedModel, new AnimatedModelNode.RebuildOptions(), ragdoll, name);
|
||||
}
|
||||
|
||||
private void OnRemoveBone(Button button)
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom editor for <see cref="SceneAnimationPlayer"/>.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(SceneAnimationPlayer)), DefaultEditor]
|
||||
public class SceneAnimationPlayerEditor : ActorEditor
|
||||
{
|
||||
private Label _infoLabel;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
base.Initialize(layout);
|
||||
|
||||
// Show playback options during simulation
|
||||
if (Editor.IsPlayMode)
|
||||
{
|
||||
var playbackGroup = layout.Group("Playback");
|
||||
playbackGroup.Panel.Open();
|
||||
|
||||
_infoLabel = playbackGroup.Label(string.Empty).Label;
|
||||
_infoLabel.AutoHeight = true;
|
||||
|
||||
var grid = playbackGroup.CustomContainer<UniformGridPanel>();
|
||||
var gridControl = grid.CustomControl;
|
||||
gridControl.ClipChildren = false;
|
||||
gridControl.Height = Button.DefaultHeight;
|
||||
gridControl.SlotsHorizontally = 3;
|
||||
gridControl.SlotsVertically = 1;
|
||||
grid.Button("Play").Button.Clicked += () => Foreach(x => x.Play());
|
||||
grid.Button("Pause").Button.Clicked += () => Foreach(x => x.Pause());
|
||||
grid.Button("Stop").Button.Clicked += () => Foreach(x => x.Stop());
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Refresh()
|
||||
{
|
||||
base.Refresh();
|
||||
|
||||
if (_infoLabel != null)
|
||||
{
|
||||
var text = string.Empty;
|
||||
foreach (var value in Values)
|
||||
{
|
||||
if (value is SceneAnimationPlayer player && player.Animation)
|
||||
text += $"Time: {player.Time:##0.0}s / {player.Animation.Duration:##0.0}s\n";
|
||||
}
|
||||
_infoLabel.Text = text;
|
||||
}
|
||||
}
|
||||
|
||||
private void Foreach(Action<SceneAnimationPlayer> func)
|
||||
{
|
||||
foreach (var value in Values)
|
||||
{
|
||||
if (value is SceneAnimationPlayer player)
|
||||
func(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEditor.CustomEditors.Editors;
|
||||
using FlaxEngine.Networking;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom editor for <see cref="FlaxEngine.Object"/>.
|
||||
/// </summary>
|
||||
public class ScriptingObjectEditor : GenericEditor
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
// Network objects debugging
|
||||
var obj = Values[0] as FlaxEngine.Object;
|
||||
if (Editor.IsPlayMode && NetworkManager.IsConnected && NetworkReplicator.HasObject(obj))
|
||||
{
|
||||
var group = layout.Group("Network");
|
||||
group.Panel.Open();
|
||||
group.Label("Role", Utilities.Utils.GetPropertyNameUI(NetworkReplicator.GetObjectRole(obj).ToString()));
|
||||
group.Label("Owner Client Id", NetworkReplicator.GetObjectOwnerClientId(obj).ToString());
|
||||
}
|
||||
|
||||
base.Initialize(layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FlaxEditor.Actions;
|
||||
using FlaxEditor.Content;
|
||||
using FlaxEditor.GUI;
|
||||
@@ -12,6 +11,7 @@ using FlaxEditor.GUI.Drag;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
using Object = FlaxEngine.Object;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Dedicated
|
||||
@@ -462,20 +462,8 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
var group = layout.Group("Missing script");
|
||||
|
||||
// Add settings button to the group
|
||||
const float settingsButtonSize = 14;
|
||||
var settingsButton = new Image
|
||||
{
|
||||
TooltipText = "Settings",
|
||||
AutoFocus = true,
|
||||
AnchorPreset = AnchorPresets.TopRight,
|
||||
Parent = group.Panel,
|
||||
Bounds = new Rectangle(group.Panel.Width - settingsButtonSize, 0, settingsButtonSize, settingsButtonSize),
|
||||
IsScrollable = false,
|
||||
Color = FlaxEngine.GUI.Style.Current.ForegroundGrey,
|
||||
Margin = new Margin(1),
|
||||
Brush = new SpriteBrush(FlaxEngine.GUI.Style.Current.Settings),
|
||||
Tag = index,
|
||||
};
|
||||
var settingsButton = group.AddSettingsButton();
|
||||
settingsButton.Tag = index;
|
||||
settingsButton.Clicked += MissingSettingsButtonOnClicked;
|
||||
}
|
||||
|
||||
@@ -665,19 +653,8 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
};
|
||||
|
||||
// Add settings button to the group
|
||||
var settingsButton = new Image
|
||||
{
|
||||
TooltipText = "Settings",
|
||||
AutoFocus = true,
|
||||
AnchorPreset = AnchorPresets.TopRight,
|
||||
Parent = group.Panel,
|
||||
Bounds = new Rectangle(group.Panel.Width - headerHeight, 0, headerHeight, headerHeight),
|
||||
IsScrollable = false,
|
||||
Color = FlaxEngine.GUI.Style.Current.ForegroundGrey,
|
||||
Margin = new Margin(1),
|
||||
Brush = new SpriteBrush(FlaxEngine.GUI.Style.Current.Settings),
|
||||
Tag = script,
|
||||
};
|
||||
var settingsButton = group.AddSettingsButton();
|
||||
settingsButton.Tag = script;
|
||||
settingsButton.Clicked += OnSettingsButtonClicked;
|
||||
|
||||
group.Panel.HeaderTextMargin = new Margin(scriptDrag.Right - 12, 15, 2, 2);
|
||||
|
||||
@@ -408,6 +408,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
private Type _cachedType;
|
||||
private bool _anchorDropDownClosed = true;
|
||||
private Button _pivotRelativeButton;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
@@ -484,13 +485,54 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
horDown.CustomControl.Height = TextBoxBase.DefaultHeight;
|
||||
|
||||
GetAnchorEquality(out _cachedXEq, out _cachedYEq, valueTypes);
|
||||
|
||||
BuildLocationSizeOffsets(horUp, horDown, _cachedXEq, _cachedYEq, valueTypes);
|
||||
BuildExtraButtons(group);
|
||||
|
||||
main.Space(10);
|
||||
BuildAnchorsDropper(main, valueTypes);
|
||||
}
|
||||
|
||||
private void BuildExtraButtons(VerticalPanelElement group)
|
||||
{
|
||||
var control = (Control)Values[0];
|
||||
var pivotRelative = Editor.Instance.Windows.PropertiesWin.UIPivotRelative;
|
||||
control.PivotRelative = pivotRelative;
|
||||
|
||||
var panel = group.CustomContainer<Panel>();
|
||||
panel.CustomControl.Height = TextBoxBase.DefaultHeight;
|
||||
panel.CustomControl.ClipChildren = false;
|
||||
panel.CustomControl.Parent = group.ContainerControl;
|
||||
|
||||
_pivotRelativeButton = new Button
|
||||
{
|
||||
TooltipText = "Toggles UI control resizing based on where the pivot is rather than just the top-left.",
|
||||
Size = new Float2(18),
|
||||
Parent = panel.ContainerControl,
|
||||
BackgroundBrush = new SpriteBrush(Editor.Instance.Icons.Scale32),
|
||||
AnchorPreset = AnchorPresets.TopRight,
|
||||
X = 77,
|
||||
};
|
||||
|
||||
SetStyle(pivotRelative);
|
||||
_pivotRelativeButton.Clicked += PivotRelativeClicked;
|
||||
}
|
||||
|
||||
private void PivotRelativeClicked()
|
||||
{
|
||||
var control = (Control)Values[0];
|
||||
var pivotRelative = control.PivotRelative;
|
||||
control.PivotRelative = !pivotRelative;
|
||||
Editor.Instance.Windows.PropertiesWin.UIPivotRelative = !pivotRelative;
|
||||
SetStyle(control.PivotRelative);
|
||||
}
|
||||
|
||||
private void SetStyle(bool current)
|
||||
{
|
||||
var style = FlaxEngine.GUI.Style.Current;
|
||||
var backgroundColor = current ? style.Foreground : style.ForegroundDisabled;
|
||||
_pivotRelativeButton.SetColors(backgroundColor);
|
||||
}
|
||||
|
||||
private void BuildAnchorsDropper(LayoutElementsContainer main, ScriptType[] valueTypes)
|
||||
{
|
||||
ScriptMemberInfo minInfo = valueTypes[0].GetProperty("AnchorMin");
|
||||
@@ -655,7 +697,9 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
if (uiControl.Name.StartsWith(previousName))
|
||||
{
|
||||
string newName = controlType.Name + uiControl.Name.Substring(previousName.Length);
|
||||
uiControl.Name = StringUtils.IncrementNameNumber(newName, x => uiControl.Parent.GetChild(x) == null);
|
||||
if (uiControl.Parent != null)
|
||||
newName = Utilities.Utils.IncrementNameNumber(newName, x => uiControl.Parent.GetChild(x) == null);
|
||||
uiControl.Name = newName;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,16 +27,6 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
element.ComboBox.SelectedIndexChanged += OnSelectedIndexChanged;
|
||||
}
|
||||
|
||||
private void GetActorsTree(List<Actor> list, Actor a)
|
||||
{
|
||||
list.Add(a);
|
||||
int cnt = a.ChildrenCount;
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
GetActorsTree(list, a.GetChild(i));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSelectedIndexChanged(ComboBox comboBox)
|
||||
{
|
||||
int value = comboBox.SelectedIndex;
|
||||
@@ -60,7 +50,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
// Note: this possibly breaks the design a little bit
|
||||
// But it's the easiest way to set value for selected actor and its children with one undo action
|
||||
List<Actor> actors = new List<Actor>(32);
|
||||
GetActorsTree(actors, actor);
|
||||
Utilities.Utils.GetActorsTree(actors, actor);
|
||||
if (Presenter.Undo != null)
|
||||
{
|
||||
using (new UndoMultiBlock(Presenter.Undo, actors.ToArray(), "Change layer"))
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user