Compare commits
1047 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bab9462409 | |||
| 5370507859 | |||
| eeb7a3d5fb | |||
| 9883008cd1 | |||
| e72a4d0a13 | |||
| 737d6e1859 | |||
| 8a997fd7ce | |||
| 754faa7730 | |||
| 67d477af77 | |||
| 314b8ce194 | |||
| 2a18d9b51f | |||
| d7adc28125 | |||
| e4265f5fdb | |||
| a3e3ea2f8e | |||
| a637aec63e | |||
| ab0b84b87e | |||
| d22abae476 | |||
| 9ce51c2d49 | |||
| 7918103b8b | |||
| 176dc79b49 | |||
| 87b95625ff | |||
| 530956889b | |||
| 54e267dfa6 | |||
| e535879262 | |||
| 740ac2a879 | |||
| 5d9f9cf284 | |||
| a6ce456c60 | |||
| c18579f777 | |||
| ad7cbd8e2e | |||
| 69adbddb46 | |||
| 42147937b2 | |||
| 56762050fb | |||
| 744a03bdfa | |||
| 8882331421 | |||
| e2aa928e95 | |||
| 25a57c099b | |||
| 490dc0f563 | |||
| 130b9091d1 | |||
| 2288feeb59 | |||
| 96798c0fbb | |||
| 9a1cae1d52 | |||
| c2fc8f78f2 | |||
| 12553edb26 | |||
| ea451dfda2 | |||
| 7c4e6870b3 | |||
| 986fba3586 | |||
| 00b45742d1 | |||
| 81e1f7d8e6 | |||
| 3bf07ce606 | |||
| d4df925b8f | |||
| 26b986de5b | |||
| 64adb052b4 | |||
| d703d79feb | |||
| 96c6e27d98 | |||
| a3377215e9 | |||
| 01df9b9d77 | |||
| 47ba741f6d | |||
| c3a37bf76c | |||
| c9cf202721 | |||
| 1ab5ca14fb | |||
| 10a394ae6c | |||
| a1419cdd1f | |||
| 2e0a7f0031 | |||
| da78010281 | |||
| 603a5bd63f | |||
| 9f1273fb32 | |||
| 9a0011c38f | |||
| bdda22cb2e | |||
| 86644e6533 | |||
| eaeadc6a52 | |||
| eb0d3b1846 | |||
| 50333571d7 | |||
| 320ce42626 | |||
| 047bdf4189 | |||
| d39a27a904 | |||
| f0cf85943f | |||
| bfd99cdda1 | |||
| 9391695fce | |||
| 3d65ec6def | |||
| c804c4b0ee | |||
| 86146782f7 | |||
| ed19fb5ce4 | |||
| 9f8aec3bc1 | |||
| 4ccbc12b48 | |||
| 86c46c629b | |||
| e2528c1b10 | |||
| eb2d6106af | |||
| 2ad6edaae3 | |||
| 73f7d0b7a3 | |||
| 27024de00e | |||
| 11447b8650 | |||
| cdaeb33e12 | |||
| 9f9ac4a7ce | |||
| e3788c0a43 | |||
| 66b8e51026 | |||
| f9808e31ec | |||
| 4988adb170 | |||
| cc1ea0f4ae | |||
| 12e2816480 | |||
| 92530c5db7 | |||
| 2fd01d0c9f | |||
| f0096aec87 | |||
| b5b3edc6ec | |||
| 82c652ca31 | |||
| b3076597e5 | |||
| 31dcc389a2 | |||
| 78c261c625 | |||
| 5107d501f5 | |||
| aad3f8ca27 | |||
| 5bc2342174 | |||
| 9f07fc8a62 | |||
| a8ccd34559 | |||
| ef8bf09210 | |||
| 2161f28766 | |||
| cebb78c2c3 | |||
| edc94e49e8 | |||
| 03ecffbf52 | |||
| f864f94207 | |||
| af90a1a334 | |||
| c3fc896dea | |||
| 9cc67fee74 | |||
| 847048825a | |||
| 55def863d3 | |||
| 0a6485ca71 | |||
| aac58ec6fa | |||
| 37338cb0f7 | |||
| 3d5aaa6f6e | |||
| 2c800ea84d | |||
| 4db972f4c8 | |||
| 4fb1dc0ddc | |||
| ec49207533 | |||
| ea51307eaa | |||
| 49e32f9b47 | |||
| b053bf625c | |||
| 0634116d59 | |||
| 7c25c48dd2 | |||
| d8baf4e579 | |||
| 9186abbbe3 | |||
| 9ff219d065 | |||
| 4376ddf0ec | |||
| e6f4685bd0 | |||
| 5a751434ac | |||
| 2f4860ae71 | |||
| 7170c31304 | |||
| 313f95cd1f | |||
| 359de7bfe5 | |||
| aba5d9e679 | |||
| cc24409d87 | |||
| d63de113fb | |||
| c672be101e | |||
| 668a9ecf69 | |||
| a87f20c66e | |||
| a22b8a572b | |||
| e84a59aeff | |||
| dd25267502 | |||
| a436cfbe35 | |||
| e74656c372 | |||
| 49b5e80af5 | |||
| 281ebc23e1 | |||
| 28f7b4666b | |||
| e53a9fc865 | |||
| bda7489fbe | |||
| abc78baad8 | |||
| 3f2723582f | |||
| e908672034 | |||
| f66b912cf4 | |||
| 81cb992fad | |||
| 7f476513cd | |||
| d82dc3162f | |||
| 6c690c5db6 | |||
| 18755d9057 | |||
| dd1e852356 | |||
| dacc0f7280 | |||
| 5517873275 | |||
| d9a73d63bd | |||
| 8acce7beb9 | |||
| f79390838a | |||
| e8d766eafb | |||
| b5bffe99fa | |||
| e62c9de7e9 | |||
| 396f1f3955 | |||
| 5197cf4cb8 | |||
| 48bf705ca4 | |||
| 34c2ac2cb9 | |||
| ebfbabdfd8 | |||
| 6a379ae9aa | |||
| d2e1f804ce | |||
| 64090f7497 | |||
| b647964839 | |||
| 7387f2406a | |||
| e83802f15e | |||
| 863b9712f9 | |||
| 42deb76c28 | |||
| 31df4dba9f | |||
| f8d811aa97 | |||
| 06d828a296 | |||
| f02eab5c51 | |||
| 199109f1ae | |||
| 233bf152b9 | |||
| 82de673ce7 | |||
| 9e6e7df3e6 | |||
| 48681e4295 | |||
| 967f15ded9 | |||
| 305bd294a0 | |||
| 52ce5356cc | |||
| 8589a5a7b4 | |||
| e1585de9b6 | |||
| 3f0bb07c16 | |||
| 104ba696c2 | |||
| a2683fbec2 | |||
| 1fd87c7376 | |||
| 7444638030 | |||
| ba1a7b324e | |||
| 7f3b842d59 | |||
| a12f1b1201 | |||
| c883687ace | |||
| 50ba7401fd | |||
| c592974055 | |||
| 253fe397f4 | |||
| 883ea8d48a | |||
| 7d8882d28d | |||
| d6122f0e31 | |||
| 7ffa0ecf6d | |||
| c775e5b74e | |||
| 617ac10c5a | |||
| 1033c78db3 | |||
| 9cc3f24c56 | |||
| a9b7d216c8 | |||
| 7c74d95efa | |||
| eee6a0906e | |||
| 8c598b18af | |||
| 3254d8e81e | |||
| 329439cf61 | |||
| 9f94be7cca | |||
| 5b3cfac48e | |||
| 306b57e1d5 | |||
| c5e58d14ea | |||
| 509b5ef111 | |||
| b2550ca58a | |||
| f8c81e4066 | |||
| b4af12025d | |||
| 031fcad641 | |||
| 4d485a1778 | |||
| e33a1133b7 | |||
| 7024f42789 | |||
| 41ad5d1e9b | |||
| 181d317d20 | |||
| 5f6277a74c | |||
| 6289564382 | |||
| 6af48afdda | |||
| cdf7da94db | |||
| 8b85282502 | |||
| 93e5cb391e | |||
| d8aa070c93 | |||
| f65bd1aca1 | |||
| ef924b9e9e | |||
| 2ce2d997be | |||
| 2958539514 | |||
| b9f9cb8495 | |||
| 160ce96e4f | |||
| 0c6dab39a8 | |||
| 9b1cd7d608 | |||
| 22a384a76a | |||
| db7c21e5d8 | |||
| 2bb7ae1883 | |||
| e958d00373 | |||
| 5297996640 | |||
| 8030cfdfde | |||
| 84d754a4e9 | |||
| 30a641d249 | |||
| 12fdc0717e | |||
| 5d8cbac06a | |||
| 90b23e11e9 | |||
| 3f685af868 | |||
| 2bd6d30dcc | |||
| 99f8749949 | |||
| 6f39b50e63 | |||
| 338202c41b | |||
| b368912c78 | |||
| 7b91300962 | |||
| f38581754a | |||
| 9b3d3e3298 | |||
| 6029d10e62 | |||
| 614f030407 | |||
| e691f072ae | |||
| a1a90e0626 | |||
| 06ecc5cd8e | |||
| e476a9d975 | |||
| 15f1020fb6 | |||
| a299117858 | |||
| 9c24d707bc | |||
| 1667d7f16e | |||
| 6bd75e3bf2 | |||
| 6a82b4928b | |||
| a64a403def | |||
| 3a2d594626 | |||
| d117f2b8a1 | |||
| 0a239c4bed | |||
| 0b35f810b6 | |||
| 66da424b90 | |||
| b2a45c2fda | |||
| 87587b00b6 | |||
| 28ad6f62ea | |||
| b989f653a0 | |||
| 6ab98292d2 | |||
| 61e057f73e | |||
| 25c8c9279c | |||
| 48a8caa292 | |||
| a99f75f2a4 | |||
| 47bb0e5d4d | |||
| 765d800842 | |||
| 7b20f305ff | |||
| 3816d9924b | |||
| afc2d019a3 | |||
| 0ed66baed0 | |||
| 90dd603cee | |||
| 7187aaa4d5 | |||
| a5f6c02a09 | |||
| f4233ba11d | |||
| 88580ca319 | |||
| beebbd0bc1 | |||
| d4edd0f5ba | |||
| 0f04b63516 | |||
| dba978e22b | |||
| 34421b8015 | |||
| 01c2971ce7 | |||
| b30711877d | |||
| fc99cee9a9 | |||
| 2603a79cc4 | |||
| a0f60e5296 | |||
| 5ffa67b31b | |||
| 1786e144bb | |||
| de6d78bef5 | |||
| 2b02c0a931 | |||
| bd2d62ddca | |||
| 4d3ecfb72c | |||
| d483c9283c | |||
| 8228597ade | |||
| 858544e231 | |||
| 4fc9d2616a | |||
| 3ac1179440 | |||
| b3ce6463b5 | |||
| f993c4a36a | |||
| dc614a6a33 | |||
| 5d34d0fd09 | |||
| 4bca5dfa92 | |||
| 00408604da | |||
| 179dd60536 | |||
| ae68b7f752 | |||
| b12b66e89a | |||
| b513f7b5b1 | |||
| d9612ba2a6 | |||
| 3b9b4a589b | |||
| 5be2422c84 | |||
| 4df15eacfb | |||
| 1e714623b7 | |||
| fc22c3f250 | |||
| dd20cb2d5d | |||
| 8c72437ecc | |||
| 2f6386069d | |||
| ab6b666fd6 | |||
| 91f91716b5 | |||
| 4e0c30488f | |||
| 1381c6c903 | |||
| d59636bcf6 | |||
| 5aa7c03022 | |||
| 2cce41062f | |||
| 07fe90eb5f | |||
| ac8c7b0c0b | |||
| 5e80db327d | |||
| bad7c4a255 | |||
| 1315baf332 | |||
| c8a588b2de | |||
| e91091d62b | |||
| 5a5e5cb258 | |||
| 0a078c7822 | |||
| 1bf3470873 | |||
| bc50bd9b9a | |||
| 8fbfeb7f9d | |||
| a6364199da | |||
| f16ac4ef9e | |||
| c5114a73fc | |||
| b87ee96805 | |||
| 90074bfe60 | |||
| 0b89ed85b7 | |||
| 64b361510d | |||
| a0c6f8ce7f | |||
| e009ea313b | |||
| a8906b4f79 | |||
| 1cc507e181 | |||
| 6f16e96de2 | |||
| cf8cbb3afb | |||
| 2fca1056c6 | |||
| 39af9cabc0 | |||
| 3908163bdf | |||
| 4480353cb2 | |||
| 7d85ea3432 | |||
| 3762453d83 | |||
| 3205408290 | |||
| c6bea826f6 | |||
| 54c0feafc2 | |||
| 46000362ba | |||
| f8825dc55a | |||
| 6fb5118afd | |||
| 23d204b9fc | |||
| 429e419327 | |||
| 69d1db06a5 | |||
| ce2699dfee | |||
| a64713fc23 | |||
| 958a262ba1 | |||
| f7e6859696 | |||
| db3a3d80d1 | |||
| a0b030290b | |||
| 629579123a | |||
| 163aabea6c | |||
| deb7c0d0c0 | |||
| bdfe3f18fe | |||
| 384324c85a | |||
| cd71da9330 | |||
| bef0d6fbca | |||
| 297b2beef8 | |||
| 00dc16eff8 | |||
| 891ccec7df | |||
| b41f18692b | |||
| d3911d4ba8 | |||
| bb9ec40c18 | |||
| 0f534731a6 | |||
| 9f233104a3 | |||
| 01d3aa725f | |||
| 8dfcccad41 | |||
| 4b533b5ff6 | |||
| 0e2d2a6fab | |||
| 3311269b23 | |||
| 8ca18725b6 | |||
| 2bed060d13 | |||
| 14140e26cd | |||
| 34664e867f | |||
| 082fd26bf1 | |||
| c8c230449e | |||
| 7f973f9a4f | |||
| 58f0dbbc84 | |||
| f4e121ae94 | |||
| f5834f8f63 | |||
| eb25f24c96 | |||
| 3f32bfda7c | |||
| 07a6c35470 | |||
| dec64e8a59 | |||
| 5d0f83b81c | |||
| a3b2da86b5 | |||
| 2d1d06899e | |||
| 1e2a6bab5b | |||
| b35409254e | |||
| 67b7a67f4b | |||
| f2dd27f443 | |||
| c6ef4f51f2 | |||
| dd55945670 | |||
| 03a8ee443d | |||
| a52fbc01a9 | |||
| 76b1bd20ae | |||
| e9de2b6f27 | |||
| f8358d117a | |||
| 9ca357e109 | |||
| 467c3f1bdd | |||
| 1ea8f67662 | |||
| 665b689410 | |||
| df6ea046c3 | |||
| 7fdd6582be | |||
| 84155274c4 | |||
| 21b828fe5c | |||
| 1cf132cb87 | |||
| 045ab0cdf6 | |||
| edb33400b3 | |||
| 691964877b | |||
| a8d54e9878 | |||
| ae044685e3 | |||
| 4499cedcb8 | |||
| 6cdef20cc2 | |||
| f74738a4e0 | |||
| 78a70765af | |||
| d1bea7f10e | |||
| ae5df73e72 | |||
| fc0f3d3790 | |||
| c736fd3b09 | |||
| 8e113f749a | |||
| e8dc823009 | |||
| 62a703974d | |||
| e235ec11f0 | |||
| 33dc9b6a18 | |||
| 364888bcc9 | |||
| 5cd53d4024 | |||
| 22c104f766 | |||
| 254097657e | |||
| b17f1d7401 | |||
| 404ee2ee3b | |||
| f8fe157352 | |||
| 61a6f3c827 | |||
| 0141f99dd1 | |||
| 67474a5cfe | |||
| 7e9fa4473c | |||
| ca69a3f9ae | |||
| 317d63d822 | |||
| 36358e7a43 | |||
| 968030535e | |||
| 6e132d25c8 | |||
| b4774a46ee | |||
| e6729b3123 | |||
| d6b3242b25 | |||
| 8a4f3f5ad6 | |||
| 9a56ee9b9d | |||
| 22d1e2d66a | |||
| 1adce5b58b | |||
| 328dee77c8 | |||
| 174a32c285 | |||
| 47e32eacd1 | |||
| d9c574f107 | |||
| 93e6954fb1 | |||
| 32050879a1 | |||
| 9660587e10 | |||
| 5ec13a073f | |||
| db3fa68052 | |||
| 423ea12856 | |||
| 9b482d609a | |||
| be06477907 | |||
| 08a6fc8a3f | |||
| 65b51c251e | |||
| 1af62d0879 | |||
| 5d71892b7c | |||
| 0c3c0c5e6a | |||
| 2fe4018d28 | |||
| 96423634ad | |||
| 3d7b12c98c | |||
| de85f201ad | |||
| a465984c52 | |||
| 0068411946 | |||
| ff658633fb | |||
| 8fbd7c7e60 | |||
| 4c4d225c03 | |||
| 0ec39f8e4e | |||
| 866037a0d7 | |||
| 50f255eea4 | |||
| e807fd556c | |||
| a26cc2eea7 | |||
| 3915af34c2 | |||
| 706c7abc55 | |||
| 1447304dd7 | |||
| 5f2900ffda | |||
| 0be4230487 | |||
| f294484c02 | |||
| 1675eb451f | |||
| 28a529088f | |||
| 292672a019 | |||
| 7b864a3201 | |||
| fffedf71d0 | |||
| e8a34255ac | |||
| 93bc8a90db | |||
| fe2d2bacd7 | |||
| f1049953c4 | |||
| 4d8526ad7e | |||
| 3e3c6088fb | |||
| 862b048b17 | |||
| 1a1110526e | |||
| ea5eedb5a5 | |||
| 8cc4bdf66b | |||
| 7a637967fe | |||
| c1dc475438 | |||
| 6c663cc87b | |||
| 9425bdc4e5 | |||
| d7b449869e | |||
| fa119d234b | |||
| b841efe4ba | |||
| 7b0deda1a6 | |||
| bc66326385 | |||
| 074189b73e | |||
| d83eabfdf1 | |||
| 25f4d49e43 | |||
| 95f2087148 | |||
| 9ec1b3a9bf | |||
| 6ee496ab1c | |||
| 9a4137e9da | |||
| 24c16ebee4 | |||
| 074f10f302 | |||
| 81b6782c9d | |||
| 521efe67db | |||
| c2a5df4be8 | |||
| 429eeb7754 | |||
| 08ac2f1125 | |||
| c2902a2246 | |||
| edaec666d1 | |||
| d8fa2ce6b0 | |||
| bcdcc8fe8c | |||
| bd998748ee | |||
| a071196f89 | |||
| b1fff7c921 | |||
| 231715bf98 | |||
| 5d9cbddb72 | |||
| 51a5e06f5c | |||
| 74006849b5 | |||
| 46888b6716 | |||
| 1d40f6d95a | |||
| d9b20f6eec | |||
| e634177ca4 | |||
| 70a92a8862 | |||
| 6dd1810038 | |||
| 978f128755 | |||
| d1c9359e96 | |||
| 83200a453b | |||
| c33522d1c7 | |||
| f048ffb6ac | |||
| 8fbb1f7d03 | |||
| cfb7fa5ca9 | |||
| e2626a0687 | |||
| c97e64c3c0 | |||
| 8808dda605 | |||
| 80764f85c1 | |||
| b6c4d703a2 | |||
| b9d0cca281 | |||
| c74099f5f8 | |||
| 8384ad3215 | |||
| e227b75472 | |||
| f65eda8b47 | |||
| 297578705e | |||
| ab84a5f936 | |||
| 61f802e9ad | |||
| f1153f59a2 | |||
| 0c6235e55b | |||
| 1c7ce84881 | |||
| 9539f7bcec | |||
| 649a65d854 | |||
| 61a6ab2e7b | |||
| 50aa535f88 | |||
| f3fec88888 | |||
| 5e46afdb0f | |||
| 7834b26ef8 | |||
| de9c92b360 | |||
| 6ccbed923e | |||
| ee0768bf3e | |||
| 7ceefa8c50 | |||
| 4add35b4ca | |||
| 045bf22e10 | |||
| 52270ab5d1 | |||
| 537d3a0ab3 | |||
| 4a285903e1 | |||
| d4b6979426 | |||
| 6e465b233f | |||
| f0485a20a8 | |||
| 6e90e178ed | |||
| 950d3134f2 | |||
| 5ac3d488a4 | |||
| ab34f8229b | |||
| f802bdd3ec | |||
| cc384efee0 | |||
| f815f3e3cf | |||
| 4e2087d6eb | |||
| e6893f58be | |||
| 9b8606483d | |||
| 2c578c6f1c | |||
| e397e4eee9 | |||
| dd86dce171 | |||
| e3813b1ea4 | |||
| bb2a4c10af | |||
| 1fc01df39c | |||
| 0e3cef813f | |||
| 87259f989d | |||
| 67d8079c47 | |||
| b247603b7e | |||
| f516148e46 | |||
| 5c50755652 | |||
| 3fae64f975 | |||
| 510360b002 | |||
| 9e4f4edb92 | |||
| ac815bf638 | |||
| 63c30b9ebe | |||
| 53ab87dc36 | |||
| 56e4b6d688 | |||
| 38d4ea72b1 | |||
| 9862ec82e3 | |||
| caa0a15803 | |||
| e909ec122c | |||
| d2cd775309 | |||
| c7a18fd4f0 | |||
| b44b88e00e | |||
| 54f5efb23f | |||
| e53f3197ac | |||
| d4fc9bbb91 | |||
| 28c54e4b39 | |||
| 1c814464c5 | |||
| 204ec93c5a | |||
| 72dbdca1f3 | |||
| 5d3a799e33 | |||
| 40a91f39ed | |||
| 5df0747642 | |||
| c64f8750e2 | |||
| dfcc851d2a | |||
| 259b4d9b35 | |||
| d46f0adb5e | |||
| eb1e780733 | |||
| 2eefae0618 | |||
| c35481f344 | |||
| 71735b10a2 | |||
| 8cf4b3fed6 | |||
| 2fdefa6040 | |||
| 55c1de8734 | |||
| 808c4a6f7a | |||
| 3a87d02696 | |||
| ce80e64b24 | |||
| c167ecc714 | |||
| 02448e176c | |||
| 7b17b4a1b9 | |||
| d70b00f30d | |||
| a476ec7976 | |||
| 19fcf60599 | |||
| 5ffe50ed02 | |||
| 3eda72e8c2 | |||
| d490d4f9f1 | |||
| e7f8ee6b91 | |||
| 4919c9c2fc | |||
| 253d8d3632 | |||
| 07505e7ef2 | |||
| 1e8b5b0523 | |||
| 63a1fa1378 | |||
| 8892f51096 | |||
| 7ef6c7ec75 | |||
| 7b8c134c21 | |||
| e3219f17dd | |||
| e738741521 | |||
| 69352babfd | |||
| 029a1ebba2 | |||
| 73a376ac6c | |||
| fe9d28bf4e | |||
| 1005a677f2 | |||
| dc71fc986c | |||
| 24a35f1174 | |||
| 473552cc81 | |||
| 6e2212de7b | |||
| fdf9866e88 | |||
| 47ba3d9028 | |||
| b24c523fa4 | |||
| 9e713bc39c | |||
| c446c07a4c | |||
| ab5584f421 | |||
| afa4d23a4f | |||
| b401f7acc1 | |||
| cc930a114f | |||
| 79ed7a335b | |||
| 12172d7b75 | |||
| 411206e45a | |||
| e146c7a337 | |||
| a5f52c4581 | |||
| a09b622a1d | |||
| c9dc592dcc | |||
| 80f3468ff8 | |||
| 12cfcb10ac | |||
| cc9cec922a | |||
| 7f8a7ea7ed | |||
| 0af0ef681f | |||
| cf42214974 | |||
| 31e6740033 | |||
| 4318adc98c | |||
| 3514d46954 | |||
| 63e29f024c | |||
| f4062010e9 | |||
| e8c1d54a96 | |||
| cac8c740fa | |||
| 73129b59d5 | |||
| 31d842fca4 | |||
| f5e7fe4245 | |||
| bf73f7edaf | |||
| 093ca0d260 | |||
| a2012a5afe | |||
| 9faaa2094d | |||
| 8075892e0e | |||
| 6cfaaf0bf9 | |||
| 05b09b4c98 | |||
| b1ccaf08bd | |||
| d0ad364ad4 | |||
| 70d05bd504 | |||
| f4533331e7 | |||
| dd6a449921 | |||
| ec9a650e65 | |||
| 3d2a103dfb | |||
| ae61e99e06 | |||
| 077b38e684 | |||
| d15cc79822 | |||
| 6bd3228990 | |||
| 7605a0253c | |||
| abf45ef9db | |||
| cf8b9e425e | |||
| 12f4ba8431 | |||
| 355201f094 | |||
| d163bad406 | |||
| 0aad2294ec | |||
| d2b0413c30 | |||
| a4c7a756f0 | |||
| 9f59000f5b | |||
| 7d8f34de17 | |||
| 9ad6347044 | |||
| 584e455f2d | |||
| 0a7525b125 | |||
| 1dad96102a | |||
| 20d011f8e9 | |||
| 637d07400e | |||
| 66a2bc2214 | |||
| 334469ef61 | |||
| e543525eb7 | |||
| 7e7f3ab297 | |||
| b0b0b62bce | |||
| 9259808f80 | |||
| 9662680bb0 | |||
| 6a24b14f0e | |||
| 57b66bdf47 | |||
| 0677aee93f | |||
| 0c73287e35 | |||
| dc75a5a5ab | |||
| c57eafcacc | |||
| f5ab5cf88a | |||
| 45e14dbb99 | |||
| cc89fc37a4 | |||
| 3ac0d8d5cb | |||
| e6f565a6c4 | |||
| 86492064aa | |||
| ba756cccc1 | |||
| 0998cb5a18 | |||
| f7f47152bd | |||
| 18d23ca20d | |||
| a88aecb993 | |||
| ab6f310013 | |||
| 4975c60ac1 | |||
| 5ca14eeaec | |||
| 031137a5fa | |||
| 6169cd05b9 | |||
| 9dff8f21bd | |||
| c5693db0e4 | |||
| ae52e9c4da | |||
| 182cbf3cc3 | |||
| b22f65f598 | |||
| b5d13180a6 | |||
| b12228c662 | |||
| d34fb5bc63 | |||
| f094acfdb5 | |||
| 4979cc0c94 | |||
| 9dfa2951f6 | |||
| 7f9f8de08a | |||
| 28f661c36f | |||
| 1256bbfec7 | |||
| bb267ff3d5 | |||
| 43d5eb5b88 | |||
| c1db0d71ed | |||
| 45fe909128 | |||
| 48c701cf1b | |||
| ebb1a00352 | |||
| 6a7f1dd393 | |||
| bd542bd6e4 | |||
| b055fc2496 | |||
| 1900f9ca80 | |||
| e010c2cecc | |||
| f92d7f89c6 | |||
| da57b20156 | |||
| 1a2259bdca | |||
| c0884705c7 | |||
| fa6c422f9b | |||
| 6dfdee75e2 | |||
| 2980f050ed | |||
| 132deac5bc | |||
| 9a43b14f80 | |||
| 619476ffed | |||
| 2a2f463d5b | |||
| ce94944c2d | |||
| 65c1b9ca5c | |||
| 95a65b05ca | |||
| d80786e99a | |||
| a868378b99 | |||
| 00ebd6df77 | |||
| 750d13779d | |||
| 6525c11b3c | |||
| 0224af64ab | |||
| 762a74624c | |||
| ac539b0150 | |||
| ad8f44b78a | |||
| fd750f3588 | |||
| 5b9403c343 | |||
| ef745a141d | |||
| 44ecd55a86 | |||
| eb1cd3e01a | |||
| cdfffa62bb | |||
| d8300a7bf9 | |||
| bda53f759e | |||
| 97d75e1d5e | |||
| 520575a839 | |||
| 989bdca736 | |||
| 3706920e16 | |||
| 00df8839e6 | |||
| dcf6c55a4e | |||
| f2b976c976 | |||
| b9eda646fc | |||
| 5b28063b52 | |||
| c1eb5f399f | |||
| 04cda22d19 | |||
| c10abd9f9f | |||
| f5d1a62ccf | |||
| 6942c36853 | |||
| 1b7408c6a1 | |||
| 66940f9c0a | |||
| a674c9b372 | |||
| 072f9a848e | |||
| 451bc9063c | |||
| 4fc4768083 | |||
| c660ac881c | |||
| eb428ba5f3 | |||
| 7d93f44e53 | |||
| 2c427816d9 | |||
| c55a1cc7f2 | |||
| ce3986bb02 | |||
| 447acc11bd | |||
| 51d82063aa | |||
| f97d54aa2a | |||
| 78c1f4f9ca | |||
| 4d3479d431 | |||
| 43c379aa0f | |||
| 3fb1b7cd87 | |||
| bd79b276e9 | |||
| 81d4344bdc | |||
| d9c3d1a602 | |||
| 54eeef5f8d | |||
| 208cad7ca1 | |||
| 043d8d81a2 | |||
| 28e8769a8b | |||
| dc9138846f | |||
| bfec11926f | |||
| 751532831a | |||
| e58e8ae263 | |||
| a90c58eb09 | |||
| d6ffdfa638 | |||
| 21bc611455 | |||
| 39a7593521 | |||
| 096f851408 | |||
| 7586c3ad25 | |||
| 762d39bdff | |||
| fb4d904ab6 | |||
| 40d78cbd92 | |||
| 55b0e2ebf6 | |||
| 885943e73f | |||
| 09247c57cf | |||
| 6117f73602 | |||
| 63d9f61bf1 | |||
| 3300fb3957 | |||
| 00d25dcc3e | |||
| 1bc255bc40 | |||
| cb05721a89 | |||
| 5801005fca | |||
| 572e09b2b1 | |||
| 3e76785b40 | |||
| 7a0c03dd21 | |||
| 1ce164a01e | |||
| a4a3d75cd9 | |||
| 70bda0c4df | |||
| 219e638316 | |||
| b16b7aaf0b | |||
| 38b6b81cd7 | |||
| 925d133466 | |||
| 6bcb5f4ae1 | |||
| c069459343 | |||
| cf814d4a97 | |||
| 841ae1d442 | |||
| 3137df4fe6 | |||
| ee2595e139 | |||
| 3c27606747 | |||
| 39ad8e85d9 | |||
| cbf38fb316 | |||
| d80226f948 | |||
| be74b4de6f | |||
| ce5bf0fe0e | |||
| 9ba093bf07 | |||
| 9c00cd3e44 | |||
| 6043a67631 | |||
| 2542cb591d | |||
| 9d1df6ec32 | |||
| f25289db20 | |||
| 470971bf70 | |||
| 6588c9d4ae | |||
| b839304f91 | |||
| b24f0dd572 | |||
| e175619543 | |||
| f369fbd227 | |||
| 4aaf27c669 | |||
| bfa763a55b | |||
| a916fa5118 | |||
| 44e752b606 | |||
| 29fcef3b9c | |||
| 2caf74946f | |||
| aca263642d | |||
| 005cc39394 | |||
| 7e07573026 | |||
| c9ee303b69 | |||
| 80da7e6275 | |||
| f81ca5c3c1 | |||
| 266e8cdd86 | |||
| 0a3df45d20 | |||
| 60a1547124 | |||
| 4b81b55849 | |||
| d41de1f7c9 | |||
| 5c4c10a1d7 | |||
| 2f3833a295 | |||
| 583783449a | |||
| bf36bc8a8f | |||
| e3e1bc7784 | |||
| 8fed9add66 | |||
| 647dfec334 | |||
| ad548840c7 | |||
| e9c2c51bc3 | |||
| b2a6a45a56 | |||
| 347352cc4c | |||
| f2cb3cd7e8 | |||
| 23e232e380 | |||
| 3eb5447f74 | |||
| f3f1336882 | |||
| ab4546e365 | |||
| ad3be0c53c | |||
| 0497029dae | |||
| bdf1a97550 | |||
| 57b8747c31 | |||
| d9287d6b1d | |||
| bccd26fb29 | |||
| 6a83c28e05 | |||
| 5af5bdd060 | |||
| 7f55554ae2 | |||
| dbb4ca6403 | |||
| 46c275c4c1 | |||
| 9ce69d23e3 | |||
| 02a8bcc324 | |||
| dd5cb5817b | |||
| ed385efa7b | |||
| 764a0296ce | |||
| 78a5719fae | |||
| b8c71d2a8e | |||
| 58e1105f2d | |||
| 0cb57774d7 | |||
| bc301c8d17 | |||
| 071c268de7 | |||
| 79776d1f6a | |||
| 0b149a6876 | |||
| 6c6dfae235 | |||
| 7cbd5d175c | |||
| 075a7b1430 | |||
| e1537d2d45 | |||
| 035e6dfe41 | |||
| 7c868585de | |||
| 2c44bae496 |
2504 changed files with 822066 additions and 75703 deletions
|
|
@ -6,6 +6,12 @@
|
||||||
"runtimeExecutable": "python3",
|
"runtimeExecutable": "python3",
|
||||||
"runtimeArgs": ["-m", "http.server", "8123", "-d", "build/web"],
|
"runtimeArgs": ["-m", "http.server", "8123", "-d", "build/web"],
|
||||||
"port": 8123
|
"port": 8123
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ludic-docs",
|
||||||
|
"runtimeExecutable": "python3",
|
||||||
|
"runtimeArgs": ["-m", "http.server", "8124", "-d", "build/pages"],
|
||||||
|
"port": 8124
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ labels:
|
||||||
|
|
||||||
## Environment
|
## Environment
|
||||||
|
|
||||||
- Command used (e.g. `bin/x app foo.ludic --headless`):
|
- Command used (e.g. `bin/ludic build foo.ludic --headless`):
|
||||||
- Target (native macOS / headless / web-wasm):
|
- Target (native macOS / headless / web-wasm):
|
||||||
- Commit (`git rev-parse --short HEAD`):
|
- Commit (`git rev-parse --short HEAD`):
|
||||||
- OS / arch:
|
- OS / arch:
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,13 @@ Closes #
|
||||||
|
|
||||||
## Checklist
|
## Checklist
|
||||||
|
|
||||||
- [ ] `bin/x test` passes.
|
- [ ] `bin/ludic-dev test` passes.
|
||||||
- [ ] For compiler/runtime changes: `bin/x reseed && bin/x bootstrap-cfree`
|
- [ ] For compiler/runtime changes: `bin/ludic-dev reseed && bin/ludic-dev bootstrap-cfree`
|
||||||
still reaches the self-hosting fixpoint with no C compiler in the loop.
|
still reaches the self-hosting fixpoint with no C compiler in the loop.
|
||||||
- [ ] `ludic-fmt` leaves the touched files unchanged (2-space, LF, UTF-8).
|
- [ ] `ludic-fmt` leaves the touched files unchanged (2-space, LF, UTF-8).
|
||||||
- [ ] New/changed stdlib symbols are documented under `docs/language/**` and
|
- [ ] New/changed stdlib symbols are documented under `docs/language/**` and
|
||||||
registered in `tools/docgen/inventory.json`
|
registered in `tools/docgen/inventory.json`
|
||||||
(`bin/x docs-gen && bin/x docs-check build/pages` passes).
|
(`bin/ludic-dev docs-gen && bin/ludic-dev docs-check build/pages` passes).
|
||||||
- [ ] Commits follow [Conventional Commits](https://www.conventionalcommits.org).
|
- [ ] Commits follow [Conventional Commits](https://www.conventionalcommits.org).
|
||||||
- [ ] No new C / Python / JS in tooling (Ludic only), and no generated
|
- [ ] No new C / Python / JS in tooling (Ludic only), and no generated
|
||||||
artifacts committed outside `build/` / `bin/`.
|
artifacts committed outside `build/` / `bin/`.
|
||||||
|
|
|
||||||
|
|
@ -25,14 +25,17 @@ jobs:
|
||||||
clang-16 --version | head -1
|
clang-16 --version | head -1
|
||||||
|
|
||||||
- name: Check out the triggering commit
|
- name: Check out the triggering commit
|
||||||
|
env:
|
||||||
|
# the repository that triggered the run, so a fork or a mirror tests itself
|
||||||
|
REPO_URL: ${{ github.server_url }}/${{ github.repository }}.git
|
||||||
run: |
|
run: |
|
||||||
set -eu
|
set -eu
|
||||||
git config --global --add safe.directory '*'
|
git config --global --add safe.directory '*'
|
||||||
git clone https://git.workshopsoft.io/workshopsoft/ludic.git .
|
git clone "$REPO_URL" .
|
||||||
git checkout "${GITHUB_SHA}" 2>/dev/null || git checkout "${GITHUB_REF_NAME:-main}"
|
git checkout "${GITHUB_SHA}" 2>/dev/null || git checkout "${GITHUB_REF_NAME:-main}"
|
||||||
git log --oneline -1
|
git log --oneline -1
|
||||||
# See ci.yml for why the Linux build injects the stdio shim via LUDIC_CC.
|
# See ci.yml for why the Linux build injects the stdio shim via LUDIC_CC.
|
||||||
echo "LUDIC_CC=clang-16 $(pwd)/tools/ci/linux_stdio_shim.ll" >> "$GITHUB_ENV"
|
echo "LUDIC_CC=clang-16 $(pwd)/tools/ci/linux_stdio_shim.ll -lm" >> "$GITHUB_ENV"
|
||||||
echo "LUDIC_HOME=$(pwd)" >> "$GITHUB_ENV"
|
echo "LUDIC_HOME=$(pwd)" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
- name: Bootstrap x from the seed
|
- name: Bootstrap x from the seed
|
||||||
|
|
@ -40,11 +43,11 @@ jobs:
|
||||||
set -eu
|
set -eu
|
||||||
mkdir -p bin
|
mkdir -p bin
|
||||||
clang-16 tools/ci/linux_stdio_shim.ll selfhost/ludicc.seed.ll -o bin/ludicc
|
clang-16 tools/ci/linux_stdio_shim.ll selfhost/ludicc.seed.ll -o bin/ludicc
|
||||||
bin/ludicc tools/x/main.ludic -o bin/x
|
bin/ludicc tools/ludic-cli/dev.ludic -o bin/ludic-dev
|
||||||
|
|
||||||
- name: Rebuild the compiler from the seed and assert byte-identity
|
- name: Rebuild the compiler from the seed and assert byte-identity
|
||||||
# `x bootstrap-cfree` assembles the seed with clang, has that seed
|
# `ludic-dev bootstrap-cfree` assembles the seed with clang, has that seed
|
||||||
# compiler recompile selfhost.ludic to out.ll, and `cmp`s out.ll against
|
# compiler recompile selfhost.ludic to out.ll, and `cmp`s out.ll against
|
||||||
# the checked-in seed. It returns non-zero if they differ — i.e. if the
|
# the checked-in seed. It returns non-zero if they differ — i.e. if the
|
||||||
# seed is stale relative to the compiler source.
|
# seed is stale relative to the compiler source.
|
||||||
run: bin/x bootstrap-cfree
|
run: bin/ludic-dev bootstrap-cfree
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ name: ci
|
||||||
|
|
||||||
# Build the language toolchain from its IR seed and run the regression suites on
|
# Build the language toolchain from its IR seed and run the regression suites on
|
||||||
# every push to main and every pull request. Until this landed the only workflow
|
# every push to main and every pull request. Until this landed the only workflow
|
||||||
# was docs.yml, so nothing gated a change on `x test` / `x test-tools` or on the
|
# was docs.yml, so nothing gated a change on `ludic-dev test` / `ludic-dev test-tools` or on the
|
||||||
# compiler even building from the seed. See also bootstrap.yml, which proves the
|
# compiler even building from the seed. See also bootstrap.yml, which proves the
|
||||||
# C-free self-rebuild reproduces the seed byte-for-byte.
|
# C-free self-rebuild reproduces the seed byte-for-byte.
|
||||||
on:
|
on:
|
||||||
|
|
@ -33,19 +33,22 @@ jobs:
|
||||||
clang-16 --version | head -1
|
clang-16 --version | head -1
|
||||||
|
|
||||||
- name: Check out the triggering commit
|
- name: Check out the triggering commit
|
||||||
|
env:
|
||||||
|
# the repository that triggered the run, so a fork or a mirror tests itself
|
||||||
|
REPO_URL: ${{ github.server_url }}/${{ github.repository }}.git
|
||||||
run: |
|
run: |
|
||||||
set -eu
|
set -eu
|
||||||
git config --global --add safe.directory '*'
|
git config --global --add safe.directory '*'
|
||||||
git clone https://git.workshopsoft.io/workshopsoft/ludic.git .
|
git clone "$REPO_URL" .
|
||||||
git checkout "${GITHUB_SHA}" 2>/dev/null || git checkout "${GITHUB_REF_NAME:-main}"
|
git checkout "${GITHUB_SHA}" 2>/dev/null || git checkout "${GITHUB_REF_NAME:-main}"
|
||||||
git log --oneline -1
|
git log --oneline -1
|
||||||
# The toolchain is macOS-first; on this Linux runner it links against a
|
# The toolchain is macOS-first; on this Linux runner it links against a
|
||||||
# tiny C-free IR shim that supplies the Darwin standard-stream globals
|
# tiny C-free IR shim that supplies the Darwin standard-stream globals
|
||||||
# (__stdoutp/__stderrp) over glibc's stdout/stderr. Injected through
|
# (__stdoutp/__stderrp) over glibc's stdout/stderr. Injected through
|
||||||
# LUDIC_CC so every clang invocation — the seed bootstrap, `x build`,
|
# LUDIC_CC so every clang invocation — the seed bootstrap, `ludic-dev build`,
|
||||||
# and each compiled test program — picks it up. Absolute path so it
|
# and each compiled test program — picks it up. Absolute path so it
|
||||||
# still resolves if a step changes directory.
|
# still resolves if a step changes directory.
|
||||||
echo "LUDIC_CC=clang-16 $(pwd)/tools/ci/linux_stdio_shim.ll" >> "$GITHUB_ENV"
|
echo "LUDIC_CC=clang-16 $(pwd)/tools/ci/linux_stdio_shim.ll -lm" >> "$GITHUB_ENV"
|
||||||
echo "LUDIC_HOME=$(pwd)" >> "$GITHUB_ENV"
|
echo "LUDIC_HOME=$(pwd)" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
- name: Bootstrap the toolchain from the IR seed (clang only)
|
- name: Bootstrap the toolchain from the IR seed (clang only)
|
||||||
|
|
@ -57,20 +60,20 @@ jobs:
|
||||||
# pre-built binaries: the language builds itself from source + seed.
|
# pre-built binaries: the language builds itself from source + seed.
|
||||||
mkdir -p bin
|
mkdir -p bin
|
||||||
clang-16 tools/ci/linux_stdio_shim.ll selfhost/ludicc.seed.ll -o bin/ludicc
|
clang-16 tools/ci/linux_stdio_shim.ll selfhost/ludicc.seed.ll -o bin/ludicc
|
||||||
bin/ludicc tools/x/main.ludic -o bin/x
|
bin/ludicc tools/ludic-cli/dev.ludic -o bin/ludic-dev
|
||||||
bin/x build
|
bin/ludic-dev build
|
||||||
|
|
||||||
- name: Regression suite (x test)
|
- name: Regression suite (ludic-dev test)
|
||||||
run: bin/x test
|
run: bin/ludic-dev test
|
||||||
|
|
||||||
- name: Editor-toolchain suite (x test-tools)
|
- name: Editor-toolchain suite (ludic-dev test-tools)
|
||||||
# Grammar/lexer/vocabulary sync, ludic-fmt idempotence (the project's
|
# Grammar/lexer/vocabulary sync, ludic-fmt idempotence (the project's
|
||||||
# formatting contract — hand alignment is deliberately preserved, so the
|
# formatting contract — hand alignment is deliberately preserved, so the
|
||||||
# gate is fmt(fmt(x)) == fmt(x), not fmt(x) == x), and the JSON/XML editor
|
# gate is fmt(fmt(x)) == fmt(x), not fmt(x) == x), and the JSON/XML editor
|
||||||
# assets. Cross-file LSP behaviour and the golden renders are macOS-ABI
|
# assets. Cross-file LSP behaviour and the golden renders are macOS-ABI
|
||||||
# bound and skip here — visibly — until the runtime's directory walk and
|
# bound and skip here — visibly — until the runtime's directory walk and
|
||||||
# windowing are portable.
|
# windowing are portable.
|
||||||
run: bin/x test-tools
|
run: bin/ludic-dev test-tools
|
||||||
|
|
||||||
- name: Docs cover the implementation
|
- name: Docs cover the implementation
|
||||||
run: |
|
run: |
|
||||||
|
|
@ -78,9 +81,9 @@ jobs:
|
||||||
# The whole docs toolchain is written in Ludic and runs through x —
|
# The whole docs toolchain is written in Ludic and runs through x —
|
||||||
# no Python anywhere. check-impl / check-vocabulary / check-docs guard
|
# no Python anywhere. check-impl / check-vocabulary / check-docs guard
|
||||||
# the sources; docs-gen builds the site and docs-check is its coverage
|
# the sources; docs-gen builds the site and docs-check is its coverage
|
||||||
# + integrity guard. (check-vocabulary also runs in `x test-tools`.)
|
# + integrity guard. (check-vocabulary also runs in `ludic-dev test-tools`.)
|
||||||
bin/x check-impl
|
bin/ludic-dev check-impl
|
||||||
bin/x check-vocabulary
|
bin/ludic-dev check-vocabulary
|
||||||
bin/x check-docs
|
bin/ludic-dev check-docs
|
||||||
bin/x docs-gen --out build/pages
|
bin/ludic-dev docs-gen --out build/pages
|
||||||
bin/x docs-check build/pages
|
bin/ludic-dev docs-check build/pages
|
||||||
|
|
|
||||||
|
|
@ -17,13 +17,12 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- name: Check out with history
|
- name: Check out with history
|
||||||
env:
|
env:
|
||||||
BEFORE: ${{ github.event.before }}
|
REPO_URL: ${{ github.server_url }}/${{ github.repository }}.git
|
||||||
BASE: ${{ github.base_ref }}
|
|
||||||
run: |
|
run: |
|
||||||
set -eu
|
set -eu
|
||||||
git config --global --add safe.directory '*'
|
git config --global --add safe.directory '*'
|
||||||
# Full clone so both endpoints of the range are present.
|
# Full clone so both endpoints of the range are present.
|
||||||
git clone https://git.workshopsoft.io/workshopsoft/ludic.git .
|
git clone "$REPO_URL" .
|
||||||
git checkout "${GITHUB_SHA}" 2>/dev/null || git checkout "${GITHUB_REF_NAME:-main}"
|
git checkout "${GITHUB_SHA}" 2>/dev/null || git checkout "${GITHUB_REF_NAME:-main}"
|
||||||
|
|
||||||
- name: Lint the new commits
|
- name: Lint the new commits
|
||||||
|
|
@ -36,10 +35,15 @@ jobs:
|
||||||
# - pull_request: base branch .. this commit
|
# - pull_request: base branch .. this commit
|
||||||
# - push: the pushed range (event.before .. this commit)
|
# - push: the pushed range (event.before .. this commit)
|
||||||
# - new branch / unknown: just the tip commit
|
# - new branch / unknown: just the tip commit
|
||||||
|
# `event.before` is only usable if it still resolves: a force-push
|
||||||
|
# rewrites (and a gc can remove) the commit it names, which made this
|
||||||
|
# job fail with "Invalid revision range" on an otherwise clean push.
|
||||||
|
# Fall back to the tip commit in that case.
|
||||||
if [ -n "${BASE:-}" ]; then
|
if [ -n "${BASE:-}" ]; then
|
||||||
git fetch --quiet origin "${BASE}" 2>/dev/null || true
|
git fetch --quiet origin "${BASE}" 2>/dev/null || true
|
||||||
RANGE="origin/${BASE}..${GITHUB_SHA}"
|
RANGE="origin/${BASE}..${GITHUB_SHA}"
|
||||||
elif [ -n "${BEFORE:-}" ] && ! printf '%s' "$BEFORE" | grep -qE '^0+$'; then
|
elif [ -n "${BEFORE:-}" ] && ! printf '%s' "$BEFORE" | grep -qE '^0+$' \
|
||||||
|
&& git cat-file -e "${BEFORE}^{commit}" 2>/dev/null; then
|
||||||
RANGE="${BEFORE}..${GITHUB_SHA}"
|
RANGE="${BEFORE}..${GITHUB_SHA}"
|
||||||
else
|
else
|
||||||
RANGE="${GITHUB_SHA}~1..${GITHUB_SHA}"
|
RANGE="${GITHUB_SHA}~1..${GITHUB_SHA}"
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,22 @@ on:
|
||||||
paths:
|
paths:
|
||||||
- 'docs/**'
|
- 'docs/**'
|
||||||
- 'tools/docgen/**'
|
- 'tools/docgen/**'
|
||||||
- 'tools/x/**'
|
- 'tools/ludic-cli/**'
|
||||||
|
# the site publishes the installer, so a change to it has to redeploy the
|
||||||
|
# site — otherwise a fixed install.sh sits in main while the old one is
|
||||||
|
# still what `curl … | sh` fetches
|
||||||
|
- 'install.sh'
|
||||||
- '.forgejo/workflows/docs.yml'
|
- '.forgejo/workflows/docs.yml'
|
||||||
workflow_dispatch: {}
|
workflow_dispatch: {}
|
||||||
|
|
||||||
|
# Deploying is a force-push of an orphan branch, so two runs racing can land out
|
||||||
|
# of order and leave `pages` holding the older build — the site would silently
|
||||||
|
# go backwards with both runs green. Serialise them, and let a newer push cancel
|
||||||
|
# an older one that is still building rather than queue behind it.
|
||||||
|
concurrency:
|
||||||
|
group: pages-deploy
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|
||||||
|
|
@ -25,8 +37,8 @@ jobs:
|
||||||
# "Waiting" forever with "no online runner found matching this label".
|
# "Waiting" forever with "no online runner found matching this label".
|
||||||
runs-on: docker
|
runs-on: docker
|
||||||
# The generator is now Ludic, so this builds the toolchain from its IR seed
|
# The generator is now Ludic, so this builds the toolchain from its IR seed
|
||||||
# (clang assembles the seed into bin/ludicc, which compiles bin/x) exactly
|
# (clang assembles the seed into bin/ludicc, which compiles bin/ludic) exactly
|
||||||
# like the ci workflow, then runs `x docs-gen`. node:20-bookworm carries git
|
# like the ci workflow, then runs `ludic-dev docs-gen`. node:20-bookworm carries git
|
||||||
# for the clone + publish; clang-16 is the only extra the bootstrap needs.
|
# for the clone + publish; clang-16 is the only extra the bootstrap needs.
|
||||||
container: node:20-bookworm
|
container: node:20-bookworm
|
||||||
steps:
|
steps:
|
||||||
|
|
@ -41,23 +53,23 @@ jobs:
|
||||||
- name: Generate the documentation site
|
- name: Generate the documentation site
|
||||||
env:
|
env:
|
||||||
SOURCE_REF: ${{ github.ref_name }}
|
SOURCE_REF: ${{ github.ref_name }}
|
||||||
|
REPO_URL: ${{ github.server_url }}/${{ github.repository }}.git
|
||||||
run: |
|
run: |
|
||||||
set -eu
|
set -eu
|
||||||
git config --global --add safe.directory '*'
|
git config --global --add safe.directory '*'
|
||||||
git clone --depth 1 --branch "${SOURCE_REF:-main}" \
|
git clone --depth 1 --branch "${SOURCE_REF:-main}" "$REPO_URL" src
|
||||||
https://git.workshopsoft.io/workshopsoft/ludic.git src
|
|
||||||
cd src
|
cd src
|
||||||
# The toolchain is macOS-first; on this Linux runner it links against a
|
# The toolchain is macOS-first; on this Linux runner it links against a
|
||||||
# tiny C-free IR shim supplying the Darwin stdout/stderr globals over
|
# tiny C-free IR shim supplying the Darwin stdout/stderr globals over
|
||||||
# glibc's, injected through LUDIC_CC. docs-gen is a pure CLI (no
|
# glibc's, injected through LUDIC_CC. docs-gen is a pure CLI (no
|
||||||
# windowing), so the C-free bootstrap is all it needs.
|
# windowing), so the C-free bootstrap is all it needs.
|
||||||
export LUDIC_CC="clang-16 $(pwd)/tools/ci/linux_stdio_shim.ll"
|
export LUDIC_CC="clang-16 $(pwd)/tools/ci/linux_stdio_shim.ll -lm"
|
||||||
export LUDIC_HOME="$(pwd)"
|
export LUDIC_HOME="$(pwd)"
|
||||||
mkdir -p bin
|
mkdir -p bin
|
||||||
clang-16 tools/ci/linux_stdio_shim.ll selfhost/ludicc.seed.ll -o bin/ludicc
|
clang-16 tools/ci/linux_stdio_shim.ll selfhost/ludicc.seed.ll -o bin/ludicc
|
||||||
bin/ludicc tools/x/main.ludic -o bin/x
|
bin/ludicc tools/ludic-cli/dev.ludic -o bin/ludic-dev
|
||||||
bin/x docs-gen --out ../public
|
bin/ludic-dev docs-gen --out ../public
|
||||||
bin/x docs-check ../public
|
bin/ludic-dev docs-check ../public
|
||||||
cd ..
|
cd ..
|
||||||
echo "--- generated files ---"
|
echo "--- generated files ---"
|
||||||
ls -la public
|
ls -la public
|
||||||
|
|
@ -67,6 +79,8 @@ jobs:
|
||||||
PAGES_TOKEN: ${{ secrets.PAGES_TOKEN }}
|
PAGES_TOKEN: ${{ secrets.PAGES_TOKEN }}
|
||||||
AUTO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
AUTO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
SOURCE_SHA: ${{ github.sha }}
|
SOURCE_SHA: ${{ github.sha }}
|
||||||
|
SERVER_URL: ${{ github.server_url }}
|
||||||
|
REPO: ${{ github.repository }}
|
||||||
run: |
|
run: |
|
||||||
set -eu
|
set -eu
|
||||||
TOKEN="${PAGES_TOKEN:-${AUTO_TOKEN:-}}"
|
TOKEN="${PAGES_TOKEN:-${AUTO_TOKEN:-}}"
|
||||||
|
|
@ -80,5 +94,6 @@ jobs:
|
||||||
git config user.email "docs@workshopsoft.io"
|
git config user.email "docs@workshopsoft.io"
|
||||||
git add -A
|
git add -A
|
||||||
git commit -q -m "docs: regenerate site from ${SOURCE_SHA}"
|
git commit -q -m "docs: regenerate site from ${SOURCE_SHA}"
|
||||||
git push -f "https://ludic-docs-bot:${TOKEN}@git.workshopsoft.io/workshopsoft/ludic.git" pages
|
# the same server and repository the run came from, with the token spliced in
|
||||||
|
git push -f "${SERVER_URL%%://*}://ludic-docs-bot:${TOKEN}@${SERVER_URL#*://}/${REPO}.git" pages
|
||||||
echo "published $(git rev-parse --short HEAD) to pages"
|
echo "published $(git rev-parse --short HEAD) to pages"
|
||||||
|
|
|
||||||
99
.forgejo/workflows/release.yml
Normal file
99
.forgejo/workflows/release.yml
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
name: release
|
||||||
|
|
||||||
|
# Cutting a release is `ludic-dev release` + `git push --tags`; everything after that
|
||||||
|
# happens here. Before this workflow existed the artifacts were built on whatever
|
||||||
|
# machine the maintainer happened to be sitting at, from whatever was in bin/ at
|
||||||
|
# the time, with no checksums and nothing proving the tagged tree even passed its
|
||||||
|
# tests. Now the tag is the trigger and CI is the only thing that publishes.
|
||||||
|
#
|
||||||
|
# The job refuses to publish unless:
|
||||||
|
# * the tag matches the VERSION file in the tagged tree,
|
||||||
|
# * CHANGELOG.md has a section for that version (it becomes the release notes),
|
||||||
|
# * the toolchain builds from the IR seed and the whole suite passes,
|
||||||
|
# * the C-free bootstrap still reproduces the seed byte-for-byte.
|
||||||
|
#
|
||||||
|
# Needs a repository secret FORGEJO_TOKEN with write access to releases.
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags: ['v*']
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
tag:
|
||||||
|
description: 'Tag to publish (e.g. v0.4.0)'
|
||||||
|
required: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: docker
|
||||||
|
container: node:20-bookworm
|
||||||
|
steps:
|
||||||
|
- name: Install clang-16
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
apt-get update -qq
|
||||||
|
apt-get install -y -qq --no-install-recommends clang-16 git ca-certificates curl
|
||||||
|
clang-16 --version | head -1
|
||||||
|
|
||||||
|
- name: Check out the tag
|
||||||
|
env:
|
||||||
|
REPO_URL: ${{ github.server_url }}/${{ github.repository }}.git
|
||||||
|
INPUT_TAG: ${{ github.event.inputs.tag }}
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
git config --global --add safe.directory '*'
|
||||||
|
# A full clone: `git archive` needs the tag object, and the tarball is
|
||||||
|
# built from the tag rather than from the working tree.
|
||||||
|
git clone "$REPO_URL" .
|
||||||
|
TAG="${INPUT_TAG:-${GITHUB_REF_NAME}}"
|
||||||
|
git checkout "$TAG"
|
||||||
|
echo "TAG=$TAG" >> "$GITHUB_ENV"
|
||||||
|
# See ci.yml for why the Linux build injects the stdio shim via LUDIC_CC.
|
||||||
|
echo "LUDIC_CC=clang-16 $(pwd)/tools/ci/linux_stdio_shim.ll -lm" >> "$GITHUB_ENV"
|
||||||
|
echo "LUDIC_HOME=$(pwd)" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
|
- name: The tag, VERSION and CHANGELOG must agree
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
VERSION="$(cat VERSION)"
|
||||||
|
if [ "$TAG" != "v${VERSION}" ]; then
|
||||||
|
echo "::error::tag ${TAG} does not match VERSION (${VERSION})"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if ! grep -q "^## v${VERSION} " CHANGELOG.md; then
|
||||||
|
echo "::error::CHANGELOG.md has no '## v${VERSION}' section to use as release notes"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "publishing ${TAG}"
|
||||||
|
|
||||||
|
- name: Build the toolchain from the IR seed (clang only)
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
mkdir -p bin
|
||||||
|
clang-16 tools/ci/linux_stdio_shim.ll selfhost/ludicc.seed.ll -o bin/ludicc
|
||||||
|
bin/ludicc tools/ludic-cli/dev.ludic -o bin/ludic-dev
|
||||||
|
bin/ludic-dev build
|
||||||
|
|
||||||
|
- name: The tagged tree must pass its own suites
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
bin/ludic-dev test
|
||||||
|
bin/ludic-dev test-tools
|
||||||
|
bin/ludic-dev bootstrap-cfree
|
||||||
|
|
||||||
|
- name: Publish the release
|
||||||
|
env:
|
||||||
|
FORGEJO_TOKEN: ${{ secrets.FORGEJO_TOKEN }}
|
||||||
|
LUDIC_FORGEJO_API: ${{ github.server_url }}/api/v1/repos/${{ github.repository }}
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
if [ -z "${FORGEJO_TOKEN:-}" ]; then
|
||||||
|
echo "::error::No FORGEJO_TOKEN secret; cannot create the release."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# ludic-dev publish builds dist/ (source tarball from the tag, this host's
|
||||||
|
# toolchain, SHA256SUMS), takes the notes from the CHANGELOG section,
|
||||||
|
# and creates the release. Re-running it only adds missing assets, so
|
||||||
|
# a maintainer can afterwards attach the macOS toolchain from a Mac
|
||||||
|
# with the same command.
|
||||||
|
bin/ludic-dev publish "$TAG"
|
||||||
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
packages/*/lib/** filter=lfs diff=lfs merge=lfs -text
|
||||||
36
.gitignore
vendored
36
.gitignore
vendored
|
|
@ -1,6 +1,6 @@
|
||||||
# Generated build tree: LLVM IR, objects, compiled apps, the headless render
|
# Generated build tree: LLVM IR, objects, compiled apps, the headless render
|
||||||
# (build/out.ppm) and the docs site all land under build/ (see `bin/x build` /
|
# (build/out.ppm) and the docs site all land under build/ (see `bin/ludic-dev build` /
|
||||||
# `bin/x clean`). Root-anchored so a source dir named "build" elsewhere is never
|
# `bin/ludic clean`). Root-anchored so a source dir named "build" elsewhere is never
|
||||||
# accidentally ignored. Nothing is written to the repo root any more.
|
# accidentally ignored. Nothing is written to the repo root any more.
|
||||||
/build/
|
/build/
|
||||||
|
|
||||||
|
|
@ -9,16 +9,24 @@
|
||||||
# packaged plugin .zip are local-only build inputs/outputs.
|
# packaged plugin .zip are local-only build inputs/outputs.
|
||||||
*.zip
|
*.zip
|
||||||
|
|
||||||
# the toolchain binaries (ludicc, ludic, x, ludic-fmt, ludic-lsp) — all built
|
# the toolchain binaries (ludicc, ludic, ludic-dev, ludic-fmt, ludic-lsp) — all built
|
||||||
# into bin/ by the one-line bootstrap + `bin/x build`; never checked in. The
|
# into bin/ by the one-line bootstrap + `bin/ludic-dev build`; never checked in. The
|
||||||
# only thing published is the source and the LLVM-IR seed (selfhost/ludicc.seed.ll).
|
# only thing published is the source and the LLVM-IR seed (selfhost/ludicc.seed.ll).
|
||||||
/bin/
|
/bin/
|
||||||
|
|
||||||
|
# package manager (issue #63): the per-project linked view into the global
|
||||||
|
# content-addressed store, and the optional hermetic copy from `ludic vendor`. Both
|
||||||
|
# are regenerated by `ludic get` / `ludic vendor` — package.ludic + package.lock.ludic
|
||||||
|
# are the tracked source of truth, so these stay out of the tree.
|
||||||
|
ludic_modules/
|
||||||
|
vendor/
|
||||||
|
|
||||||
# editor toolchain build artifacts
|
# editor toolchain build artifacts
|
||||||
tools/editors/vscode/node_modules/
|
tools/editors/vscode/node_modules/
|
||||||
tools/editors/vscode/*.vsix
|
tools/editors/vscode/*.vsix
|
||||||
tools/editors/jetbrains/.gradle/
|
tools/editors/jetbrains/.gradle/
|
||||||
tools/editors/jetbrains/build/
|
tools/editors/jetbrains/build/
|
||||||
|
tools/editors/jetbrains/.kotlin/
|
||||||
|
|
||||||
# IntelliJ plugin SDK sandbox (tools/editors/jetbrains)
|
# IntelliJ plugin SDK sandbox (tools/editors/jetbrains)
|
||||||
.intellijPlatform/
|
.intellijPlatform/
|
||||||
|
|
@ -32,5 +40,23 @@ tools/editors/jetbrains/build/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.pyc
|
*.pyc
|
||||||
|
|
||||||
# Release artifacts produced by `x release`
|
# Release artifacts produced by `ludic-dev release`
|
||||||
/dist/
|
/dist/
|
||||||
|
|
||||||
|
# Build/release tarballs anywhere in the tree. `git -C <repo> archive -o foo.tgz`
|
||||||
|
# resolves -o relative to the repo, not the caller's directory, so a stray
|
||||||
|
# archive lands in the root and a blanket `git add -A` will commit it.
|
||||||
|
*.tar.gz
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# The CC0 Poly Haven downloads are fetched, not committed (`ludic-dev fetch-assets`
|
||||||
|
# reads the manifest that ships with the renderer, packages/ludic.render3d/assets.manifest,
|
||||||
|
# so a game outside this repository fetches the same set with `ludic assets`).
|
||||||
|
assets/polyhaven/hdri/
|
||||||
|
assets/polyhaven/textures/
|
||||||
|
assets/polyhaven/models/
|
||||||
|
# `ludic run` beside an example writes its binary into a build/ there
|
||||||
|
examples/**/build/
|
||||||
|
|
||||||
|
# a package native/build.sh writes its objects under the package (phase 15)
|
||||||
|
packages/*/build/
|
||||||
|
|
|
||||||
1211
CHANGELOG.md
1211
CHANGELOG.md
File diff suppressed because it is too large
Load diff
119
COMPILING.md
119
COMPILING.md
|
|
@ -1,37 +1,46 @@
|
||||||
# Compiling Ludic
|
# Compiling Ludic
|
||||||
|
|
||||||
> **Note (2026-08-27):** `ludicc` is now **written in Ludic** (`selfhost/*.ludic`)
|
> **Note:** `ludicc` is **written in Ludic** (`selfhost/*.ludic`) and built from a
|
||||||
> and built from a checked-in IR seed — the C compiler this document describes has
|
> checked-in IR seed — the C compiler this document once described has been
|
||||||
> been deleted. The native pipeline below (Ludic → LLVM IR → object → binary) is
|
> deleted. The native pipeline below (Ludic → LLVM IR → object → binary) is
|
||||||
> unchanged. `ludicc` now drives clang itself (via an `os_system` intrinsic), so
|
> unchanged. `ludicc` drives clang itself (via an `os_system` intrinsic), so
|
||||||
> `ludicc app.ludic -o bin/app` and `--emit-llvm` work directly, and a sibling
|
> `ludicc app.ludic -o bin/app` and `--emit-llvm` work directly. `--fmt` is
|
||||||
> command `ludic app.ludic` compiles to a temporary binary and runs it in one
|
> reimplemented as a lex+parse gate (the doc-check hook). The `--target`/
|
||||||
> step. The whole toolchain is built by `bin/x build`; `bin/x app` remains as a
|
> cross-compile and `--shared` paths are still features of the old C driver not
|
||||||
> convenience wrapper over the compiler. `--fmt` is reimplemented as a lex+parse
|
> yet re-implemented on the self-hosted toolchain. See the
|
||||||
> gate (the doc-check hook). The `--target`/cross-compile and `--shared` paths are
|
> [Bootstrap deep-dive](https://git.workshopsoft.io/workshopsoft/ludic/wiki/Bootstrap) §5.7 on the wiki.
|
||||||
> still features of the old C driver not yet re-implemented on the self-hosted
|
|
||||||
> toolchain. See the [Bootstrap deep-dive](https://git.workshopsoft.io/workshopsoft/ludic/wiki/Bootstrap) §5.7 on the wiki.
|
|
||||||
>
|
>
|
||||||
> From a clean checkout, build the compiler and the task-runner in one line, then
|
> Most people never invoke `ludicc` directly: the `ludic` CLI drives it.
|
||||||
> let `bin/x` do the rest (run it from the repository root):
|
|
||||||
>
|
>
|
||||||
> ```bash
|
> ```bash
|
||||||
> # one-time bootstrap: clang assembles the seed, then ludicc compiles bin/x
|
> curl -fsSL https://workshopsoft.pages.workshopsoft.io/ludic/install.sh | sh # the toolchain, into ~/.ludic
|
||||||
> clang selfhost/ludicc.seed.ll -o bin/ludicc && bin/ludicc tools/x/main.ludic -o bin/x
|
> ludic new mygame && cd mygame
|
||||||
> bin/x build # rebuild the whole toolchain into bin/
|
> ludic run # compile + run
|
||||||
> # (ludicc, ludic, x, ludic-fmt, ludic-lsp)
|
> ludic build --headless # compile, deterministic render
|
||||||
> bin/ludicc examples/games/snake.ludic -o bin/snake # compile
|
|
||||||
> bin/ludic examples/games/snake.ludic # compile + run
|
|
||||||
> bin/x help # list every command
|
|
||||||
> ```
|
> ```
|
||||||
>
|
>
|
||||||
> The binaries are multi-call (one native binary under two names): invoked as
|
> From a clean checkout, the compiler and the CLI come up in two lines and the
|
||||||
> `ludicc` it compiles, as `ludic` it compiles-and-runs. A `.ludic` file with
|
> CLI does the rest (run it from the repository root):
|
||||||
> systems is a game and links windowed by default; `--headless` and `--windowed`
|
>
|
||||||
> force the mode. The runtime (`runtime/native/cocoa.ll`) is found via
|
> ```bash
|
||||||
> `$LUDIC_HOME`, defaulting to the directory the binary sits in — keep them in
|
> # one-time bootstrap: clang assembles the seed, then ludicc compiles bin/ludic
|
||||||
> `bin/`, or set `LUDIC_HOME` and put them on `PATH`. `$LUDIC_CC` overrides the
|
> mkdir -p bin && clang selfhost/ludicc.seed.ll -o bin/ludicc
|
||||||
> assembler/linker (default `clang`).
|
> bin/ludicc --unsafe --globals tools/ludic-cli/dev.ludic -o bin/ludic-dev
|
||||||
|
> bin/ludic-dev build # the whole toolchain into bin/
|
||||||
|
> # (ludicc, ludic, ludic-fmt, ludic-lsp)
|
||||||
|
> bin/ludicc examples/games/snake.ludic -o bin/snake # the compiler, directly
|
||||||
|
> bin/ludic build examples/games/snake.ludic # or through the CLI
|
||||||
|
> bin/ludic help # every command
|
||||||
|
> ```
|
||||||
|
>
|
||||||
|
> A `.ludic` file with handlers is a game and links windowed by default;
|
||||||
|
> `--headless` and `--windowed` force the mode. The engine runtime
|
||||||
|
> (`runtime/native/cocoa.ll`, the spliced `runtime/native/*.ludic`) and the
|
||||||
|
> bundled `ludic.*` packages are found under the **install root**: `$LUDIC_HOME`
|
||||||
|
> if set, otherwise derived from the binary's own location — the parent of its
|
||||||
|
> `bin/` directory, which is both `~/.ludic` for an install and the repository
|
||||||
|
> root for a checkout. `$LUDIC_CC` overrides the assembler/linker (default
|
||||||
|
> `clang`).
|
||||||
|
|
||||||
|
|
||||||
`ludicc` is a compiler, not a translator. It lexes, parses, checks and lowers
|
`ludicc` is a compiler, not a translator. It lexes, parses, checks and lowers
|
||||||
|
|
@ -42,10 +51,10 @@ and find your program rewritten in another language.
|
||||||
|
|
||||||
```
|
```
|
||||||
app.ludic
|
app.ludic
|
||||||
│ ludicc — lex, parse, check, lower (compiler/ludicc.c,
|
│ ludicc — lex, parse, lower (selfhost/frontend/*.ludic,
|
||||||
▼ compiler/native.c)
|
▼ selfhost/backend/*.ludic)
|
||||||
app.ll LLVM IR: your systems, your properties, your runtime
|
app.ll LLVM IR: your handlers, your properties, your runtime
|
||||||
│ IR assembler (compiler/driver.c)
|
│ IR assembler (selfhost/main.ludic drives $LUDIC_CC)
|
||||||
▼
|
▼
|
||||||
app.o Mach-O / ELF / COFF object code
|
app.o Mach-O / ELF / COFF object code
|
||||||
│ system linker
|
│ system linker
|
||||||
|
|
@ -64,6 +73,9 @@ point at a different LLVM toolchain if you have one.
|
||||||
| a windowed native executable | `ludicc game.ludic -o build/game` |
|
| a windowed native executable | `ludicc game.ludic -o build/game` |
|
||||||
| a headless executable | `ludicc game.ludic --headless -o build/game` |
|
| a headless executable | `ludicc game.ludic --headless -o build/game` |
|
||||||
| the IR, to read | `ludicc src.ludic --emit-llvm -o src.ll` |
|
| the IR, to read | `ludicc src.ludic --emit-llvm -o src.ll` |
|
||||||
|
| the schema an editor reads (records, registries and their entries, consts) | `ludicc src.ludic --emit-schema schema.json` |
|
||||||
|
| every error, as a JSON array on stdout | `ludicc src.ludic --check --diagnostics=json` |
|
||||||
|
| the same, with an unsaved buffer on stdin standing for one of its files | `ludicc src.ludic --check --diagnostics=json --stdin-file lib/a.ludic < buf` |
|
||||||
| a shared library † | `ludicc lib.ludic --shared -o build/liblib.dylib` |
|
| a shared library † | `ludicc lib.ludic --shared -o build/liblib.dylib` |
|
||||||
| a game that runs in a browser † | `ludicc game.ludic --target wasm32-unknown-unknown -o build/web/game.wasm` |
|
| a game that runs in a browser † | `ludicc game.ludic --target wasm32-unknown-unknown -o build/web/game.wasm` |
|
||||||
| an object file † | `ludicc src.ludic -c -o src.o` |
|
| an object file † | `ludicc src.ludic -c -o src.o` |
|
||||||
|
|
@ -73,32 +85,33 @@ the old C driver and are **not yet re-implemented** on the self-hosted toolchain
|
||||||
(see the note at the top). The rows above the line work today via the
|
(see the note at the top). The rows above the line work today via the
|
||||||
self-hosted `ludicc`.
|
self-hosted `ludicc`.
|
||||||
|
|
||||||
`bin/x app` wraps the common cases:
|
`bin/ludic build` wraps the common cases:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bin/x app examples/games/snake.ludic # -> build/snake (native)
|
bin/ludic build examples/games/snake.ludic # -> build/snake (native)
|
||||||
bin/x app examples/library/combat.ludic --lib # -> build/libcombat.* (library)
|
bin/ludic build examples/library/combat.ludic --lib # -> build/libcombat.* (library)
|
||||||
bin/x app examples/games/snake.ludic --headless # -> build/snake_headless (out.ppm)
|
bin/ludic build examples/games/snake.ludic --headless # -> build/snake_headless (out.ppm)
|
||||||
bin/x app examples/games/snake.ludic --web # -> build/web/ (browser)
|
bin/ludic build examples/games/snake.ludic --web # -> build/web/ (browser)
|
||||||
```
|
```
|
||||||
|
|
||||||
The `--lib` and `--web` targets were part of the old C driver and are **not yet
|
The `--lib` and `--web` targets were part of the old C driver and are **not yet
|
||||||
re-implemented** on the self-hosted toolchain — `bin/x app` supports the native
|
re-implemented** on the self-hosted toolchain — `bin/ludic build` supports the native
|
||||||
windowed and `--headless` builds today.
|
windowed and `--headless` builds today.
|
||||||
|
|
||||||
## Programs and libraries
|
## Programs and libraries
|
||||||
|
|
||||||
> **Not yet on the self-hosted toolchain.** `--shared` and the `nm`/library
|
> **Not yet on the self-hosted toolchain.** `--shared` and the `nm`/library
|
||||||
> workflow below describe the old C driver's behavior; the self-hosted `ludicc`
|
> workflow below describe the old C driver's behavior; the self-hosted `ludicc`
|
||||||
> builds executables only for now. The `module`/`@export fn` semantics are
|
> builds executables only for now. The `@export function` semantics are
|
||||||
> unchanged — only the packaging step is pending.
|
> unchanged — only the packaging step is pending.
|
||||||
|
|
||||||
A source file opens with `game Name { … }` or `module Name { … }`.
|
A source file opens with `program Name { … }`.
|
||||||
|
|
||||||
* A **game** gets an entry point and the phase-ordered frame loop
|
* A program with **handlers** is a game: it gets the phase-ordered frame loop
|
||||||
(`Start`, then `Input → FixedUpdate → Update → LateUpdate → Render` each tick).
|
(`Start`, then `Input → FixedUpdate → Update → LateUpdate → Render` each tick).
|
||||||
* A **module** gets neither. It is a library, and only its `@export fn`s become
|
* A program with only an **`entry`** block is a tool: it runs `entry` and exits.
|
||||||
public symbols; everything else stays private to the library.
|
* Either kind can be a library: only its `@export function`s become public
|
||||||
|
symbols; everything else stays private.
|
||||||
|
|
||||||
```ludic
|
```ludic
|
||||||
# doc-check: skip — illustrative: elided body
|
# doc-check: skip — illustrative: elided body
|
||||||
|
|
@ -196,8 +209,11 @@ intrinsics compile to nothing there, so a headless binary never references a
|
||||||
symbol the window would have provided.
|
symbol the window would have provided.
|
||||||
|
|
||||||
Other platforms build headless today. A Win32 or X11 port is another `.ll` file
|
Other platforms build headless today. A Win32 or X11 port is another `.ll` file
|
||||||
with the same five entry points — `win_open`, `win_poll`, `win_present`,
|
with the same entry points — the window (`win_open`, `win_poll`, `win_present`,
|
||||||
`win_running`, `win_close` — and no compiler change.
|
`win_running`, `win_close`), keys (`win_held`, `win_held_bit`), the mouse and
|
||||||
|
cursor (`win_mouse`, `win_cursor_mode`, `win_cursor_confine`,
|
||||||
|
`win_cursor_maintain`), gamepad (`win_pad`) and touch (`win_touch`) — and no
|
||||||
|
compiler change.
|
||||||
|
|
||||||
## The web
|
## The web
|
||||||
|
|
||||||
|
|
@ -219,7 +235,7 @@ only the triple changes.
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bin/x app examples/games/chronorift.ludic --web
|
bin/ludic build examples/games/chronorift.ludic --web
|
||||||
python3 -m http.server -d build/web 8000 # then open http://localhost:8000/
|
python3 -m http.server -d build/web 8000 # then open http://localhost:8000/
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -307,7 +323,7 @@ node tools/ludic-web/run.mjs build/web/snake_headless.wasm --stdin=ddss
|
||||||
```
|
```
|
||||||
|
|
||||||
Because Ludic is fixed-point and its RNG is seeded, the native headless binary
|
Because Ludic is fixed-point and its RNG is seeded, the native headless binary
|
||||||
and the wasm one must render byte-identical frames from the same input. `bin/x test`
|
and the wasm one must render byte-identical frames from the same input. `bin/ludic-dev test`
|
||||||
asserts exactly that, which is a much stronger check on the backend than
|
asserts exactly that, which is a much stronger check on the backend than
|
||||||
"it started".
|
"it started".
|
||||||
|
|
||||||
|
|
@ -321,13 +337,13 @@ entity allocator, save/load snapshots, the frame loop, the window, and the whole
|
||||||
graphics stack — framebuffer, PNG decoding, sprites, 9-slice, TrueType text and
|
graphics stack — framebuffer, PNG decoding, sprites, 9-slice, TrueType text and
|
||||||
the retained UI.
|
the retained UI.
|
||||||
|
|
||||||
None of it goes through C. `bin/x test` asserts that directly: no C source
|
None of it goes through C. `bin/ludic-dev test` asserts that directly: no C source
|
||||||
survives in `runtime/`, no C emitter survives in `ludicc`, and the examples all
|
survives in `runtime/`, no C emitter survives in `ludicc`, and the examples all
|
||||||
build, run and render from IR alone.
|
build, run and render from IR alone.
|
||||||
|
|
||||||
## Every flag
|
## Every flag
|
||||||
|
|
||||||
The self-hosted `ludicc`/`ludic` (built with `bin/x build-cli`) accept:
|
The self-hosted `ludicc`/`ludic` (built with `bin/ludic-dev build-cli`) accept:
|
||||||
|
|
||||||
```
|
```
|
||||||
<file.ludic> the program to compile (first non-flag argument)
|
<file.ludic> the program to compile (first non-flag argument)
|
||||||
|
|
@ -337,15 +353,18 @@ The self-hosted `ludicc`/`ludic` (built with `bin/x build-cli`) accept:
|
||||||
--windowed force a windowed (Cocoa) build
|
--windowed force a windowed (Cocoa) build
|
||||||
--headless force a headless build (stdin input, out.ppm output)
|
--headless force a headless build (stdin input, out.ppm output)
|
||||||
--emit-llvm stop at LLVM IR — write it and exit, no clang
|
--emit-llvm stop at LLVM IR — write it and exit, no clang
|
||||||
|
--check every check a build makes (types, modules, uses, layers, ports, binds); write nothing
|
||||||
--fmt lex + parse only; exit 0 if it parses, 1 on a parse error
|
--fmt lex + parse only; exit 0 if it parses, 1 on a parse error
|
||||||
(the check-docs gate; canonical formatting not yet restored)
|
(the check-docs gate; canonical formatting not yet restored)
|
||||||
--save-temps keep the intermediate .ll
|
--save-temps keep the intermediate .ll
|
||||||
--run compile then run (implicit when invoked as `ludic`)
|
--run compile then run (what `ludic run` uses)
|
||||||
(unknown -flags are ignored with a warning, never taken as the input file)
|
(unknown -flags are ignored with a warning, never taken as the input file)
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
LUDIC_CC the LLVM that assembles IR and drives the linker (clang)
|
LUDIC_CC the LLVM that assembles IR and drives the linker (clang)
|
||||||
LUDIC_HOME where runtime/native/ lives (default: the binary's dir)
|
LUDIC_HOME the install root — runtime/, packages/, VERSION
|
||||||
|
(default: the parent of the binary's bin/ directory)
|
||||||
|
LUDIC_MODULES the project's fetched packages (default: ./ludic_modules)
|
||||||
```
|
```
|
||||||
|
|
||||||
Mode is automatic when neither `--windowed` nor `--headless` is given: a program
|
Mode is automatic when neither `--windowed` nor `--headless` is given: a program
|
||||||
|
|
|
||||||
175
CONTRIBUTING.md
175
CONTRIBUTING.md
|
|
@ -18,18 +18,25 @@ runtime, and the tooling are all written in Ludic and built by Ludic.
|
||||||
From a clean checkout, one line lifts the toolchain off the seed:
|
From a clean checkout, one line lifts the toolchain off the seed:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
clang selfhost/ludicc.seed.ll -o bin/ludicc && bin/ludicc tools/x/main.ludic -o bin/x
|
mkdir -p bin && clang selfhost/ludicc.seed.ll -o bin/ludicc
|
||||||
|
bin/ludicc --unsafe --globals tools/ludic-cli/dev.ludic -o bin/ludic-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
That gives you `bin/x`, the Ludic task runner that replaces every build/test
|
That gives you `bin/ludic-dev`, the contributor tool: it replaces every
|
||||||
shell script in the repo. From then on it builds everything — including itself:
|
build/test shell script in the repo and builds everything, including itself and
|
||||||
|
`bin/ludic`. It is deliberately a separate binary from the `ludic` users install
|
||||||
|
— that one carries none of these tasks and is never asked to.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bin/x build # rebuild the whole toolchain into bin/ (ludicc, ludic, x, ludic-fmt, ludic-lsp)
|
bin/ludic-dev build # the whole toolchain into bin/ (ludicc, ludic, ludic-dev, ludic-fmt, ludic-lsp)
|
||||||
bin/x help # list every command
|
bin/ludic-dev help # every contributor task
|
||||||
|
bin/ludic help # what a user of the language sees
|
||||||
```
|
```
|
||||||
|
|
||||||
Always run `x` from the repository root, so `assets/` and `selfhost/` resolve.
|
Always run `ludic-dev` from the repository root, so `assets/` and `selfhost/`
|
||||||
|
resolve. (A checkout is also an install root: `bin/` beside `runtime/` and
|
||||||
|
`packages/`, exactly the shape `install.sh` lays down under `~/.ludic`, which is
|
||||||
|
why `bin/ludic` behaves there exactly as an installed one does.)
|
||||||
|
|
||||||
## The development loop
|
## The development loop
|
||||||
|
|
||||||
|
|
@ -37,18 +44,18 @@ When you change the compiler or runtime, prove the self-hosting fixpoint still
|
||||||
holds before you push:
|
holds before you push:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bin/x reseed # regenerate selfhost/ludicc.seed.ll after a compiler change
|
bin/ludic-dev reseed # regenerate selfhost/ludicc.seed.ll after a compiler change
|
||||||
bin/x bootstrap-cfree # rebuild the compiler from the seed with NO C compiler in the loop
|
bin/ludic-dev bootstrap-cfree # rebuild the compiler from the seed with NO C compiler in the loop
|
||||||
bin/x test # the full regression suite
|
bin/ludic-dev test # the full regression suite
|
||||||
```
|
```
|
||||||
|
|
||||||
Other useful targets:
|
Other useful targets:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bin/x app <file.ludic> [--headless] # compile a program to a native app in build/
|
bin/ludic build <file.ludic> [--headless] # compile a program to a native app in build/
|
||||||
bin/x selfhost-test # correctness + bootstrap fixpoints
|
bin/ludic-dev selfhost-test # correctness + bootstrap fixpoints
|
||||||
bin/x test-tools # the editor-toolchain suite (ludic-fmt, ludic-lsp)
|
bin/ludic-dev test-tools # the editor-toolchain suite (ludic-fmt, ludic-lsp)
|
||||||
bin/x clean # remove build/, out.ppm and stray artifacts
|
bin/ludic clean # remove build/, out.ppm and stray artifacts
|
||||||
```
|
```
|
||||||
|
|
||||||
## Adding to the standard library
|
## Adding to the standard library
|
||||||
|
|
@ -61,7 +68,7 @@ The stdlib lives in the runtime (`runtime/`) and is surfaced as namespaces
|
||||||
and register its id in `tools/docgen/inventory.json`. Each documented
|
and register its id in `tools/docgen/inventory.json`. Each documented
|
||||||
namespace gets exactly **one** directory (the docs check enforces this).
|
namespace gets exactly **one** directory (the docs check enforces this).
|
||||||
3. Add or extend an example under `examples/` and a case in the test suite.
|
3. Add or extend an example under `examples/` and a case in the test suite.
|
||||||
4. Run `python3 tools/docgen/gen.py && python3 tools/docgen/check.py` — the
|
4. Run `bin/ludic-dev docs-gen --out build/pages && bin/ludic-dev docs-check build/pages` — the
|
||||||
check fails if any inventory symbol lacks a page or is still seed text.
|
check fails if any inventory symbol lacks a page or is still seed text.
|
||||||
5. Add a **changeset** for the user-facing change: a small file under
|
5. Add a **changeset** for the user-facing change: a small file under
|
||||||
[`changes/`](changes/README.md) with a `bump:` level and a one-line summary.
|
[`changes/`](changes/README.md) with a `bump:` level and a one-line summary.
|
||||||
|
|
@ -70,20 +77,105 @@ The stdlib lives in the runtime (`runtime/`) and is surfaced as namespaces
|
||||||
## Versioning & releases
|
## Versioning & releases
|
||||||
|
|
||||||
The toolchain is versioned with [SemVer](https://semver.org); `VERSION` is the
|
The toolchain is versioned with [SemVer](https://semver.org); `VERSION` is the
|
||||||
single source of truth and `ludicc --version` (or `x version`) reports it.
|
single source of truth and `ludicc --version` (or `ludic version`) reports it.
|
||||||
|
|
||||||
Releases are changeset-driven. Every user-facing change ships with a changeset
|
Releases are changeset-driven. Every user-facing change ships with a changeset
|
||||||
(step 5 above). To cut a release:
|
(step 5 above). Read the next release before cutting it:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
x release [major|minor|patch] # omit the level to derive it from the changesets
|
ludic-dev release --dry-run # render the CHANGELOG section, write nothing
|
||||||
```
|
```
|
||||||
|
|
||||||
That aggregates the pending changesets into a new `CHANGELOG.md` section, bumps
|
Then cut it:
|
||||||
`VERSION`, commits `chore(release): vX.Y.Z`, and tags it. Add `--publish` (with
|
|
||||||
`FORGEJO_TOKEN` set) to also push and create the Forgejo release with source and
|
```bash
|
||||||
toolchain tarballs. The tag doubles as the reproducible bootstrap point: the
|
ludic-dev release [major|minor|patch] # omit the level to derive it from the changesets
|
||||||
source archive plus its checked-in seed rebuild that exact toolchain.
|
git push origin main --follow-tags
|
||||||
|
```
|
||||||
|
|
||||||
|
`ludic-dev release` aggregates the pending changesets into a new `CHANGELOG.md` section
|
||||||
|
— grouped by change type, with each changeset's markdown kept intact — bumps
|
||||||
|
`VERSION`, commits `chore(release): vX.Y.Z`, and tags it.
|
||||||
|
|
||||||
|
**Pushing the tag is what publishes.** The `release` workflow builds the
|
||||||
|
toolchain from the IR seed, runs `ludic-dev test`, `ludic-dev test-tools` and `ludic-dev bootstrap-cfree`
|
||||||
|
against the tagged tree, and only then creates the Forgejo release — with the
|
||||||
|
source tarball, a Linux toolchain build, a `.sha256` beside each, and that version's
|
||||||
|
`CHANGELOG.md` section as the notes. It refuses to publish if the tag and
|
||||||
|
`VERSION` disagree or the changelog has no section for it.
|
||||||
|
|
||||||
|
Each toolchain artifact is a complete install root — `bin/` beside `runtime/`,
|
||||||
|
`packages/` and `VERSION` — which is exactly what `install.sh` unpacks into
|
||||||
|
`~/.ludic`. A release with no artifact for a platform is not a broken install
|
||||||
|
there: the installer falls back to bootstrapping from the source tarball's IR
|
||||||
|
seed. But the macOS artifacts are the ones most people get, so attach them.
|
||||||
|
|
||||||
|
macOS artifacts cannot be produced on the Linux runner — a `darwin-arm64` build
|
||||||
|
needs a macOS host, and there is no cross-compile path (it would need the Xcode
|
||||||
|
SDK and a Mach-O linker). Attaching one therefore means either registering a
|
||||||
|
macOS runner and giving it a job, or running the same command CI runs from a
|
||||||
|
Mac. Either way it is `ludic-dev publish`, which only adds assets the release is missing:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
FORGEJO_TOKEN=… ludic-dev publish v0.4.0
|
||||||
|
```
|
||||||
|
|
||||||
|
Checksums are one `.sha256` file per artifact rather than a single `SHA256SUMS`,
|
||||||
|
precisely because a release can be assembled from more than one host and an
|
||||||
|
asset that already exists is never overwritten. Verify one with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
shasum -a 256 -c ludic-0.4.0-src.tar.gz.sha256
|
||||||
|
```
|
||||||
|
|
||||||
|
The tag doubles as the reproducible bootstrap point: the source archive plus its
|
||||||
|
checked-in seed rebuild that exact toolchain.
|
||||||
|
|
||||||
|
## Where the name and the URLs live
|
||||||
|
|
||||||
|
The language may yet be renamed and the project may yet move hosts, so the
|
||||||
|
things that carry a name are kept few and listed here rather than discovered one
|
||||||
|
broken link at a time. Everything host-shaped has an environment override, so a
|
||||||
|
move can be rehearsed before it is committed.
|
||||||
|
|
||||||
|
**Hosts and URLs.** The install one-liner is served from the documentation site,
|
||||||
|
which publishes `install.sh` beside the pages that quote it (`ludic-dev docs-gen`
|
||||||
|
copies it in; `docs-check` fails without it). Change the host in:
|
||||||
|
|
||||||
|
| Where | What |
|
||||||
|
|---|---|
|
||||||
|
| `install.sh` | `REPO_API`, `REPO_URL`, `INSTALL_URL` — each `${LUDIC_…:-default}`, so `LUDIC_REPO_URL=… sh install.sh` tests a move without editing anything |
|
||||||
|
| `tools/ludic-cli/project.ludic` | `install_url()` (`$LUDIC_INSTALL_URL`), used by `ludic upgrade` and `ludic doctor` |
|
||||||
|
| `tools/ludic-cli/forgejo.ludic` | `FORGEJO_API_DEFAULT` (`$LUDIC_FORGEJO_API`), used by `ludic-dev publish` |
|
||||||
|
| `docs/site/site.json` | `repo_url`, the `start.terminal` one-liner, and the doc links in `nav_links` |
|
||||||
|
| Prose | `README.md`, `COMPILING.md`, `tools/editors/README.md`, and the two editor plugins' "server not found" messages |
|
||||||
|
|
||||||
|
**The name itself.** A rename touches, in rough order of blast radius:
|
||||||
|
|
||||||
|
- **The file extension** `.ludic` — the compiler (`strip_ludic`, `do_import`,
|
||||||
|
`is_ludic_file`), every editor asset (`tools/editors/shared/*.json`,
|
||||||
|
`vscode/package.json`, the JetBrains `LudicFileType`), and every source file
|
||||||
|
in the tree.
|
||||||
|
- **The binaries** `ludic`, `ludicc`, `ludic-dev`, `ludic-fmt`, `ludic-lsp` —
|
||||||
|
`cmd_dev_build` in `toolchain.ludic`, the release staging in `release.ludic`,
|
||||||
|
`install.sh`, the editors' executable-name lists. Only the first, third and
|
||||||
|
fourth of those ship: `ludic-dev` is built from a checkout and stays there.
|
||||||
|
- **The install root** `~/.ludic` and the source directories `tools/ludic-cli/`,
|
||||||
|
`tools/ludic-tools/`, `packages/ludic.*`.
|
||||||
|
- **The environment variables** `LUDIC_HOME`, `LUDIC_CC`, `LUDIC_MODULES`,
|
||||||
|
`LUDIC_STORE`, `LUDIC_PKG_PROXY`, `LUDIC_INSTALL_URL`, `LUDIC_KEEP_TMP`,
|
||||||
|
`LUDIC_COVERAGE` — keep the old names working for a release if anyone has them
|
||||||
|
in a script.
|
||||||
|
- **Identifiers that are contracts with other software**: the TextMate scope
|
||||||
|
`source.ludic`, the VS Code language id `ludic`, the JetBrains plugin id
|
||||||
|
`io.ludic.ide`, and the `ludic` code-fence tag understood by the Markdown
|
||||||
|
injection and by `ludic-dev check-docs`.
|
||||||
|
- **The prose**: `README.md`, `LANGUAGE.md`, `COMPILING.md`, `docs/**`, and
|
||||||
|
`docs/site/site.json`'s `brand`/`meta`.
|
||||||
|
|
||||||
|
`ludic-dev test` is the safety net for the mechanical part — it builds the
|
||||||
|
toolchain, stages an install, and runs `new` → `build` → `test` through it, so a
|
||||||
|
half-finished rename fails there rather than in someone's terminal.
|
||||||
|
|
||||||
## Conventions
|
## Conventions
|
||||||
|
|
||||||
|
|
@ -99,7 +191,7 @@ source archive plus its checked-in seed rebuild that exact toolchain.
|
||||||
| `perf` | a performance improvement |
|
| `perf` | a performance improvement |
|
||||||
| `docs` | documentation only (`docs/`, README, comments) |
|
| `docs` | documentation only (`docs/`, README, comments) |
|
||||||
| `test` | tests only |
|
| `test` | tests only |
|
||||||
| `build` | the build/bootstrap machinery (seed, `bin/x`, linking) |
|
| `build` | the build/bootstrap machinery (seed, `bin/ludic`, linking) |
|
||||||
| `ci` | CI workflows under `.forgejo/` |
|
| `ci` | CI workflows under `.forgejo/` |
|
||||||
| `style` | formatting/whitespace, no behaviour change |
|
| `style` | formatting/whitespace, no behaviour change |
|
||||||
| `chore` | routine housekeeping with no other bucket |
|
| `chore` | routine housekeeping with no other bucket |
|
||||||
|
|
@ -121,7 +213,7 @@ source archive plus its checked-in seed rebuild that exact toolchain.
|
||||||
so a green local commit is a green CI run.
|
so a green local commit is a green CI run.
|
||||||
|
|
||||||
- **Formatting:** `ludic-fmt` is the source of truth (2-space indent, LF, UTF-8);
|
- **Formatting:** `ludic-fmt` is the source of truth (2-space indent, LF, UTF-8);
|
||||||
the repo `.editorconfig` mirrors it. Run `bin/ludic-fmt -w` on files you touch.
|
the repo `.editorconfig` mirrors it. Run `bin/ludic fmt` on files you touch.
|
||||||
The contract CI enforces is *idempotence* — `ludic-fmt` re-run on its own output
|
The contract CI enforces is *idempotence* — `ludic-fmt` re-run on its own output
|
||||||
is a no-op — which leaves deliberate hand alignment in place; it is not a
|
is a no-op — which leaves deliberate hand alignment in place; it is not a
|
||||||
blanket `fmt(x) == x`.
|
blanket `fmt(x) == x`.
|
||||||
|
|
@ -149,11 +241,44 @@ non-destructive version of "tidy the history" without touching a single commit.
|
||||||
## Pull requests
|
## Pull requests
|
||||||
|
|
||||||
- Base your branch on `main`.
|
- Base your branch on `main`.
|
||||||
- Ensure `bin/x test` (and `bin/x bootstrap-cfree` for compiler/runtime changes)
|
- Ensure `bin/ludic-dev test` (and `bin/ludic-dev bootstrap-cfree` for compiler/runtime changes)
|
||||||
pass, and that `ludic-fmt` leaves your files unchanged.
|
pass, and that `ludic-fmt` leaves your files unchanged.
|
||||||
- Fill in the PR template checklist. Reference the issue you close with
|
- Fill in the PR template checklist. Reference the issue you close with
|
||||||
`Closes #NN` in the description or a commit message.
|
`Closes #NN` in the description or a commit message.
|
||||||
|
|
||||||
|
## CI (self-hosted runners)
|
||||||
|
|
||||||
|
Every workflow starts by cloning `${{ github.server_url }}/${{ github.repository }}`.
|
||||||
|
On a self-hosted Forgejo runner that URL is usually the instance's *internal*
|
||||||
|
address (e.g. `http://forgejo:3000`), so **the job container must be able to
|
||||||
|
resolve it**. The runner puts each job on a fresh per-job network by default,
|
||||||
|
which the Forgejo container is not attached to — so the clone fails with:
|
||||||
|
|
||||||
|
```
|
||||||
|
fatal: unable to access 'http://forgejo:3000/…': Could not resolve host: forgejo
|
||||||
|
```
|
||||||
|
|
||||||
|
Give the runner a config that pins job containers to a network Forgejo is also
|
||||||
|
on. A dedicated network is better than the general application network, so a CI
|
||||||
|
job cannot reach unrelated services:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# the runner's config.yml, passed with: forgejo-runner daemon --config …
|
||||||
|
container:
|
||||||
|
network: forgejo-ci
|
||||||
|
```
|
||||||
|
|
||||||
|
with `forgejo-ci` attached to the Forgejo container as well. Verify it without
|
||||||
|
running a workflow:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --rm --network forgejo-ci alpine:3 getent hosts forgejo
|
||||||
|
```
|
||||||
|
|
||||||
|
This failure mode is intermittent if left unfixed: Docker forwards names it
|
||||||
|
cannot resolve to the host's resolver, which may answer for the container name
|
||||||
|
often enough that CI looks healthy for a while.
|
||||||
|
|
||||||
## Reporting issues
|
## Reporting issues
|
||||||
|
|
||||||
Use the templates under [`.forgejo/issue_template/`](.forgejo/issue_template):
|
Use the templates under [`.forgejo/issue_template/`](.forgejo/issue_template):
|
||||||
|
|
|
||||||
1940
LANGUAGE.md
1940
LANGUAGE.md
File diff suppressed because it is too large
Load diff
293
README.md
293
README.md
|
|
@ -1,177 +1,200 @@
|
||||||
# Ludic
|
# Ludic
|
||||||
|
|
||||||
Ludic is an **ahead-of-time compiled** language for 2D games with an
|
A compiled language for 2D games. The entity-component system is part of the
|
||||||
entity-component core, a deterministic fixed-point runtime, and its graphics
|
syntax, the runtime is deterministic fixed-point, and `ludicc` lowers Ludic
|
||||||
stack built into the language. `ludicc` lowers Ludic straight to LLVM IR and
|
straight to LLVM IR — **no C is generated, compiled or linked in a build.**
|
||||||
emits a native binary — and **`ludicc` is itself written in Ludic**, compiles
|
|
||||||
its own source to a byte-exact fixpoint, and rebuilds from a checked-in IR seed
|
|
||||||
with **no C compiler in the loop**.
|
|
||||||
|
|
||||||
```
|
The compiler is written in Ludic. It compiles its own source to a byte-exact
|
||||||
.ludic ──► ludicc ──► LLVM IR ──► object ──► native binary
|
fixpoint and rebuilds from a checked-in IR seed with clang alone; CI asserts
|
||||||
(in Ludic)
|
that on every push.
|
||||||
|
|
||||||
|
- **Documentation:** <https://workshopsoft.pages.workshopsoft.io/ludic/>
|
||||||
|
- **API reference:** <https://workshopsoft.pages.workshopsoft.io/ludic/api.html>
|
||||||
|
- **Issues:** <https://git.workshopsoft.io/workshopsoft/ludic/issues>
|
||||||
|
|
||||||
|
```ludic
|
||||||
|
program Hello {
|
||||||
|
|
||||||
|
property Position { column: int = 0, row: int = 0 }
|
||||||
|
property Velocity { delta_x: int = 0, delta_y: int = 0 }
|
||||||
|
|
||||||
|
handler SpawnEnemies phase Start {
|
||||||
|
spawn Enemy { Position { column: 3, row: 4 }, Velocity { delta_x: 1, delta_y: 0 } }
|
||||||
|
spawn Enemy { Position { column: 10, row: 2 }, Velocity { delta_x: 0, delta_y: 1 } }
|
||||||
|
}
|
||||||
|
|
||||||
|
# a handler declares the entities it touches; the body runs
|
||||||
|
# once per match, with each property bound by name.
|
||||||
|
@Queries(these: [Position, Velocity])
|
||||||
|
handler AdvancePositions phase FixedUpdate {
|
||||||
|
Position.column += Velocity.delta_x
|
||||||
|
Position.row += Velocity.delta_y
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**No C is generated, compiled or linked in a build.** No interpreter, no
|
## Getting started
|
||||||
transpiler, no C runtime: the framebuffer, sprites, PNG/DEFLATE decoding,
|
|
||||||
TrueType text, the retained UI, the registers and the RNG are all written in
|
|
||||||
Ludic (`runtime/native/*.ludic`); only the window seam — five `win_*` functions
|
|
||||||
— is hand-written LLVM IR against the platform ABI (`runtime/native/cocoa.ll`),
|
|
||||||
the same floor Rust and Swift stand on.
|
|
||||||
|
|
||||||
## Backends
|
Install the toolchain — the compiler, the `ludic` CLI, the engine runtime, the
|
||||||
|
formatter and the language server — with one command:
|
||||||
| Backend | Status |
|
|
||||||
|---|---|
|
|
||||||
| **Native 2D** (macOS/Cocoa window; headless render for CI) | **Shipping** — the default `bin/x app` target. |
|
|
||||||
| **Web / wasm32** | **In progress.** The browser platform layer is in-tree and documented — `runtime/web/` (the `<canvas>` window `platform.js`, the libc-free `wasm.ll` floor) and a Node harness that diffs native vs. wasm frame-for-frame (`tools/ludic-web/run.mjs`). Emitting wasm was a capability of the retired C compiler and is **not yet re-wired on the self-hosted toolchain**; see [COMPILING.md](COMPILING.md). |
|
|
||||||
|
|
||||||
The same is true of `--target` cross-compilation and `--shared` libraries: both
|
|
||||||
are designed and documented, both lived in the old C compiler, and both are
|
|
||||||
pending re-implementation on the self-hosted native toolchain.
|
|
||||||
|
|
||||||
## Quick start
|
|
||||||
|
|
||||||
`bin/x` is the project's task runner — one native binary, written in Ludic and
|
|
||||||
compiled by Ludic, that replaces every build/test/bootstrap shell script.
|
|
||||||
Bootstrap it once from a clean checkout (the only step Ludic can't do for
|
|
||||||
itself, since compiling Ludic needs a compiler) with clang alone:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
clang selfhost/ludicc.seed.ll -o bin/ludicc && bin/ludicc tools/x/main.ludic -o bin/x
|
curl -fsSL https://workshopsoft.pages.workshopsoft.io/ludic/install.sh | sh
|
||||||
```
|
```
|
||||||
|
|
||||||
Then build the whole toolchain and run a game:
|
It installs into `~/.ludic` and puts `~/.ludic/bin` on your `PATH` in every
|
||||||
|
shell — the PATH line lives in `~/.ludic/env`, sourced from `~/.profile`,
|
||||||
|
`~/.zshenv` and your bash or fish config. Nothing else on the machine is touched;
|
||||||
|
uninstalling is `rm -rf ~/.ludic` and deleting those two-line blocks. Where a
|
||||||
|
prebuilt toolchain exists for your platform it is downloaded and verified against
|
||||||
|
a published checksum; where it does not, the installer bootstraps from the
|
||||||
|
compiler's own IR seed with clang. Either way you need clang (or Xcode's Command
|
||||||
|
Line Tools) to link, since Ludic emits LLVM IR and links it natively.
|
||||||
|
|
||||||
|
Then make a game:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bin/x build # -> bin/{ludicc,ludic,x,ludic-fmt,ludic-lsp}
|
ludic new mygame
|
||||||
bin/x app examples/games/snake.ludic # compile + open a native window
|
cd mygame
|
||||||
./build/snake
|
ludic run # compiles src/main.ludic and opens a native window
|
||||||
```
|
```
|
||||||
|
|
||||||
Render a frame headlessly (what CI checks) — output lands in `build/`, never the
|
`ludic new` writes a manifest, a program that already moves something on screen,
|
||||||
repo root:
|
and a test. `ludic build` stops at the binary; `ludic bundle` goes on to the
|
||||||
|
thing you can actually give someone. Rendering is deterministic, so a frame can
|
||||||
|
be produced without a window, which is what CI diffs:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bin/x app examples/games/chronorift.ludic --headless
|
ludic test
|
||||||
mkdir -p build && printf 'ddddwww' | ./build/chronorift_headless # writes build/out.ppm
|
ludic build --headless
|
||||||
sips -s format png build/out.ppm --out frame.png
|
printf 'ddddwww' | ./build/mygame_headless # writes build/out.ppm
|
||||||
```
|
```
|
||||||
|
|
||||||
Run the suites:
|
`ludic help` lists every command, and `ludic doctor` checks the install.
|
||||||
|
[`examples/`](examples/README.md) is a tour grouped by intent: games, rendering,
|
||||||
|
ECS, events, networking, language features and the standard library — compile any
|
||||||
|
of them with `ludic build examples/games/snake.ludic`.
|
||||||
|
|
||||||
|
### Building from a checkout
|
||||||
|
|
||||||
|
Contributors also get `ludic-dev`, a second binary carrying the toolchain's own
|
||||||
|
tasks — building the compiler, the suites, the docs site, releases. It is built
|
||||||
|
from a checkout and is not part of an install, so nothing a user runs is mixed
|
||||||
|
up with it. Bootstrapping is the only step Ludic cannot do for itself, since
|
||||||
|
compiling Ludic needs a compiler — clang assembles the checked-in IR seed, and
|
||||||
|
that compiler builds the rest:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bin/x test # full regression: compiler builds from seed, every example, golden renders
|
mkdir -p bin && clang selfhost/ludicc.seed.ll -o bin/ludicc
|
||||||
bin/x selfhost-test # correctness + the self-hosting / C-free bootstrap fixpoints
|
bin/ludicc tools/ludic-cli/dev.ludic -o bin/ludic-dev
|
||||||
bin/x help # every command
|
bin/ludic-dev build # -> bin/{ludicc,ludic,ludic-dev,ludic-fmt,ludic-lsp}
|
||||||
|
bin/ludic-dev test # the regression suite
|
||||||
```
|
```
|
||||||
|
|
||||||
## Layout
|
## The language
|
||||||
|
|
||||||
| Path | What it is |
|
- **ECS in the syntax.** `property`, `model` and `handler` are keywords. Query
|
||||||
|------|-----------|
|
with `for (a, b) in query [A, B, {Tag}] where <expr> { … }`; `spawn` and
|
||||||
| [`selfhost/*.ludic`](selfhost/) | **the compiler, written in Ludic** — lexer, parser, and the LLVM-IR backend (ECS storage, queries, spawn, `match`/`machine`, UI, scenes, save/load, fixed-point). Built from `selfhost/ludicc.seed.ll` with clang alone. |
|
`despawn` recycle entity slots; `@`-annotations drive lifecycle hooks.
|
||||||
| [`selfhost/golden/renders.sha256`](selfhost/golden/renders.sha256) | text baseline of render-output hashes (replaces binary `.ppm` fixtures); regenerate with `bin/x golden`. |
|
- **Deterministic by construction.** Q16.16 `fixed` arithmetic and a seeded RNG
|
||||||
| [`tools/x/*.ludic`](tools/x/) | **the task runner, written in Ludic** — one binary (`bin/x`) that builds, tests, bootstraps and reseeds the project, replacing every shell script. |
|
give the same frame byte-for-byte on every run — the basis for replays,
|
||||||
| [`runtime/native/`](runtime/native/) | the runtime **in Ludic** for the native path: `core` (framebuffer, input, RNG), `image`/`inflate` (PNG + DEFLATE, no zlib), `truetype` (glyph rasterizer), `ui` (retained widget tree); plus `cocoa.ll`, the macOS window seam in LLVM IR. |
|
lockstep netcode and golden-image tests.
|
||||||
| [`runtime/web/`](runtime/web/) | the browser platform layer: `platform.js` (the `<canvas>` window), `wasm.ll` (the libc-free floor), `index.html`. |
|
- **Scenes and state machines.** `scene` / `layer` / `become` model
|
||||||
| [`examples/`](examples/README.md) | the example tour, grouped by intent — `games/`, `rendering/`, `ecs/`, `events/`, `networking/`, `lang/`, `library/`. See [examples/README.md](examples/README.md). |
|
mutually-exclusive game states with enter and exit hooks; `match` / `machine`
|
||||||
| [`tools/ludic-tools/`](tools/ludic-tools/) | the editor toolchain **in Ludic**: `ludic-fmt` (formatter) and `ludic-lsp` (language server) — one lexer, one vocabulary shared by both. |
|
/ `state` handle dispatch and per-entity FSMs.
|
||||||
| [`tools/editors/`](tools/editors/README.md) | plugins for VS Code and JetBrains, plus config for Neovim, Helix, Emacs, Sublime and Zed. |
|
- **Events and networking.** A cancellable event bus (`event` / `emit` / `@On`)
|
||||||
| [`docs/`](docs/) | the per-symbol API reference, regenerated into the docs site. |
|
and networking primitives (`@Sync`, ownership, RPCs) over a built-in transport.
|
||||||
| [`COMPILING.md`](COMPILING.md) | the native pipeline: `ludicc → LLVM IR → exe`, the `rt_*` runtime protocol, and the (pending) wasm/cross-compile/shared-library paths. |
|
- **Batteries in the language.** Framebuffer primitives, PNG sprites, TrueType
|
||||||
|
text and a retained `ui` widget tree declared as data, plus a namespaced
|
||||||
|
standard library (`Math`, `Text`, `List`, `Random`, `Crypto`, `Tiled`, …).
|
||||||
|
- **Whole-world snapshots.** `save()` and `load()` serialize every entity,
|
||||||
|
property and program `var` in one call.
|
||||||
|
|
||||||
The design and roadmap material lives on the **[wiki](https://git.workshopsoft.io/workshopsoft/ludic/wiki)**:
|
[LANGUAGE.md](LANGUAGE.md) is the full reference; the
|
||||||
the [Events](https://git.workshopsoft.io/workshopsoft/ludic/wiki/Design/Events),
|
[API reference](https://workshopsoft.pages.workshopsoft.io/ludic/api.html)
|
||||||
[Networking](https://git.workshopsoft.io/workshopsoft/ludic/wiki/Design/Networking),
|
documents every symbol on its own page.
|
||||||
[Scenes](https://git.workshopsoft.io/workshopsoft/ludic/wiki/Design/Scenes),
|
|
||||||
[Lifecycle](https://git.workshopsoft.io/workshopsoft/ludic/wiki/Design/Lifecycle),
|
|
||||||
[Mobile](https://git.workshopsoft.io/workshopsoft/ludic/wiki/Design/Mobile) and
|
|
||||||
[Syntax-redesign](https://git.workshopsoft.io/workshopsoft/ludic/wiki/Design/Syntax-Redesign)
|
|
||||||
design records, the [Bootstrap deep-dive](https://git.workshopsoft.io/workshopsoft/ludic/wiki/Bootstrap),
|
|
||||||
and the [Luanti roadmap](https://git.workshopsoft.io/workshopsoft/ludic/wiki/Roadmap/Luanti).
|
|
||||||
The root keeps only this README plus the two user-facing references,
|
|
||||||
[`LANGUAGE.md`](LANGUAGE.md) and [`COMPILING.md`](COMPILING.md).
|
|
||||||
|
|
||||||
## Language at a glance
|
## Shipping
|
||||||
|
|
||||||
- `program` / `property` (typed fields + defaults) / `model` (named entity kinds)
|
A built binary is a program, not an application: it opens its assets by a path
|
||||||
/ `system` (`phase`, `@annotations`, `reads`/`writes`).
|
relative to the working directory, so it runs from the project root and nowhere
|
||||||
- ECS queries `for (a, b) in query [A, B, {Tag}] where <expr> { … }`,
|
else, and it wears the generic executable icon.
|
||||||
`spawn`/`despawn` with slot reuse, `@`-driven lifecycle hooks.
|
|
||||||
- An **event bus** (`event` / `emit` / `@On`, cancellable, `@Public` promotion)
|
|
||||||
and **networking** primitives (`@Sync`, ownership, RPCs) over a built-in
|
|
||||||
loopback transport — all deterministic, all pure Ludic.
|
|
||||||
- `scene` / `layer` / `become`, `match` / `machine` + `state`.
|
|
||||||
- Types `int`, `fixed` (Q16.16), `bool`, `entity`, `str`, `byte`, typed buffers;
|
|
||||||
a growing namespaced **standard library** (`Math`, `Vector`, `Time`/`Date`/
|
|
||||||
`Duration`/`Clock`, `Random`, `Hash`, `Crypto`, sorting, …).
|
|
||||||
- Deterministic seeded RNG and `save()`/`load()` snapshot of the whole World.
|
|
||||||
- Built-in 2D: framebuffer primitives, PNG sprites, TrueType text, 9-slice, and
|
|
||||||
a retained `ui` widget tree declared as data.
|
|
||||||
|
|
||||||
See [LANGUAGE.md](LANGUAGE.md) for the full reference, and
|
```bash
|
||||||
[examples/README.md](examples/README.md) for runnable demos of each feature.
|
ludic pack # every asset the game opens, into one .lpak
|
||||||
|
ludic bundle # ...and that, the binary, an icon and the metadata, as a .app
|
||||||
|
```
|
||||||
|
|
||||||
|
Nothing about how the game is written changes. `gltf_load("assets/kit/hiker",
|
||||||
|
…)` reads a file during development and a run of bytes inside the bundle once
|
||||||
|
shipped, and cannot tell which — the pack is spliced in at `file_open`, the one
|
||||||
|
place every asset in a Ludic program comes through. A bundled game also gets a
|
||||||
|
boot splash it controls (`App.splash_hide()`) and a writable home under
|
||||||
|
Application Support, because Finder starts a `.app` at `/` where no save could
|
||||||
|
be written.
|
||||||
|
|
||||||
|
Without a pack beside it — which is every `ludic run` — nothing mounts and every
|
||||||
|
open goes to the filesystem exactly as before. See [docs/SHIPPING.md](docs/SHIPPING.md).
|
||||||
|
|
||||||
|
## Packages
|
||||||
|
|
||||||
|
Dependencies are identified by URL, resolved with minimal version selection, and
|
||||||
|
cached in a content-addressed store:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ludic add git.workshopsoft.io/user/pkg # resolve, fetch, link into ludic_modules/
|
||||||
|
ludic get # install from package.ludic, write the lock
|
||||||
|
ludic remove git.workshopsoft.io/user/pkg # the inverse of add
|
||||||
|
ludic verify # check locked packages against the store
|
||||||
|
```
|
||||||
|
|
||||||
|
The `ludic.*` packages — canonical ECS components, the gameplay, platformer,
|
||||||
|
RPG, shooter and NPC-AI modules — ship with the toolchain, so importing one needs
|
||||||
|
no fetch step at all.
|
||||||
|
|
||||||
|
See [`docs/PACKAGES.md`](docs/PACKAGES.md) for the manifest and lockfile model.
|
||||||
|
|
||||||
## Editor support
|
## Editor support
|
||||||
|
|
||||||
```bash
|
Editors spawn `ludic lsp`; the server ships with the toolchain, so there is
|
||||||
bin/x tools # -> bin/ludic-fmt, bin/ludic-lsp
|
nothing extra to install. It speaks LSP 3.17 over stdio, so one binary serves
|
||||||
```
|
every editor: completion, diagnostics from the compiler itself, go-to-definition
|
||||||
|
and rename across imports, and comment-preserving formatting. `ludic fmt` runs
|
||||||
|
the same formatter as a CLI, for pre-commit hooks. Both understand
|
||||||
|
```` ```ludic ```` fences in Markdown. Plugins and drop-in config for VS Code, JetBrains, Neovim,
|
||||||
|
Helix, Emacs, Sublime and Zed are in [`tools/editors/`](tools/editors/README.md).
|
||||||
|
|
||||||
`ludic-lsp` speaks LSP 3.17 over stdio, so one binary serves every editor:
|
## Status
|
||||||
context-aware completion, diagnostics from the compiler itself,
|
|
||||||
go-to-definition and rename across `import`ed files, and comment-preserving
|
|
||||||
formatting. `ludic-fmt` is the same formatter as a CLI, for pre-commit hooks and
|
|
||||||
CI. Both also understand ```` ```ludic ```` fences in Markdown. Plugins and
|
|
||||||
drop-in config are in [`tools/editors/`](tools/editors/README.md).
|
|
||||||
|
|
||||||
## Chrono Rift — the flagship game
|
The native 2D backend ships: a Cocoa window on macOS, a headless renderer for
|
||||||
|
CI, and the whole runtime — framebuffer, PNG/DEFLATE decoding, TrueType
|
||||||
|
rasterizer, retained UI, RNG — written in Ludic under
|
||||||
|
[`runtime/native/`](runtime/native/). Only the window seam (`win_*`: window,
|
||||||
|
keys, mouse, cursor, gamepad, touch) is hand-written LLVM IR against the
|
||||||
|
platform ABI, the same floor Rust and Swift stand on.
|
||||||
|
|
||||||
[`examples/games/chronorift.ludic`](examples/games/chronorift.ludic) is a
|
The **web/wasm32 backend is not currently available.** The browser platform
|
||||||
playable co-op JRPG — overworld, dungeon, random encounters, a turn-based co-op
|
layer is in-tree under [`runtime/web/`](runtime/web/), but emitting wasm was a
|
||||||
battle, a boss, an item shop and snapshot save/load — split across modules under
|
capability of the retired C compiler and has not been re-wired on the
|
||||||
[`games/chronorift/`](examples/games/chronorift/). Its art is CC0
|
self-hosted toolchain. `--target` cross-compilation and `--shared` libraries are
|
||||||
[Kenney](https://kenney.nl) sprites, decoded from PNG at runtime by the
|
in the same position. See [COMPILING.md](COMPILING.md).
|
||||||
Ludic-written PNG/DEFLATE decoder — no zlib, no external dependency.
|
|
||||||
|
|
||||||
- **Overworld:** `WASD` move, `K` save, `L` load.
|
Releases follow SemVer and are cut from changesets by `ludic-dev release`, then built
|
||||||
- **Battle (local co-op):** P1/Knight `W`/`S` select, `Space` confirm;
|
and published by CI from the tag; see [CHANGELOG.md](CHANGELOG.md).
|
||||||
P2/Mage `I`/`K` select, `J` confirm.
|
|
||||||
|
|
||||||
## Status & roadmap
|
|
||||||
|
|
||||||
The compiler self-hosts to a byte-exact fixpoint and rebuilds from its IR seed
|
|
||||||
with no C compiler; the ECS runtime, windowed + headless 2D rendering, the event
|
|
||||||
bus, the deterministic networking stack, scenes, and save/load are all in place
|
|
||||||
and covered by `bin/x test`. CI gates every push and PR on the build, the test
|
|
||||||
suites, and that C-free fixpoint. The toolchain is versioned with SemVer
|
|
||||||
(`ludicc --version`); releases and the `CHANGELOG.md` are cut from changesets by
|
|
||||||
`x release`.
|
|
||||||
|
|
||||||
Active work and proposals — the standard library, a fuller type system,
|
|
||||||
rendering/animation/lighting extras, input, filesystem/IO, testing, and
|
|
||||||
re-wiring the web/wasm and cross-compile backends — are tracked as issues, not
|
|
||||||
inlined here:
|
|
||||||
|
|
||||||
- **Issues & proposals:** <https://git.workshopsoft.io/workshopsoft/ludic/issues>
|
|
||||||
- **Docs site (API reference):** <https://workshopsoft.pages.workshopsoft.io/ludic/>
|
|
||||||
- **Wiki (design & roadmap):** <https://git.workshopsoft.io/workshopsoft/ludic/wiki>
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
See [CONTRIBUTING.md](CONTRIBUTING.md) for the development loop
|
[CONTRIBUTING.md](CONTRIBUTING.md) covers the development loop, the commit and
|
||||||
(`bin/x reseed` → `bin/x bootstrap-cfree` → `bin/x test`), the code and commit
|
code conventions, how the bootstrap fixpoint works, and what a self-hosted CI
|
||||||
conventions, and how the bootstrap fixpoint works. Issue and pull-request
|
runner needs. Issue and pull-request templates are under
|
||||||
templates live under [`.forgejo/`](.forgejo/).
|
[`.forgejo/`](.forgejo/).
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
The Ludic compiler and runtime source are licensed under the
|
The compiler and runtime are licensed under the
|
||||||
[Apache License 2.0](LICENSE) (`SPDX-License-Identifier: Apache-2.0`) — a
|
[Apache License 2.0](LICENSE) (`SPDX-License-Identifier: Apache-2.0`).
|
||||||
permissive license with an explicit patent grant.
|
|
||||||
|
|
||||||
The bundled [Kenney](https://kenney.nl) art under `assets/kenney/` is
|
The bundled [Kenney](https://kenney.nl) art under `assets/kenney/` is
|
||||||
third-party and released under **CC0 1.0** (public domain); each pack keeps its
|
third-party and released under **CC0 1.0**; each pack keeps its own
|
||||||
own `License.txt`. Code and assets are licensed separately: Apache-2.0 covers
|
`License.txt`. Code and assets are licensed separately — Apache-2.0 covers the
|
||||||
the source, not the art.
|
source, not the art.
|
||||||
|
|
|
||||||
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
||||||
0.2.0
|
0.22.0
|
||||||
|
|
|
||||||
1981
assets/kenney/tiny-dungeon/Tiled/sampleMap.tmj
Normal file
1981
assets/kenney/tiny-dungeon/Tiled/sampleMap.tmj
Normal file
File diff suppressed because it is too large
Load diff
3
assets/polyhaven/LICENSE.txt
Normal file
3
assets/polyhaven/LICENSE.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
Everything under assets/polyhaven/ is fetched from https://polyhaven.com and is
|
||||||
|
released by Poly Haven under CC0 1.0 (public domain). Files are not committed;
|
||||||
|
see manifest.txt for the exact sources. Re-fetch with tools/glgen/fetch_assets.sh.
|
||||||
29
assets/tiled-fixtures/README.md
Normal file
29
assets/tiled-fixtures/README.md
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
# Tiled golden fixtures
|
||||||
|
|
||||||
|
The curated, version-pinned corpus for the Ludic Tiled reader (design record:
|
||||||
|
[Design: Tiled maps](https://git.workshopsoft.io/workshopsoft/ludic/wiki/Design%2FTiled),
|
||||||
|
issues #67–#74). No single Tiled file covers the format surface, so this is a
|
||||||
|
subset of the official [`mapeditor/tiled`](https://github.com/mapeditor/tiled)
|
||||||
|
`examples/` tree plus a few hand-authored files for the gaps the official
|
||||||
|
examples miss.
|
||||||
|
|
||||||
|
## Vendored from mapeditor/tiled (`examples/`)
|
||||||
|
|
||||||
|
Fetched from `https://raw.githubusercontent.com/mapeditor/tiled/master/examples/`.
|
||||||
|
Tiled's example assets carry their own licenses (see the upstream repo's
|
||||||
|
per-folder `*.license`/README); vendored here with attribution for testing only.
|
||||||
|
|
||||||
|
| File | Exercises |
|
||||||
|
|---|---|
|
||||||
|
| `desert.tmx` + `desert.tsx` | orthogonal, external `.tsx`, base64+zlib (P0/P1) |
|
||||||
|
| `sewers.tmx` | orthogonal, base64+zlib, embedded tileset, opacity (P0) |
|
||||||
|
| `orthogonal-outside.tmx` | object layers, shapes, custom properties (P4) |
|
||||||
|
| `perspective_walls.tsx` | per-tile bool properties, `<tileoffset>` (P4) |
|
||||||
|
| `isometric_grass_and_water.tmx` | isometric orientation, Wang set (P5) |
|
||||||
|
| `hexagonal-mini.tmx` | hexagonal orientation (P5) |
|
||||||
|
|
||||||
|
## Hand-authored (CC0 / public domain)
|
||||||
|
|
||||||
|
| File | Exercises |
|
||||||
|
|---|---|
|
||||||
|
| `handmade.tmx` + `handmade.tsx` | a 4×4 orthogonal map whose four layers carry the **same** GID array in CSV, base64-uncompressed, base64+gzip and base64+zlib — so every encoding path must decode identically. The last tile is GID 1 with the horizontal-flip flag (`0x80000001`), forcing real GID decode. `handmade.tsx` also carries a `solid` bool property and a per-tile `<objectgroup>` collision shape for P2. |
|
||||||
16
assets/tiled-fixtures/anim_map.tmx
Normal file
16
assets/tiled-fixtures/anim_map.tmx
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Hand-authored P3 fixture: animated tile + tile object (issue #71). CC0. -->
|
||||||
|
<map version="1.10" tiledversion="1.10.2" orientation="orthogonal" renderorder="right-down" width="4" height="4" tilewidth="16" tileheight="16" infinite="0" nextlayerid="3" nextobjectid="2">
|
||||||
|
<tileset firstgid="1" source="anim_tiles.tsx"/>
|
||||||
|
<layer id="1" name="bg" width="4" height="4">
|
||||||
|
<data encoding="csv">
|
||||||
|
1,0,0,0,
|
||||||
|
0,0,0,0,
|
||||||
|
0,0,0,0,
|
||||||
|
0,0,0,0
|
||||||
|
</data>
|
||||||
|
</layer>
|
||||||
|
<objectgroup id="2" name="objects">
|
||||||
|
<object id="1" gid="53" x="16" y="32" width="16" height="16"/>
|
||||||
|
</objectgroup>
|
||||||
|
</map>
|
||||||
12
assets/tiled-fixtures/anim_tiles.tsx
Normal file
12
assets/tiled-fixtures/anim_tiles.tsx
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Hand-authored animated tileset over the Kenney atlas (issue #71). CC0. -->
|
||||||
|
<tileset version="1.10" tiledversion="1.10.2" name="anim" tilewidth="16" tileheight="16" spacing="1" tilecount="132" columns="12">
|
||||||
|
<image source="../kenney/tiny-dungeon/Tilemap/tilemap.png" width="203" height="186"/>
|
||||||
|
<tile id="0">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="0" duration="100"/>
|
||||||
|
<frame tileid="40" duration="100"/>
|
||||||
|
<frame tileid="80" duration="100"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
</tileset>
|
||||||
267
assets/tiled-fixtures/beach_tileset.tsx
Normal file
267
assets/tiled-fixtures/beach_tileset.tsx
Normal file
|
|
@ -0,0 +1,267 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<tileset version="1.8" tiledversion="1.8.2" name="beach_tileset" tilewidth="16" tileheight="16" tilecount="936" columns="36">
|
||||||
|
<image source="beach_tileset.png" width="576" height="416"/>
|
||||||
|
<tile id="37">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="37" duration="250"/>
|
||||||
|
<frame tileid="46" duration="250"/>
|
||||||
|
<frame tileid="55" duration="250"/>
|
||||||
|
<frame tileid="64" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="38">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="38" duration="250"/>
|
||||||
|
<frame tileid="47" duration="250"/>
|
||||||
|
<frame tileid="56" duration="250"/>
|
||||||
|
<frame tileid="65" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="39">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="39" duration="250"/>
|
||||||
|
<frame tileid="48" duration="250"/>
|
||||||
|
<frame tileid="57" duration="250"/>
|
||||||
|
<frame tileid="66" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="41">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="41" duration="250"/>
|
||||||
|
<frame tileid="50" duration="250"/>
|
||||||
|
<frame tileid="59" duration="250"/>
|
||||||
|
<frame tileid="68" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="42">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="42" duration="250"/>
|
||||||
|
<frame tileid="51" duration="250"/>
|
||||||
|
<frame tileid="60" duration="250"/>
|
||||||
|
<frame tileid="69" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="43">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="43" duration="250"/>
|
||||||
|
<frame tileid="52" duration="250"/>
|
||||||
|
<frame tileid="61" duration="250"/>
|
||||||
|
<frame tileid="70" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="73">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="73" duration="250"/>
|
||||||
|
<frame tileid="82" duration="250"/>
|
||||||
|
<frame tileid="91" duration="250"/>
|
||||||
|
<frame tileid="100" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="75">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="75" duration="250"/>
|
||||||
|
<frame tileid="84" duration="250"/>
|
||||||
|
<frame tileid="93" duration="250"/>
|
||||||
|
<frame tileid="102" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="76">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="76" duration="250"/>
|
||||||
|
<frame tileid="85" duration="250"/>
|
||||||
|
<frame tileid="94" duration="250"/>
|
||||||
|
<frame tileid="103" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="77">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="77" duration="250"/>
|
||||||
|
<frame tileid="86" duration="250"/>
|
||||||
|
<frame tileid="95" duration="250"/>
|
||||||
|
<frame tileid="104" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="79">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="79" duration="250"/>
|
||||||
|
<frame tileid="88" duration="250"/>
|
||||||
|
<frame tileid="97" duration="250"/>
|
||||||
|
<frame tileid="106" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="109">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="109" duration="250"/>
|
||||||
|
<frame tileid="118" duration="250"/>
|
||||||
|
<frame tileid="127" duration="250"/>
|
||||||
|
<frame tileid="136" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="110">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="110" duration="250"/>
|
||||||
|
<frame tileid="119" duration="250"/>
|
||||||
|
<frame tileid="128" duration="250"/>
|
||||||
|
<frame tileid="137" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="114">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="114" duration="250"/>
|
||||||
|
<frame tileid="123" duration="250"/>
|
||||||
|
<frame tileid="132" duration="250"/>
|
||||||
|
<frame tileid="141" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="115">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="115" duration="250"/>
|
||||||
|
<frame tileid="124" duration="250"/>
|
||||||
|
<frame tileid="133" duration="250"/>
|
||||||
|
<frame tileid="142" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="146">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="146" duration="250"/>
|
||||||
|
<frame tileid="155" duration="250"/>
|
||||||
|
<frame tileid="164" duration="250"/>
|
||||||
|
<frame tileid="173" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="148">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="148" duration="250"/>
|
||||||
|
<frame tileid="157" duration="250"/>
|
||||||
|
<frame tileid="166" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="150">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="150" duration="250"/>
|
||||||
|
<frame tileid="159" duration="250"/>
|
||||||
|
<frame tileid="168" duration="250"/>
|
||||||
|
<frame tileid="177" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="181">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="181" duration="250"/>
|
||||||
|
<frame tileid="190" duration="250"/>
|
||||||
|
<frame tileid="199" duration="250"/>
|
||||||
|
<frame tileid="208" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="182">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="182" duration="250"/>
|
||||||
|
<frame tileid="191" duration="250"/>
|
||||||
|
<frame tileid="200" duration="250"/>
|
||||||
|
<frame tileid="209" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="186">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="186" duration="250"/>
|
||||||
|
<frame tileid="195" duration="250"/>
|
||||||
|
<frame tileid="204" duration="250"/>
|
||||||
|
<frame tileid="213" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="187">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="187" duration="250"/>
|
||||||
|
<frame tileid="196" duration="250"/>
|
||||||
|
<frame tileid="205" duration="250"/>
|
||||||
|
<frame tileid="214" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="217">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="217" duration="250"/>
|
||||||
|
<frame tileid="226" duration="250"/>
|
||||||
|
<frame tileid="235" duration="250"/>
|
||||||
|
<frame tileid="244" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="219">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="219" duration="250"/>
|
||||||
|
<frame tileid="228" duration="250"/>
|
||||||
|
<frame tileid="237" duration="250"/>
|
||||||
|
<frame tileid="246" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="220">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="220" duration="250"/>
|
||||||
|
<frame tileid="229" duration="250"/>
|
||||||
|
<frame tileid="238" duration="250"/>
|
||||||
|
<frame tileid="247" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="221">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="221" duration="250"/>
|
||||||
|
<frame tileid="230" duration="250"/>
|
||||||
|
<frame tileid="239" duration="250"/>
|
||||||
|
<frame tileid="248" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="223">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="223" duration="250"/>
|
||||||
|
<frame tileid="232" duration="250"/>
|
||||||
|
<frame tileid="241" duration="250"/>
|
||||||
|
<frame tileid="250" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="253">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="253" duration="250"/>
|
||||||
|
<frame tileid="262" duration="250"/>
|
||||||
|
<frame tileid="271" duration="250"/>
|
||||||
|
<frame tileid="280" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="254">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="254" duration="250"/>
|
||||||
|
<frame tileid="263" duration="250"/>
|
||||||
|
<frame tileid="272" duration="250"/>
|
||||||
|
<frame tileid="281" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="255">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="255" duration="250"/>
|
||||||
|
<frame tileid="264" duration="250"/>
|
||||||
|
<frame tileid="273" duration="250"/>
|
||||||
|
<frame tileid="282" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="257">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="257" duration="250"/>
|
||||||
|
<frame tileid="266" duration="250"/>
|
||||||
|
<frame tileid="275" duration="250"/>
|
||||||
|
<frame tileid="284" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="258">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="258" duration="250"/>
|
||||||
|
<frame tileid="267" duration="250"/>
|
||||||
|
<frame tileid="276" duration="250"/>
|
||||||
|
<frame tileid="285" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
<tile id="259">
|
||||||
|
<animation>
|
||||||
|
<frame tileid="259" duration="250"/>
|
||||||
|
<frame tileid="268" duration="250"/>
|
||||||
|
<frame tileid="277" duration="250"/>
|
||||||
|
<frame tileid="286" duration="250"/>
|
||||||
|
</animation>
|
||||||
|
</tile>
|
||||||
|
</tileset>
|
||||||
9
assets/tiled-fixtures/collision.tsx
Normal file
9
assets/tiled-fixtures/collision.tsx
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Hand-authored collision tileset for the Ludic Tiled demos (issue #69). CC0. -->
|
||||||
|
<tileset version="1.10" tiledversion="1.10.2" name="collision" tilewidth="16" tileheight="16" tilecount="2" columns="1">
|
||||||
|
<tile id="1">
|
||||||
|
<properties>
|
||||||
|
<property name="oneway" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
</tileset>
|
||||||
1
assets/tiled-fixtures/demo.world
Normal file
1
assets/tiled-fixtures/demo.world
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
{"maps": [{"fileName": "zstd_map.tmx", "x": 0, "y": 0, "width": 384, "height": 256}, {"fileName": "grid_maze.tmx", "x": 384, "y": 0, "width": 128, "height": 80}], "onlyShowAdjacentMaps": false, "type": "world"}
|
||||||
9
assets/tiled-fixtures/desert.tmx
Normal file
9
assets/tiled-fixtures/desert.tmx
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<map version="1.0" tiledversion="1.1.5" orientation="orthogonal" renderorder="right-down" width="40" height="40" tilewidth="32" tileheight="32" infinite="0" nextlayerid="2" nextobjectid="1">
|
||||||
|
<tileset firstgid="1" source="desert.tsx"/>
|
||||||
|
<layer id="1" name="Ground" width="40" height="40">
|
||||||
|
<data encoding="base64" compression="zlib">
|
||||||
|
eJztmNkKwjAQRaN9cAPrAq5Yq3Xf6v9/nSM2VIbQJjEZR+nDwQZScrwztoORECLySBcIgZ7nc2y4KfyWDLx+Jb9nViNgDEwY+KioAXUgQN4+zpoCMwPmQAtoAx2CLFbA2oDEo9+hwG8DnIDtF/2K8ks086Tw2zH0uyMv7HcRr/6/EvvhnsPrsrxwX7rwU/0ODig/eV3mh3N1ld8eraWPaX6+64s9McesfrqcHfg1MpoifxcVEWjukyw+9AtFPl/I71pER3Of6j4bv7HI54s+MChhqLlPdZ/P3qMmFuo5h5NnTOhjM5tReN2yT51n5/v7J3F0vi46fk+ne7aX0i9l6If7mpufTX3f5wsqv9TAD2fJLT9VrTn7UeZnM5tR+v0LMQOHXwFnxe2/warGFRWf8QDjOLfP
|
||||||
|
</data>
|
||||||
|
</layer>
|
||||||
|
</map>
|
||||||
68
assets/tiled-fixtures/desert.tsx
Normal file
68
assets/tiled-fixtures/desert.tsx
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<tileset version="1.4" tiledversion="1.4.3" name="Desert" tilewidth="32" tileheight="32" spacing="1" margin="1" tilecount="48" columns="8">
|
||||||
|
<image source="tmw_desert_spacing.png" width="265" height="199"/>
|
||||||
|
<tile id="30" probability="0.01"/>
|
||||||
|
<tile id="31" probability="0.01"/>
|
||||||
|
<tile id="37" probability="0.01"/>
|
||||||
|
<tile id="38" probability="0.01"/>
|
||||||
|
<tile id="39" probability="0.01"/>
|
||||||
|
<tile id="45" probability="0"/>
|
||||||
|
<tile id="46" probability="0.01"/>
|
||||||
|
<tile id="47" probability="0.01"/>
|
||||||
|
<wangsets>
|
||||||
|
<wangset name="Desert" type="corner" tile="5">
|
||||||
|
<wangcolor name="Desert" color="#ff0000" tile="29" probability="1"/>
|
||||||
|
<wangcolor name="Brick" color="#00ff00" tile="9" probability="1"/>
|
||||||
|
<wangcolor name="Cobblestone" color="#0000ff" tile="33" probability="1"/>
|
||||||
|
<wangcolor name="Dirt" color="#ff7700" tile="14" probability="1"/>
|
||||||
|
<wangtile tileid="0" wangid="0,1,0,2,0,1,0,1"/>
|
||||||
|
<wangtile tileid="1" wangid="0,1,0,2,0,2,0,1"/>
|
||||||
|
<wangtile tileid="2" wangid="0,1,0,1,0,2,0,1"/>
|
||||||
|
<wangtile tileid="3" wangid="0,4,0,1,0,4,0,4"/>
|
||||||
|
<wangtile tileid="4" wangid="0,4,0,4,0,1,0,4"/>
|
||||||
|
<wangtile tileid="5" wangid="0,1,0,4,0,1,0,1"/>
|
||||||
|
<wangtile tileid="6" wangid="0,1,0,4,0,4,0,1"/>
|
||||||
|
<wangtile tileid="7" wangid="0,1,0,1,0,4,0,1"/>
|
||||||
|
<wangtile tileid="8" wangid="0,2,0,2,0,1,0,1"/>
|
||||||
|
<wangtile tileid="9" wangid="0,2,0,2,0,2,0,2"/>
|
||||||
|
<wangtile tileid="10" wangid="0,1,0,1,0,2,0,2"/>
|
||||||
|
<wangtile tileid="11" wangid="0,1,0,4,0,4,0,4"/>
|
||||||
|
<wangtile tileid="12" wangid="0,4,0,4,0,4,0,1"/>
|
||||||
|
<wangtile tileid="13" wangid="0,4,0,4,0,1,0,1"/>
|
||||||
|
<wangtile tileid="14" wangid="0,4,0,4,0,4,0,4"/>
|
||||||
|
<wangtile tileid="15" wangid="0,1,0,1,0,4,0,4"/>
|
||||||
|
<wangtile tileid="16" wangid="0,2,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="17" wangid="0,2,0,1,0,1,0,2"/>
|
||||||
|
<wangtile tileid="18" wangid="0,1,0,1,0,1,0,2"/>
|
||||||
|
<wangtile tileid="19" wangid="0,2,0,1,0,2,0,2"/>
|
||||||
|
<wangtile tileid="20" wangid="0,2,0,2,0,1,0,2"/>
|
||||||
|
<wangtile tileid="21" wangid="0,4,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="22" wangid="0,4,0,1,0,1,0,4"/>
|
||||||
|
<wangtile tileid="23" wangid="0,1,0,1,0,1,0,4"/>
|
||||||
|
<wangtile tileid="24" wangid="0,1,0,3,0,1,0,1"/>
|
||||||
|
<wangtile tileid="25" wangid="0,1,0,3,0,3,0,1"/>
|
||||||
|
<wangtile tileid="26" wangid="0,1,0,1,0,3,0,1"/>
|
||||||
|
<wangtile tileid="27" wangid="0,1,0,2,0,2,0,2"/>
|
||||||
|
<wangtile tileid="28" wangid="0,2,0,2,0,2,0,1"/>
|
||||||
|
<wangtile tileid="29" wangid="0,1,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="30" wangid="0,1,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="31" wangid="0,1,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="32" wangid="0,3,0,3,0,1,0,1"/>
|
||||||
|
<wangtile tileid="33" wangid="0,3,0,3,0,3,0,3"/>
|
||||||
|
<wangtile tileid="34" wangid="0,1,0,1,0,3,0,3"/>
|
||||||
|
<wangtile tileid="35" wangid="0,3,0,1,0,3,0,3"/>
|
||||||
|
<wangtile tileid="36" wangid="0,3,0,3,0,1,0,3"/>
|
||||||
|
<wangtile tileid="37" wangid="0,1,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="38" wangid="0,1,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="39" wangid="0,1,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="40" wangid="0,3,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="41" wangid="0,3,0,1,0,1,0,3"/>
|
||||||
|
<wangtile tileid="42" wangid="0,1,0,1,0,1,0,3"/>
|
||||||
|
<wangtile tileid="43" wangid="0,1,0,3,0,3,0,3"/>
|
||||||
|
<wangtile tileid="44" wangid="0,3,0,3,0,3,0,1"/>
|
||||||
|
<wangtile tileid="45" wangid="0,1,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="46" wangid="0,1,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="47" wangid="0,1,0,1,0,1,0,1"/>
|
||||||
|
</wangset>
|
||||||
|
</wangsets>
|
||||||
|
</tileset>
|
||||||
14
assets/tiled-fixtures/grid_maze.tmx
Normal file
14
assets/tiled-fixtures/grid_maze.tmx
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Hand-authored map for the Ludic Tiled demos (issue #69). CC0. -->
|
||||||
|
<map version="1.10" tiledversion="1.10.2" orientation="orthogonal" renderorder="right-down" width="8" height="5" tilewidth="16" tileheight="16" infinite="0" nextlayerid="2" nextobjectid="1">
|
||||||
|
<tileset firstgid="1" source="collision.tsx"/>
|
||||||
|
<layer id="1" name="collision" width="8" height="5">
|
||||||
|
<data encoding="csv">
|
||||||
|
1,1,1,1,1,1,1,1,
|
||||||
|
1,0,0,0,0,0,0,1,
|
||||||
|
1,0,1,1,1,1,0,1,
|
||||||
|
1,0,0,0,0,1,0,1,
|
||||||
|
1,1,1,1,1,1,1,1
|
||||||
|
</data>
|
||||||
|
</layer>
|
||||||
|
</map>
|
||||||
65
assets/tiled-fixtures/handmade.tmj
Normal file
65
assets/tiled-fixtures/handmade.tmj
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
{
|
||||||
|
"type": "map",
|
||||||
|
"version": "1.10",
|
||||||
|
"tiledversion": "1.10.2",
|
||||||
|
"orientation": "orthogonal",
|
||||||
|
"renderorder": "right-down",
|
||||||
|
"width": 4,
|
||||||
|
"height": 4,
|
||||||
|
"tilewidth": 16,
|
||||||
|
"tileheight": 16,
|
||||||
|
"infinite": false,
|
||||||
|
"nextlayerid": 3,
|
||||||
|
"nextobjectid": 1,
|
||||||
|
"tilesets": [
|
||||||
|
{
|
||||||
|
"firstgid": 1,
|
||||||
|
"source": "handmade.tsx"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"type": "tilelayer",
|
||||||
|
"id": 1,
|
||||||
|
"name": "csv",
|
||||||
|
"width": 4,
|
||||||
|
"height": 4,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"opacity": 1,
|
||||||
|
"visible": true,
|
||||||
|
"data": [
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
5,
|
||||||
|
6,
|
||||||
|
7,
|
||||||
|
8,
|
||||||
|
9,
|
||||||
|
10,
|
||||||
|
11,
|
||||||
|
12,
|
||||||
|
13,
|
||||||
|
14,
|
||||||
|
15,
|
||||||
|
2147483649
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "tilelayer",
|
||||||
|
"id": 2,
|
||||||
|
"name": "zlib",
|
||||||
|
"width": 4,
|
||||||
|
"height": 4,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"opacity": 1,
|
||||||
|
"visible": true,
|
||||||
|
"encoding": "base64",
|
||||||
|
"compression": "zlib",
|
||||||
|
"data": "eJwNw4cNACAMBLEPvYaVGT1nySYpMbOwsrFzcHJx8/DS+WjSDw1EAPo="
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
25
assets/tiled-fixtures/handmade.tmx
Normal file
25
assets/tiled-fixtures/handmade.tmx
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Hand-authored fixture for the Ludic Tiled reader (issue #67). Public domain (CC0). -->
|
||||||
|
<map version="1.10" tiledversion="1.10.2" orientation="orthogonal" renderorder="right-down" width="4" height="4" tilewidth="16" tileheight="16" infinite="0" nextlayerid="4" nextobjectid="1">
|
||||||
|
<tileset firstgid="1" source="handmade.tsx"/>
|
||||||
|
<layer id="1" name="csv" width="4" height="4">
|
||||||
|
<data encoding="csv">
|
||||||
|
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,2147483649
|
||||||
|
</data>
|
||||||
|
</layer>
|
||||||
|
<layer id="2" name="base64" width="4" height="4">
|
||||||
|
<data encoding="base64">
|
||||||
|
AQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAAQAAgA==
|
||||||
|
</data>
|
||||||
|
</layer>
|
||||||
|
<layer id="3" name="gzip" width="4" height="4">
|
||||||
|
<data encoding="base64" compression="gzip">
|
||||||
|
H4sIAAAAAAAC/w3Dhw0AIAwEsQ+9hpUZPWfJJikxs7CysXNwcnHz8NL5aNIPlvf4ekAAAAA=
|
||||||
|
</data>
|
||||||
|
</layer>
|
||||||
|
<layer id="4" name="zlib" width="4" height="4">
|
||||||
|
<data encoding="base64" compression="zlib">
|
||||||
|
eJwNw4cNACAMBLEPvYaVGT1nySYpMbOwsrFzcHJx8/DS+WjSDw1EAPo=
|
||||||
|
</data>
|
||||||
|
</layer>
|
||||||
|
</map>
|
||||||
15
assets/tiled-fixtures/handmade.tsx
Normal file
15
assets/tiled-fixtures/handmade.tsx
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Hand-authored fixture for the Ludic Tiled reader (issue #67). Public domain (CC0). -->
|
||||||
|
<tileset version="1.10" tiledversion="1.10.2" name="handmade" tilewidth="16" tileheight="16" spacing="0" margin="0" tilecount="16" columns="4">
|
||||||
|
<image source="handmade.png" width="64" height="64"/>
|
||||||
|
<tile id="4">
|
||||||
|
<properties>
|
||||||
|
<property name="solid" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="6">
|
||||||
|
<objectgroup draworder="index">
|
||||||
|
<object id="1" x="0" y="8" width="16" height="8"/>
|
||||||
|
</objectgroup>
|
||||||
|
</tile>
|
||||||
|
</tileset>
|
||||||
12
assets/tiled-fixtures/hexagonal-mini.tmx
Normal file
12
assets/tiled-fixtures/hexagonal-mini.tmx
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<map version="1.0" orientation="hexagonal" renderorder="right-down" width="20" height="20" tilewidth="14" tileheight="12" hexsidelength="6" staggeraxis="y" staggerindex="odd" nextobjectid="2">
|
||||||
|
<tileset firstgid="1" name="hex mini" tilewidth="18" tileheight="18">
|
||||||
|
<tileoffset x="0" y="1"/>
|
||||||
|
<image source="hexmini.png" width="106" height="72"/>
|
||||||
|
</tileset>
|
||||||
|
<layer name="Ground" width="20" height="20">
|
||||||
|
<data encoding="base64" compression="zlib">
|
||||||
|
eJyl1FEKhDAMBNBSt6jVaL3/Za2QwDAkVdiPQda2zyTonimlU1N6Ws+lkZ6l56AUXcPY2qlniv5uL5Z5BdyDvFXXMoX3Rp44axl6nqFejj3LLK6xgmf3Zg06Qs+O+qiaDOZOVgXPs7jfCme8Hkce1+fNlGdlM3myDTzc580fz1htW2Baj15/R/J72wLvcVZN5HnzGnmVPJ5hNH+0dt33j4ex91TARUs+WjNZz/fewKvJfy+/1naR+dX7OfdEnUYefyOeZZ7Vht/b5HjefxJbO1iTE7YWuEpg5hfPzi8D782x3Mg7DV4=
|
||||||
|
</data>
|
||||||
|
</layer>
|
||||||
|
</map>
|
||||||
18
assets/tiled-fixtures/img_group.tmx
Normal file
18
assets/tiled-fixtures/img_group.tmx
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Hand-authored P5 fixture: image + group layers (issue #73). CC0. -->
|
||||||
|
<map version="1.10" tiledversion="1.10.2" orientation="orthogonal" renderorder="right-down" width="4" height="4" tilewidth="16" tileheight="16" infinite="0" nextlayerid="4" nextobjectid="1">
|
||||||
|
<tileset firstgid="1" source="anim_tiles.tsx"/>
|
||||||
|
<imagelayer id="1" name="bg" offsetx="8" offsety="4" repeatx="1">
|
||||||
|
<image source="../kenney/tiny-dungeon/Tilemap/tilemap.png" width="203" height="186"/>
|
||||||
|
</imagelayer>
|
||||||
|
<group id="2" name="grp" offsetx="16" opacity="0.5" tintcolor="#ff0000">
|
||||||
|
<layer id="3" name="inner" width="4" height="4">
|
||||||
|
<data encoding="csv">
|
||||||
|
2,0,0,0,
|
||||||
|
0,0,0,0,
|
||||||
|
0,0,0,0,
|
||||||
|
0,0,0,0
|
||||||
|
</data>
|
||||||
|
</layer>
|
||||||
|
</group>
|
||||||
|
</map>
|
||||||
1
assets/tiled-fixtures/infinite_map.tmj
Normal file
1
assets/tiled-fixtures/infinite_map.tmj
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
{"type": "map", "version": "1.10", "orientation": "orthogonal", "renderorder": "right-down", "width": 0, "height": 0, "tilewidth": 16, "tileheight": 16, "infinite": true, "tilesets": [{"firstgid": 1, "source": "collision.tsx"}], "layers": [{"type": "tilelayer", "id": 1, "name": "ground", "width": 0, "height": 0, "startx": 0, "starty": 0, "chunks": [{"x": 0, "y": 0, "width": 16, "height": 16, "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]}, {"x": 16, "y": 0, "width": 16, "height": 16, "data": [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]}]}]}
|
||||||
15
assets/tiled-fixtures/infinite_map.tmx
Normal file
15
assets/tiled-fixtures/infinite_map.tmx
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Hand-authored P6 infinite/chunked fixture (issue #74). CC0. -->
|
||||||
|
<map version="1.10" tiledversion="1.10.2" orientation="orthogonal" renderorder="right-down" width="0" height="0" tilewidth="16" tileheight="16" infinite="1" nextlayerid="2" nextobjectid="1">
|
||||||
|
<tileset firstgid="1" source="collision.tsx"/>
|
||||||
|
<layer id="1" name="ground" width="0" height="0">
|
||||||
|
<data encoding="csv">
|
||||||
|
<chunk x="0" y="0" width="16" height="16">
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
|
||||||
|
</chunk>
|
||||||
|
<chunk x="16" y="0" width="16" height="16">
|
||||||
|
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
|
||||||
|
</chunk>
|
||||||
|
</data>
|
||||||
|
</layer>
|
||||||
|
</map>
|
||||||
43
assets/tiled-fixtures/isometric_grass_and_water.tmx
Normal file
43
assets/tiled-fixtures/isometric_grass_and_water.tmx
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<map version="1.4" tiledversion="1.4.3" orientation="isometric" renderorder="right-down" width="25" height="25" tilewidth="64" tileheight="32" infinite="0" nextlayerid="2" nextobjectid="1">
|
||||||
|
<tileset firstgid="1" name="isometric_grass_and_water" tilewidth="64" tileheight="64" tilecount="24" columns="4">
|
||||||
|
<tileoffset x="0" y="16"/>
|
||||||
|
<grid orientation="isometric" width="64" height="32"/>
|
||||||
|
<image source="isometric_grass_and_water.png" width="256" height="384"/>
|
||||||
|
<wangsets>
|
||||||
|
<wangset name="Grass and Water" type="corner" tile="15">
|
||||||
|
<wangcolor name="Grass" color="#8ab022" tile="0" probability="1"/>
|
||||||
|
<wangcolor name="Water" color="#378dc2" tile="23" probability="1"/>
|
||||||
|
<wangtile tileid="0" wangid="0,1,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="1" wangid="0,1,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="2" wangid="0,1,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="3" wangid="0,1,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="4" wangid="0,1,0,2,0,1,0,1"/>
|
||||||
|
<wangtile tileid="5" wangid="0,1,0,1,0,2,0,1"/>
|
||||||
|
<wangtile tileid="6" wangid="0,1,0,1,0,1,0,2"/>
|
||||||
|
<wangtile tileid="7" wangid="0,2,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="8" wangid="0,2,0,2,0,2,0,1"/>
|
||||||
|
<wangtile tileid="9" wangid="0,1,0,2,0,2,0,2"/>
|
||||||
|
<wangtile tileid="10" wangid="0,2,0,1,0,2,0,2"/>
|
||||||
|
<wangtile tileid="11" wangid="0,2,0,2,0,1,0,2"/>
|
||||||
|
<wangtile tileid="12" wangid="0,1,0,2,0,2,0,1"/>
|
||||||
|
<wangtile tileid="13" wangid="0,1,0,1,0,2,0,2"/>
|
||||||
|
<wangtile tileid="14" wangid="0,2,0,1,0,1,0,2"/>
|
||||||
|
<wangtile tileid="15" wangid="0,2,0,2,0,1,0,1"/>
|
||||||
|
<wangtile tileid="16" wangid="0,1,0,2,0,2,0,1"/>
|
||||||
|
<wangtile tileid="17" wangid="0,1,0,1,0,2,0,2"/>
|
||||||
|
<wangtile tileid="18" wangid="0,2,0,1,0,1,0,2"/>
|
||||||
|
<wangtile tileid="19" wangid="0,2,0,2,0,1,0,1"/>
|
||||||
|
<wangtile tileid="20" wangid="0,2,0,1,0,2,0,1"/>
|
||||||
|
<wangtile tileid="21" wangid="0,1,0,2,0,1,0,2"/>
|
||||||
|
<wangtile tileid="22" wangid="0,2,0,2,0,2,0,2"/>
|
||||||
|
<wangtile tileid="23" wangid="0,2,0,2,0,2,0,2"/>
|
||||||
|
</wangset>
|
||||||
|
</wangsets>
|
||||||
|
</tileset>
|
||||||
|
<layer id="1" name="Tile Layer 1" width="25" height="25">
|
||||||
|
<data encoding="base64" compression="zlib">
|
||||||
|
eJx1lttywjAMROVgyqVtAoFC/v9L68xoh5PFPGhIYktrrVYyS0QszZ7Nvpvd0n7y24L1Q7MhrTSreN/le821HZ7lv9qYa6sdE0cYs/kX7PXYwtfaevYp7WDrd+SnHByjYr/npP1zZ4/elcuM71rjeckdc5KNHX75fMwc9s2uzb6AsYstJzwrv5/Tz89SLIZy8v203llV8xl7yMU+462/v81OqA114/UhrzUxRqwprnh6ZGzp2PNQfPqRu/X9hnMV8F/xLg1L42erDf2oaa2RI2qPtbgbhmw2H69nMUxx/gVccXdC3AW/o/HV60vW59Lhu8arDxmfGIPFUV1qbLVQEIs4PlOeHQxqVjmzr5mLYsmf+5Qj5yM1r3Ne4p1D5VcMh3qWZibLx2fYkBhPYOv81I9wbrGd45zFU7zrndpwDjkHXXfej9zHc3EG+D3AWcCZMJif7hTnVxr6i9edtoBDz8N7kxqbY6sN9gJnsnqIOqCme7Un76579sIV8dccHvHqZefH76BP9wjzkVapM2rL+5/8cR6QS9eh8p2AT12y5oO9+7yh5hzLZypnHX29/pzB9PE7bOg8Mza5KvGu4R7mp/89zqvr7x+TnxEn
|
||||||
|
</data>
|
||||||
|
</layer>
|
||||||
|
</map>
|
||||||
285
assets/tiled-fixtures/orthogonal-outside.tmx
Normal file
285
assets/tiled-fixtures/orthogonal-outside.tmx
Normal file
|
|
@ -0,0 +1,285 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<map version="1.8" tiledversion="1.8.5" orientation="orthogonal" renderorder="right-down" width="45" height="31" tilewidth="16" tileheight="16" infinite="0" nextlayerid="4" nextobjectid="38">
|
||||||
|
<properties>
|
||||||
|
<property name="enemyTint" type="color" value="#ffa33636"/>
|
||||||
|
</properties>
|
||||||
|
<tileset firstgid="1" name="outdoor" tilewidth="16" tileheight="16" tilecount="288" columns="24">
|
||||||
|
<image source="buch-outdoor.png" width="384" height="192"/>
|
||||||
|
<tile id="6" probability="0.1"/>
|
||||||
|
<tile id="27" probability="0.05"/>
|
||||||
|
<tile id="28" probability="0.05"/>
|
||||||
|
<tile id="30" probability="0.1"/>
|
||||||
|
<tile id="51" probability="0.05"/>
|
||||||
|
<tile id="52" probability="0.05"/>
|
||||||
|
<tile id="54" probability="0.1"/>
|
||||||
|
<tile id="75" probability="0.05"/>
|
||||||
|
<tile id="76" probability="0.05"/>
|
||||||
|
<tile id="78" probability="0.1"/>
|
||||||
|
<tile id="82" probability="0.1"/>
|
||||||
|
<tile id="83" probability="0.1"/>
|
||||||
|
<tile id="99" probability="0.05"/>
|
||||||
|
<tile id="102" probability="0.1"/>
|
||||||
|
<tile id="106" probability="0.1"/>
|
||||||
|
<tile id="107" probability="0.1"/>
|
||||||
|
<tile id="126" probability="0.1"/>
|
||||||
|
<wangsets>
|
||||||
|
<wangset name="Terrains" type="corner" tile="25">
|
||||||
|
<wangcolor name="Grass" color="#fce94f" tile="150" probability="1"/>
|
||||||
|
<wangcolor name="Dirt" color="#ef2929" tile="100" probability="1"/>
|
||||||
|
<wangcolor name="Dark Dirt" color="#f57900" tile="34" probability="1"/>
|
||||||
|
<wangcolor name="Water" color="#729fcf" tile="171" probability="1"/>
|
||||||
|
<wangtile tileid="0" wangid="0,1,0,2,0,1,0,1"/>
|
||||||
|
<wangtile tileid="1" wangid="0,1,0,2,0,2,0,1"/>
|
||||||
|
<wangtile tileid="2" wangid="0,1,0,2,0,2,0,1"/>
|
||||||
|
<wangtile tileid="3" wangid="0,1,0,2,0,2,0,1"/>
|
||||||
|
<wangtile tileid="4" wangid="0,1,0,2,0,2,0,1"/>
|
||||||
|
<wangtile tileid="5" wangid="0,1,0,1,0,2,0,1"/>
|
||||||
|
<wangtile tileid="6" wangid="0,1,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="7" wangid="0,2,0,3,0,2,0,2"/>
|
||||||
|
<wangtile tileid="8" wangid="0,2,0,3,0,3,0,2"/>
|
||||||
|
<wangtile tileid="9" wangid="0,2,0,3,0,3,0,2"/>
|
||||||
|
<wangtile tileid="10" wangid="0,2,0,3,0,3,0,2"/>
|
||||||
|
<wangtile tileid="11" wangid="0,2,0,3,0,3,0,2"/>
|
||||||
|
<wangtile tileid="12" wangid="0,2,0,2,0,3,0,2"/>
|
||||||
|
<wangtile tileid="13" wangid="0,1,0,3,0,1,0,1"/>
|
||||||
|
<wangtile tileid="14" wangid="0,1,0,3,0,3,0,1"/>
|
||||||
|
<wangtile tileid="15" wangid="0,1,0,3,0,3,0,1"/>
|
||||||
|
<wangtile tileid="16" wangid="0,1,0,3,0,3,0,1"/>
|
||||||
|
<wangtile tileid="17" wangid="0,1,0,3,0,3,0,1"/>
|
||||||
|
<wangtile tileid="18" wangid="0,1,0,1,0,3,0,1"/>
|
||||||
|
<wangtile tileid="24" wangid="0,2,0,2,0,1,0,1"/>
|
||||||
|
<wangtile tileid="25" wangid="0,2,0,1,0,2,0,2"/>
|
||||||
|
<wangtile tileid="26" wangid="0,2,0,2,0,1,0,2"/>
|
||||||
|
<wangtile tileid="27" wangid="0,2,0,2,0,2,0,2"/>
|
||||||
|
<wangtile tileid="28" wangid="0,2,0,2,0,2,0,2"/>
|
||||||
|
<wangtile tileid="29" wangid="0,1,0,1,0,2,0,2"/>
|
||||||
|
<wangtile tileid="30" wangid="0,1,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="31" wangid="0,3,0,3,0,2,0,2"/>
|
||||||
|
<wangtile tileid="32" wangid="0,3,0,2,0,3,0,3"/>
|
||||||
|
<wangtile tileid="33" wangid="0,3,0,3,0,2,0,3"/>
|
||||||
|
<wangtile tileid="34" wangid="0,3,0,3,0,3,0,3"/>
|
||||||
|
<wangtile tileid="35" wangid="0,3,0,3,0,3,0,3"/>
|
||||||
|
<wangtile tileid="36" wangid="0,2,0,2,0,3,0,3"/>
|
||||||
|
<wangtile tileid="37" wangid="0,3,0,3,0,1,0,1"/>
|
||||||
|
<wangtile tileid="38" wangid="0,3,0,1,0,3,0,3"/>
|
||||||
|
<wangtile tileid="39" wangid="0,3,0,3,0,1,0,3"/>
|
||||||
|
<wangtile tileid="40" wangid="0,3,0,3,0,3,0,3"/>
|
||||||
|
<wangtile tileid="42" wangid="0,1,0,1,0,3,0,3"/>
|
||||||
|
<wangtile tileid="48" wangid="0,2,0,2,0,1,0,1"/>
|
||||||
|
<wangtile tileid="49" wangid="0,1,0,2,0,2,0,2"/>
|
||||||
|
<wangtile tileid="50" wangid="0,2,0,2,0,2,0,1"/>
|
||||||
|
<wangtile tileid="51" wangid="0,2,0,2,0,2,0,2"/>
|
||||||
|
<wangtile tileid="52" wangid="0,2,0,2,0,2,0,2"/>
|
||||||
|
<wangtile tileid="53" wangid="0,1,0,1,0,2,0,2"/>
|
||||||
|
<wangtile tileid="54" wangid="0,1,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="55" wangid="0,3,0,3,0,2,0,2"/>
|
||||||
|
<wangtile tileid="56" wangid="0,2,0,3,0,3,0,3"/>
|
||||||
|
<wangtile tileid="57" wangid="0,3,0,3,0,3,0,2"/>
|
||||||
|
<wangtile tileid="58" wangid="0,3,0,3,0,3,0,3"/>
|
||||||
|
<wangtile tileid="59" wangid="0,3,0,3,0,3,0,3"/>
|
||||||
|
<wangtile tileid="60" wangid="0,2,0,2,0,3,0,3"/>
|
||||||
|
<wangtile tileid="61" wangid="0,3,0,3,0,1,0,1"/>
|
||||||
|
<wangtile tileid="62" wangid="0,1,0,3,0,3,0,3"/>
|
||||||
|
<wangtile tileid="63" wangid="0,3,0,3,0,3,0,1"/>
|
||||||
|
<wangtile tileid="66" wangid="0,1,0,1,0,3,0,3"/>
|
||||||
|
<wangtile tileid="72" wangid="0,2,0,2,0,1,0,1"/>
|
||||||
|
<wangtile tileid="73" wangid="0,2,0,1,0,2,0,1"/>
|
||||||
|
<wangtile tileid="74" wangid="0,1,0,2,0,1,0,2"/>
|
||||||
|
<wangtile tileid="75" wangid="0,2,0,2,0,2,0,2"/>
|
||||||
|
<wangtile tileid="76" wangid="0,2,0,2,0,2,0,2"/>
|
||||||
|
<wangtile tileid="77" wangid="0,1,0,1,0,2,0,2"/>
|
||||||
|
<wangtile tileid="78" wangid="0,1,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="79" wangid="0,3,0,3,0,2,0,2"/>
|
||||||
|
<wangtile tileid="80" wangid="0,3,0,2,0,3,0,2"/>
|
||||||
|
<wangtile tileid="81" wangid="0,2,0,3,0,2,0,3"/>
|
||||||
|
<wangtile tileid="82" wangid="0,3,0,3,0,3,0,3"/>
|
||||||
|
<wangtile tileid="83" wangid="0,3,0,3,0,3,0,3"/>
|
||||||
|
<wangtile tileid="84" wangid="0,2,0,2,0,3,0,3"/>
|
||||||
|
<wangtile tileid="85" wangid="0,3,0,3,0,1,0,1"/>
|
||||||
|
<wangtile tileid="86" wangid="0,3,0,1,0,3,0,1"/>
|
||||||
|
<wangtile tileid="87" wangid="0,1,0,3,0,1,0,3"/>
|
||||||
|
<wangtile tileid="90" wangid="0,1,0,1,0,3,0,3"/>
|
||||||
|
<wangtile tileid="96" wangid="0,2,0,2,0,1,0,1"/>
|
||||||
|
<wangtile tileid="97" wangid="0,1,0,2,0,1,0,2"/>
|
||||||
|
<wangtile tileid="98" wangid="0,2,0,1,0,2,0,1"/>
|
||||||
|
<wangtile tileid="99" wangid="0,2,0,2,0,2,0,2"/>
|
||||||
|
<wangtile tileid="100" wangid="0,2,0,2,0,2,0,2"/>
|
||||||
|
<wangtile tileid="101" wangid="0,1,0,1,0,2,0,2"/>
|
||||||
|
<wangtile tileid="102" wangid="0,1,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="103" wangid="0,3,0,3,0,2,0,2"/>
|
||||||
|
<wangtile tileid="104" wangid="0,2,0,3,0,2,0,3"/>
|
||||||
|
<wangtile tileid="105" wangid="0,3,0,2,0,3,0,2"/>
|
||||||
|
<wangtile tileid="106" wangid="0,3,0,3,0,3,0,3"/>
|
||||||
|
<wangtile tileid="107" wangid="0,3,0,3,0,3,0,3"/>
|
||||||
|
<wangtile tileid="108" wangid="0,2,0,2,0,3,0,3"/>
|
||||||
|
<wangtile tileid="109" wangid="0,3,0,3,0,1,0,1"/>
|
||||||
|
<wangtile tileid="110" wangid="0,1,0,3,0,1,0,3"/>
|
||||||
|
<wangtile tileid="111" wangid="0,3,0,1,0,3,0,1"/>
|
||||||
|
<wangtile tileid="114" wangid="0,1,0,1,0,3,0,3"/>
|
||||||
|
<wangtile tileid="120" wangid="0,2,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="121" wangid="0,2,0,1,0,1,0,2"/>
|
||||||
|
<wangtile tileid="122" wangid="0,2,0,1,0,1,0,2"/>
|
||||||
|
<wangtile tileid="123" wangid="0,2,0,1,0,1,0,2"/>
|
||||||
|
<wangtile tileid="124" wangid="0,2,0,1,0,1,0,2"/>
|
||||||
|
<wangtile tileid="125" wangid="0,1,0,1,0,1,0,2"/>
|
||||||
|
<wangtile tileid="126" wangid="0,1,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="127" wangid="0,3,0,2,0,2,0,2"/>
|
||||||
|
<wangtile tileid="128" wangid="0,3,0,2,0,2,0,3"/>
|
||||||
|
<wangtile tileid="129" wangid="0,3,0,2,0,2,0,3"/>
|
||||||
|
<wangtile tileid="130" wangid="0,3,0,2,0,2,0,3"/>
|
||||||
|
<wangtile tileid="131" wangid="0,3,0,2,0,2,0,3"/>
|
||||||
|
<wangtile tileid="132" wangid="0,2,0,2,0,2,0,3"/>
|
||||||
|
<wangtile tileid="133" wangid="0,3,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="134" wangid="0,3,0,1,0,1,0,3"/>
|
||||||
|
<wangtile tileid="135" wangid="0,3,0,1,0,1,0,3"/>
|
||||||
|
<wangtile tileid="136" wangid="0,3,0,1,0,1,0,3"/>
|
||||||
|
<wangtile tileid="137" wangid="0,3,0,1,0,1,0,3"/>
|
||||||
|
<wangtile tileid="138" wangid="0,1,0,1,0,1,0,3"/>
|
||||||
|
<wangtile tileid="144" wangid="0,1,0,4,0,1,0,1"/>
|
||||||
|
<wangtile tileid="145" wangid="0,1,0,4,0,4,0,1"/>
|
||||||
|
<wangtile tileid="146" wangid="0,1,0,4,0,4,0,1"/>
|
||||||
|
<wangtile tileid="147" wangid="0,1,0,4,0,4,0,1"/>
|
||||||
|
<wangtile tileid="148" wangid="0,1,0,4,0,4,0,1"/>
|
||||||
|
<wangtile tileid="149" wangid="0,1,0,1,0,4,0,1"/>
|
||||||
|
<wangtile tileid="150" wangid="0,1,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="151" wangid="0,2,0,4,0,2,0,2"/>
|
||||||
|
<wangtile tileid="152" wangid="0,2,0,4,0,4,0,2"/>
|
||||||
|
<wangtile tileid="153" wangid="0,2,0,4,0,4,0,2"/>
|
||||||
|
<wangtile tileid="154" wangid="0,2,0,4,0,4,0,2"/>
|
||||||
|
<wangtile tileid="155" wangid="0,2,0,4,0,4,0,2"/>
|
||||||
|
<wangtile tileid="156" wangid="0,2,0,2,0,4,0,2"/>
|
||||||
|
<wangtile tileid="168" wangid="0,4,0,4,0,1,0,1"/>
|
||||||
|
<wangtile tileid="169" wangid="0,4,0,1,0,4,0,4"/>
|
||||||
|
<wangtile tileid="170" wangid="0,4,0,4,0,1,0,4"/>
|
||||||
|
<wangtile tileid="171" wangid="0,4,0,4,0,4,0,4"/>
|
||||||
|
<wangtile tileid="172" wangid="0,4,0,4,0,4,0,4"/>
|
||||||
|
<wangtile tileid="173" wangid="0,1,0,1,0,4,0,4"/>
|
||||||
|
<wangtile tileid="174" wangid="0,1,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="175" wangid="0,4,0,4,0,2,0,2"/>
|
||||||
|
<wangtile tileid="176" wangid="0,4,0,2,0,4,0,4"/>
|
||||||
|
<wangtile tileid="177" wangid="0,4,0,4,0,2,0,4"/>
|
||||||
|
<wangtile tileid="178" wangid="0,4,0,4,0,4,0,4"/>
|
||||||
|
<wangtile tileid="179" wangid="0,4,0,4,0,4,0,4"/>
|
||||||
|
<wangtile tileid="180" wangid="0,2,0,2,0,4,0,4"/>
|
||||||
|
<wangtile tileid="192" wangid="0,4,0,4,0,1,0,1"/>
|
||||||
|
<wangtile tileid="193" wangid="0,1,0,4,0,4,0,4"/>
|
||||||
|
<wangtile tileid="194" wangid="0,4,0,4,0,4,0,1"/>
|
||||||
|
<wangtile tileid="195" wangid="0,4,0,4,0,4,0,4"/>
|
||||||
|
<wangtile tileid="196" wangid="0,4,0,4,0,4,0,4"/>
|
||||||
|
<wangtile tileid="197" wangid="0,1,0,1,0,4,0,4"/>
|
||||||
|
<wangtile tileid="198" wangid="0,1,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="199" wangid="0,4,0,4,0,2,0,2"/>
|
||||||
|
<wangtile tileid="200" wangid="0,2,0,4,0,4,0,4"/>
|
||||||
|
<wangtile tileid="201" wangid="0,4,0,4,0,4,0,2"/>
|
||||||
|
<wangtile tileid="202" wangid="0,4,0,4,0,4,0,4"/>
|
||||||
|
<wangtile tileid="203" wangid="0,4,0,4,0,4,0,4"/>
|
||||||
|
<wangtile tileid="204" wangid="0,2,0,2,0,4,0,4"/>
|
||||||
|
<wangtile tileid="216" wangid="0,4,0,4,0,1,0,1"/>
|
||||||
|
<wangtile tileid="217" wangid="0,4,0,1,0,4,0,1"/>
|
||||||
|
<wangtile tileid="218" wangid="0,1,0,4,0,1,0,4"/>
|
||||||
|
<wangtile tileid="219" wangid="0,4,0,4,0,4,0,4"/>
|
||||||
|
<wangtile tileid="220" wangid="0,4,0,4,0,4,0,4"/>
|
||||||
|
<wangtile tileid="221" wangid="0,1,0,1,0,4,0,4"/>
|
||||||
|
<wangtile tileid="222" wangid="0,1,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="223" wangid="0,4,0,4,0,2,0,2"/>
|
||||||
|
<wangtile tileid="224" wangid="0,4,0,2,0,4,0,2"/>
|
||||||
|
<wangtile tileid="225" wangid="0,2,0,4,0,2,0,4"/>
|
||||||
|
<wangtile tileid="226" wangid="0,4,0,4,0,4,0,4"/>
|
||||||
|
<wangtile tileid="227" wangid="0,4,0,4,0,4,0,4"/>
|
||||||
|
<wangtile tileid="228" wangid="0,2,0,2,0,4,0,4"/>
|
||||||
|
<wangtile tileid="240" wangid="0,4,0,4,0,1,0,1"/>
|
||||||
|
<wangtile tileid="241" wangid="0,1,0,4,0,1,0,4"/>
|
||||||
|
<wangtile tileid="242" wangid="0,4,0,1,0,4,0,1"/>
|
||||||
|
<wangtile tileid="243" wangid="0,4,0,4,0,4,0,4"/>
|
||||||
|
<wangtile tileid="244" wangid="0,4,0,4,0,4,0,4"/>
|
||||||
|
<wangtile tileid="245" wangid="0,1,0,1,0,4,0,4"/>
|
||||||
|
<wangtile tileid="246" wangid="0,1,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="247" wangid="0,4,0,4,0,2,0,2"/>
|
||||||
|
<wangtile tileid="248" wangid="0,2,0,4,0,2,0,4"/>
|
||||||
|
<wangtile tileid="249" wangid="0,4,0,2,0,4,0,2"/>
|
||||||
|
<wangtile tileid="250" wangid="0,4,0,4,0,4,0,4"/>
|
||||||
|
<wangtile tileid="251" wangid="0,4,0,4,0,4,0,4"/>
|
||||||
|
<wangtile tileid="252" wangid="0,2,0,2,0,4,0,4"/>
|
||||||
|
<wangtile tileid="264" wangid="0,4,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="265" wangid="0,4,0,1,0,1,0,4"/>
|
||||||
|
<wangtile tileid="266" wangid="0,4,0,1,0,1,0,4"/>
|
||||||
|
<wangtile tileid="267" wangid="0,4,0,1,0,1,0,4"/>
|
||||||
|
<wangtile tileid="268" wangid="0,4,0,1,0,1,0,4"/>
|
||||||
|
<wangtile tileid="269" wangid="0,1,0,1,0,1,0,4"/>
|
||||||
|
<wangtile tileid="270" wangid="0,1,0,1,0,1,0,1"/>
|
||||||
|
<wangtile tileid="271" wangid="0,4,0,2,0,2,0,2"/>
|
||||||
|
<wangtile tileid="272" wangid="0,4,0,2,0,2,0,4"/>
|
||||||
|
<wangtile tileid="273" wangid="0,4,0,2,0,2,0,4"/>
|
||||||
|
<wangtile tileid="274" wangid="0,4,0,2,0,2,0,4"/>
|
||||||
|
<wangtile tileid="275" wangid="0,4,0,2,0,2,0,4"/>
|
||||||
|
<wangtile tileid="276" wangid="0,2,0,2,0,2,0,4"/>
|
||||||
|
</wangset>
|
||||||
|
</wangsets>
|
||||||
|
</tileset>
|
||||||
|
<layer id="1" name="Ground" width="45" height="31">
|
||||||
|
<data encoding="base64" compression="zlib">
|
||||||
|
eJyNWE1vVVUU3Y0KQeXL4kBL7QAiEkcopQOIkjgysXagYeLIpE0HGucEtY5U6giw1Bj8AdiWxhZ+ANLS4nv+AJKW1+TVH9DklWfSR+LeeWt51j3eWxmsnPvuPR9rr7P3Pvu8hpkd7DFb8dYb24Pf89bFtOOio8/xquNreZ/jdccxx0nH53j+SN7F81nHOfz+BGs1vP0C706i/1kZ+6asMWRdrvMY+4q3bzmedTwj/FfAO/i2HVcc10s4f+t4QzidcEw6vnd8lz0HfrAu3wOO8xj3seO44AT6cY0GONPWTx1jjp8cvzjO4Fsbfan/luP3XXgrJ+4XtWnjeQX9VzBmErgsdud8lXdwCb94G5w3HE+g+R5ZcwDPDx114U3dY569wkW5UZ8J8I6+AfalPbT7MvhS03nMMV3CNzT+A5zHMt70obvezjrWwfue47HwynUhH3JivwG01E1Be0cs8eW3mOd9x2lwXHVsOx7AP8bgI/PCZ5+PmwHvHceSaK76UZO2cGyg1X2mT/eKrtOwUX2Le/RcicbB4zfHyz6239sPs3VijtB6E33XRPPr0CbXmpwaAvrEPPyBvsDvOn4IbQ+4jkHnDaxfE52POl6zFIe0n1oH12Vw37Hq2HzH8W5o6DgE9FrRn+l7uk8rVvSZi6LvDdF4GaBPU2edS32kDjub1vWrMt6Mq8gJkc/OwQbypq9T54jrKcfVkrl+Fq5ctwn9/hTOZefIgPC+7VhEW9tFb+bwyL2Rw3le5DHGeVuY6xrma0DPJtpYL+Ip/JT+TM7uT9/k649jji3MEWMO+5gF2Py4hLOel8y/A1bMKdRbeW8K99BkzlIOmMVe37GuL2u+y/PYCNbbAkfGwCo0vyX9cq0nwbcsXnP/e97xAjADzutoQ6def3+kJ2lMnCmZL/wl/C7y87bsTXDuOB5Bt//jpbgiflBlQwe6am4bE40Dw6J1PscW9inmiJhlvvzVcaAn7fnT8JyC/ZG77u/SX3Nx8CPnQNRxl6xY05XZPYN5HoBv+F+VL49kccF9on9GG757q2J84KXMD0bBrw/+EHt7yro5umqOh7IW1330FHtNvkvQdg72co8GKtajnn2ib+QJ1p7T2XMgzlDPI//mv+C8Db5NWVO/MeangB/Bt4Y9CnuXs7FVIEfWofy9d5cxPF8mRKtNaDQLvxiy5O/xvgMteQ5si7Y1PLdkf8owjvW+hIan7L85gnXJRLd/wQ+ZD+jPjOU1K9ao1JLfeWatgfdtvGcNsBtnzjcu+/+VdWMubNA6i3lNx9MWahl7qvUHa1RqS79pWjord9C/hedFjLsKaByQ72KJLax1437GmqZX+OV2Mz+FP9y0dI52wKuFd3y/CH3Zh1qz1f7x7n62X/USHm3ggqU7pdYyeZ57EedTxI3W1XXw25T1a+DFs4vn/Bz4d7BHm5bOOe4XvzdLeBBRO0YdwzszeYevjFvymYg1xiv1qFvKtx1o17QUi1EXMHYOgfsR8G9Z8hXWiZyrjvFVnFl/kfOxjDdrmeAZeeuapTOce8x6gHquAVEv6jnL51VozH6shdbAn3VnrBvxdtCS7/LdeUv/NUQNxntlG7ypK/dxHWuw/tbzlTVIrMlaKu4Zeu4egm30I+a/WbTL+KaaHoeWh8GX+sZ/I1HnDlixFr9nqY5dtFQztjK+vMurbsH7hqU7J/X+GxyXMGcNWJI9oy9csOJ/PKEr/0cJe96Dvjdl/3g/2ZZ1uH9/Wbe2GnR8AC7Rb8dSPOV2jaIfc7ae6ew7akX/nQRP+kC8j/OO98vgvA95Yj/q2v2SK7Sm5fx5rC2gT/R/YsXacRT7EeMXLMVdcNa4rYrByMd6B676j44+3QFn1U7jTLkzz6nGw/I93m9Yyot5HcdzhPkrELkrYjD8mnGZc2a9pnUO+Q5mPEO/fivG21Grtktty+8eqjM58b873tk+s25c6t0+cNdS/cAYv1Oxfhn6pR20oh+dzvoOZ/b+A6OnAUo=
|
||||||
|
</data>
|
||||||
|
</layer>
|
||||||
|
<layer id="2" name="Fringe" width="45" height="31">
|
||||||
|
<data encoding="base64" compression="zlib">
|
||||||
|
eJzVl9lNw0AURZ8ltgr4YquAjliaYPl8DdAChCVABRB2KkBhpwK2sKQC4FgiShQ8tseMx/aVjmRLY+fO3JnnFxGRGZiVamkBFos2EaOBQGQw6N6PFmcltcbwOx50vU+neKYztsb1OmzAZq4uo9XxbjO2wfUBHMJRjt5c6RyacAlXcF2oGzu9wCu0YCohpwcPftJqFdZ+r9uGMf1nvWjtwX7P/UiEN5vzUiZRW5Qao9QarUHRftKI2qLUGKXWaCOjZ9/zprYoNUapNdrM+Hsu5m0jaotSY5Rao62M73Ax70d4gme4yOgjSb01tH/eu/947xd8izvfS7Ds6F2+VZP8e5oVx+8rY0/D90dN385QPnuapN7DZnxvT1O2HiCNqtYD2GaXt3aot9tQh62K9CJn+DyFEziuiOd7fN7BLdyUxDN5C7kL+Yf74I8+8fkB7/AGQ+zdYU/7t21YI/IWchfyD/dBoibwO1nwmSNvIXch/3AfxCopE18ibyF3If9wH8TKNhOfMq2nTSZ5yXSeTOvZn0nU83Mw78Bb1P/tUKbzlHY9k87jD20Li3Y=
|
||||||
|
</data>
|
||||||
|
</layer>
|
||||||
|
<objectgroup id="3" name="Objects">
|
||||||
|
<object id="1" name="maggots" type="Location" x="435" y="74" width="155" height="99">
|
||||||
|
<properties>
|
||||||
|
<property name="spawncount" type="int" value="5"/>
|
||||||
|
<property name="spawntype" value="maggot"/>
|
||||||
|
</properties>
|
||||||
|
</object>
|
||||||
|
<object id="2" name="discover chest" type="Trigger" x="201" y="200" width="127" height="127">
|
||||||
|
<properties>
|
||||||
|
<property name="script" type="file" value="chest-discovered.lua"/>
|
||||||
|
</properties>
|
||||||
|
<ellipse/>
|
||||||
|
</object>
|
||||||
|
<object id="3" name="unreachable" type="Fixture" x="2" y="158">
|
||||||
|
<properties>
|
||||||
|
<property name="static" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
<polygon points="0,0 55,-23 96,-117 110,-61 104,-42 119,-33 116,6 104,9 100,36 60,43 53,58 43,58 34,74 21,69 18,90 0,89"/>
|
||||||
|
</object>
|
||||||
|
<object id="5" name="guard" type="NPC" x="22" y="361">
|
||||||
|
<polyline points="-3,120 87,91 154,96 181,16 273,-1"/>
|
||||||
|
</object>
|
||||||
|
<object id="6" name="guard" type="NPC" x="277" y="18">
|
||||||
|
<polyline points="0,0 75,78 133,82 176,179 274,183"/>
|
||||||
|
</object>
|
||||||
|
<object id="10" gid="282" x="413.333" y="225.333" width="16" height="16"/>
|
||||||
|
<object id="11" gid="282" x="421.667" y="218" width="16" height="16"/>
|
||||||
|
<object id="12" gid="2147483930" x="423" y="235.333" width="16" height="16"/>
|
||||||
|
<object id="13" gid="282" x="5" y="70" width="16" height="16"/>
|
||||||
|
<object id="14" gid="282" x="-3.66667" y="80.3333" width="16" height="16"/>
|
||||||
|
<object id="16" gid="283" x="538" y="418.333" width="16" height="16"/>
|
||||||
|
<object id="17" gid="283" x="407.667" y="462" width="16" height="16"/>
|
||||||
|
<object id="18" gid="283" x="417" y="473.667" width="16" height="16"/>
|
||||||
|
<object id="19" gid="283" x="402.667" y="469" width="16" height="16"/>
|
||||||
|
<object id="21" gid="2147483930" x="683.333" y="260.5" width="16" height="16"/>
|
||||||
|
<object id="22" gid="282" x="692.167" y="269.167" width="16" height="16"/>
|
||||||
|
<object id="23" gid="282" x="701.667" y="247.833" width="16" height="16"/>
|
||||||
|
<object id="24" gid="282" x="688.5" y="242" width="16" height="16"/>
|
||||||
|
<object id="25" gid="282" x="670.5" y="263.5" width="16" height="16"/>
|
||||||
|
<object id="26" gid="282" x="680" y="284" width="16" height="16"/>
|
||||||
|
<object id="27" gid="282" x="643.833" y="283.667" width="16" height="16"/>
|
||||||
|
<object id="28" gid="282" x="63.4165" y="386" width="16" height="16"/>
|
||||||
|
<object id="29" gid="282" x="9.0835" y="356.167" width="16" height="16"/>
|
||||||
|
<object id="30" gid="282" x="11.9165" y="385" width="16" height="16"/>
|
||||||
|
<object id="31" gid="282" x="54.2495" y="378.5" width="16" height="16"/>
|
||||||
|
<object id="32" gid="2147483930" x="2.4165" y="364.5" width="16" height="16"/>
|
||||||
|
<object id="33" gid="2147483930" x="41.5835" y="382.833" width="16" height="16"/>
|
||||||
|
<object id="34" type="Sign" gid="257" x="670.667" y="87" width="16" height="16">
|
||||||
|
<properties>
|
||||||
|
<property name="text" value="East West"/>
|
||||||
|
</properties>
|
||||||
|
</object>
|
||||||
|
<object id="37" name="player-start" type="Location" x="192" y="160">
|
||||||
|
<point/>
|
||||||
|
</object>
|
||||||
|
</objectgroup>
|
||||||
|
</map>
|
||||||
47
assets/tiled-fixtures/p2_map.tmx
Normal file
47
assets/tiled-fixtures/p2_map.tmx
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Hand-authored P2 collision fixture (issue #70). CC0. -->
|
||||||
|
<map version="1.10" tiledversion="1.10.2" orientation="orthogonal" renderorder="right-down" width="16" height="10" tilewidth="16" tileheight="16" infinite="0" nextlayerid="4" nextobjectid="1">
|
||||||
|
<tileset firstgid="1" source="p2_tiles.tsx"/>
|
||||||
|
<layer id="1" name="collision" width="16" height="10">
|
||||||
|
<data encoding="csv">
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
</data>
|
||||||
|
</layer>
|
||||||
|
<layer id="2" name="props" width="16" height="10">
|
||||||
|
<data encoding="csv">
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,4,4,4,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
</data>
|
||||||
|
</layer>
|
||||||
|
<layer id="3" name="floor" width="16" height="10">
|
||||||
|
<data encoding="csv">
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
</data>
|
||||||
|
</layer>
|
||||||
|
</map>
|
||||||
12
assets/tiled-fixtures/p2_tiles.tsx
Normal file
12
assets/tiled-fixtures/p2_tiles.tsx
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Hand-authored collision-metadata tileset (issue #70). CC0. -->
|
||||||
|
<tileset version="1.10" tiledversion="1.10.2" name="p2tiles" tilewidth="16" tileheight="16" tilecount="5" columns="5">
|
||||||
|
<tile id="1">
|
||||||
|
<objectgroup draworder="index">
|
||||||
|
<object id="1" x="0" y="0" width="16" height="16"/>
|
||||||
|
</objectgroup>
|
||||||
|
</tile>
|
||||||
|
<tile id="2"><properties><property name="oneway" type="bool" value="true"/></properties></tile>
|
||||||
|
<tile id="3"><properties><property name="solid" type="bool" value="true"/></properties></tile>
|
||||||
|
<tile id="4"><properties><property name="trigger" type="bool" value="true"/></properties></tile>
|
||||||
|
</tileset>
|
||||||
8
assets/tiled-fixtures/p4_enemy.tx
Normal file
8
assets/tiled-fixtures/p4_enemy.tx
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<template>
|
||||||
|
<object type="Enemy" width="16" height="16">
|
||||||
|
<properties>
|
||||||
|
<property name="hp" type="int" value="25"/>
|
||||||
|
</properties>
|
||||||
|
</object>
|
||||||
|
</template>
|
||||||
19
assets/tiled-fixtures/p4_map.tmx
Normal file
19
assets/tiled-fixtures/p4_map.tmx
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Hand-authored P4 fixture: object shapes, custom types, templates (issue #72). CC0. -->
|
||||||
|
<map version="1.10" tiledversion="1.10.2" orientation="orthogonal" renderorder="right-down" width="16" height="16" tilewidth="16" tileheight="16" infinite="0" nextlayerid="3" nextobjectid="13">
|
||||||
|
<objectgroup id="1" name="shapes">
|
||||||
|
<object id="1" x="10" y="10" width="20" height="30"/>
|
||||||
|
<object id="2" x="40" y="10" width="20" height="20"><ellipse/></object>
|
||||||
|
<object id="3" x="70" y="10"><point/></object>
|
||||||
|
<object id="4" x="90" y="10"><polygon points="0,0 16,0 16,16 0,16"/></object>
|
||||||
|
<object id="5" x="120" y="10"><polyline points="0,0 10,10 20,0"/></object>
|
||||||
|
<object id="6" x="10" y="60" width="80" height="20"><text pixelsize="12" halign="center">Hello</text></object>
|
||||||
|
</objectgroup>
|
||||||
|
<objectgroup id="2" name="spawns">
|
||||||
|
<object id="10" type="Enemy" x="32" y="48" width="16" height="16">
|
||||||
|
<properties><property name="hp" type="int" value="99"/></properties>
|
||||||
|
</object>
|
||||||
|
<object id="11" type="Enemy" x="64" y="48" width="16" height="16"/>
|
||||||
|
<object id="12" template="p4_enemy.tx" x="80" y="48"/>
|
||||||
|
</objectgroup>
|
||||||
|
</map>
|
||||||
8
assets/tiled-fixtures/p4_types.xml
Normal file
8
assets/tiled-fixtures/p4_types.xml
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<objecttypes>
|
||||||
|
<objecttype name="Enemy" color="#ff0000">
|
||||||
|
<property name="hp" type="int" default="10"/>
|
||||||
|
<property name="speed" type="int" default="3"/>
|
||||||
|
<property name="boss" type="bool" default="false"/>
|
||||||
|
</objecttype>
|
||||||
|
</objecttypes>
|
||||||
20
assets/tiled-fixtures/perspective_walls.tsx
Normal file
20
assets/tiled-fixtures/perspective_walls.tsx
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<tileset name="perspective_walls" tilewidth="64" tileheight="64">
|
||||||
|
<tileoffset x="-32" y="0"/>
|
||||||
|
<image source="perspective_walls.png"/>
|
||||||
|
<tile id="13">
|
||||||
|
<properties>
|
||||||
|
<property name="door" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="14">
|
||||||
|
<properties>
|
||||||
|
<property name="door" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="15">
|
||||||
|
<properties>
|
||||||
|
<property name="pickup" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
</tileset>
|
||||||
19
assets/tiled-fixtures/physics_map.tmx
Normal file
19
assets/tiled-fixtures/physics_map.tmx
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Hand-authored map for the Ludic Tiled demos (issue #69). CC0. -->
|
||||||
|
<map version="1.10" tiledversion="1.10.2" orientation="orthogonal" renderorder="right-down" width="16" height="10" tilewidth="16" tileheight="16" infinite="0" nextlayerid="2" nextobjectid="1">
|
||||||
|
<tileset firstgid="1" source="collision.tsx"/>
|
||||||
|
<layer id="1" name="collision" width="16" height="10">
|
||||||
|
<data encoding="csv">
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,
|
||||||
|
0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
</data>
|
||||||
|
</layer>
|
||||||
|
</map>
|
||||||
16
assets/tiled-fixtures/sewers.tmx
Normal file
16
assets/tiled-fixtures/sewers.tmx
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<map version="1.0" orientation="orthogonal" width="50" height="50" tilewidth="24" tileheight="24">
|
||||||
|
<tileset firstgid="1" name="sewer_tileset" tilewidth="24" tileheight="24">
|
||||||
|
<image source="sewer_tileset.png" trans="ff00ff" width="192" height="217"/>
|
||||||
|
</tileset>
|
||||||
|
<layer name="Bottom" width="50" height="50">
|
||||||
|
<data encoding="base64" compression="zlib">
|
||||||
|
eJzt19kKwjAQBdDim0sFqwguL3Vf/sP//ySnkIFhSGrSdEnxPhyQxqJ32kySPMuyJTkZC5KLa2dyNEo1Lsds3wkl/4f+7V/0/f+Y40Je5GpUn2+J5NiQCdmO/HlMyYzMI3JwLUJx7drIsSIFWUfk4FrY3GvGuHb8vr4jcmhNcnAtpIflmmar3VA5nqaWMUKeQ1d9dyht59iRPTmMPEdpua8Put/Frh88P5q84zFkv/NZP2TOlOaH7Hc+64fMmdL8cPVbV9+tcn5MzpTmR0gv12uDbQ4MNT8AIA73Uq3v3hqLe2ldTx4D21k1tf2ubw59Vk1tX+KbQ59VXfuSlMn9SJHV70tS5jqrYu8BAAAAAAAAAABd+wIHfQq1
|
||||||
|
</data>
|
||||||
|
</layer>
|
||||||
|
<layer name="Top" width="50" height="50" opacity="0.49">
|
||||||
|
<data encoding="base64" compression="zlib">
|
||||||
|
eJzt1jsKgDAQQEELtVKvYuGvEDvvfya3MBeQQAzMwCPdsum2af5lL71AJv7xL7X+Y46WtzXayq7z2RGd0f2+V6a5bdRFfaZ5pQzRGE2lFwEAoArpDk7Veg+nOzjlHgYAAAAAIIcHvboDlQ==
|
||||||
|
</data>
|
||||||
|
</layer>
|
||||||
|
</map>
|
||||||
15
assets/tiled-fixtures/zstd_map.tmx
Normal file
15
assets/tiled-fixtures/zstd_map.tmx
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Hand-authored P6 zstd fixture (issue #74). CC0. -->
|
||||||
|
<map version="1.10" tiledversion="1.10.2" orientation="orthogonal" renderorder="right-down" width="24" height="16" tilewidth="16" tileheight="16" infinite="0" nextlayerid="3" nextobjectid="1">
|
||||||
|
<tileset firstgid="1" source="collision.tsx"/>
|
||||||
|
<layer id="1" name="csv" width="24" height="16">
|
||||||
|
<data encoding="csv">
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,3,2,3,3,3,3,3,2,3,3,3,3,3,2,3,3,3,3,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,3,2,3,3,3,3,3,2,3,3,3,3,3,2,3,3,3,3,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,3,2,3,3,3,3,3,2,3,3,3,3,3,2,3,3,3,3,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
|
||||||
|
</data>
|
||||||
|
</layer>
|
||||||
|
<layer id="2" name="zstd" width="24" height="16">
|
||||||
|
<data encoding="base64" compression="zstd">
|
||||||
|
KLUv/WAABe0AADgBAAAAAwIBBgC4mgT54KqgO9JxR0xFgOm26RIB
|
||||||
|
</data>
|
||||||
|
</layer>
|
||||||
|
</map>
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
# Changesets
|
# Changesets
|
||||||
|
|
||||||
A **changeset** is one small Markdown file describing a single user-facing change,
|
A **changeset** is one small Markdown file describing a single user-facing change,
|
||||||
dropped in this directory. `x release` consumes every changeset here into a new
|
dropped in this directory. `ludic-dev release` consumes every changeset here into a new
|
||||||
`CHANGELOG.md` section, bumps `VERSION`, and deletes the consumed files.
|
`CHANGELOG.md` section, bumps `VERSION`, and deletes the consumed files.
|
||||||
|
|
||||||
## Format
|
## Format
|
||||||
|
|
@ -14,12 +14,38 @@ the changelog. Markdown is fine.
|
||||||
```
|
```
|
||||||
|
|
||||||
- `bump:` — `major`, `minor`, or `patch` (SemVer). The release version is bumped
|
- `bump:` — `major`, `minor`, or `patch` (SemVer). The release version is bumped
|
||||||
by the **highest** level among the pending changesets (unless `x release <level>`
|
by the **highest** level among the pending changesets (unless `ludic-dev release <level>`
|
||||||
overrides it).
|
overrides it).
|
||||||
- `type:` — the Conventional Commit type (`feat`, `fix`, `perf`, `docs`, …); it
|
- `type:` — the Conventional Commit type (`feat`, `fix`, `perf`, `docs`, …). It
|
||||||
becomes the bold prefix of the changelog bullet.
|
decides which group the change lands in: `feat` → **Features**, `fix` →
|
||||||
|
**Fixes**, `perf` → **Performance**, and so on, in that order. A type with no
|
||||||
|
known heading gets one named after itself.
|
||||||
|
|
||||||
|
## Writing the body
|
||||||
|
|
||||||
|
The body is markdown and reaches the changelog as markdown: it becomes one list
|
||||||
|
item, with continuation lines indented to stay inside it. Nested bullets, blank
|
||||||
|
lines between paragraphs and inline code all survive.
|
||||||
|
|
||||||
|
```
|
||||||
|
bump: minor
|
||||||
|
type: feat
|
||||||
|
**Tiled map support** — load and draw Tiled maps.
|
||||||
|
|
||||||
|
- **TMX/TSX** — the XML formats, decoded to the same intermediate as JSON.
|
||||||
|
- **Collision** — the `collision` layer projects onto the engine tilemap.
|
||||||
|
```
|
||||||
|
|
||||||
|
Lead with the thing that changed, not with the mechanism. A reader scanning the
|
||||||
|
release should be able to stop after your first clause.
|
||||||
|
|
||||||
## Adding one
|
## Adding one
|
||||||
|
|
||||||
Create a file with a short, unique name, e.g. `changes/regex-namespace.md`. Any
|
Create a file with a short, unique name, e.g. `changes/regex-namespace.md`. Any
|
||||||
filename works except this `README.md`, which the release step always skips.
|
filename works except this `README.md`, which the release step always skips.
|
||||||
|
|
||||||
|
Preview how the next release will read before cutting it — this writes nothing:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ludic-dev release --dry-run
|
||||||
|
```
|
||||||
|
|
|
||||||
8
changes/a-hidden-body-still-stands-in-the-sun.md
Normal file
8
changes/a-hidden-body-still-stands-in-the-sun.md
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
bump: patch
|
||||||
|
type: fix
|
||||||
|
`Actor.cast_hidden` separates being DRAWN from CASTING. `ac_visible` rejected any hidden
|
||||||
|
actor from the shadow pass as well as the scene pass, so a game that hides the player's
|
||||||
|
own body - first person, or a viewfinder held to the eye - lost that player's shadow
|
||||||
|
entirely. An actor hidden because the camera is inside its head is still standing in the
|
||||||
|
sun; set this on it and it keeps its shadow. Everything else still stops casting when it
|
||||||
|
is hidden.
|
||||||
17
changes/a-leaf-is-not-matte.md
Normal file
17
changes/a-leaf-is-not-matte.md
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
bump: patch
|
||||||
|
type: fix
|
||||||
|
A leaf is not matte.
|
||||||
|
|
||||||
|
Foliage roughness was pinned to 1.0 and grazing Fresnel switched off, so nothing green in
|
||||||
|
the game had a highlight anywhere: the glint off waxy leaves and wet needles, which is
|
||||||
|
most of what makes a real stand look alive rather than painted, was simply absent.
|
||||||
|
|
||||||
|
The reason it was switched off is real. A crown is card quads, and at a grazing angle the
|
||||||
|
card's normal is a lie, so a plain specular lobe frosted whole crowns white against the
|
||||||
|
sky. So the sheen comes back as its own term gated on exactly that: it fades out as the
|
||||||
|
card turns edge-on, which is where its normal stops meaning anything. A tight lobe for the
|
||||||
|
glint, a weak wide one for the waxy rim, and nothing at all at the angles that frosted.
|
||||||
|
|
||||||
|
Thin-leaf translucency reaches further with it - a backlit stand glows for as far as you
|
||||||
|
can see it, not 140 m - and a dense crown passes 0.45 of it rather than 0.3. The distance
|
||||||
|
cap that stops a two-pixel clump card becoming a lime disc stays.
|
||||||
28
changes/a-lens-and-an-edge.md
Normal file
28
changes/a-lens-and-an-edge.md
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
bump: minor
|
||||||
|
type: feat
|
||||||
|
Anti-aliasing that exists, and a lens for the viewfinder.
|
||||||
|
|
||||||
|
THE SHIPPING DEFAULT HAD NO ANTI-ALIASING AT ALL. The temporal resolve was removed (for
|
||||||
|
good reasons - it reprojected water through the surface plane and dragged the mirror image
|
||||||
|
behind the camera), the setting's first option went on saying "Temporal", and MSAA defaults
|
||||||
|
to one sample. Every machine without DLSS - which is every Mac - drew a frame full of grass
|
||||||
|
blades and needle cards with nothing smoothing a single edge.
|
||||||
|
|
||||||
|
FXAA now, in the sharpen pass, because that pass already reads this pixel's neighbourhood
|
||||||
|
and runs last on the LDR image. It has no history, so it cannot drag or smear a reflection.
|
||||||
|
Measured on edge pixels: 25.5% less single-pixel staircase.
|
||||||
|
|
||||||
|
One trap worth recording. The unsharp mask's delta is computed from the RAW image and only
|
||||||
|
then applied to the anti-aliased colour. Taking the centre from the FXAA result and the
|
||||||
|
neighbours from the raw texture measures a difference that is half smoothing and half
|
||||||
|
signal, so the mask sharpens exactly the edges FXAA just softened - measured, that first
|
||||||
|
version was 29% WORSE than no anti-aliasing at all.
|
||||||
|
|
||||||
|
And depth of field, for the photo mode: a disc of taps whose radius is the pixel's circle
|
||||||
|
of confusion, signed so the two sides of the focal plane differ and normalised by the focus
|
||||||
|
distance, because a lens focused at two metres throws a background out far harder than one
|
||||||
|
focused at two hundred. A tap only counts if it is at least as out of focus as the pixel
|
||||||
|
it is blurring into, which is what keeps a sharp foreground from haloing into a blurred
|
||||||
|
background. It runs between the scene and the bloom so a blurred highlight still blooms,
|
||||||
|
and the whole pass is skipped when the aperture is shut - in ordinary play there is no lens
|
||||||
|
and this never draws.
|
||||||
11
changes/actions.md
Normal file
11
changes/actions.md
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
bump: minor
|
||||||
|
type: feature
|
||||||
|
**Actions and reducers.** `action PickUp { item: int }` is a typed record of something that
|
||||||
|
happened; `reducer Bag on PickUp(b: mut Bag, a: PickUp) { ... }`, in the module that owns the state,
|
||||||
|
says what it means for that one state - a reducer takes exactly its state and the action, and a
|
||||||
|
second state is refused; `dispatch PickUp { item: 7 }` queues one from anywhere. The queue is drained
|
||||||
|
at the end of every phase of the frame loop, after every phase of ludic.base's `core_tick_all`, and
|
||||||
|
where a program calls `drain_actions()`: in dispatch order, each action's reducers in the order of
|
||||||
|
their states' names, an action a reducer dispatches queued behind (a queue still growing after 64
|
||||||
|
rounds stops the program, naming the action). `ludic deps` reports `widest_function` - the most
|
||||||
|
states any function or entry point of the program takes - and `--check` ratchets it.
|
||||||
15
changes/an-aspen-quakes.md
Normal file
15
changes/an-aspen-quakes.md
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
bump: minor
|
||||||
|
type: feat
|
||||||
|
An aspen leaf hangs on a flattened stalk and turns in air a spruce never feels, and the
|
||||||
|
kit had no way to say so. `layer_flutter(l, v)` gives a scatter layer a per-leaf tremble:
|
||||||
|
the vertex stage offsets each leaf by a phase taken from its own place on the card, so
|
||||||
|
neighbouring leaves are never in step, and writes the result out as a varying the
|
||||||
|
fragment stage uses to flash the leaf's pale underside as it turns. The flash is the part
|
||||||
|
that reads - a still frame of a tremble is a still frame of nothing. One uniform, one
|
||||||
|
varying, no extra pass, and every other layer leaves it at zero.
|
||||||
|
|
||||||
|
Also fixes the sway itself, which was measured in METRES: `hgt * hgt * 0.35` is right for
|
||||||
|
a 40 cm flower and puts ten metres of sideways into a 14 m trunk, so every tall tree in
|
||||||
|
the valley stood bent over like a fishing rod. It is a fraction of the model's own height
|
||||||
|
now, so the tip moves a few per cent of the tree whatever the tree is and the base does
|
||||||
|
not move at all.
|
||||||
9
changes/anim-ozz.md
Normal file
9
changes/anim-ozz.md
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
bump: minor
|
||||||
|
type: feature
|
||||||
|
**`ludic.anim` carries ozz-animation (0.17.0, MIT) as a native library**, the second package to do
|
||||||
|
so after `ludic.physics`. Its skeleton and each clip are built at LOAD from the numbers the package
|
||||||
|
already reads - a skin's parents and rest pose, a clip's flattened channels - so there is no bake
|
||||||
|
step and no new file. `anim_oz_skel(sk)`, `anim_oz_clip(c)`, `anim_oz_ctx(s)` and
|
||||||
|
`anim_oz_sample(ctx, clip, t, rot, pos, n)` are the first step (Maroon Lake's phase 19.1): a sampled
|
||||||
|
rotation agrees with `anim_mix` to within 1e-4 a component. `anim_play` is unchanged. The library is
|
||||||
|
built by `native/build.sh` from the pinned release, and on Windows it imports KERNEL32 alone.
|
||||||
6
changes/asset-map.md
Normal file
6
changes/asset-map.md
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
bump: minor
|
||||||
|
type: feature
|
||||||
|
**`@Asset(kind, map)`: a path under each map's directory.** A field whose file lives in the map's own folder
|
||||||
|
(a grass kind's density picture, `ground/blades.png`) says so, and `ludicc --check` looks for it in every
|
||||||
|
map - a @PerMap row's in its map, a game-wide row's in all of them - refusing a map that lacks it unless the
|
||||||
|
field is `@Asset(kind, map, optional)`. The schema marks the attribute `"scope": "map"`.
|
||||||
7
changes/attrs-before-export.md
Normal file
7
changes/attrs-before-export.md
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
bump: patch
|
||||||
|
type: fix
|
||||||
|
**An attribute before `export` is kept.** `@ToClients export event E`, `@Sync export property P`,
|
||||||
|
`@Owned export model M` and the rest lost the attributes written in front of `export`: the parser read
|
||||||
|
them, then parsed the declaration afresh and forgot them - so an exported remote event was silently
|
||||||
|
local; and `export @ToClients event` was refused outright. Attributes and `export` now read in
|
||||||
|
either order into the same declaration.
|
||||||
8
changes/bake-expand.md
Normal file
8
changes/bake-expand.md
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
bump: minor
|
||||||
|
type: feature
|
||||||
|
**A bake's inputs can follow the data.** `bake_expand(inputs, map)` gives a Bakes row's inputs as they are
|
||||||
|
hashed: `{map}` put as the map's key, and each input with a `*` put as the paths it matches, sorted as whole
|
||||||
|
paths byte by byte, dot-names left out, a glob matching nothing gone. `bake_maps(first_input)` is the maps a
|
||||||
|
`{map}` row covers: each directory under assets/maps holding its first input (`bake_maps_in` under another
|
||||||
|
root). A runner hashes `bake_inputs_hash(bake_expand(row.inputs, map))`, the same path the check takes, so
|
||||||
|
the two cannot disagree on stale; a game's Python tools are its checked twin.
|
||||||
11
changes/bake-images.md
Normal file
11
changes/bake-images.md
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
bump: minor
|
||||||
|
type: feature
|
||||||
|
**Bakes you can look at, and three more of the renderer's textures read from one.** `ludic.lab` writes
|
||||||
|
raw 8-bit pixels (1 to 4 channels) as a PNG (`lab_png_write`, `png_write.ludic`, importable alone with its
|
||||||
|
own `LabPngState`) and turns float textures into honest previews (`png_convert.ludic`: R32F min..max as
|
||||||
|
grey, RG16F as red and green x255, HDR RGBA16F as x/(1+x) then sRGB). `ludic.render3d` takes three bakes
|
||||||
|
the game names (`bake_load.ludic`) and makes each as before when one is missing or stale: an impostor's
|
||||||
|
atlases as BC7 with their baked mips, through the compressed upload (`impostor_from_baked`,
|
||||||
|
`impostor_fill_bc7`; a fog opening past its cards reads the bake again instead of painting), the sky's image-based light at the start yaw per prefilter width (`sky_baked_in`; any other
|
||||||
|
turn of the sky is convolved), and the grass carpet (`carpet_from_baked`, `carpet_bytes`).
|
||||||
|
`impostor_from_bytes` returns null, keeping nothing, when the bytes are not the impostor's shape.
|
||||||
8
changes/baked-textures.md
Normal file
8
changes/baked-textures.md
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
bump: minor
|
||||||
|
type: feature
|
||||||
|
**Textures a game baked at build time are read before the PNG.** `png_decode` first takes
|
||||||
|
`assets/baked/png/<path>.tex` (a game's `ludic bake` output: the samples, ready to upload), and a cut-out
|
||||||
|
load (`tex_load_ex` with dilate) first takes `assets/baked/cutouts/<path>.bc7` (padded as `tex_dilate`
|
||||||
|
pads, then BC7 with its mips) - so a boot decodes, pads and converts nothing it can take ready-made. Both
|
||||||
|
are ludic.base's baked form, read by hand (baked_tex.ludic: the "LBAK" header, the key and version); a
|
||||||
|
missing or stale one falls back to the PNG as before. `tex_load_dds_at` reads a .dds at an offset.
|
||||||
5
changes/bind-variable.md
Normal file
5
changes/bind-variable.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
bump: minor
|
||||||
|
type: feature
|
||||||
|
**`bind Purse { money: g_money }` - a port member bound to a variable.** A member that takes nothing
|
||||||
|
may name a global instead of a function; the compiler writes the getter in the bind's file, so the
|
||||||
|
one-line wrapper is gone. A member that takes something is refused a variable.
|
||||||
7
changes/build-ir-in-temp.md
Normal file
7
changes/build-ir-in-temp.md
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
bump: patch
|
||||||
|
type: fix
|
||||||
|
**`ludic build` keeps its LLVM IR out of the project.** The intermediate `.ll` was written beside
|
||||||
|
the binary (`build/<name>.ll`) and deleted after linking, so a project's tree held one for the
|
||||||
|
length of every build, and two builds at once deleted each other's - which surfaced as a
|
||||||
|
`clang: no such file` that read exactly like a compile error. It now goes to the run's own
|
||||||
|
temporary directory and goes with it. `--save-temps` still keeps it at `build/<name>.ll`.
|
||||||
9
changes/builtin-names.md
Normal file
9
changes/builtin-names.md
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
bump: patch
|
||||||
|
type: fix
|
||||||
|
**A function named like a built-in a call always takes is refused.** `function words(st, k)` compiled,
|
||||||
|
and every call to it became the built-in `words(n)` - n zeroed ints, with a pointer for n - and LLVM
|
||||||
|
refused the IR far from the cause. A top-level function whose name a call always takes as the
|
||||||
|
compiler's own (`words`, `keep`, `print`, `save`, `load`, `key`, ...; the table is
|
||||||
|
`selfhost/check/check_builtins.ludic`, held to `emit_call` by `ludic-dev syntax --check`) is now an
|
||||||
|
error at its declaration, as `run` already was. Every other built-in (`buffer`, `floats`, `double`,
|
||||||
|
...) yields to a function the program declares, in the checker as it already did in codegen.
|
||||||
7
changes/check-build.md
Normal file
7
changes/check-build.md
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
bump: minor
|
||||||
|
type: feature
|
||||||
|
**`ludic build --check` / `ludicc --check`: check without building.** The parse, the type checker
|
||||||
|
and the module rules (`export`, `uses`, layers, ports, registries) run, and nothing is emitted or
|
||||||
|
linked - about three seconds on Maroon Lake where a build takes about a minute. In this mode the
|
||||||
|
checker asks the module rules at each reference it resolves, since the emitter that usually asks
|
||||||
|
them does not run.
|
||||||
9
changes/check-stdin-file.md
Normal file
9
changes/check-stdin-file.md
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
bump: minor
|
||||||
|
type: feat
|
||||||
|
**Check an unsaved buffer.** `ludic build --check --diagnostics=json --stdin-file <path>` (and
|
||||||
|
`ludicc --check --stdin-file <path>`) checks the program as usual, but wherever the compiler would open
|
||||||
|
`<path>` - the entry, an import reached through a barrel, a component's `.xml` / `.lss`, an `.lres` -
|
||||||
|
it reads the text on stdin instead, so an editor's diagnostics follow typing without a save. Paths are
|
||||||
|
matched after normalising both (separators, relative to the working directory, `.` / `..` folded).
|
||||||
|
Diagnostics carry the file's usual name with lines and columns in the buffer; a `<path>` the program
|
||||||
|
never opens is reported as one warning.
|
||||||
7
changes/chunked-keys.md
Normal file
7
changes/chunked-keys.md
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
bump: patch
|
||||||
|
type: fix
|
||||||
|
**A chunked table's keys are unique across its map, and not interned.** A row's id is `(map, key)`, so a
|
||||||
|
tree moved into another chunk keeps it, and `ludicc --check` refuses a key written in two of a map's
|
||||||
|
chunk files, naming both. The keys are no longer interned: interning every key a player walked past would
|
||||||
|
have filled the bounded intern table and kept them all for good. A chunk slot keeps its keys in its own
|
||||||
|
buffers, rewritten in place when the slot is refilled; `intern(row.key)` keeps one past `_out`.
|
||||||
9
changes/contact-darkening.md
Normal file
9
changes/contact-darkening.md
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
bump: patch
|
||||||
|
type: feat
|
||||||
|
Things sit ON the ground rather than hovering over it. The screen-space GI pass takes
|
||||||
|
a second, much tighter set of taps (a 0.40 m radius that grows with distance, with a
|
||||||
|
range check so a far surface behind a near one cannot darken it) and folds the result
|
||||||
|
into the ambient occlusion it already had. The wide radius answers "how enclosed is
|
||||||
|
this", which a trunk meeting grass barely registers; the tight one answers "is
|
||||||
|
something touching here", which is the shadow the eye looks for to place an object.
|
||||||
|
It is eight taps on a buffer the pass had already bound.
|
||||||
9
changes/declared-namespaces.md
Normal file
9
changes/declared-namespaces.md
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
bump: minor
|
||||||
|
type: feature
|
||||||
|
**Namespaces are declared in Ludic.** `alias meth(labels) = target` in a `namespace` block makes
|
||||||
|
`Ns.meth(...)` a call to `target`, taking named arguments by those labels; with no label list the
|
||||||
|
target's own parameter names are the labels. The engine's 41 table-driven namespaces - `Http`,
|
||||||
|
`Udp`, `Process`, `Json`, `Value`, `Screen`, `Input`, `Audio`, `World`, `Tiled` and the rest, 438
|
||||||
|
methods - moved out of the compiler into `runtime/native/namespaces.ludic`, and a package owns an
|
||||||
|
API the same way. The code a program compiles to is unchanged byte for byte, and the checker now
|
||||||
|
checks an alias call's arguments against its target.
|
||||||
7
changes/def-from-resource.md
Normal file
7
changes/def-from-resource.md
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
bump: minor
|
||||||
|
type: feature
|
||||||
|
**`def Recipes from "recipes.lres"` - a game fills a package's open registry from its own resource
|
||||||
|
file.** The entries are checked against the registry's record as the file is read, with errors at
|
||||||
|
the resource file's line, and they are defs of the module that wrote the line: the registry must be
|
||||||
|
open to it, and they sit in the stable order (the declaring module's entries, then other modules'
|
||||||
|
by name, and file order within a file).
|
||||||
134
changes/defaults-views-templates.md
Normal file
134
changes/defaults-views-templates.md
Normal file
|
|
@ -0,0 +1,134 @@
|
||||||
|
bump: minor
|
||||||
|
type: feature
|
||||||
|
**Default parameters, components, views and templates.** A parameter can have a default (`pad: float = 8.0`).
|
||||||
|
A call leaves out what it does not change, and may pass its first arguments by position and the
|
||||||
|
rest by name.
|
||||||
|
|
||||||
|
A `view` declaration is the one bridge between a program and its UI. It names the fields a
|
||||||
|
template may read, the functions it may ask and the `on` events it may send, and it writes
|
||||||
|
`view_<name>() -> UiView`.
|
||||||
|
|
||||||
|
A `component Name { prop, state, fields, functions, on events }` declaration beside `Name.xml` and
|
||||||
|
`Name.lss` is a UI component. Its template and styles are compiled in (with `@import` inlined), each
|
||||||
|
mounted instance keeps its own props and state, styles are scoped to it, and a parent's `class`,
|
||||||
|
`style` and `id` land on its root.
|
||||||
|
|
||||||
|
`ludic.ui` is now a template runtime. Screens and components are XML files loaded at run time,
|
||||||
|
with:
|
||||||
|
- `{expression}` bindings;
|
||||||
|
- `<if>`, `<else>` and `<each>`;
|
||||||
|
- props, `<slot/>` and per-instance `<state>`;
|
||||||
|
- `on-press` actions that send events, `set` state or `emit` to the component's user;
|
||||||
|
- component libraries (`export="true"`, `<import src as>`);
|
||||||
|
- HTML's elements (`div`, `p`, `h1`-`h6`, `ul`/`li`, `img`, `hr`, ...), with a default stylesheet;
|
||||||
|
- HTML's attributes: `id`, `class`, `style`, `hidden`, `disabled` and `onclick`, with any other
|
||||||
|
attribute kept for selectors;
|
||||||
|
- the CSS box model (padding and margin in 1-4 values, borders, `px` and `%`) and flex layout
|
||||||
|
(`flex-grow`, `justify-content`, `align-items`/`align-self`, `flex-wrap`, min and max sizes)
|
||||||
|
under CSS's property names;
|
||||||
|
- stylesheets, in a `<style>` or an `.lss` file (a Ludic StyleSheet) that others import and that
|
||||||
|
can `@import` more;
|
||||||
|
- CSS's selectors: `#id`, compound classes, `[attr=value]`, descendant and `>` combinators,
|
||||||
|
`:hover`, `:disabled`, `:first-child`, `:last-child`, `:nth-child`, `:not` and more, weighed by
|
||||||
|
specificity.
|
||||||
|
|
||||||
|
- more CSS: custom properties and `var()`, `position` with insets and `z-index`, `em`/`rem`/`vw`/`vh`,
|
||||||
|
`@media`, wrapping text and ellipsis, `overflow`, `+`/`~`, `:nth-child(an+b)`, `:checked`, `:active`;
|
||||||
|
- more React: keyed lists, `<let>`, `<provide>` context, `<fragment>`, named slots, `on-mount` and
|
||||||
|
`on-unmount`;
|
||||||
|
- native elements a program draws itself (`ui_native`, `ui_fire`), and form controls;
|
||||||
|
- errors with file and line, hot reload (`ui_reload`), and an inspector-style dump.
|
||||||
|
|
||||||
|
The runtime is a UI framework, not only a template engine:
|
||||||
|
- it takes input itself: focus and keyboard navigation, the pointer, scroll boxes, `autofocus`;
|
||||||
|
- it has built-in controls (button, checkbox, radio, range, select, text, key), styled as CSS
|
||||||
|
parts;
|
||||||
|
- `ludic.ui/render3d.ludic` is a render3d backend, with textures, atlases, nine-slices, clipping
|
||||||
|
and scale;
|
||||||
|
- more CSS: `rgba()`/`#rrggbbaa`, `border-radius`, `outline`, `box-shadow`, `background-image`,
|
||||||
|
`border-image`, group `opacity`, `@keyframes` / `animation` / `transition`;
|
||||||
|
- HTML mixed content, and boolean attributes;
|
||||||
|
- `popover` (a top layer that keeps the pointer and keys, with light dismissal), `title` tooltips,
|
||||||
|
and `<progress>` / `<meter>`;
|
||||||
|
- importing `ludic.ui/render3d.ludic` installs the backend, and atlases take rows;
|
||||||
|
- hooks for the program's language, sounds and clock.
|
||||||
|
|
||||||
|
What a game's screens found missing, now in `ludic.ui`:
|
||||||
|
- `<input type="number" min max step>`: typed digits, Enter or leaving it commits them clamped, the
|
||||||
|
arrows step it;
|
||||||
|
- `<input type="key">` listens for any key (Tab and the arrows included) once Enter or a click starts
|
||||||
|
it; Esc stops it, Backspace clears it, `shown` names the value, and `ui_capturing()` tells the host;
|
||||||
|
- `note="..."` under any control's label (`.ui-note`); a range's `decimals`, `format="percent"` and
|
||||||
|
`unit`; a track laid out as a row, with the range's fill as tall as it;
|
||||||
|
- popovers anchored beside an element (`anchor="id"`, or a bare `anchor` for the element before it,
|
||||||
|
`placement`), flipped to the other side and kept on the screen;
|
||||||
|
- `flex-shrink` (a scroll box in a column takes the room its siblings leave), `flex: grow shrink`,
|
||||||
|
`order`, and text in a row wrapping in the room its siblings leave;
|
||||||
|
- `calc()` over px, %, em, rem, vw, vh and `var()`; `width: 0` and `height: 0` mean 0;
|
||||||
|
- `text-shadow`; tooltips of several lines; `ui_opacity()` for a native's draw;
|
||||||
|
- `border-image` drawn as painted with no background colour, tinted by one, and not at all under
|
||||||
|
`transparent`; a picture file drawn untinted (an atlas cell still takes `color`);
|
||||||
|
- the render3d backend loads a picture again when its file changes (`ui_image_reload`), draws a path
|
||||||
|
with a drive letter as a path, and slices a nine-slice by its texture's own width and height;
|
||||||
|
- a component root that is itself a component takes every user's class, style and id, and the
|
||||||
|
sheets that style it are weighed together by specificity;
|
||||||
|
- a component's event may be called `set`; a `string` prop given a number reads it as text; two
|
||||||
|
components of one name are an error naming both files;
|
||||||
|
- the scrollbar is `.ui-scrollbar` and `.ui-thumb`: a press on the thumb holds it where it was taken,
|
||||||
|
a press on the track jumps the thumb's middle there, and neither presses what is under the bar;
|
||||||
|
- a popover's own controls take its presses whatever lies under it, a press outside only closes it,
|
||||||
|
and while one is up the scroll boxes outside it do not take the pointer;
|
||||||
|
- the first gamepad moves the focus (d-pad, left stick), steps ranges and selects, and presses (A)
|
||||||
|
and goes back (B); a held direction, on the pad or the arrow keys, repeats after 0.42 s and then
|
||||||
|
every 0.11 s on the ui clock (`UiInput.held_*`, `pad_a`, `pad_b` for a host);
|
||||||
|
- pointer events: `on-pointerdown` / `pointermove` / `pointerup` / `drag` / `wheel` with `event.x`,
|
||||||
|
`y`, `dx`, `dy`, `button` and `wheel`, and `ui_native_input(tag, fn)` for a native; a press captures
|
||||||
|
the pointer until release; the pointer hits the topmost element in painting order, and
|
||||||
|
`pointer-events: none` lets it through;
|
||||||
|
- `on-down` and `on-up` on a button (the pointer, Enter or A), with `:active` true while it is held
|
||||||
|
there rather than whenever the pointer is down over it;
|
||||||
|
- an anchored popover's `align="start|center|end"`, and `within="id"` (by default the nearest
|
||||||
|
scroll box around it) for the bounds it is flipped against and kept inside;
|
||||||
|
- `text-fit: shrink MIN` shrinks a line to its box, then cuts it with an ellipsis; `line-height`;
|
||||||
|
an `em` reads the font size the element ends with (a `font-size` later in the rule, or in a later
|
||||||
|
rule), not the one it had so far;
|
||||||
|
- `min()`, `max()` and `clamp()`, in `calc()` or on their own; `top` / `right` / `bottom` / `left`
|
||||||
|
as a percentage or a `calc()` of one, of the containing block;
|
||||||
|
- a nine-slice's corners are clamped to half the box in each direction on its own and cut on whole
|
||||||
|
pixels (`ui_nine_cuts`), so a small key cap has no seam;
|
||||||
|
- `scroll-top="{px}"` holds a scroll box at an offset, with `on-scroll` when the player moves it;
|
||||||
|
`ui_scroll_set(id, px)` moves one once;
|
||||||
|
- `linear-gradient(...)` backgrounds; `aspect-ratio`; `object-fit` for pictures (the renderer's
|
||||||
|
`image_w` / `image_h`) and `ui_object_fit` for natives;
|
||||||
|
- `translate="no"` keeps an element's text as written; a title of several lines is translated whole,
|
||||||
|
else line by line;
|
||||||
|
- `<input type="key">` takes a mouse button (`UI_MOUSE_LEFT` / `RIGHT` / `MIDDLE`, 256-258) and is
|
||||||
|
`:capturing` while it listens;
|
||||||
|
- a `title` shows for the keyboard's focus too, after the same half second; a focus ring drawn
|
||||||
|
through a renderer with no `rect` no longer crashes;
|
||||||
|
- a component with no stylesheet of its own reads a theme's `:root` variables from around it (it
|
||||||
|
did; now a test says so);
|
||||||
|
- `ui_scale()` and `ui_box("id")`, the scale and an element's laid-out box, for a host;
|
||||||
|
- `on-submit` on a text field (Enter or A; the focus and text stay unless `clear-on-submit`);
|
||||||
|
- `zoom` on any element, and a length over a length in `calc()` is a plain number;
|
||||||
|
- `on-hold` every frame a button is held, with `event.dt` and `event.t`;
|
||||||
|
- a transition lands exactly on its end value (it had stopped a rounding error short of it, at every
|
||||||
|
frame rate).
|
||||||
|
|
||||||
|
render3d gains `tex_width` / `tex_height`, and the XML reader keeps text runs among elements in
|
||||||
|
order (`mixed`).
|
||||||
|
|
||||||
|
A `view` field set to a literal or a named function's result needs no type.
|
||||||
|
|
||||||
|
Screens are drawn through a registered renderer. `Value` gains a float kind.
|
||||||
|
|
||||||
|
Also:
|
||||||
|
- A program's function named like one of the runtime's is refused; it had been silently taking the
|
||||||
|
runtime's own calls. So is one named like a compiler built-in (`run`, `exit`, `free`, `fill`,
|
||||||
|
...): every call to a program's own `run` compiled into C's `system()`, and clang failed on the IR.
|
||||||
|
- An index is evaluated before the slice's elements are read. A `xs[f()]` whose `f` grew `xs`
|
||||||
|
read stale memory.
|
||||||
|
- A runtime error names the file its expression is in, not the program's.
|
||||||
|
|
||||||
|
Two declarations with one name (a package's private global and a program's, say) are reported as
|
||||||
|
such before type checking. They used to surface as a page of type errors about the wrong type.
|
||||||
6
changes/deps-alias-writes.md
Normal file
6
changes/deps-alias-writes.md
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
bump: patch
|
||||||
|
type: feature
|
||||||
|
**`ludic deps --writes` warns about a write through a local alias.** `let t = thing_cur` and then
|
||||||
|
`t.used = 1` writes another module's record just as `thing_cur.used = 1` does; a local bound straight
|
||||||
|
from another module's global (or from such a local) is now followed within its function and each
|
||||||
|
write through it listed as a warning. A reference that arrives from a function's result is not.
|
||||||
9
changes/deps-reach-32-bits.md
Normal file
9
changes/deps-reach-32-bits.md
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
bump: patch
|
||||||
|
type: fix
|
||||||
|
**`ludic deps`: a reach counts every state apart, however the states are numbered.** The reach and
|
||||||
|
write-reach bitsets packed 60 states to a word, but an `int` is 32 bits, so `1 << 45` came back as bit
|
||||||
|
13 and states 32 apart shared a bit: a function taking both counted one, fewer than it takes, and the
|
||||||
|
counts (`widest_reach`, `widest_write_reach`, `--reach`, `--wreach`) rose and fell with how a program's
|
||||||
|
states happened to be numbered. The sets now hold 30 to a word. On Maroon Lake `widest_reach` goes
|
||||||
|
58 -> 76 and `widest_write_reach` 54 -> 64 - the real numbers, which the old count hid.
|
||||||
|
`examples/state/reach_wide.ludic` (40 states, S00 and S32 taken together) holds it.
|
||||||
10
changes/deps-reach.md
Normal file
10
changes/deps-reach.md
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
bump: minor
|
||||||
|
type: feat
|
||||||
|
**`ludic deps` sees through fn values, and lists the widest functions.** A step list or a registry of
|
||||||
|
fn values takes no state and still reaches every state its steps take; `widest_reach` is the most
|
||||||
|
states any function can come to - by a call, a `fn f` it writes, or a global holding fn values it
|
||||||
|
reads - reported beside `widest_function` with how many of them it does not take itself
|
||||||
|
(`the widest reach: app_boot (src/app/boot.ludic:30), 72 states (72 through calls and fn values it
|
||||||
|
does not take)`). `--widest N` lists the N functions that take the most states with what each
|
||||||
|
reaches; `--reach N` orders them by reach. A baseline written before this has no `widest_reach` and
|
||||||
|
does not hold it until it is rewritten.
|
||||||
7
changes/deps-write-reach.md
Normal file
7
changes/deps-write-reach.md
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
bump: minor
|
||||||
|
type: feat
|
||||||
|
**`ludic deps` says what a function can come to CHANGE** (`widest_write_reach`, and `--wreach N`
|
||||||
|
lists the functions by it): the states it reaches as `mut`, through calls, `fn` values and step
|
||||||
|
lists. Reach itself is sharper: `Port.member()` reaches that member's binding only, and
|
||||||
|
`Registry[i].field` (or a local holding `Registry[i]`) reaches that field only - a question asked of
|
||||||
|
a port or a table that also holds verbs no longer reaches the verbs.
|
||||||
7
changes/devlink-ui.md
Normal file
7
changes/devlink-ui.md
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
bump: minor
|
||||||
|
type: feature
|
||||||
|
**`ludic.devlink`: the interface's verbs.** A `DevlinkUi` port, every member defaulting to "not offered":
|
||||||
|
`ui_screen` (the screen's root class and its components), `ui_model "<Class>" "<out>"` and `ui_tree "<out>"`
|
||||||
|
(the game writes a component's model or the whole tree to a file, no `..`, and the answer names it, so a
|
||||||
|
datagram stays small) and `ui_override "<path>" "<file>"` (a template or stylesheet read from another file
|
||||||
|
and reloaded keeping state; `""` clears one, `"" ""` all). Answered at once; nothing made per frame.
|
||||||
9
changes/devlink.md
Normal file
9
changes/devlink.md
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
bump: minor
|
||||||
|
type: feature
|
||||||
|
**`ludic.devlink`: an editor's live link into a running dev build** (protocol v1, frozen with Ludic
|
||||||
|
Studio). Loopback UDP through the `DevlinkNet` port, one request a frame parsed in place from one fixed
|
||||||
|
8 KB buffer and answered into another; every verb a `DevlinkWorld` member defaulting to "not offered":
|
||||||
|
`ping`, `hello` (the build's schema hash as 16 hex digits), `cam_get` / `cam_set` / `cam_release`, `goto`,
|
||||||
|
`map_load`, `time`, `weather`, `shot`, `pause` / `resume` / `step`, the slow three answered later by id.
|
||||||
|
A socket is opened only when `enabled()` says so (a game binds `dev_tools`), a sender off this machine is
|
||||||
|
dropped, and a connected co-op session refuses everything but `ping` and `hello`.
|
||||||
8
changes/dilate-parallel.md
Normal file
8
changes/dilate-parallel.md
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
bump: patch
|
||||||
|
type: performance
|
||||||
|
**Cut-out edge padding runs on every core.** `tex_dilate`'s passes hand their rows, sixteen at a time, to
|
||||||
|
`Job.parallel_for`: within a pass a row writes only its own still-masked texels and reads only
|
||||||
|
neighbours the mask already let go, so the bytes are the ones the single-threaded loop made. The worker
|
||||||
|
is handed plain buffers in a `DilateJob` and makes nothing. `tex_dilate_bytes` is the slice-taking
|
||||||
|
form (safe_api.ludic), and `examples/rendering/dilate.ludic` holds the result against the old loop
|
||||||
|
(prints DILATE OK). It was 206 ms of the main thread in a Maroon Lake boot.
|
||||||
10
changes/dispatch-kept-records.md
Normal file
10
changes/dispatch-kept-records.md
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
bump: patch
|
||||||
|
type: fix
|
||||||
|
**A dispatched action no longer allocates a record each time.** `dispatch A { ... }` made a fresh
|
||||||
|
record for the queue, and Ludic frees nothing, so a system dispatching every frame (an input's
|
||||||
|
`Move`, a frame's time) grew the program by a record a frame. The queue now keeps a list per
|
||||||
|
action: a dispatch takes the next one (making one only when all are queued), fills every field
|
||||||
|
as `new` would - given, or its default - and `drain_actions()` hands them all back once the queue
|
||||||
|
is empty. A reducer reads its action only during the drain, so nothing sees a record after it is
|
||||||
|
reused; keep what must last in the state, not the action. `ludic.base`'s `actions_test` holds a
|
||||||
|
reused record getting its defaults back.
|
||||||
8
changes/duplicate-definitions.md
Normal file
8
changes/duplicate-definitions.md
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
bump: minor
|
||||||
|
type: feat
|
||||||
|
**A name is defined once, for every kind of declaration.** Two functions with one name were
|
||||||
|
already an error; two `var`s or `const`s (or an enum and a const), or two `property` / `event`
|
||||||
|
records, kept the first definition silently. A game lost months to it: two files both said
|
||||||
|
`KEY_LEFT`, one meaning an arrow key's code and one a binding slot, and the menus read the slot.
|
||||||
|
They are now an error that names both files and lines. `examples/rejected/` holds the two cases,
|
||||||
|
checked by a new `reject_case` in the test runner (an example the compiler must refuse).
|
||||||
9
changes/ecs-growable-stores.md
Normal file
9
changes/ecs-growable-stores.md
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
bump: minor
|
||||||
|
type: feature
|
||||||
|
**The built-in ECS grows.** Every component was a fixed array of 1024 slots, so a game past 1024
|
||||||
|
entities could not have them (and until the last release silently corrupted memory trying). The
|
||||||
|
per-entity stores are heap blocks now, doubled by `L_grow` as entities outgrow them, the new slots
|
||||||
|
zero: 100 000 entities spawn and query. `Prop.has` bounds against the live capacity and
|
||||||
|
`Pool.capacity` answers it. A snapshot (`save`/`load`, `world_save`/`world_load`) records its slot
|
||||||
|
count first and a load grows to it before reading the stores back, so a snapshot's size follows the
|
||||||
|
world's instead of a fixed 1024. A mod's registered components grow with the rest.
|
||||||
31
changes/editor-schema.md
Normal file
31
changes/editor-schema.md
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
bump: minor
|
||||||
|
type: feat
|
||||||
|
**A schema for editors, and every error as JSON.** `ludicc --emit-schema out.json` (and `ludic
|
||||||
|
schema [file] [-o FILE]`) writes what the compiler resolved once the program type-checks: every
|
||||||
|
record with its fields' types, defaults, doc comments and places; every registry with its record,
|
||||||
|
prefix, resource file, openness and its entries in their final order after the open-registry merge
|
||||||
|
(key, constant, index, file:line:col of the entry and of each field value, and which file brought
|
||||||
|
which entries in); every const; and every function a `fn` value can name, with the `fn_type` a field sees (its states stripped).
|
||||||
|
Deterministic, `"schema_version": 1`. Fields and registries carry editor attributes on the existing
|
||||||
|
`@` syntax - `@Ref(Registry)`, `@OneOf(PREFIX_)`, `@Range(lo, hi)`, `@Unit("m/s")`, `@Asset("gltf")`,
|
||||||
|
`@Color`, `@Node(field)`, `@Clip(field)`, `@Material(field)`, `@Tint(SLOT)`, `@Derived`, `@Text`, `@Multiline`, `@Key`, and `@AppendOnly` / `@ByKey` on
|
||||||
|
a registry - which change nothing but go into the schema; `@Ref` naming no registry is an error, and
|
||||||
|
so is `@Node` / `@Clip` naming a field that is not a glTF (`@Asset("gltf")`, or an `@Ref` to one), and
|
||||||
|
a listing `@OneOf` (`@OneOf(A, B)`, not a prefix `@OneOf(P_)`) naming a constant that does not exist, and `@Tint` naming no constant. A field may now carry several attributes. `ludicc --check
|
||||||
|
--diagnostics=json` (`ludic build --check --diagnostics=json`) prints every error as one JSON array
|
||||||
|
of `{file, line, col, severity, message}` on stdout; tokens and nodes now know their column.
|
||||||
|
|
||||||
|
`Build.schema_hash()` answers FNV-1a 64 of the program's own schema (the bytes `ludic schema` prints),
|
||||||
|
computed only when a program names it, and 0 under `ludicc --release`, which `ludic bundle` now passes.
|
||||||
|
|
||||||
|
A target no part of the program declares (an `@Ref` registry, an `@Tint` or listed `@OneOf` constant) is
|
||||||
|
a warning and `"unresolved": true` in the schema, so a package can name the game's registry; a name of
|
||||||
|
another kind is an error. `@OneOf` on a string field takes words, and every registry row's value is
|
||||||
|
checked against them.
|
||||||
|
|
||||||
|
The schema has a `components` list: each UI component's module, place, doc, template and stylesheet
|
||||||
|
paths, its `props` and `state` (type, default as written, place, doc), `states_read` (the states its
|
||||||
|
header names, apart from its model), `derived` fields with their types, and the `functions` and
|
||||||
|
`events` its template calls with their parameters (states and instance stripped), and the
|
||||||
|
registered native tags its template uses. A `natives` list gives every `ui_native` /
|
||||||
|
`ui_native_input` call with a literal tag: the tag, the function called, its handler and its place.
|
||||||
6
changes/engine-alias-shadow.md
Normal file
6
changes/engine-alias-shadow.md
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
bump: patch
|
||||||
|
type: fix
|
||||||
|
**A function named like an engine namespace method's target is refused where that method is
|
||||||
|
called.** `Random.range` is `rng_range`, so a package's own `rng_range(a, b, c)` silently took
|
||||||
|
every `Random.range(1, 6)` (and the checker then asked for its third argument). It is now an error
|
||||||
|
naming the function, the namespace method and the call.
|
||||||
5
changes/expect-eq-strings.md
Normal file
5
changes/expect-eq-strings.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
bump: patch
|
||||||
|
type: fix
|
||||||
|
**`expect_eq` on strings compares their text.** It lowered to an integer compare of two pointers,
|
||||||
|
which the IR refused; now two strings with the same text are equal (a null only to a null), and a
|
||||||
|
failure prints both: `expect_eq failed (got "camp", want "lake")`.
|
||||||
5
changes/expect-floats.md
Normal file
5
changes/expect-floats.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
bump: patch
|
||||||
|
type: fix
|
||||||
|
**`expect_eq` and `expect_near` take floats.** On a float or a double they compared with an integer
|
||||||
|
instruction, and the build failed in clang ("defined with type 'float' but expected 'i32'"); they
|
||||||
|
compare as floats now (the wider kind of the two) and a failure prints the numbers.
|
||||||
12
changes/fmt-editor-output.md
Normal file
12
changes/fmt-editor-output.md
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
bump: minor
|
||||||
|
type: feat
|
||||||
|
**`ludic fmt` for editors.** `ludic fmt --lint --json` prints the violations `--lint` reports as one JSON
|
||||||
|
array on stdout, `[{"file", "line", "col", "rule", "message"}]` ordered by file, line and column (the
|
||||||
|
summary on stderr, `--lint`'s exit status, and the baseline never rewritten). `ludic fmt -` formats
|
||||||
|
stdin to stdout under the project found from the working directory (the nearest `package.ludic`
|
||||||
|
upwards), and refuses a buffer that does not read as Ludic - an open string, a bracket never closed or
|
||||||
|
closed by the wrong one - with exit 2 and `<name>:<line>:<col>: error: ...` on stderr.
|
||||||
|
`--stdin-name <path>` makes the buffer that file: the project is found from its directory, and
|
||||||
|
`ludic fmt - --lint --json --stdin-name <path>` judges it against that file's baseline and `lint
|
||||||
|
paths`, reporting it under the name given. Hooks around `fmt` and `get` read nothing from stdin and
|
||||||
|
write to stderr when the command's stdout is a program's (`--json`, `-`).
|
||||||
5
changes/friend-of.md
Normal file
5
changes/friend-of.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
bump: minor
|
||||||
|
type: feature
|
||||||
|
**`friend module lab of fishing, data` - a friend of some modules, not all.** A scoped friend sees
|
||||||
|
the private names of the modules it names and only the exports of every other; `friend module lab`
|
||||||
|
alone still sees everything.
|
||||||
9
changes/function-values.md
Normal file
9
changes/function-values.md
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
bump: minor
|
||||||
|
type: feat
|
||||||
|
**Functions are values (L2).** `fn(int, float) -> bool` is a type, `fn name` is any top-level
|
||||||
|
function's value (it used to be only a thread worker's address), and a call through a local, a
|
||||||
|
global, a record field, a slice element, a parameter or a result of a function type is an
|
||||||
|
indirect call. Two different function types do not mix, a call through one checks its argument
|
||||||
|
count, and a value may be `null`. A registry can hold behaviour and a package can take
|
||||||
|
callbacks. `Job.parallel_for` still checks that its worker takes (int, pointer) and returns
|
||||||
|
nothing. `ludic-dev selfhost-build` now says why it failed instead of exiting 1 silently.
|
||||||
5
changes/gb-window-fill.md
Normal file
5
changes/gb-window-fill.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
bump: patch
|
||||||
|
type: feature
|
||||||
|
**The blades' density window can be filled without a GPU.** grass_density.ludic's gb_frame is split: gb_window_fill
|
||||||
|
fills the GB_TILES x GB_TILES window of density tiles round the camera's (zeros off the map) and sets its corner,
|
||||||
|
and gb_frame sends it. The same bytes as before; a test reads gb_win after gb_window_fill.
|
||||||
8
changes/generics.md
Normal file
8
changes/generics.md
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
bump: minor
|
||||||
|
type: feature
|
||||||
|
**Generic records and functions.** `property Pool<T> { items: []T }`, `function first<T>(xs: []T)
|
||||||
|
-> T` and `function map<T, U>(xs: []T, f: fn(T) -> U) -> []U`; a type writes an instance as
|
||||||
|
`Pool<Thing>`, nested as deep as needed. A call's type arguments come from its arguments, or from
|
||||||
|
the declared type its result is written into, and are refused with the parameter named when
|
||||||
|
neither says. Each instance is compiled once as an ordinary record or function. `ludic-fmt` keeps
|
||||||
|
`Pool<Thing>` together while still spacing `a < b`.
|
||||||
13
changes/ground-painted-zones.md
Normal file
13
changes/ground-painted-zones.md
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
bump: minor
|
||||||
|
type: feat
|
||||||
|
**`ludic.render3d`: painted ground layers grow solid things, with ids, and the trample is data.**
|
||||||
|
`ground_fill`'s candidate is its own function, `ground_candidate` (pure `gf_*` steps with the density read
|
||||||
|
between them, into a caller-held `GroundCand`), and `ground_fill` draws exactly its answers - the same
|
||||||
|
operations in the same order as before, so every cover layer grows bit for bit what it did. A layer with
|
||||||
|
`solid: true` is filled at `step0` with band 0's hashes whatever the camera, a far band drawing a stable
|
||||||
|
subset; each thing has an int id from (layer, chunk, cell) (`ground_solid_id`), and `ground_solid_list` /
|
||||||
|
`ground_solid_at` answer a chunk's things or one by id for physics, the nav bake and saves.
|
||||||
|
`r3d_ground_clearing(x, z, r_in, r_out, floor)` hands the trample over as discs the editor can see, beside
|
||||||
|
the `r3d_on_ground_trample` callback, which still works. `tests/ground_fill_test.ludic` holds all of it to
|
||||||
|
`tests/ground_fill_golden.json` (written by `tests/gen/ground_fill_golden.ludic`), the file the studio's
|
||||||
|
TypeScript generator is tested against.
|
||||||
6
changes/http-text-copy.md
Normal file
6
changes/http-text-copy.md
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
bump: patch
|
||||||
|
type: fix
|
||||||
|
**`Http.text` and `Http.header` return copies.** They handed back the handle's own buffer (and on macOS the
|
||||||
|
response object's string), which `Http.free` then released: a text read before the free and used after it
|
||||||
|
was garbage or empty - maroon-lake's map list wrote a 0-byte maps.json. Each call now returns a string that
|
||||||
|
is the caller's to keep. Read a body once per response.
|
||||||
8
changes/i18n-error-mode.md
Normal file
8
changes/i18n-error-mode.md
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
bump: minor
|
||||||
|
type: feature
|
||||||
|
**English left is an error (phase 26.9).** Under a `lang` line, a template's own words, a text
|
||||||
|
attribute's, a quoted choice that reads as words and a `@Text` row still holding English now refuse
|
||||||
|
the build, where they were warnings; `ludic deps` still counts them as `english_left`. Hole counts and
|
||||||
|
undescribed splits stay warnings. ludic.ui's own words - the key field's "Right click", "Middle
|
||||||
|
click", "Left click" and "press a key..." - are keys (`ui_tk(ui_st, k"ui.right_click", plain)`,
|
||||||
|
`ui.*` in the program's `.po`), with their plain English for a program that binds no translator.
|
||||||
9
changes/i18n-fill-nested.md
Normal file
9
changes/i18n-fill-nested.md
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
bump: patch
|
||||||
|
type: fix
|
||||||
|
**Text keys below a row, padding, and `tr`'s cast.** A `@Text Key` in a record nested in a registry
|
||||||
|
row (and in each item of a list of them) is filled with its derived key, `<registry>.<row>.<field>.<i>.<field>`,
|
||||||
|
as a top-level one is, and a `@Text []Key` a row leaves out takes `<...>.0`, `.1`, ... for as many as
|
||||||
|
the source `.po` has - so no `.lres` spells a key. `field: null` is no text. `trf` / `trn`'s trailing
|
||||||
|
`""` arguments are padding and not counted against the English's holes. And `string(x)` of a string or
|
||||||
|
a `Key` is no allocation to the escape analysis: it is `x` itself, so a `tr(key)` that returns it
|
||||||
|
passes `arena strict` (a template's lone hole still copies).
|
||||||
9
changes/i18n-keys-only.md
Normal file
9
changes/i18n-keys-only.md
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
bump: minor
|
||||||
|
type: change
|
||||||
|
**ludic.i18n draws plain text as it is: the English path is gone (phase 26.9).** `L` makes a key, a
|
||||||
|
key glued into text, or a line bracketed inside another; anything else - a player's name, a chat
|
||||||
|
line, a number - is drawn as it is, in every language, so a player named "Settings" stays
|
||||||
|
"Settings". Removed with it: the lookup of English words (exact lines, patterns with holes, a
|
||||||
|
paragraph a sentence at a time, padding), `Ln` (use `trn(kn"...")`), `i18n_pattern_count`, and an
|
||||||
|
English argument's own lookup inside a key's hole. A language `.po` is read for its keys and
|
||||||
|
plurals only. A game still on English msgids draws them untranslated until they are keys.
|
||||||
10
changes/i18n-keys.md
Normal file
10
changes/i18n-keys.md
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
bump: minor
|
||||||
|
type: feature
|
||||||
|
**`ludic.i18n`: keys (phase 26).** A key names what a text is for, and `en.po` says it in English like any
|
||||||
|
other language. A key is a string with a marker byte (`I18N_KEY`, `I18N_PLURAL`), its arguments after
|
||||||
|
byte 31, so the code that makes text never takes `I18nState`: `tr(k)`, `trf(k, a, b, c, d)` and
|
||||||
|
`trn(k, n, a, b, c)` build it, and `L` makes it into text where it is drawn - the language in use, else
|
||||||
|
en.po (read the first time a key is asked for), else the key itself, `[[key]]` in a developer's build
|
||||||
|
(`i18n_loud`). Holes take their arguments in the language's order, a key argument made first; plural
|
||||||
|
keys go by each language's rule. A string with no marker takes the old English path, so a game can
|
||||||
|
move over a file at a time.
|
||||||
6
changes/i18n-listener-keys.md
Normal file
6
changes/i18n-listener-keys.md
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
bump: patch
|
||||||
|
type: fix
|
||||||
|
**A key used only in a listener counts as used.** The key check walked the program's declarations but
|
||||||
|
not the bodies kept beside them - `@On` listeners, the lifecycle hooks, tests, computed fields and
|
||||||
|
scenes - so a key used only there was never checked against en.po and `ludic schema` listed it
|
||||||
|
unused. They are walked now, as every other pass walks them.
|
||||||
8
changes/inflate-context.md
Normal file
8
changes/inflate-context.md
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
bump: minor
|
||||||
|
type: feature
|
||||||
|
**Inflate in a caller-owned context.** `ZInflate` holds everything one inflate works in - the bit reader,
|
||||||
|
the RFC's length and distance tables, and every Huffman table and scratch list a block builds - made once
|
||||||
|
by `z_inflate_new()` and rebuilt in place, so an inflate allocates nothing and each thread that inflates
|
||||||
|
holds a context of its own. `z_inflate_in(z, src, len, out, cap)`, `z_uncompress_in` (zlib) and
|
||||||
|
`z_gunzip_in` (gzip) take the context; `z_inflate` / `z_uncompress` / `z_gunzip` keep their signatures,
|
||||||
|
working in the one context `RtInflateState` holds, so no caller changes.
|
||||||
6
changes/int-min-literal.md
Normal file
6
changes/int-min-literal.md
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
bump: patch
|
||||||
|
type: fix
|
||||||
|
**The most negative int is emitted as itself.** The compiler's `itoa` negated a negative value before
|
||||||
|
taking its digits, and `-(-2147483648)` overflows back to itself, so a literal such as `0x80000000` in an
|
||||||
|
int (`b & 0x80000000`) was written into the IR as a bare `-` and the build failed in LLVM. The digits are
|
||||||
|
now taken off the value as it is. Needs a reseed to reach `bin/ludicc`.
|
||||||
6
changes/json-escape-linear.md
Normal file
6
changes/json-escape-linear.md
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
bump: patch
|
||||||
|
type: fix
|
||||||
|
**`Json.parse` decodes an escaped string in one pass.** A string with escapes in it was joined a character
|
||||||
|
at a time, and every shorter copy was kept: a long escaped text took gigabytes (ui-preview's story model
|
||||||
|
reached 6.5 GB in three seconds). It is now decoded into one buffer sized from the text. ui-preview's
|
||||||
|
protocol-v1.md states how an `@import` path is resolved and which key a `file` override answers to.
|
||||||
5
changes/json-unicode.md
Normal file
5
changes/json-unicode.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
bump: patch
|
||||||
|
type: fix
|
||||||
|
**`Json.parse` decodes `\uXXXX`.** An escaped code point is UTF-8 now - a surrogate pair joined into one, a
|
||||||
|
lone surrogate or bad hex as U+FFFD - where the backslash was dropped and the hex kept as text ("iu015f"),
|
||||||
|
and `\t`, `\r`, `\b` and `\f` are the characters they name. Python's `json.dump` writes non-ASCII this way.
|
||||||
7
changes/json-write-file.md
Normal file
7
changes/json-write-file.md
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
bump: minor
|
||||||
|
type: feature
|
||||||
|
**`Json.write_file(value, path)` saves without keeping anything.** It writes the text
|
||||||
|
`Json.encode` would give straight to the file (through `path.tmp` and a rename), built in a buffer
|
||||||
|
the runtime keeps, so a game that saves often holds nothing more for it. `Json.encode` itself is
|
||||||
|
built the same way and makes only the string it returns: it used to join its text with `+`, keeping
|
||||||
|
every piece and every number's text. `examples/lang/json_saves.ludic`: 1000 saves, 0 bytes.
|
||||||
3
changes/lab-png-16-bit.md
Normal file
3
changes/lab-png-16-bit.md
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
bump: patch
|
||||||
|
type: feature
|
||||||
|
**ludic.lab: 16-bit PNGs** — `lab_png_write16_from(st, path, w, h, channels, px, at)` writes 16-bit samples (two bytes each, most significant first) the way `lab_png_write_from` writes 8-bit ones, so a test can write a height map render3d's decoder reads back as R16; `lp_png_bytes(stride, h)` is the size of one.
|
||||||
39
changes/leaves-light-and-the-bole.md
Normal file
39
changes/leaves-light-and-the-bole.md
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
bump: minor
|
||||||
|
type: feat
|
||||||
|
Three things a crown and a hand light were getting wrong.
|
||||||
|
|
||||||
|
**An aspen's trunk quaked with its leaves.** `layer_flutter`'s mask was the vertex's
|
||||||
|
HEIGHT alone — anything more than 1.2 m up trembled — so on a ten metre aspen the whole
|
||||||
|
bole moved, and a tree that is supposed to shiver read as a column of cloth. What
|
||||||
|
separates a leaf from a bole is not height, it is distance from the model's own centre
|
||||||
|
line: the leaves are out at the edge of the crown and the trunk is on the axis. The mask
|
||||||
|
is radial now, and small plants keep the old one, because a flower is all leaf.
|
||||||
|
|
||||||
|
**Foliage in the camera's face.** A third-person camera walks into a crown and the branch
|
||||||
|
between it and the body is an opaque wall a metre from the lens; in first person it is the
|
||||||
|
whole screen. `#define NEAR_FADE` dithers tree foliage out inside arm's length of the
|
||||||
|
camera — in the depth PREPASS, so the lit pass never sees those pixels either and the
|
||||||
|
equal-depth optimisation is untouched. `gl_Position.w` is the view depth for a perspective
|
||||||
|
projection, so it costs one varying and no uniform. Blades, cards and flowers are left
|
||||||
|
alone on purpose: they live at the player's feet, they are always that close, and fading
|
||||||
|
them opens a hole in the meadow. Nor is the BOLE ever faded: a trunk and its needle cards
|
||||||
|
are one mesh drawn by one program, so the first cut dissolved the trunk into a dither
|
||||||
|
pattern as you walked up to it - a solid tree you can see through reads as a fault, where
|
||||||
|
a branch getting out of your way reads as the camera being polite. The mask is the same
|
||||||
|
signal the quake uses. The shadow pass keeps every leaf, or a tree would stop shading the
|
||||||
|
ground it stands on as you walked up to it.
|
||||||
|
|
||||||
|
**A hand light had the reach of a candle, whatever it was meant to be.** `handLight`'s
|
||||||
|
falloff was an inverse square windowed off between 26 and 6 metres, with both numbers
|
||||||
|
hard-coded: two per cent of its own near field by ten metres out, so carrying a torch at
|
||||||
|
night lit your boots and nothing else. `daylight_hand` takes a `reach` in metres now and
|
||||||
|
the falloff is a gentle power out to it — about nine tenths at a metre, half at half the
|
||||||
|
reach, a tenth at nine tenths of it, nothing past it. A pool of light with a gradient in
|
||||||
|
it rather than a hotspot with a cliff.
|
||||||
|
|
||||||
|
**And the wheel on macOS did nothing, or everything.** `scrollingDeltaY` is a double, and
|
||||||
|
the Cocoa event pump truncated it to an int PER EVENT before accumulating: a trackpad or a
|
||||||
|
Magic Mouse sends a stream of fractions of a line, every one of which truncated to zero, so
|
||||||
|
the wheel was dead; a notched mouse sends three to ten lines at once, so it jumped. The
|
||||||
|
fraction is accumulated now, a precise delta is scaled from points to notches, and the
|
||||||
|
remainder carries to the next frame - one gesture, one step, on both kinds of mouse.
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue