Compare commits
544 Commits
playtest-2
...
playtest-2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
82acdbc32a | ||
|
|
462a3ef3c0 | ||
|
|
d4e6815f64 | ||
|
|
723ffdf33d | ||
|
|
8376b09129 | ||
|
|
fa9ce3e2ac | ||
|
|
605681b252 | ||
|
|
a3c5945f2a | ||
|
|
d7ef22d64f | ||
|
|
d907192be0 | ||
|
|
74f8db0578 | ||
|
|
9dca6ef1c3 | ||
|
|
c093e7c90b | ||
|
|
66cf912da0 | ||
|
|
42baa0c42f | ||
|
|
305ba1c567 | ||
|
|
a84b7591f6 | ||
|
|
9d8f0634b1 | ||
|
|
4cd4e1f8ea | ||
|
|
3207d01cf2 | ||
|
|
9fc0f79703 | ||
|
|
1a2d43fc99 | ||
|
|
b944b21325 | ||
|
|
c7e0bc4c08 | ||
|
|
a69417f0a6 | ||
|
|
c36609cc9f | ||
|
|
1edf313090 | ||
|
|
813d48dd70 | ||
|
|
9caf12d133 | ||
|
|
de5bcbbca5 | ||
|
|
8aa548f70c | ||
|
|
ce6e73dc92 | ||
|
|
4a02e6c6cc | ||
|
|
d6a31bb0cc | ||
|
|
f5daa19a1c | ||
|
|
a96e445e4d | ||
|
|
30b1f926f2 | ||
|
|
58e8b123db | ||
|
|
be04d232c0 | ||
|
|
659ec5e335 | ||
|
|
7f37454666 | ||
|
|
433d69af7a | ||
|
|
21c21e4963 | ||
|
|
1c0885c636 | ||
|
|
dccb3ce9ce | ||
|
|
22b39f35aa | ||
|
|
5ab3276a2d | ||
|
|
36420114e0 | ||
|
|
7cda031888 | ||
|
|
fc85a4864d | ||
|
|
99226c3df5 | ||
|
|
ed395c8ace | ||
|
|
edbded8f0a | ||
|
|
c095690619 | ||
|
|
628cc837ef | ||
|
|
0c32fca6c0 | ||
|
|
56b5ace109 | ||
|
|
5572650da2 | ||
|
|
41669d246f | ||
|
|
49c837e7d0 | ||
|
|
bc5e7d1497 | ||
|
|
78bef8a98f | ||
|
|
4f3d8f4caa | ||
|
|
0369f7516d | ||
|
|
3b0415678c | ||
|
|
69867b6c06 | ||
|
|
231bf01f18 | ||
|
|
56fe08cb00 | ||
|
|
f752e04b03 | ||
|
|
a50e72f68d | ||
|
|
0958197df2 | ||
|
|
f336a956cf | ||
|
|
19fa03435b | ||
|
|
fa65e7fd3f | ||
|
|
f794cf69f9 | ||
|
|
366dc5383c | ||
|
|
fd2b14f464 | ||
|
|
590976a8e7 | ||
|
|
bdbb651b98 | ||
|
|
703618be19 | ||
|
|
1f37728ecf | ||
|
|
d955efff14 | ||
|
|
3fdee06dc7 | ||
|
|
c0cd7259b3 | ||
|
|
c31f2abfc9 | ||
|
|
06df75ffee | ||
|
|
855e839b77 | ||
|
|
06437df9b0 | ||
|
|
f4af5c1764 | ||
|
|
277699cbd5 | ||
|
|
e4cac1fffc | ||
|
|
e164e48aae | ||
|
|
5eec9d29cb | ||
|
|
94abd8a928 | ||
|
|
b18c2fe855 | ||
|
|
02a7ff87db | ||
|
|
7c0f6ead3a | ||
|
|
d72b1ffd49 | ||
|
|
c82be175e1 | ||
|
|
dac35a60ad | ||
|
|
ee02af3605 | ||
|
|
74ed202b29 | ||
|
|
300281695a | ||
|
|
de22556153 | ||
|
|
5bcb1a678c | ||
|
|
8a9426a0d4 | ||
|
|
dd9ab16401 | ||
|
|
12e6932930 | ||
|
|
95f18d4bc3 | ||
|
|
8c9cc93185 | ||
|
|
b58a8aaa0f | ||
|
|
c5b7728ac9 | ||
|
|
c9dddc342c | ||
|
|
8433bc0948 | ||
|
|
52a916012f | ||
|
|
2fe7e1bff9 | ||
|
|
0788e5ff3e | ||
|
|
0fb5853b7a | ||
|
|
b30285e38d | ||
|
|
02e4bfba95 | ||
|
|
b5f5d5f9d5 | ||
|
|
f2b3a9f837 | ||
|
|
6af14c16c9 | ||
|
|
211f7160dc | ||
|
|
8a1463a471 | ||
|
|
b623214e04 | ||
|
|
6b536ca88a | ||
|
|
445b736885 | ||
|
|
e8dd85419f | ||
|
|
b1fd392486 | ||
|
|
e487c3366d | ||
|
|
ade27ad8b9 | ||
|
|
34bcae9abb | ||
|
|
8894fdeaf9 | ||
|
|
ff14b75e1b | ||
|
|
b5ef9c29cf | ||
|
|
f344ccb714 | ||
|
|
9b71317280 | ||
|
|
1ac6912c2a | ||
|
|
3188532e59 | ||
|
|
d9d8c23c63 | ||
|
|
dfe0c15399 | ||
|
|
0751b30d33 | ||
|
|
f4dc29f9db | ||
|
|
ce7f9e71c1 | ||
|
|
05f21fcbe2 | ||
|
|
00f2ba1a53 | ||
|
|
991e0a4c9a | ||
|
|
aa28881726 | ||
|
|
6d288aba2f | ||
|
|
0980856072 | ||
|
|
0d98405bdc | ||
|
|
69441a4fee | ||
|
|
a65bb17d68 | ||
|
|
6e6bf1ca81 | ||
|
|
474463111f | ||
|
|
0b4a54ab54 | ||
|
|
65c0cf1065 | ||
|
|
1c2ce0dcc0 | ||
|
|
e251126dd4 | ||
|
|
f2a4e7b984 | ||
|
|
9e659cacf2 | ||
|
|
c5e9567875 | ||
|
|
44f1af7059 | ||
|
|
8f511a3bb6 | ||
|
|
4f7a01a291 | ||
|
|
af6330b1bd | ||
|
|
55ff0ac1f4 | ||
|
|
51bbfc39b0 | ||
|
|
90bb2db349 | ||
|
|
0d36bc19c6 | ||
|
|
a9a7777293 | ||
|
|
bf66068557 | ||
|
|
68eec52cef | ||
|
|
a065e6a47c | ||
|
|
efe135e38b | ||
|
|
07e47b6a28 | ||
|
|
8f5d8de1c2 | ||
|
|
2867334c00 | ||
|
|
dc390a7301 | ||
|
|
ad683d9226 | ||
|
|
1c2eaa2654 | ||
|
|
7ef1dccdcf | ||
|
|
ff488b77b5 | ||
|
|
92cceea2b8 | ||
|
|
8b522680e3 | ||
|
|
7507333cd3 | ||
|
|
f470f9ab91 | ||
|
|
a120b9d37e | ||
|
|
1b1b9dc29b | ||
|
|
ef04e2e1e8 | ||
|
|
321d4b8afd | ||
|
|
c3e6c4685f | ||
|
|
6362bbd176 | ||
|
|
07fb5e8027 | ||
|
|
8fe82ed976 | ||
|
|
25b8e7fefc | ||
|
|
ad4a443fc2 | ||
|
|
01eaa6b228 | ||
|
|
c442bd83f8 | ||
|
|
ff799303b0 | ||
|
|
f09241d263 | ||
|
|
1db982276a | ||
|
|
718c6d03cc | ||
|
|
57fba4e18e | ||
|
|
b219731173 | ||
|
|
a0eea7bcc0 | ||
|
|
0c3071b9c6 | ||
|
|
0066010792 | ||
|
|
0b61954e39 | ||
|
|
a0cd008da6 | ||
|
|
3d2ba9d5bf | ||
|
|
01e6babd54 | ||
|
|
96d023de87 | ||
|
|
3ca2bb1d23 | ||
|
|
595717fff0 | ||
|
|
d838d08570 | ||
|
|
265f915442 | ||
|
|
dcac966d49 | ||
|
|
4110c199fb | ||
|
|
14c0d011ea | ||
|
|
a167f9680f | ||
|
|
062dc2bd40 | ||
|
|
1ce9acd442 | ||
|
|
8a285f9b19 | ||
|
|
164abfdae1 | ||
|
|
bd2b3d9793 | ||
|
|
cbd0583289 | ||
|
|
023d80b94d | ||
|
|
5254348819 | ||
|
|
4ec5a4b34a | ||
|
|
e4ba9733fe | ||
|
|
a332fba702 | ||
|
|
83561d639d | ||
|
|
9dd4f938da | ||
|
|
1a2aafa17c | ||
|
|
a4e80e1153 | ||
|
|
a261abbc3f | ||
|
|
27f780c5d1 | ||
|
|
11ab4a7935 | ||
|
|
4dd532f60e | ||
|
|
138715b509 | ||
|
|
d97df78f4f | ||
|
|
56c0680685 | ||
|
|
95f675becd | ||
|
|
a5ef6801c9 | ||
|
|
75a47aabb5 | ||
|
|
73f29005bd | ||
|
|
f1d439a07f | ||
|
|
9ce4ef0bff | ||
|
|
9e081763ad | ||
|
|
378f66a1ff | ||
|
|
3d0efa1cbe | ||
|
|
cae07bb408 | ||
|
|
c94c1f8a6c | ||
|
|
0847cd33bd | ||
|
|
dc40442118 | ||
|
|
2959a2c137 | ||
|
|
bf00577d33 | ||
|
|
c4bd9fb7aa | ||
|
|
482f2fc335 | ||
|
|
925e042455 | ||
|
|
c525c48d25 | ||
|
|
f90dba2c6b | ||
|
|
e28f45f785 | ||
|
|
87eca8f2c0 | ||
|
|
960f829221 | ||
|
|
8a4303cc94 | ||
|
|
7a4ac01348 | ||
|
|
6dda4fa9f7 | ||
|
|
af2b32e7ba | ||
|
|
069b7c5500 | ||
|
|
ae1983faba | ||
|
|
bcfa0c9ae9 | ||
|
|
88ba974ea5 | ||
|
|
721c03d9af | ||
|
|
384435f8eb | ||
|
|
e808549637 | ||
|
|
bde13a8572 | ||
|
|
98c4eaca83 | ||
|
|
e64c0a35c5 | ||
|
|
6bedc4697b | ||
|
|
2dbefaf375 | ||
|
|
2050d55b21 | ||
|
|
d61178de41 | ||
|
|
9cb2d19654 | ||
|
|
8a59982420 | ||
|
|
c5aee7b2cf | ||
|
|
d0285b058b | ||
|
|
64e84554d3 | ||
|
|
8a18c2e4b6 | ||
|
|
43bb9e4302 | ||
|
|
cb8921dc22 | ||
|
|
64933ed04b | ||
|
|
040fbf9694 | ||
|
|
4500d964b3 | ||
|
|
fceab4f388 | ||
|
|
b3d468aca1 | ||
|
|
3b0b15abb9 | ||
|
|
f0cf728825 | ||
|
|
c35ab081ff | ||
|
|
1f3403717b | ||
|
|
a6f3db0a45 | ||
|
|
b051211842 | ||
|
|
279869b4c5 | ||
|
|
b69adb518a | ||
|
|
b7cdcf419f | ||
|
|
7cd4272350 | ||
|
|
992ba1a9a2 | ||
|
|
dab3ca0025 | ||
|
|
939f715e3c | ||
|
|
37afd6094e | ||
|
|
c916a00624 | ||
|
|
f6e5bee334 | ||
|
|
63b9f18d05 | ||
|
|
7b9dafcd19 | ||
|
|
53e9f44972 | ||
|
|
52fd564eac | ||
|
|
edaf11cb89 | ||
|
|
ad122c8e32 | ||
|
|
8ee6957e6a | ||
|
|
65e28d5562 | ||
|
|
422a228cea | ||
|
|
0b01b73111 | ||
|
|
555aac3f64 | ||
|
|
5b70d344cc | ||
|
|
71ce515d6d | ||
|
|
a4f9ceaf09 | ||
|
|
d4135d608e | ||
|
|
4b3f7034b2 | ||
|
|
e64c77fdde | ||
|
|
8d0fe52dd8 | ||
|
|
157d1b32dc | ||
|
|
b06cbd7a95 | ||
|
|
2cccae96fe | ||
|
|
e758678140 | ||
|
|
6c96405ab2 | ||
|
|
63aa34cb35 | ||
|
|
5a2a448c32 | ||
|
|
5e52d067c8 | ||
|
|
bf960b6eae | ||
|
|
ede5412526 | ||
|
|
78c41b84a1 | ||
|
|
99c289e063 | ||
|
|
3402031399 | ||
|
|
837c70f857 | ||
|
|
4f6095c3d4 | ||
|
|
2d4119e88d | ||
|
|
4991f2f892 | ||
|
|
10def52ad9 | ||
|
|
99c1a4448b | ||
|
|
8223161959 | ||
|
|
67ba3e55de | ||
|
|
6d7c73d498 | ||
|
|
80bb828fe5 | ||
|
|
b0dca05e50 | ||
|
|
8b4500146f | ||
|
|
ee35cbc0d0 | ||
|
|
0b6f335c9f | ||
|
|
40e8061797 | ||
|
|
bb8e6ab03c | ||
|
|
807bd4d06a | ||
|
|
e1a7fb1cc8 | ||
|
|
5032b2b872 | ||
|
|
640e9d68b7 | ||
|
|
049d0283f9 | ||
|
|
3f0c3a8b9c | ||
|
|
68fddf818c | ||
|
|
6997c442c6 | ||
|
|
78677fd8ab | ||
|
|
20a16ad5f8 | ||
|
|
19613ed833 | ||
|
|
63bc73d9d2 | ||
|
|
5c7b8955dc | ||
|
|
2c51e791ad | ||
|
|
c3fcbf77ed | ||
|
|
6321432d97 | ||
|
|
4135079290 | ||
|
|
287428b487 | ||
|
|
af23888b95 | ||
|
|
4a554431ff | ||
|
|
947f53a991 | ||
|
|
835537fcc2 | ||
|
|
08ba35763c | ||
|
|
14ad4e168e | ||
|
|
a614375982 | ||
|
|
e4bb13ea07 | ||
|
|
84add8a03d | ||
|
|
f5aa2f153a | ||
|
|
f56b0ea0d0 | ||
|
|
77b06ac9f7 | ||
|
|
3f2007cd2c | ||
|
|
6f87c565ac | ||
|
|
949b993a4a | ||
|
|
ca7e7c2304 | ||
|
|
38e52c062e | ||
|
|
8be3ac863b | ||
|
|
e1b78c4821 | ||
|
|
c1da198f5d | ||
|
|
474de014f8 | ||
|
|
c3752d1c18 | ||
|
|
f67b6f6cad | ||
|
|
9b2e291a46 | ||
|
|
867efcc6e8 | ||
|
|
847bbf5710 | ||
|
|
f013a003a0 | ||
|
|
7cdc8c4ec5 | ||
|
|
3dd1fd6b00 | ||
|
|
e13a7aed90 | ||
|
|
5b8f148c50 | ||
|
|
04c3cd6ec5 | ||
|
|
05c83a9dbb | ||
|
|
3ef0b3be95 | ||
|
|
84e7eb144b | ||
|
|
75d65b3d20 | ||
|
|
12af8506f8 | ||
|
|
0d24f2c08b | ||
|
|
dca07d240c | ||
|
|
ba011ffc5f | ||
|
|
faf12f93a4 | ||
|
|
1dc44c4047 | ||
|
|
9cd3981b94 | ||
|
|
44be6cea94 | ||
|
|
5bf7fe852c | ||
|
|
5f80e93aee | ||
|
|
80b92fb667 | ||
|
|
29d21545a6 | ||
|
|
326f8115a0 | ||
|
|
129db98a2f | ||
|
|
15fe2d5594 | ||
|
|
e3e012a9ed | ||
|
|
04648a66e6 | ||
|
|
edd0068d88 | ||
|
|
79d786708b | ||
|
|
921da2f19e | ||
|
|
0b94a0639e | ||
|
|
fb93281beb | ||
|
|
b75976b6d8 | ||
|
|
b0aea7b810 | ||
|
|
f65c3a09db | ||
|
|
d4d6d5b7c0 | ||
|
|
56ff98a2a3 | ||
|
|
6d438a9d61 | ||
|
|
e21f94f36a | ||
|
|
34543e2952 | ||
|
|
b1ffe0edd5 | ||
|
|
19ecddcd86 | ||
|
|
982c97dc6c | ||
|
|
27c602fc30 | ||
|
|
943751547e | ||
|
|
24ed5f7a1a | ||
|
|
0d654d5e53 | ||
|
|
ffa015dc21 | ||
|
|
a6eb00f326 | ||
|
|
5a12f44a25 | ||
|
|
5ffb564376 | ||
|
|
6bcf2f718c | ||
|
|
7c2be4ce3c | ||
|
|
25935bbe99 | ||
|
|
2ba52f1b94 | ||
|
|
e2e541a251 | ||
|
|
363a0e1d1e | ||
|
|
80945cd08a | ||
|
|
a17e1671f0 | ||
|
|
b619dd14c5 | ||
|
|
55cf40ec52 | ||
|
|
f3e44094a1 | ||
|
|
43094742fb | ||
|
|
70549fce14 | ||
|
|
360a5b293d | ||
|
|
f4965915ee | ||
|
|
39e48d9e8d | ||
|
|
d8ebb96077 | ||
|
|
11e5d19f32 | ||
|
|
82d0546d16 | ||
|
|
a0f17b15ec | ||
|
|
46caa2d889 | ||
|
|
475468ccc7 | ||
|
|
f3dc168dbd | ||
|
|
4ffd81bd41 | ||
|
|
0f149f1143 | ||
|
|
8513de0b47 | ||
|
|
614603089e | ||
|
|
e280e0f31c | ||
|
|
c739447598 | ||
|
|
e60f7bb125 | ||
|
|
18e36b96db | ||
|
|
2b57b6be1d | ||
|
|
45d4a2c7e2 | ||
|
|
6fccd6be84 | ||
|
|
767ac1c4e2 | ||
|
|
b14caf004d | ||
|
|
d72d25c369 | ||
|
|
640e52d4b4 | ||
|
|
9ba51c6b51 | ||
|
|
8297fcff30 | ||
|
|
aefa49a831 | ||
|
|
e251377f7c | ||
|
|
760a1245c5 | ||
|
|
4f016f149f | ||
|
|
c14b585433 | ||
|
|
2d78dae01a | ||
|
|
b0036a2d3e | ||
|
|
3091504c7e | ||
|
|
bd678659a2 | ||
|
|
06edc3dff1 | ||
|
|
c2208ce8fe | ||
|
|
1add57e5ad | ||
|
|
435c999abf | ||
|
|
c82b8244e8 | ||
|
|
8703cfc4f4 | ||
|
|
63411f9938 | ||
|
|
60f35f779d | ||
|
|
1a2ef49100 | ||
|
|
6fbdc2c221 | ||
|
|
14b5504ea7 | ||
|
|
6f4f0c4e8f | ||
|
|
ac92162825 | ||
|
|
a25558b550 | ||
|
|
e8d9e2dfa9 | ||
|
|
aa878c9dc8 | ||
|
|
7aa50d412c | ||
|
|
69949f9d53 | ||
|
|
0c8ae195ae | ||
|
|
e6682d2108 | ||
|
|
9fa6c47dc5 | ||
|
|
f5b169ab54 | ||
|
|
09b32f7f98 | ||
|
|
621c85059e | ||
|
|
b62cf7ee9a | ||
|
|
5d118e2634 | ||
|
|
807e9b5496 | ||
|
|
0c47a0a710 | ||
|
|
35eb246080 | ||
|
|
7188f88ba1 | ||
|
|
fcc8f53b59 | ||
|
|
a9da6bb2d8 | ||
|
|
f7286b525c | ||
|
|
4517734fbe | ||
|
|
bd882c98c7 | ||
|
|
ed9880f801 | ||
|
|
8ae5383698 | ||
|
|
98e7058486 | ||
|
|
0aced08204 |
830
.editorconfig
830
.editorconfig
@@ -8,24 +8,444 @@ end_of_line = LF
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
; 4-column tab indentation
|
||||
[*.yaml]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
; 4-column tab indentation and .NET coding conventions
|
||||
[*.cs]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
dotnet_separate_import_directive_groups = false
|
||||
dotnet_sort_system_directives_first = true
|
||||
#### Code Style Rules
|
||||
#### https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/
|
||||
|
||||
csharp_style_var_elsewhere = true:suggestion
|
||||
csharp_style_var_for_built_in_types = true:suggestion
|
||||
csharp_style_var_when_type_is_apparent = true:suggestion
|
||||
# Severity Levels: https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/configuration-options#severity-level
|
||||
# Below we enable specific rules by setting severity to warning.
|
||||
# Rules are disabled by setting severity to silent (to still allow use in IDE) or none (to prevent all use).
|
||||
# Rules are listed below with any options available.
|
||||
# Options are commented out if they match the defaults.
|
||||
|
||||
csharp_prefer_braces = when_multiline:suggestion
|
||||
csharp_using_directive_placement = outside_namespace:suggestion
|
||||
csharp_new_line_before_open_brace = all
|
||||
csharp_space_around_binary_operators = before_and_after
|
||||
### Language Rules
|
||||
### https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/language-rules
|
||||
|
||||
## Naming styles:
|
||||
## this and Me preferences
|
||||
|
||||
# IDE0003/IDE0009 Remove 'this' or 'Me' qualification/Add 'this' or 'Me' qualification
|
||||
#dotnet_style_qualification_for_field = false
|
||||
#dotnet_style_qualification_for_property = false
|
||||
#dotnet_style_qualification_for_method = false
|
||||
#dotnet_style_qualification_for_event = false
|
||||
dotnet_diagnostic.IDE0003.severity = warning
|
||||
dotnet_diagnostic.IDE0009.severity = warning
|
||||
|
||||
## Use languages keywords for types
|
||||
|
||||
# IDE0049 Use language keywords instead of framework type names for type references
|
||||
#dotnet_style_predefined_type_for_locals_parameters_members = true
|
||||
#dotnet_style_predefined_type_for_member_access = true
|
||||
dotnet_diagnostic.IDE0049.severity = warning
|
||||
|
||||
## Modifier preferences
|
||||
|
||||
# IDE0036 Order modifiers
|
||||
#csharp_preferred_modifier_order = public, private, protected, internal, file, static, extern, new, virtual, abstract, sealed, override, readonly, unsafe, required, volatile, async
|
||||
dotnet_diagnostic.IDE0036.severity = warning
|
||||
|
||||
# IDE0040 Add accessibility modifiers
|
||||
dotnet_style_require_accessibility_modifiers = omit_if_default
|
||||
dotnet_diagnostic.IDE0040.severity = warning
|
||||
|
||||
# IDE0044 Add readonly modifier
|
||||
#dotnet_style_readonly_field = true
|
||||
dotnet_diagnostic.IDE0044.severity = warning
|
||||
|
||||
# IDE0062 Make local function static
|
||||
#csharp_prefer_static_local_function = true
|
||||
dotnet_diagnostic.IDE0062.severity = warning
|
||||
|
||||
# IDE0064 Make struct fields writable
|
||||
# No options
|
||||
dotnet_diagnostic.IDE0064.severity = warning
|
||||
|
||||
## Parentheses preferences
|
||||
|
||||
# IDE0047/IDE0048 Remove unnecessary parentheses/Add parentheses for clarity
|
||||
dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary
|
||||
dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary
|
||||
#dotnet_style_parentheses_in_other_binary_operators = always_for_clarity
|
||||
#dotnet_style_parentheses_in_other_operators = never_if_unnecessary
|
||||
dotnet_diagnostic.IDE0047.severity = warning
|
||||
dotnet_diagnostic.IDE0048.severity = warning
|
||||
|
||||
## Expression-level preferences
|
||||
|
||||
# IDE0010 Add missing cases to switch statement
|
||||
# No options
|
||||
dotnet_diagnostic.IDE0010.severity = silent
|
||||
|
||||
# IDE0017 Use object initializers
|
||||
#dotnet_style_object_initializer = true
|
||||
dotnet_diagnostic.IDE0017.severity = warning
|
||||
|
||||
# IDE0018 Inline variable declaration
|
||||
#csharp_style_inlined_variable_declaration = true
|
||||
dotnet_diagnostic.IDE0018.severity = warning
|
||||
|
||||
# IDE0028 Use collection initializers
|
||||
#dotnet_style_collection_initializer = true
|
||||
dotnet_diagnostic.IDE0028.severity = warning
|
||||
|
||||
# IDE0032 Use auto-implemented property
|
||||
#dotnet_style_prefer_auto_properties = true
|
||||
dotnet_diagnostic.IDE0032.severity = warning
|
||||
|
||||
# IDE0033 Use explicitly provided tuple name
|
||||
#dotnet_style_explicit_tuple_names = true
|
||||
dotnet_diagnostic.IDE0033.severity = warning
|
||||
|
||||
# IDE0034 Simplify 'default' expression
|
||||
#csharp_prefer_simple_default_expression = true
|
||||
dotnet_diagnostic.IDE0034.severity = warning
|
||||
|
||||
# IDE0037 Use inferred member name
|
||||
#dotnet_style_prefer_inferred_tuple_names = true
|
||||
#dotnet_style_prefer_inferred_anonymous_type_member_names = true
|
||||
dotnet_diagnostic.IDE0037.severity = silent
|
||||
|
||||
# IDE0039 Use local function instead of lambda
|
||||
#csharp_style_prefer_local_over_anonymous_function = true
|
||||
dotnet_diagnostic.IDE0039.severity = warning
|
||||
|
||||
# IDE0042 Deconstruct variable declaration
|
||||
#csharp_style_deconstructed_variable_declaration = true
|
||||
dotnet_diagnostic.IDE0042.severity = warning
|
||||
|
||||
# IDE0045 Use conditional expression for assignment
|
||||
#dotnet_style_prefer_conditional_expression_over_assignment = true
|
||||
dotnet_diagnostic.IDE0045.severity = silent
|
||||
|
||||
# IDE0046 Use conditional expression for return
|
||||
#dotnet_style_prefer_conditional_expression_over_return = true
|
||||
dotnet_diagnostic.IDE0046.severity = silent
|
||||
|
||||
# IDE0050 Convert anonymous type to tuple
|
||||
# No options
|
||||
dotnet_diagnostic.IDE0050.severity = silent
|
||||
|
||||
# IDE0054/IDE0074 Use compound assignment/Use coalesce compound assignment
|
||||
#dotnet_style_prefer_compound_assignment = true
|
||||
dotnet_diagnostic.IDE0054.severity = warning
|
||||
dotnet_diagnostic.IDE0074.severity = warning
|
||||
|
||||
# IDE0056 Use index operator
|
||||
#csharp_style_prefer_index_operator = true
|
||||
dotnet_diagnostic.IDE0056.severity = warning
|
||||
|
||||
# IDE0057 Use range operator
|
||||
#csharp_style_prefer_range_operator = true
|
||||
dotnet_diagnostic.IDE0057.severity = warning
|
||||
|
||||
# IDE0070 Use 'System.HashCode.Combine'
|
||||
# No options
|
||||
dotnet_diagnostic.IDE0070.severity = warning
|
||||
|
||||
# IDE0071 Simplify interpolation
|
||||
#dotnet_style_prefer_simplified_interpolation = true
|
||||
dotnet_diagnostic.IDE0071.severity = warning
|
||||
|
||||
# IDE0072 Add missing cases to switch expression
|
||||
# No options
|
||||
dotnet_diagnostic.IDE0072.severity = silent
|
||||
|
||||
# IDE0075 Simplify conditional expression
|
||||
#dotnet_style_prefer_simplified_boolean_expressions = true
|
||||
dotnet_diagnostic.IDE0075.severity = warning
|
||||
|
||||
# IDE0082 Convert 'typeof' to 'nameof'
|
||||
# No options
|
||||
dotnet_diagnostic.IDE0082.severity = warning
|
||||
|
||||
# IDE0090 Simplify 'new' expression
|
||||
#csharp_style_implicit_object_creation_when_type_is_apparent = true
|
||||
dotnet_diagnostic.IDE0090.severity = warning
|
||||
|
||||
# IDE0180 Use tuple to swap values
|
||||
#csharp_style_prefer_tuple_swap = true
|
||||
dotnet_diagnostic.IDE0180.severity = warning
|
||||
|
||||
## Namespace declaration preferences
|
||||
|
||||
# IDE0160/IDE0161 Use block-scoped namespace/Use file-scoped namespace
|
||||
#csharp_style_namespace_declarations = block_scoped
|
||||
dotnet_diagnostic.IDE0160.severity = warning
|
||||
dotnet_diagnostic.IDE0161.severity = warning
|
||||
|
||||
## Null-checking preferences
|
||||
|
||||
# IDE0016 Use throw expression
|
||||
#csharp_style_throw_expression = true
|
||||
dotnet_diagnostic.IDE0016.severity = silent
|
||||
|
||||
# IDE0029/IDE0030/IDE0270 Use coalesce expression (non-nullable types)/Use coalesce expression (nullable types)/Use coalesce expression (if null)
|
||||
#dotnet_style_coalesce_expression = true
|
||||
dotnet_diagnostic.IDE0029.severity = warning
|
||||
dotnet_diagnostic.IDE0030.severity = warning
|
||||
dotnet_diagnostic.IDE0270.severity = silent
|
||||
|
||||
# IDE0031 Use null propagation
|
||||
#dotnet_style_null_propagation = true
|
||||
dotnet_diagnostic.IDE0031.severity = warning
|
||||
|
||||
# IDE0041 Use 'is null' check
|
||||
#dotnet_style_prefer_is_null_check_over_reference_equality_method = true
|
||||
dotnet_diagnostic.IDE0041.severity = warning
|
||||
|
||||
# IDE0150 Prefer 'null' check over type check
|
||||
#csharp_style_prefer_null_check_over_type_check = true
|
||||
dotnet_diagnostic.IDE0150.severity = warning
|
||||
|
||||
# IDE1005 Use conditional delegate call
|
||||
csharp_style_conditional_delegate_call = true # true is the default, but the rule is not triggered if this is not specified.
|
||||
dotnet_diagnostic.IDE1005.severity = warning
|
||||
|
||||
## var preferences
|
||||
|
||||
# IDE0007/IDE0008 Use 'var' instead of explicit type/Use explicit type instead of 'var'
|
||||
csharp_style_var_for_built_in_types = true
|
||||
csharp_style_var_when_type_is_apparent = true
|
||||
csharp_style_var_elsewhere = true
|
||||
dotnet_diagnostic.IDE0007.severity = warning
|
||||
dotnet_diagnostic.IDE0008.severity = warning
|
||||
|
||||
## Expression-bodied-members
|
||||
|
||||
# IDE0021 Use expression body for constructors
|
||||
#csharp_style_expression_bodied_constructors = false
|
||||
dotnet_diagnostic.IDE0021.severity = silent
|
||||
|
||||
# IDE0022 Use expression body for methods
|
||||
#csharp_style_expression_bodied_methods = false
|
||||
dotnet_diagnostic.IDE0022.severity = silent
|
||||
|
||||
# IDE0023/IDE0024 Use expression body for conversion operators/Use expression body for operators
|
||||
#csharp_style_expression_bodied_operators = false
|
||||
dotnet_diagnostic.IDE0023.severity = silent
|
||||
dotnet_diagnostic.IDE0024.severity = silent
|
||||
|
||||
# IDE0025 Use expression body for properties
|
||||
#csharp_style_expression_bodied_properties = true
|
||||
dotnet_diagnostic.IDE0025.severity = silent
|
||||
|
||||
# IDE0026 Use expression body for indexers
|
||||
#csharp_style_expression_bodied_indexers = true
|
||||
dotnet_diagnostic.IDE0026.severity = silent
|
||||
|
||||
# IDE0027 Use expression body for accessors
|
||||
#csharp_style_expression_bodied_accessors = true
|
||||
dotnet_diagnostic.IDE0027.severity = warning
|
||||
|
||||
# IDE0053 Use expression body for lambdas
|
||||
# This rule is buggy and not enforced for builds. ':warning' will at least enforce it in the IDE.
|
||||
csharp_style_expression_bodied_lambdas = when_on_single_line:warning
|
||||
dotnet_diagnostic.IDE0053.severity = warning
|
||||
|
||||
# IDE0061 Use expression body for local functions
|
||||
csharp_style_expression_bodied_local_functions = when_on_single_line
|
||||
dotnet_diagnostic.IDE0061.severity = warning
|
||||
|
||||
## Pattern matching preferences
|
||||
|
||||
# IDE0019 Use pattern matching to avoid 'as' followed by a 'null' check
|
||||
#csharp_style_pattern_matching_over_as_with_null_check = true
|
||||
dotnet_diagnostic.IDE0019.severity = warning
|
||||
|
||||
# IDE0020/IDE0038 Use pattern matching to avoid 'is' check followed by a cast (with variable)/Use pattern matching to avoid 'is' check followed by a cast (without variable)
|
||||
#csharp_style_pattern_matching_over_is_with_cast_check = true
|
||||
dotnet_diagnostic.IDE0020.severity = warning
|
||||
dotnet_diagnostic.IDE0038.severity = warning
|
||||
|
||||
# IDE0066 Use switch expression
|
||||
#csharp_style_prefer_switch_expression = true
|
||||
dotnet_diagnostic.IDE0066.severity = silent
|
||||
|
||||
# IDE0078 Use pattern matching
|
||||
#csharp_style_prefer_pattern_matching = true
|
||||
dotnet_diagnostic.IDE0078.severity = silent
|
||||
|
||||
# IDE0083 Use pattern matching ('not' operator)
|
||||
#csharp_style_prefer_not_pattern = true
|
||||
dotnet_diagnostic.IDE0083.severity = warning
|
||||
|
||||
# IDE0170 Simplify property pattern
|
||||
#csharp_style_prefer_extended_property_pattern = true
|
||||
dotnet_diagnostic.IDE0170.severity = silent # Requires C# 10
|
||||
|
||||
## Code block preferences
|
||||
|
||||
# IDE0011 Add braces
|
||||
#csharp_prefer_braces = true
|
||||
# No options match the style used in OpenRA.
|
||||
dotnet_diagnostic.IDE0011.severity = none
|
||||
|
||||
# IDE0063 Use simple 'using' statement
|
||||
#csharp_prefer_simple_using_statement = true
|
||||
dotnet_diagnostic.IDE0063.severity = silent
|
||||
|
||||
## 'using' directive preferences
|
||||
|
||||
# IDE0065 'using' directive placement
|
||||
#csharp_using_directive_placement = outside_namespace
|
||||
dotnet_diagnostic.IDE0065.severity = silent
|
||||
|
||||
## File header preferences
|
||||
|
||||
# IDE0073 Require file header
|
||||
#file_header_template = unset
|
||||
# This rule does not allow us to enforce our desired header, as it prefixes the header lines with // comments, meaning we can't apply a region.
|
||||
dotnet_diagnostic.IDE0073.severity = none
|
||||
|
||||
## Namespace naming preferences
|
||||
|
||||
# IDE0130 Namespace does not match folder structure
|
||||
#dotnet_style_namespace_match_folder = true
|
||||
# This rule doesn't appear to work (never reports violations)
|
||||
dotnet_diagnostic.IDE0130.severity = none
|
||||
|
||||
### Unnecessary Code Rules
|
||||
### https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/unnecessary-code-rules
|
||||
|
||||
# IDE0001 Simplify name
|
||||
# No options
|
||||
dotnet_diagnostic.IDE0001.severity = warning
|
||||
|
||||
# IDE0002 Simplify member access
|
||||
# No options
|
||||
dotnet_diagnostic.IDE0002.severity = warning
|
||||
|
||||
# IDE0004 Remove unnecessary cast
|
||||
# No options
|
||||
dotnet_diagnostic.IDE0004.severity = warning
|
||||
|
||||
# IDE0005 Remove unnecessary import
|
||||
# No options
|
||||
# IDE0005 is only enabled in the IDE by default. https://github.com/dotnet/roslyn/issues/41640
|
||||
# To enable it for builds outside the IDE the 'GenerateDocumentationFile' property must be enabled on the build.
|
||||
# GenerateDocumentationFile generates additional warnings about XML docs, so disable any we don't care about.
|
||||
dotnet_diagnostic.CS1591.severity = none # Missing XML comment for publicly visible type or member
|
||||
dotnet_diagnostic.IDE0005.severity = warning
|
||||
|
||||
# IDE0035 Remove unreachable code
|
||||
# No options
|
||||
# Duplicates compiler warning CS0162
|
||||
dotnet_diagnostic.IDE0035.severity = none
|
||||
|
||||
# IDE0051 Remove unused private member
|
||||
# No options
|
||||
dotnet_diagnostic.IDE0051.severity = warning
|
||||
|
||||
# IDE0052 Remove unread private member
|
||||
# No options
|
||||
dotnet_diagnostic.IDE0052.severity = warning
|
||||
|
||||
# IDE0058 Remove unnecessary expression value
|
||||
#csharp_style_unused_value_expression_statement_preference = discard_variable
|
||||
dotnet_diagnostic.IDE0058.severity = silent
|
||||
|
||||
# IDE0059 Remove unnecessary value assignment
|
||||
#csharp_style_unused_value_assignment_preference = discard_variable
|
||||
dotnet_diagnostic.IDE0059.severity = warning
|
||||
|
||||
# IDE0060 Remove unused parameter
|
||||
dotnet_code_quality_unused_parameters = non_public
|
||||
dotnet_diagnostic.IDE0060.severity = warning
|
||||
|
||||
# IDE0079 Remove unnecessary suppression
|
||||
#dotnet_remove_unnecessary_suppression_exclusions = none
|
||||
dotnet_diagnostic.IDE0079.severity = warning
|
||||
|
||||
# IDE0080 Remove unnecessary suppression operator
|
||||
# No options
|
||||
dotnet_diagnostic.IDE0080.severity = warning
|
||||
|
||||
# IDE0100 Remove unnecessary equality operator
|
||||
# No options
|
||||
dotnet_diagnostic.IDE0100.severity = warning
|
||||
|
||||
# IDE0110 Remove unnecessary discard
|
||||
# No options
|
||||
dotnet_diagnostic.IDE0110.severity = warning
|
||||
|
||||
### Miscellaneous Rules
|
||||
### https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/miscellaneous-rules
|
||||
|
||||
# IDE0076 Remove invalid global 'SuppressMessageAttribute'
|
||||
# No options
|
||||
dotnet_diagnostic.IDE0076.severity = warning
|
||||
|
||||
# IDE0077 Avoid legacy format target in global 'SuppressMessageAttribute'
|
||||
# No options
|
||||
dotnet_diagnostic.IDE0077.severity = warning
|
||||
|
||||
### Formatting Rules (IDE0055)
|
||||
### https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0055
|
||||
|
||||
# We may eventually wish to enforce this rule, however some existing formatting conflicts with the rule despite being reasonable.
|
||||
# Additionally, the rule is buggy and likes to report spuriously after invoking Format Document in the IDE.
|
||||
dotnet_diagnostic.IDE0055.severity = none
|
||||
|
||||
#dotnet_sort_system_directives_first = true
|
||||
#dotnet_separate_import_directive_groups = false
|
||||
#dotnet_style_namespace_match_folder = true
|
||||
|
||||
#csharp_new_line_before_open_brace = all
|
||||
#csharp_new_line_before_else = true
|
||||
#csharp_new_line_before_catch = true
|
||||
#csharp_new_line_before_finally = true
|
||||
#csharp_new_line_before_members_in_object_initializers = true
|
||||
#csharp_new_line_before_members_in_anonymous_types = true
|
||||
#csharp_new_line_between_query_expression_clauses = true
|
||||
|
||||
#csharp_indent_case_contents = true
|
||||
#csharp_indent_switch_labels = true
|
||||
#csharp_indent_labels = one_less_than_current
|
||||
#csharp_indent_block_contents = true
|
||||
#csharp_indent_braces = false
|
||||
#csharp_indent_case_contents_when_block = true
|
||||
|
||||
#csharp_space_after_cast = false
|
||||
#csharp_space_after_keywords_in_control_flow_statements = true
|
||||
#csharp_space_between_parentheses =
|
||||
#csharp_space_before_colon_in_inheritance_clause = true
|
||||
#csharp_space_after_colon_in_inheritance_clause = true
|
||||
#csharp_space_around_binary_operators = before_and_after
|
||||
#csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||
#csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||
#csharp_space_between_method_declaration_name_and_open_parenthesis = false
|
||||
#csharp_space_between_method_call_parameter_list_parentheses = false
|
||||
#csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||
#csharp_space_between_method_call_name_and_opening_parenthesis = false
|
||||
#csharp_space_after_comma = true
|
||||
#csharp_space_before_comma = false
|
||||
#csharp_space_after_dot = false
|
||||
#csharp_space_before_dot = false
|
||||
#csharp_space_after_semicolon_in_for_statement = true
|
||||
#csharp_space_before_semicolon_in_for_statement = false
|
||||
#csharp_space_around_declaration_statements = false
|
||||
#csharp_space_before_open_square_brackets = false
|
||||
#csharp_space_between_empty_square_brackets = false
|
||||
#csharp_space_between_square_brackets = false
|
||||
|
||||
#csharp_preserve_single_line_statements = true
|
||||
#csharp_preserve_single_line_blocks = true
|
||||
|
||||
|
||||
### Naming Rules (IDE1006)
|
||||
### https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/naming-rules
|
||||
dotnet_diagnostic.IDE1006.severity = warning
|
||||
|
||||
## Naming styles
|
||||
|
||||
dotnet_naming_style.camel_case.capitalization = camel_case
|
||||
|
||||
@@ -34,7 +454,7 @@ dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
dotnet_naming_style.i_prefix_pascal_case.capitalization = pascal_case
|
||||
dotnet_naming_style.i_prefix_pascal_case.required_prefix = I
|
||||
|
||||
## Symbol specifications:
|
||||
## Naming Symbols
|
||||
|
||||
dotnet_naming_symbols.const_locals.applicable_kinds = local
|
||||
dotnet_naming_symbols.const_locals.applicable_accessibilities = *
|
||||
@@ -64,7 +484,7 @@ dotnet_naming_symbols.parameters_and_locals.applicable_accessibilities = *
|
||||
dotnet_naming_symbols.most_symbols.applicable_kinds = namespace, class, struct, enum, field, property, method, local_function, event, delegate, type_parameter
|
||||
dotnet_naming_symbols.most_symbols.applicable_accessibilities = *
|
||||
|
||||
## Naming rules:
|
||||
## Naming Rules
|
||||
|
||||
dotnet_naming_rule.const_locals_should_be_pascal_case.symbols = const_locals
|
||||
dotnet_naming_rule.const_locals_should_be_pascal_case.style = pascal_case
|
||||
@@ -98,86 +518,378 @@ dotnet_naming_rule.most_symbols_should_be_pascal_case.symbols = most_symbols
|
||||
dotnet_naming_rule.most_symbols_should_be_pascal_case.style = pascal_case
|
||||
dotnet_naming_rule.most_symbols_should_be_pascal_case.severity = warning
|
||||
|
||||
## Formatting:
|
||||
|
||||
# Also handled by StyleCopAnalyzers - SA1024: ColonsMustBeSpacedCorrectly.
|
||||
csharp_space_after_colon_in_inheritance_clause = true
|
||||
### StyleCop.Analyzers
|
||||
### https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/DOCUMENTATION.md
|
||||
|
||||
# Also handled by StyleCopAnalyzers - SA1024: ColonsMustBeSpacedCorrectly.
|
||||
csharp_space_before_colon_in_inheritance_clause = true
|
||||
# Below we enable rule categories by setting severity to warning.
|
||||
# We'll only list rules to disable.
|
||||
# Individual rules we wish to disable are typically set to none severity.
|
||||
|
||||
# Also handled by StyleCopAnalyzers - SA1000: KeywordsMustBeSpacedCorrectly.
|
||||
csharp_space_after_keywords_in_control_flow_statements = true
|
||||
# Covers SAxxxx and SXxxxx rules
|
||||
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.DocumentationRules.severity = warning
|
||||
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.LayoutRules.severity = warning
|
||||
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.MaintainabilityRules.severity = warning
|
||||
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.NamingRules.severity = warning
|
||||
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.OrderingRules.severity = warning
|
||||
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.ReadabilityRules.severity = warning
|
||||
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.SpacingRules.severity = warning
|
||||
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.SpecialRules.severity = warning
|
||||
|
||||
# Leave code block on single line.
|
||||
csharp_preserve_single_line_blocks = true
|
||||
# Rules that are covered by IDE0001 Simplify name
|
||||
dotnet_diagnostic.SA1125.severity = none # UseShorthandForNullableTypes
|
||||
|
||||
# Leave statements and member declarations on the same line.
|
||||
csharp_preserve_single_line_statements = true
|
||||
# Rules that are covered by IDE0047 Remove unnecessary parentheses
|
||||
dotnet_diagnostic.SA1119.severity = none # StatementMustNotUseUnnecessaryParenthesis
|
||||
|
||||
# IDE0049, IDE-only counterpart of StyleCopAnalyzers - SA1121: UseBuiltInTypeAlias.
|
||||
dotnet_style_predefined_type_for_member_access = true
|
||||
# Rules that are covered by IDE0055 Formatting Rules
|
||||
dotnet_diagnostic.SA1027.severity = none # UseTabsCorrectly
|
||||
|
||||
# IDE0049, IDE-only counterpart of StyleCopAnalyzers - SA1121: UseBuiltInTypeAlias.
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true
|
||||
# Rules that are covered by IDE1006 Naming Rules
|
||||
dotnet_diagnostic.SA1300.severity = none # ElementMustBeginWithUpperCaseLetter
|
||||
dotnet_diagnostic.SA1302.severity = none # InterfaceNamesMustBeginWithI
|
||||
dotnet_diagnostic.SA1303.severity = none # ConstFieldNamesMustBeginWithUpperCaseLetter
|
||||
dotnet_diagnostic.SA1304.severity = none # NonPrivateReadonlyFieldsMustBeginWithUpperCaseLetter
|
||||
dotnet_diagnostic.SA1306.severity = none # FieldNamesMustBeginWithLowerCaseLetter
|
||||
dotnet_diagnostic.SA1307.severity = none # AccessibleFieldsMustBeginWithUpperCaseLetter
|
||||
dotnet_diagnostic.SA1311.severity = none # StaticReadonlyFieldsMustBeginWithUpperCaseLetter
|
||||
dotnet_diagnostic.SA1312.severity = none # VariableNamesMustBeginWithLowerCaseLetter
|
||||
dotnet_diagnostic.SA1313.severity = none # ParameterNamesMustBeginWithLowerCaseLetter
|
||||
|
||||
## Others:
|
||||
# Rules that conflict with OpenRA project style conventions
|
||||
dotnet_diagnostic.SA1101.severity = none # PrefixLocalCallsWithThis
|
||||
dotnet_diagnostic.SA1107.severity = none # CodeMustNotContainMultipleStatementsOnOneLine
|
||||
dotnet_diagnostic.SA1116.severity = none # SplitParametersMustStartOnLineAfterDeclaration
|
||||
dotnet_diagnostic.SA1117.severity = none # ParametersMustBeOnSameLineOrSeparateLines
|
||||
dotnet_diagnostic.SA1118.severity = none # ParameterMustNotSpanMultipleLines
|
||||
dotnet_diagnostic.SA1122.severity = none # UseStringEmptyForEmptyStrings
|
||||
dotnet_diagnostic.SA1124.severity = none # DoNotUseRegions
|
||||
dotnet_diagnostic.SA1127.severity = none # GenericTypeConstraintsMustBeOnOwnLine
|
||||
dotnet_diagnostic.SA1132.severity = none # DoNotCombineFields
|
||||
dotnet_diagnostic.SA1135.severity = none # UsingDirectivesMustBeQualified
|
||||
dotnet_diagnostic.SA1136.severity = none # EnumValuesShouldBeOnSeparateLines
|
||||
dotnet_diagnostic.SA1200.severity = none # UsingDirectivesMustBePlacedCorrectly
|
||||
dotnet_diagnostic.SA1201.severity = none # ElementsMustAppearInTheCorrectOrder
|
||||
dotnet_diagnostic.SA1202.severity = none # ElementsMustBeOrderedByAccess
|
||||
dotnet_diagnostic.SA1204.severity = none # StaticElementsMustAppearBeforeInstanceElements
|
||||
dotnet_diagnostic.SA1214.severity = none # ReadonlyElementsMustAppearBeforeNonReadonlyElements
|
||||
dotnet_diagnostic.SX1309.severity = none # FieldNamesMustBeginWithUnderscore
|
||||
dotnet_diagnostic.SX1309S.severity = none # StaticFieldNamesMustBeginWithUnderscore
|
||||
dotnet_diagnostic.SA1314.severity = none # TypeParameterNamesMustBeginWithT
|
||||
dotnet_diagnostic.SA1400.severity = none # AccessModifierMustBeDeclared
|
||||
dotnet_diagnostic.SA1401.severity = none # FieldsMustBePrivate
|
||||
dotnet_diagnostic.SA1402.severity = none # FileMayOnlyContainASingleType
|
||||
dotnet_diagnostic.SA1407.severity = none # ArithmeticExpressionsMustDeclarePrecedence
|
||||
dotnet_diagnostic.SA1413.severity = none # UseTrailingCommasInMultiLineInitializers
|
||||
dotnet_diagnostic.SA1501.severity = none # StatementMustNotBeOnSingleLine
|
||||
dotnet_diagnostic.SA1502.severity = none # ElementMustNotBeOnSingleLine
|
||||
dotnet_diagnostic.SA1503.severity = none # BracesMustNotBeOmitted
|
||||
dotnet_diagnostic.SA1516.severity = none # ElementsMustBeSeparatedByBlankLine
|
||||
dotnet_diagnostic.SA1519.severity = none # BracesMustNotBeOmittedFromMultiLineChildStatement
|
||||
dotnet_diagnostic.SA1520.severity = none # UseBracesConsistently
|
||||
dotnet_diagnostic.SA1600.severity = none # ElementsMustBeDocumented
|
||||
dotnet_diagnostic.SA1601.severity = none # PartialElementsMustBeDocumented
|
||||
dotnet_diagnostic.SA1602.severity = none # EnumerationItemsMustBeDocumented
|
||||
dotnet_diagnostic.SA1611.severity = none # ElementParametersShouldBeDocumented
|
||||
dotnet_diagnostic.SA1615.severity = none # ElementReturnValueShouldBeDocumented
|
||||
dotnet_diagnostic.SA1618.severity = none # GenericTypeParametersShouldBeDocumented
|
||||
dotnet_diagnostic.SA1623.severity = none # PropertySummaryDocumentationShouldMatchAccessors
|
||||
dotnet_diagnostic.SA1633.severity = none # FileMustHaveHeader
|
||||
dotnet_diagnostic.SA1642.severity = none # ConstructorSummaryDocumentationShouldBeginWithStandardText
|
||||
dotnet_diagnostic.SA1649.severity = none # FileNameMustMatchTypeName
|
||||
|
||||
# Show an IDE warning when default access modifiers are explicitly specified.
|
||||
dotnet_style_require_accessibility_modifiers = omit_if_default:warning
|
||||
#### Code Quality Rules
|
||||
#### https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/
|
||||
|
||||
# Don't prefer braces (for one liners).
|
||||
dotnet_diagnostic.IDE0011.severity = silent
|
||||
# Below we enable specific rules by setting severity to warning.
|
||||
# Rules are listed below with any options available.
|
||||
# Options are commented out if they match the defaults.
|
||||
|
||||
# Object initialization can be simplified / Use object initializer.
|
||||
dotnet_diagnostic.IDE0017.severity = warning
|
||||
# Rule options that apply over multiple rules are set here.
|
||||
# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/code-quality-rule-options
|
||||
dotnet_code_quality.api_surface = all
|
||||
|
||||
# Collection initialization can be simplified
|
||||
dotnet_diagnostic.IDE0028.severity = warning
|
||||
### Design Rules
|
||||
### https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/design-warnings
|
||||
|
||||
# Simplify 'default' expression
|
||||
dotnet_diagnostic.IDE0034.severity = warning
|
||||
# Collections should implement generic interface.
|
||||
#dotnet_code_quality.CA1010.additional_required_generic_interfaces =
|
||||
dotnet_diagnostic.CA1010.severity = warning
|
||||
|
||||
# Modifiers are not ordered.
|
||||
dotnet_diagnostic.IDE0036.severity = warning
|
||||
# Abstract types should not have public constructors.
|
||||
dotnet_diagnostic.CA1012.severity = warning
|
||||
|
||||
# Raise a warning on build when default access modifiers are explicitly specified.
|
||||
dotnet_diagnostic.IDE0040.severity = warning
|
||||
# Mark attributes with 'AttributeUsageAttribute'.
|
||||
dotnet_diagnostic.CA1018.severity = warning
|
||||
|
||||
# Make field readonly.
|
||||
dotnet_diagnostic.IDE0044.severity = warning
|
||||
# Override methods on comparable types.
|
||||
dotnet_diagnostic.CA1036.severity = warning
|
||||
|
||||
# Unused private member.
|
||||
dotnet_diagnostic.IDE0052.severity = warning
|
||||
# Provide ObsoleteAttribute message.
|
||||
dotnet_diagnostic.CA1041.severity = warning
|
||||
|
||||
# Unnecessary value assignment.
|
||||
dotnet_diagnostic.IDE0059.severity = warning
|
||||
# Do not declare protected members in sealed types.
|
||||
dotnet_diagnostic.CA1047.severity = warning
|
||||
|
||||
# Unused parameter.
|
||||
dotnet_diagnostic.IDE0060.severity = warning
|
||||
# Declare types in namespaces.
|
||||
dotnet_diagnostic.CA1050.severity = warning
|
||||
|
||||
# Naming rule violation.
|
||||
dotnet_diagnostic.IDE1006.severity = warning
|
||||
# Static holder types should be 'Static' or 'NotInheritable'.
|
||||
dotnet_diagnostic.CA1052.severity = warning
|
||||
|
||||
# Avoid unnecessary zero-length array allocations.
|
||||
# Do not hide base class methods.
|
||||
dotnet_diagnostic.CA1061.severity = warning
|
||||
|
||||
# Exceptions should be public.
|
||||
dotnet_diagnostic.CA1064.severity = warning
|
||||
|
||||
# Implement 'IEquatable' when overriding 'Equals'.
|
||||
dotnet_diagnostic.CA1066.severity = warning
|
||||
|
||||
# Override 'Equals' when implementing 'IEquatable'.
|
||||
dotnet_diagnostic.CA1067.severity = warning
|
||||
|
||||
# 'CancellationToken' parameters must come last.
|
||||
dotnet_diagnostic.CA1068.severity = warning
|
||||
|
||||
# Do not declare event fields as virtual.
|
||||
dotnet_diagnostic.CA1070.severity = warning
|
||||
|
||||
### Documentation Rules
|
||||
### https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/documentation-warnings
|
||||
|
||||
# Avoid using 'cref' tags with a prefix.
|
||||
dotnet_diagnostic.CA1200.severity = warning
|
||||
|
||||
### Globalization Rules
|
||||
### https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/globalization-warnings
|
||||
|
||||
### Portability and Interoperability Rules
|
||||
### https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/interoperability-warnings
|
||||
|
||||
# Do not use 'OutAttribute' on string parameters for P/Invokes.
|
||||
dotnet_diagnostic.CA1417.severity = warning
|
||||
|
||||
### Maintainability Rules
|
||||
### https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/maintainability-warnings
|
||||
|
||||
# Use 'nameof' in place of string.
|
||||
dotnet_diagnostic.CA1507.severity = warning
|
||||
|
||||
### Naming Rules
|
||||
### https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/naming-warnings
|
||||
|
||||
# Do not prefix enum values with type name.
|
||||
dotnet_code_quality.CA1712.enum_values_prefix_trigger = AnyEnumValue
|
||||
dotnet_diagnostic.CA1712.severity = warning
|
||||
|
||||
# Flags enums should have plural names.
|
||||
dotnet_diagnostic.CA1714.severity = warning
|
||||
|
||||
# Only 'FlagsAttribute' enums should have plural names.
|
||||
dotnet_diagnostic.CA1717.severity = warning
|
||||
|
||||
### Performance Rules
|
||||
### https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/performance-warnings
|
||||
|
||||
# Use Literals Where Appropriate.
|
||||
#dotnet_code_quality.CA1802.required_modifiers = static
|
||||
dotnet_diagnostic.CA1802.severity = warning
|
||||
|
||||
# Remove empty finalizers.
|
||||
dotnet_diagnostic.CA1821.severity = warning
|
||||
|
||||
# Mark members as static.
|
||||
dotnet_code_quality.CA1822.api_surface = private,internal
|
||||
dotnet_diagnostic.CA1822.severity = warning
|
||||
|
||||
# Avoid unused private fields.
|
||||
dotnet_diagnostic.CA1823.severity = warning
|
||||
|
||||
# Avoid zero-length array allocations.
|
||||
dotnet_diagnostic.CA1825.severity = warning
|
||||
|
||||
# Do not use Enumerable methods on indexable collections. Instead use the collection directly.
|
||||
# Use property instead of Linq Enumerable method.
|
||||
#dotnet_code_quality.CA1826.exclude_ordefault_methods = false
|
||||
dotnet_diagnostic.CA1826.severity = warning
|
||||
|
||||
# Count() is used where Any() could be used instead to improve performance.
|
||||
# Do not use Count/LongCount when Any can be used.
|
||||
dotnet_diagnostic.CA1827.severity = warning
|
||||
|
||||
# Do not use CountAsync/LongCountAsync when AnyAsync can be used.
|
||||
dotnet_diagnostic.CA1828.severity = warning
|
||||
|
||||
# Use Length/Count property instead of Enumerable.Count method.
|
||||
dotnet_diagnostic.CA1829.severity = warning
|
||||
|
||||
# Prefer strongly-typed Append and Insert method overloads on StringBuilder.
|
||||
dotnet_diagnostic.CA1830.severity = warning
|
||||
|
||||
# Use AsSpan instead of Range-based indexers for string when appropriate.
|
||||
dotnet_diagnostic.CA1831.severity = warning
|
||||
|
||||
# Use AsSpan or AsMemory instead of Range-based indexers for getting ReadOnlySpan or ReadOnlyMemory portion of an array.
|
||||
dotnet_diagnostic.CA1832.severity = warning
|
||||
|
||||
# Use AsSpan or AsMemory instead of Range-based indexers for getting Span or Memory portion of an array.
|
||||
dotnet_diagnostic.CA1833.severity = warning
|
||||
|
||||
# Use StringBuilder.Append(char) for single character strings.
|
||||
dotnet_diagnostic.CA1834.severity = warning
|
||||
|
||||
# Prefer the memory-based overloads of ReadAsync/WriteAsync methods in stream-based classes.
|
||||
dotnet_diagnostic.CA1835.severity = warning
|
||||
|
||||
# Prefer IsEmpty over Count when available.
|
||||
dotnet_diagnostic.CA1836.severity = warning
|
||||
|
||||
# Use Environment.ProcessId instead of Process.GetCurrentProcess().Id.
|
||||
dotnet_diagnostic.CA1837.severity = warning
|
||||
|
||||
# Avoid StringBuilder parameters for P/Invokes.
|
||||
dotnet_diagnostic.CA1838.severity = warning
|
||||
|
||||
# Use Environment.ProcessPath instead of Process.GetCurrentProcess().MainModule.FileName.
|
||||
dotnet_diagnostic.CA1839.severity = warning
|
||||
|
||||
# Use Environment.CurrentManagedThreadId instead of Thread.CurrentThread.ManagedThreadId.
|
||||
dotnet_diagnostic.CA1840.severity = warning
|
||||
|
||||
# Prefer Dictionary Contains methods.
|
||||
dotnet_diagnostic.CA1841.severity = warning
|
||||
|
||||
# Do not use 'WhenAll' with a single task.
|
||||
dotnet_diagnostic.CA1842.severity = warning
|
||||
|
||||
# Do not use 'WaitAll' with a single task.
|
||||
dotnet_diagnostic.CA1843.severity = warning
|
||||
|
||||
# Provide memory-based overrides of async methods when subclassing 'Stream'.
|
||||
dotnet_diagnostic.CA1844.severity = warning
|
||||
|
||||
# Use span-based 'string.Concat'. (Not available on mono)
|
||||
dotnet_diagnostic.CA1845.severity = none
|
||||
|
||||
# Prefer AsSpan over Substring.
|
||||
dotnet_diagnostic.CA1846.severity = warning
|
||||
|
||||
# Use string.Contains(char) instead of string.Contains(string) with single characters.
|
||||
dotnet_diagnostic.CA1847.severity = warning
|
||||
|
||||
; 4-column tab indentation
|
||||
[*.yaml]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
# Call async methods when in an async method.
|
||||
dotnet_diagnostic.CA1849.severity = warning
|
||||
|
||||
# Prefer static HashData method over ComputeHash. (Not available on mono)
|
||||
dotnet_diagnostic.CA1850.severity = none
|
||||
|
||||
# Seal internal types.
|
||||
dotnet_diagnostic.CA1852.severity = warning
|
||||
|
||||
# Unnecessary call to 'Dictionary.ContainsKey(key)'.
|
||||
dotnet_diagnostic.CA1853.severity = warning
|
||||
|
||||
# Prefer the IDictionary.TryGetValue(TKey, out TValue) method.
|
||||
dotnet_diagnostic.CA1854.severity = warning
|
||||
|
||||
# Use Span<T>.Clear() instead of Span<T>.Fill().
|
||||
dotnet_diagnostic.CA1855.severity = warning
|
||||
|
||||
# Use StartsWith instead of IndexOf.
|
||||
dotnet_diagnostic.CA1858.severity = warning
|
||||
|
||||
# Avoid using 'Enumerable.Any()' extension method.
|
||||
dotnet_diagnostic.CA1860.severity = warning
|
||||
|
||||
### Reliability Rules
|
||||
### https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/reliability-warnings
|
||||
|
||||
# Do not assign property within its setter.
|
||||
dotnet_diagnostic.CA2011.severity = warning
|
||||
|
||||
# Use ValueTasks correctly.
|
||||
dotnet_diagnostic.CA2012.severity = warning
|
||||
|
||||
# Do not use ReferenceEquals with value types.
|
||||
dotnet_diagnostic.CA2013.severity = warning
|
||||
|
||||
# Do not use stackalloc in loops.
|
||||
dotnet_diagnostic.CA2014.severity = warning
|
||||
|
||||
# Forward the CancellationToken parameter to methods that take one.
|
||||
dotnet_diagnostic.CA2016.severity = warning
|
||||
|
||||
# The 'count' argument to Buffer.BlockCopy should specify the number of bytes to copy.
|
||||
dotnet_diagnostic.CA2018.severity = warning
|
||||
|
||||
# ThreadStatic fields should not use inline initialization.
|
||||
dotnet_diagnostic.CA2019.severity = warning
|
||||
|
||||
### Security Rules
|
||||
### https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/security-warnings
|
||||
|
||||
# Do Not Use Broken Cryptographic Algorithms.
|
||||
dotnet_diagnostic.CA5351.severity = warning
|
||||
|
||||
### Usage Rules
|
||||
### https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/usage-warnings
|
||||
|
||||
# Call GC.SuppressFinalize correctly.
|
||||
dotnet_diagnostic.CA1816.severity = warning
|
||||
|
||||
# Rethrow to preserve stack details.
|
||||
dotnet_diagnostic.CA2200.severity = warning
|
||||
|
||||
# Initialize value type static fields inline.
|
||||
dotnet_diagnostic.CA2207.severity = warning
|
||||
|
||||
# Instantiate argument exceptions correctly.
|
||||
dotnet_diagnostic.CA2208.severity = warning
|
||||
|
||||
# Dispose methods should call base class dispose.
|
||||
dotnet_diagnostic.CA2215.severity = warning
|
||||
|
||||
# Disposable types should declare finalizer.
|
||||
dotnet_diagnostic.CA2216.severity = warning
|
||||
|
||||
# Override GetHashCode on overriding Equals.
|
||||
dotnet_diagnostic.CA2218.severity = warning
|
||||
|
||||
# Overload operator equals on overriding ValueType.Equals.
|
||||
dotnet_diagnostic.CA2231.severity = warning
|
||||
|
||||
# Provide correct arguments to formatting methods.
|
||||
#dotnet_code_quality.CA2241.additional_string_formatting_methods =
|
||||
dotnet_code_quality.CA2241.try_determine_additional_string_formatting_methods_automatically = true
|
||||
dotnet_diagnostic.CA2241.severity = warning
|
||||
|
||||
# Test for NaN correctly.
|
||||
dotnet_diagnostic.CA2242.severity = warning
|
||||
|
||||
# Attribute string literals should parse correctly.
|
||||
dotnet_diagnostic.CA2243.severity = warning
|
||||
|
||||
# Do not duplicate indexed element initializations.
|
||||
dotnet_diagnostic.CA2244.severity = warning
|
||||
|
||||
# Do not assign a property to itself.
|
||||
dotnet_diagnostic.CA2245.severity = warning
|
||||
|
||||
# Argument passed to TaskCompletionSource constructor should be TaskCreationOptions enum instead of TaskContinuationOptions enum.
|
||||
dotnet_diagnostic.CA2247.severity = warning
|
||||
|
||||
# Provide correct enum argument to Enum.HasFlag.
|
||||
dotnet_diagnostic.CA2248.severity = warning
|
||||
|
||||
# Use ThrowIfCancellationRequested.
|
||||
dotnet_diagnostic.CA2250.severity = warning
|
||||
|
||||
# Ensure ThreadStatic is only used with static fields.
|
||||
dotnet_diagnostic.CA2259.severity = warning
|
||||
|
||||
### Roslynator
|
||||
### https://github.com/JosefPihrt/Roslynator/tree/main/docs/analyzers
|
||||
|
||||
# Below we enable specific rules by setting severity to warning.
|
||||
|
||||
# Use 'Count' property instead of 'Any' method.
|
||||
dotnet_diagnostic.RCS1080.severity = warning
|
||||
|
||||
@@ -3,39 +3,43 @@ name: Continuous Integration
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
branches: [ bleed ]
|
||||
branches: [ bleed, 'prep-*' ]
|
||||
|
||||
permissions:
|
||||
contents: read # to fetch code (actions/checkout)
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
name: Linux (.NET 6.0)
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Clone Repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install .NET 6.0
|
||||
uses: actions/setup-dotnet@v1
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: '6.0.x'
|
||||
|
||||
- name: Check Code
|
||||
run: |
|
||||
make check
|
||||
make tests
|
||||
|
||||
- name: Check Mods
|
||||
run: |
|
||||
sudo apt-get install lua5.1
|
||||
make check-scripts
|
||||
make test
|
||||
make TREAT_WARNINGS_AS_ERRORS=true test
|
||||
|
||||
linux-mono:
|
||||
name: Linux (mono)
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Clone Repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Check Code
|
||||
run: |
|
||||
@@ -45,7 +49,7 @@ jobs:
|
||||
- name: Check Mods
|
||||
run: |
|
||||
# check-scripts does not depend on .net/mono, so is not needed here
|
||||
make RUNTIME=mono test
|
||||
make RUNTIME=mono TREAT_WARNINGS_AS_ERRORS=true test
|
||||
|
||||
windows:
|
||||
name: Windows (.NET 6.0)
|
||||
@@ -53,10 +57,10 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Clone Repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install .NET 6.0
|
||||
uses: actions/setup-dotnet@v1
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: '6.0.x'
|
||||
|
||||
@@ -66,12 +70,12 @@ jobs:
|
||||
# Work around runtime failures on the GH Actions runner
|
||||
dotnet nuget add source https://api.nuget.org/v3/index.json -n nuget.org
|
||||
.\make.ps1 check
|
||||
dotnet build OpenRA.Test\OpenRA.Test.csproj -c Debug --nologo -p:TargetPlatform=win-x64
|
||||
dotnet test bin\OpenRA.Test.dll --test-adapter-path:.
|
||||
.\make.ps1 tests
|
||||
|
||||
- name: Check Mods
|
||||
run: |
|
||||
chocolatey install lua --version 5.1.5.52
|
||||
choco install lua --version 5.1.5.52
|
||||
$ENV:Path = $ENV:Path + ";C:\Program Files (x86)\Lua\5.1\"
|
||||
$ENV:TREAT_WARNINGS_AS_ERRORS = "true"
|
||||
.\make.ps1 check-scripts
|
||||
.\make.ps1 test
|
||||
38
.github/workflows/documentation.yml
vendored
38
.github/workflows/documentation.yml
vendored
@@ -8,19 +8,22 @@ on:
|
||||
required: true
|
||||
default: 'release-xxxxxxxx'
|
||||
|
||||
permissions:
|
||||
contents: read # to fetch code (actions/checkout)
|
||||
|
||||
jobs:
|
||||
wiki:
|
||||
name: Update Wiki
|
||||
if: github.repository == 'openra/openra'
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Clone Repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.inputs.tag }}
|
||||
|
||||
- name: Install .NET 6
|
||||
uses: actions/setup-dotnet@v1
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: '6.0.x'
|
||||
|
||||
@@ -29,7 +32,7 @@ jobs:
|
||||
make all
|
||||
|
||||
- name: Clone Wiki
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: openra/openra.wiki
|
||||
token: ${{ secrets.DOCS_TOKEN }}
|
||||
@@ -63,15 +66,15 @@ jobs:
|
||||
docs:
|
||||
name: Update docs.openra.net
|
||||
if: github.repository == 'openra/openra'
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Clone Repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.inputs.tag }}
|
||||
|
||||
- name: Install .NET 6
|
||||
uses: actions/setup-dotnet@v1
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: '6.0.x'
|
||||
|
||||
@@ -79,19 +82,29 @@ jobs:
|
||||
run: |
|
||||
make all
|
||||
|
||||
- name: Clone docs.openra.net
|
||||
uses: actions/checkout@v2
|
||||
- name: Clone docs.openra.net (Playtest)
|
||||
if: startsWith(github.event.inputs.tag, 'playtest-')
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: openra/docs
|
||||
token: ${{ secrets.DOCS_TOKEN }}
|
||||
path: docs
|
||||
ref: playtest
|
||||
|
||||
- name: Clone docs.openra.net (Release)
|
||||
if: startsWith(github.event.inputs.tag, 'release-')
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: openra/docs
|
||||
token: ${{ secrets.DOCS_TOKEN }}
|
||||
path: docs
|
||||
ref: release
|
||||
|
||||
- name: Update docs.openra.net (Playtest)
|
||||
if: startsWith(github.event.inputs.tag, 'playtest-')
|
||||
env:
|
||||
GIT_TAG: ${{ github.event.inputs.tag }}
|
||||
run: |
|
||||
git checkout playtest
|
||||
./utility.sh all --docs "${GIT_TAG}" | python3 ./packaging/format-docs.py > "docs/api/traits.md"
|
||||
./utility.sh all --weapon-docs "${GIT_TAG}" | python3 ./packaging/format-docs.py > "docs/api/weapons.md"
|
||||
./utility.sh all --sprite-sequence-docs "${GIT_TAG}" | python3 ./packaging/format-docs.py > "docs/api/sprite-sequences.md"
|
||||
@@ -102,7 +115,6 @@ jobs:
|
||||
env:
|
||||
GIT_TAG: ${{ github.event.inputs.tag }}
|
||||
run: |
|
||||
git checkout release
|
||||
./utility.sh all --docs "${GIT_TAG}" | python3 ./packaging/format-docs.py > "docs/api/traits.md"
|
||||
./utility.sh all --weapon-docs "${GIT_TAG}" | python3 ./packaging/format-docs.py > "docs/api/weapons.md"
|
||||
./utility.sh all --sprite-sequence-docs "${GIT_TAG}" | python3 ./packaging/format-docs.py > "docs/api/sprite-sequences.md"
|
||||
@@ -115,15 +127,17 @@ jobs:
|
||||
cd docs
|
||||
git config --local user.email "actions@github.com"
|
||||
git config --local user.name "GitHub Actions"
|
||||
git add *.md
|
||||
git add api/*.md
|
||||
git commit -m "Update auto-generated documentation for ${GIT_TAG}"
|
||||
|
||||
- name: Push docs.openra.net (Release)
|
||||
if: startsWith(github.event.inputs.tag, 'release-')
|
||||
run: |
|
||||
cd docs
|
||||
git push origin release
|
||||
|
||||
- name: Push docs.openra.net (Playtest)
|
||||
if: startsWith(github.event.inputs.tag, 'playtest-')
|
||||
run: |
|
||||
cd docs
|
||||
git push origin playtest
|
||||
|
||||
3
.github/workflows/itch.yml
vendored
3
.github/workflows/itch.yml
vendored
@@ -8,10 +8,11 @@ on:
|
||||
required: true
|
||||
default: 'release-xxxxxxxx'
|
||||
|
||||
permissions: {}
|
||||
jobs:
|
||||
itch:
|
||||
name: Deploy to itch.io
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
if: github.repository == 'openra/openra'
|
||||
steps:
|
||||
- name: Download Packages
|
||||
|
||||
30
.github/workflows/packaging.yml
vendored
30
.github/workflows/packaging.yml
vendored
@@ -7,13 +7,16 @@ on:
|
||||
- 'playtest-*'
|
||||
- 'devtest-*'
|
||||
|
||||
permissions:
|
||||
contents: write # for release creation (svenstaro/upload-release-action)
|
||||
|
||||
jobs:
|
||||
source:
|
||||
name: Source Tarball
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Clone Repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Prepare Environment
|
||||
run: echo "GIT_TAG=${GITHUB_REF#refs/tags/}" >> ${GITHUB_ENV}
|
||||
@@ -34,13 +37,13 @@ jobs:
|
||||
|
||||
linux:
|
||||
name: Linux AppImages
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Clone Repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install .NET 6.0
|
||||
uses: actions/setup-dotnet@v1
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: '6.0.x'
|
||||
|
||||
@@ -50,6 +53,7 @@ jobs:
|
||||
- name: Package AppImages
|
||||
run: |
|
||||
mkdir -p build/linux
|
||||
sudo apt install libfuse2
|
||||
./packaging/linux/buildpackage.sh "${GIT_TAG}" "${PWD}/build/linux"
|
||||
|
||||
- name: Upload Packages
|
||||
@@ -62,21 +66,21 @@ jobs:
|
||||
file: build/linux/*
|
||||
|
||||
macos:
|
||||
name: macOS Disk Images
|
||||
name: macOS Disk Image
|
||||
runs-on: macos-11
|
||||
steps:
|
||||
- name: Clone Repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install .NET 6.0
|
||||
uses: actions/setup-dotnet@v1
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: '6.0.x'
|
||||
|
||||
- name: Prepare Environment
|
||||
run: echo "GIT_TAG=${GITHUB_REF#refs/tags/}" >> ${GITHUB_ENV}
|
||||
|
||||
- name: Package Disk Images
|
||||
- name: Package Disk Image
|
||||
env:
|
||||
MACOS_DEVELOPER_IDENTITY: ${{ secrets.MACOS_DEVELOPER_IDENTITY }}
|
||||
MACOS_DEVELOPER_CERTIFICATE_BASE64: ${{ secrets.MACOS_DEVELOPER_CERTIFICATE_BASE64 }}
|
||||
@@ -87,7 +91,7 @@ jobs:
|
||||
mkdir -p build/macos
|
||||
./packaging/macos/buildpackage.sh "${GIT_TAG}" "${PWD}/build/macos"
|
||||
|
||||
- name: Upload Packages
|
||||
- name: Upload Package
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -98,13 +102,13 @@ jobs:
|
||||
|
||||
windows:
|
||||
name: Windows Installers
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Clone Repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install .NET 6.0
|
||||
uses: actions/setup-dotnet@v1
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: '6.0.x'
|
||||
|
||||
|
||||
2
AUTHORS
2
AUTHORS
@@ -74,6 +74,7 @@ Also thanks to:
|
||||
* Glenn Martin Jensen (Baxxster)
|
||||
* Gordon Martin (Happy0)
|
||||
* Guido Lipke (LipkeGu)
|
||||
* Guillermo Cuenca (Wylli)
|
||||
* Hervé Matysiak (Herve-M)
|
||||
* Huw Pascoe
|
||||
* Ian T. Jacobsen (Smilex)
|
||||
@@ -119,6 +120,7 @@ Also thanks to:
|
||||
* Mike Gagné (AngryBirdz)
|
||||
* Muh
|
||||
* Mustafa Alperen Seki (MustaphaTR)
|
||||
* Nathan Nichols (cracksmoka420)
|
||||
* Neil Shivkar (havok13888)
|
||||
* Nikolay Fomin (netnazgul)
|
||||
* Nooze
|
||||
|
||||
@@ -5,15 +5,16 @@
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Optimize>true</Optimize>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<LangVersion>9</LangVersion>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<EngineRootPath Condition="'$(EngineRootPath)' == ''">..</EngineRootPath>
|
||||
<OutputPath>$(EngineRootPath)/bin</OutputPath>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<ExternalConsole>false</ExternalConsole>
|
||||
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
||||
<CodeAnalysisRuleSet>$(EngineRootPath)/OpenRA.ruleset</CodeAnalysisRuleSet>
|
||||
<Nullable>disable</Nullable>
|
||||
<Product>OpenRA</Product>
|
||||
<Copyright>Copyright (c) The OpenRA Developers and Contributors</Copyright>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
@@ -30,6 +31,12 @@
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<Optimize>false</Optimize>
|
||||
<!-- Enable only for Debug builds to improve compile-time performance for Release builds -->
|
||||
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
|
||||
<!-- Enabling GenerateDocumentationFile is required for IDE0005 (Remove unnecessary import)
|
||||
rule to run in command line builds. https://github.com/dotnet/roslyn/issues/41640
|
||||
Enable only for Debug builds to improve compile-time performance for Release builds -->
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -46,7 +53,6 @@
|
||||
|
||||
<!-- StyleCop -->
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.2" PrivateAssets="All" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -17,7 +17,7 @@ Run the game with `launch-game.cmd`. It can be handed arguments that specify the
|
||||
Linux
|
||||
=====
|
||||
|
||||
.NET 6 or Mono (version 6.4 or later) is required to compile OpenRA. We recommend using .NET 6 when possible, as Mono is poorly packaged by most Linux distributions (e.g. missing the required `msbuild` toolchain), and has been deprecated as a standalone project.
|
||||
.NET 6 or Mono (version 6.12 or later) is required to compile OpenRA. We recommend using .NET 6 when possible, as Mono is poorly packaged by most Linux distributions (e.g. missing the required `msbuild` toolchain), and has been deprecated as a standalone project.
|
||||
|
||||
The [.NET 6 download page](https://dotnet.microsoft.com/download/dotnet/6.0) provides repositories for various package managers and binary releases for several architectures. If you prefer to use Mono, we suggest adding the [upstream repository](https://www.mono-project.com/download/stable/#download-lin) for your distro to obtain the latest version and the `msbuild` toolchain.
|
||||
|
||||
@@ -78,6 +78,6 @@ Type `sudo make install` for system-wide installation. Run `sudo make install-li
|
||||
macOS
|
||||
=====
|
||||
|
||||
[.NET 6](https://dotnet.microsoft.com/download/dotnet/6.0) or [Mono](https://www.mono-project.com/download/stable/#download-mac) (version 6.4 or later) is required to compile OpenRA. We recommend using .NET 6 unless you are running a very old version of macOS (10.9 through 10.14).
|
||||
[.NET 6](https://dotnet.microsoft.com/download/dotnet/6.0) or [Mono](https://www.mono-project.com/download/stable/#download-mac) (version 6.12 or later) is required to compile OpenRA. We recommend using .NET 6 unless you are running a very old version of macOS (10.9 through 10.14).
|
||||
|
||||
To compile OpenRA, run `make` from the command line (or `make RUNTIME=mono` if using Mono). Run with `./launch-game.sh`.
|
||||
|
||||
32
Makefile
32
Makefile
@@ -3,7 +3,7 @@
|
||||
# to compile, run:
|
||||
# make
|
||||
#
|
||||
# to compile using Mono (version 6.4 or greater) instead of .NET 6, run:
|
||||
# to compile using Mono (version 6.12 or greater) instead of .NET 6, run:
|
||||
# make RUNTIME=mono
|
||||
#
|
||||
# to compile using system libraries for native dependencies, run:
|
||||
@@ -58,6 +58,8 @@ RM_RF = $(RM) -rf
|
||||
|
||||
RUNTIME ?= net6
|
||||
CONFIGURATION ?= Release
|
||||
DOTNET_RID = $(shell ${DOTNET} --info | grep RID: | cut -w -f3)
|
||||
ARCH_X64 = $(shell echo ${DOTNET_RID} | grep x64)
|
||||
|
||||
# Only for use in target version:
|
||||
VERSION := $(shell git name-rev --name-only --tags --no-undefined HEAD 2>/dev/null || (c=$$(git rev-parse --short HEAD 2>/dev/null) && echo git-$$c))
|
||||
@@ -67,22 +69,30 @@ ifndef TARGETPLATFORM
|
||||
UNAME_S := $(shell uname -s)
|
||||
UNAME_M := $(shell uname -m)
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
ifeq ($(ARCH_X64),)
|
||||
TARGETPLATFORM = osx-arm64
|
||||
else
|
||||
TARGETPLATFORM = osx-x64
|
||||
endif
|
||||
else
|
||||
ifeq ($(UNAME_M),x86_64)
|
||||
TARGETPLATFORM = linux-x64
|
||||
else
|
||||
ifeq ($(UNAME_M),aarch64)
|
||||
TARGETPLATFORM = linux-arm64
|
||||
else
|
||||
TARGETPLATFORM = unix-generic
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
##################### DEVELOPMENT BUILDS AND TESTS #####################
|
||||
#
|
||||
all:
|
||||
@echo "Compiling in ${CONFIGURATION} mode..."
|
||||
ifeq ($(RUNTIME), mono)
|
||||
@command -v $(firstword $(MSBUILD)) >/dev/null || (echo "OpenRA requires the '$(MSBUILD)' tool provided by Mono >= 6.4."; exit 1)
|
||||
@command -v $(firstword $(MSBUILD)) >/dev/null || (echo "OpenRA requires the '$(MSBUILD)' tool provided by Mono >= 6.12."; exit 1)
|
||||
@$(MSBUILD) -t:Build -restore -p:Configuration=${CONFIGURATION} -p:TargetPlatform=$(TARGETPLATFORM)
|
||||
else
|
||||
@$(DOTNET) build -c ${CONFIGURATION} -nologo -p:TargetPlatform=$(TARGETPLATFORM)
|
||||
@@ -102,11 +112,10 @@ check:
|
||||
@echo
|
||||
@echo "Compiling in Debug mode..."
|
||||
ifeq ($(RUNTIME), mono)
|
||||
# Enabling EnforceCodeStyleInBuild and GenerateDocumentationFile as a workaround for some code style rules (in particular IDE0005) being bugged and not reporting warnings/errors otherwise.
|
||||
@$(MSBUILD) -t:build -restore -p:Configuration=Debug -warnaserror -p:TargetPlatform=$(TARGETPLATFORM) -p:EnforceCodeStyleInBuild=true -p:GenerateDocumentationFile=true
|
||||
@$(MSBUILD) -t:clean\;build -restore -p:Configuration=Debug -warnaserror -p:TargetPlatform=$(TARGETPLATFORM)
|
||||
else
|
||||
# Enabling EnforceCodeStyleInBuild and GenerateDocumentationFile as a workaround for some code style rules (in particular IDE0005) being bugged and not reporting warnings/errors otherwise.
|
||||
@$(DOTNET) build -c Debug -nologo -warnaserror -p:TargetPlatform=$(TARGETPLATFORM) -p:EnforceCodeStyleInBuild=true -p:GenerateDocumentationFile=true
|
||||
@$(DOTNET) clean -c Debug --nologo --verbosity minimal
|
||||
@$(DOTNET) build -c Debug -nologo -warnaserror -p:TargetPlatform=$(TARGETPLATFORM)
|
||||
endif
|
||||
ifeq ($(TARGETPLATFORM), unix-generic)
|
||||
@./configure-system-libraries.sh
|
||||
@@ -121,7 +130,7 @@ endif
|
||||
check-scripts:
|
||||
@echo
|
||||
@echo "Checking for Lua syntax errors..."
|
||||
@find lua/ mods/*/{maps,scripts}/ -iname "*.lua" -print0 | xargs -0n1 luac -p
|
||||
@find mods/*/maps/ mods/*/scripts/ -iname "*.lua" -print0 | xargs -0n1 luac -p
|
||||
|
||||
test: all
|
||||
@echo
|
||||
@@ -137,6 +146,11 @@ test: all
|
||||
@echo "Testing Red Alert mod MiniYAML..."
|
||||
@./utility.sh ra --check-yaml
|
||||
|
||||
tests:
|
||||
@dotnet build OpenRA.Test/OpenRA.Test.csproj -c Debug --nologo -p:TargetPlatform=$(TARGETPLATFORM)
|
||||
@echo
|
||||
@dotnet test bin/OpenRA.Test.dll --test-adapter-path:.
|
||||
|
||||
############# LOCAL INSTALLATION AND DOWNSTREAM PACKAGING ##############
|
||||
#
|
||||
version: VERSION mods/ra/mod.yaml mods/cnc/mod.yaml mods/d2k/mod.yaml mods/ts/mod.yaml mods/modcontent/mod.yaml mods/all/mod.yaml
|
||||
@@ -164,14 +178,14 @@ help:
|
||||
@echo 'to compile, run:'
|
||||
@echo ' make'
|
||||
@echo
|
||||
@echo 'to compile using Mono (version 6.4 or greater) instead of .NET 6, run:'
|
||||
@echo 'to compile using Mono (version 6.12 or greater) instead of .NET 6, run:'
|
||||
@echo ' make RUNTIME=mono'
|
||||
@echo
|
||||
@echo 'to compile using system libraries for native dependencies, run:'
|
||||
@echo ' make [RUNTIME=net6] TARGETPLATFORM=unix-generic'
|
||||
@echo
|
||||
@echo 'to check the official mods for erroneous yaml files, run:'
|
||||
@echo ' make [RUNTIME=net6] test'
|
||||
@echo ' make [RUNTIME=net6] [TREAT_WARNINGS_AS_ERRORS=false] test'
|
||||
@echo
|
||||
@echo 'to check the engine and official mod dlls for code style violations, run:'
|
||||
@echo ' make [RUNTIME=net6] check'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -86,7 +86,7 @@ namespace OpenRA.Activities
|
||||
bool firstRunCompleted;
|
||||
bool lastRun;
|
||||
|
||||
public Activity()
|
||||
protected Activity()
|
||||
{
|
||||
IsInterruptible = true;
|
||||
ChildHasPriority = true;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -35,6 +35,9 @@ namespace OpenRA
|
||||
|
||||
public sealed class Actor : IScriptBindable, IScriptNotifyBind, ILuaTableBinding, ILuaEqualityBinding, ILuaToStringBinding, IEquatable<Actor>, IDisposable
|
||||
{
|
||||
/// <summary>Value used to represent an invalid token.</summary>
|
||||
public const int InvalidConditionToken = -1;
|
||||
|
||||
internal readonly struct SyncHash
|
||||
{
|
||||
public readonly ISync Trait;
|
||||
@@ -78,27 +81,24 @@ namespace OpenRA
|
||||
|
||||
public WRot Orientation => facing?.Orientation ?? WRot.None;
|
||||
|
||||
/// <summary>Value used to represent an invalid token.</summary>
|
||||
public static readonly int InvalidConditionToken = -1;
|
||||
|
||||
class ConditionState
|
||||
sealed class ConditionState
|
||||
{
|
||||
/// <summary>Delegates that have registered to be notified when this condition changes.</summary>
|
||||
public readonly List<VariableObserverNotifier> Notifiers = new List<VariableObserverNotifier>();
|
||||
public readonly List<VariableObserverNotifier> Notifiers = new();
|
||||
|
||||
/// <summary>Unique integers identifying granted instances of the condition.</summary>
|
||||
public readonly HashSet<int> Tokens = new HashSet<int>();
|
||||
public readonly HashSet<int> Tokens = new();
|
||||
}
|
||||
|
||||
readonly Dictionary<string, ConditionState> conditionStates = new Dictionary<string, ConditionState>();
|
||||
readonly Dictionary<string, ConditionState> conditionStates = new();
|
||||
|
||||
/// <summary>Each granted condition receives a unique token that is used when revoking.</summary>
|
||||
readonly Dictionary<int, string> conditionTokens = new Dictionary<int, string>();
|
||||
readonly Dictionary<int, string> conditionTokens = new();
|
||||
|
||||
int nextConditionToken = 1;
|
||||
|
||||
/// <summary>Cache of condition -> enabled state for quick evaluation of token counter conditions.</summary>
|
||||
readonly Dictionary<string, int> conditionCache = new Dictionary<string, int>();
|
||||
readonly Dictionary<string, int> conditionCache = new();
|
||||
|
||||
/// <summary>Read-only version of conditionCache that is passed to IConditionConsumers.</summary>
|
||||
readonly IReadOnlyDictionary<string, int> readOnlyConditionCache;
|
||||
@@ -587,7 +587,7 @@ namespace OpenRA
|
||||
return InvalidConditionToken;
|
||||
}
|
||||
|
||||
/// <summary>Returns whether the specified token is valid for RevokeCondition</summary>
|
||||
/// <summary>Returns whether the specified token is valid for RevokeCondition.</summary>
|
||||
public bool TokenValid(int token)
|
||||
{
|
||||
return conditionTokens.ContainsKey(token);
|
||||
@@ -600,8 +600,7 @@ namespace OpenRA
|
||||
Lazy<ScriptActorInterface> luaInterface;
|
||||
public void OnScriptBind(ScriptContext context)
|
||||
{
|
||||
if (luaInterface == null)
|
||||
luaInterface = Exts.Lazy(() => new ScriptActorInterface(context, this));
|
||||
luaInterface ??= Exts.Lazy(() => new ScriptActorInterface(context, this));
|
||||
}
|
||||
|
||||
public LuaValue this[LuaRuntime runtime, LuaValue keyValue]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -41,7 +41,7 @@ namespace OpenRA
|
||||
Bits = (x & 0xFFF) << 20 | (y & 0xFFF) << 8 | layer;
|
||||
}
|
||||
|
||||
public static readonly CPos Zero = new CPos(0, 0, 0);
|
||||
public static readonly CPos Zero = new(0, 0, 0);
|
||||
|
||||
public static explicit operator CPos(int2 a) { return new CPos(a.X, a.Y); }
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace OpenRA
|
||||
public override int GetHashCode() { return Bits.GetHashCode(); }
|
||||
|
||||
public bool Equals(CPos other) { return Bits == other.Bits; }
|
||||
public override bool Equals(object obj) { return obj is CPos && Equals((CPos)obj); }
|
||||
public override bool Equals(object obj) { return obj is CPos cell && Equals(cell); }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -22,7 +22,7 @@ namespace OpenRA
|
||||
public readonly int X, Y;
|
||||
|
||||
public CVec(int x, int y) { X = x; Y = y; }
|
||||
public static readonly CVec Zero = new CVec(0, 0);
|
||||
public static readonly CVec Zero = new(0, 0);
|
||||
|
||||
public static CVec operator +(CVec a, CVec b) { return new CVec(a.X + b.X, a.Y + b.Y); }
|
||||
public static CVec operator -(CVec a, CVec b) { return new CVec(a.X - b.X, a.Y - b.Y); }
|
||||
@@ -55,7 +55,7 @@ namespace OpenRA
|
||||
public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode(); }
|
||||
|
||||
public bool Equals(CVec other) { return other == this; }
|
||||
public override bool Equals(object obj) { return obj is CVec && Equals((CVec)obj); }
|
||||
public override bool Equals(object obj) { return obj is CVec vec && Equals(vec); }
|
||||
|
||||
public override string ToString() { return X + "," + Y; }
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -187,8 +187,10 @@ namespace OpenRA
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Write("debug", "Failed to decrypt string with exception: {0}", e);
|
||||
Console.WriteLine("String decryption failed: {0}", e);
|
||||
Log.Write("debug", "Failed to decrypt string with exception:");
|
||||
Log.Write("debug", e);
|
||||
Console.WriteLine("String decryption failed:");
|
||||
Console.WriteLine(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -211,8 +213,10 @@ namespace OpenRA
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Write("debug", "Failed to sign string with exception: {0}", e);
|
||||
Console.WriteLine("String signing failed: {0}", e);
|
||||
Log.Write("debug", "Failed to sign string with exception");
|
||||
Log.Write("debug", e);
|
||||
Console.WriteLine("String signing failed:");
|
||||
Console.WriteLine(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -235,8 +239,10 @@ namespace OpenRA
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Write("debug", "Failed to verify signature with exception: {0}", e);
|
||||
Console.WriteLine("Signature validation failed: {0}", e);
|
||||
Log.Write("debug", "Failed to verify signature with exception:");
|
||||
Log.Write("debug", e);
|
||||
Console.WriteLine("Signature validation failed:");
|
||||
Console.WriteLine(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Effects
|
||||
{
|
||||
public class AsyncAction : IEffect
|
||||
{
|
||||
readonly Action a;
|
||||
readonly IAsyncResult ar;
|
||||
|
||||
public AsyncAction(IAsyncResult ar, Action a)
|
||||
{
|
||||
this.a = a;
|
||||
this.ar = ar;
|
||||
}
|
||||
|
||||
public void Tick(World world)
|
||||
{
|
||||
if (ar.IsCompleted)
|
||||
{
|
||||
world.AddFrameEndTask(w => { w.Remove(this); a(); });
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer r) { yield break; }
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -41,7 +41,7 @@ namespace OpenRA
|
||||
|
||||
public class ExternalMods : IReadOnlyDictionary<string, ExternalMod>
|
||||
{
|
||||
readonly Dictionary<string, ExternalMod> mods = new Dictionary<string, ExternalMod>();
|
||||
readonly Dictionary<string, ExternalMod> mods = new();
|
||||
readonly SheetBuilder sheetBuilder;
|
||||
|
||||
Sheet CreateSheet()
|
||||
@@ -81,8 +81,8 @@ namespace OpenRA
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Write("debug", "Failed to parse mod metadata file '{0}'", path);
|
||||
Log.Write("debug", e.ToString());
|
||||
Log.Write("debug", $"Failed to parse mod metadata file '{path}'");
|
||||
Log.Write("debug", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,17 +174,19 @@ namespace OpenRA
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Write("debug", "Failed to register current mod metadata");
|
||||
Log.Write("debug", e.ToString());
|
||||
Log.Write("debug", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes invalid mod registrations:
|
||||
/// * LaunchPath no longer exists
|
||||
/// * LaunchPath and mod id matches the active mod, but the version is different
|
||||
/// * Filename doesn't match internal key
|
||||
/// * Fails to parse as a mod registration
|
||||
/// <list type="bullet">
|
||||
/// <item>LaunchPath no longer exists.</item>
|
||||
/// <item>LaunchPath and mod id matches the active mod, but the version is different.</item>
|
||||
/// <item>Filename doesn't match internal key.</item>
|
||||
/// <item>Fails to parse as a mod registration.</item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
internal void ClearInvalidRegistrations(ModRegistration registration)
|
||||
{
|
||||
@@ -211,8 +213,8 @@ namespace OpenRA
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Write("debug", "Failed to parse mod metadata file '{0}'", path);
|
||||
Log.Write("debug", e.ToString());
|
||||
Log.Write("debug", $"Failed to parse mod metadata file '{path}'");
|
||||
Log.Write("debug", e);
|
||||
}
|
||||
|
||||
// Remove from the ingame mod switcher
|
||||
@@ -223,12 +225,12 @@ namespace OpenRA
|
||||
try
|
||||
{
|
||||
File.Delete(path);
|
||||
Log.Write("debug", "Removed invalid mod metadata file '{0}'", path);
|
||||
Log.Write("debug", $"Removed invalid mod metadata file '{path}'");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Write("debug", "Failed to remove mod metadata file '{0}'", path);
|
||||
Log.Write("debug", e.ToString());
|
||||
Log.Write("debug", $"Failed to remove mod metadata file '{path}'");
|
||||
Log.Write("debug", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -249,13 +251,13 @@ namespace OpenRA
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Write("debug", "Failed to remove mod metadata file '{0}'", path);
|
||||
Log.Write("debug", e.ToString());
|
||||
Log.Write("debug", $"Failed to remove mod metadata file '{path}'");
|
||||
Log.Write("debug", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerable<string> GetSupportDirs(ModRegistration registration)
|
||||
static IEnumerable<string> GetSupportDirs(ModRegistration registration)
|
||||
{
|
||||
var sources = new HashSet<string>(4);
|
||||
if (registration.HasFlag(ModRegistration.System))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -27,11 +27,6 @@ namespace OpenRA
|
||||
return string.Compare(str.ToUpperInvariant(), str, false) == 0;
|
||||
}
|
||||
|
||||
public static string F(this string fmt, params object[] args)
|
||||
{
|
||||
return string.Format(fmt, args);
|
||||
}
|
||||
|
||||
public static T WithDefault<T>(T def, Func<T> f)
|
||||
{
|
||||
try { return f(); }
|
||||
@@ -45,21 +40,16 @@ namespace OpenRA
|
||||
return a.GetTypes().Select(t => t.Namespace).Distinct().Where(n => n != null);
|
||||
}
|
||||
|
||||
public static bool HasAttribute<T>(this MemberInfo mi)
|
||||
public static bool HasAttribute<TAttribute>(this MemberInfo mi)
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
return Attribute.IsDefined(mi, typeof(T));
|
||||
return Attribute.IsDefined(mi, typeof(TAttribute));
|
||||
}
|
||||
|
||||
public static T[] GetCustomAttributes<T>(this MemberInfo mi, bool inherit)
|
||||
where T : class
|
||||
public static TAttribute[] GetCustomAttributes<TAttribute>(this MemberInfo mi, bool inherit)
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
return (T[])mi.GetCustomAttributes(typeof(T), inherit);
|
||||
}
|
||||
|
||||
public static T[] GetCustomAttributes<T>(this ParameterInfo mi)
|
||||
where T : class
|
||||
{
|
||||
return (T[])mi.GetCustomAttributes(typeof(T), true);
|
||||
return (TAttribute[])mi.GetCustomAttributes(typeof(TAttribute), inherit);
|
||||
}
|
||||
|
||||
public static T Clamp<T>(this T val, T min, T max) where T : IComparable<T>
|
||||
@@ -119,13 +109,23 @@ namespace OpenRA
|
||||
|
||||
public static V GetOrAdd<K, V>(this Dictionary<K, V> d, K k, V v)
|
||||
{
|
||||
#if NET5_0_OR_GREATER
|
||||
// SAFETY: Dictionary cannot be modified whilst the ref is alive.
|
||||
ref var value = ref System.Runtime.InteropServices.CollectionsMarshal.GetValueRefOrAddDefault(d, k, out var exists);
|
||||
if (!exists)
|
||||
value = v;
|
||||
return value;
|
||||
#else
|
||||
if (!d.TryGetValue(k, out var ret))
|
||||
d.Add(k, ret = v);
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static V GetOrAdd<K, V>(this Dictionary<K, V> d, K k, Func<K, V> createFn)
|
||||
{
|
||||
// Cannot use CollectionsMarshal.GetValueRefOrAddDefault here,
|
||||
// the creation function could mutate the dictionary which would invalidate the ref.
|
||||
if (!d.TryGetValue(k, out var ret))
|
||||
d.Add(k, ret = createFn(k));
|
||||
return ret;
|
||||
@@ -149,7 +149,7 @@ namespace OpenRA
|
||||
static T Random<T>(IEnumerable<T> ts, MersenneTwister r, bool throws)
|
||||
{
|
||||
var xs = ts as ICollection<T>;
|
||||
xs = xs ?? ts.ToList();
|
||||
xs ??= ts.ToList();
|
||||
if (xs.Count == 0)
|
||||
{
|
||||
if (throws)
|
||||
@@ -396,8 +396,8 @@ namespace OpenRA
|
||||
string debugName, Func<TKey, string> logKey = null, Func<TElement, string> logValue = null)
|
||||
{
|
||||
// Fall back on ToString() if null functions are provided:
|
||||
logKey = logKey ?? (s => s.ToString());
|
||||
logValue = logValue ?? (s => s.ToString());
|
||||
logKey ??= s => s.ToString();
|
||||
logValue ??= s => s.ToString();
|
||||
|
||||
// Try to build a dictionary and log all duplicates found (if any):
|
||||
var dupKeys = new Dictionary<TKey, List<string>>();
|
||||
@@ -515,7 +515,7 @@ namespace OpenRA
|
||||
|
||||
public static bool IsTraitEnabled<T>(this T trait)
|
||||
{
|
||||
return !(trait is IDisabledTrait disabledTrait) || !disabledTrait.IsTraitDisabled;
|
||||
return trait is not IDisabledTrait disabledTrait || !disabledTrait.IsTraitDisabled;
|
||||
}
|
||||
|
||||
public static T FirstEnabledTraitOrDefault<T>(this IEnumerable<T> ts)
|
||||
@@ -595,8 +595,8 @@ namespace OpenRA
|
||||
return true;
|
||||
}
|
||||
|
||||
Current = span.Slice(0, index);
|
||||
str = span.Slice(index + 1);
|
||||
Current = span[..index];
|
||||
str = span[(index + 1)..];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -56,24 +56,20 @@ namespace OpenRA
|
||||
}
|
||||
|
||||
public static Func<string, Type, string, object> InvalidValueAction = (s, t, f) =>
|
||||
{
|
||||
throw new YamlException($"FieldLoader: Cannot parse `{s}` into `{f}.{t}` ");
|
||||
};
|
||||
|
||||
public static Action<string, Type> UnknownFieldAction = (s, f) =>
|
||||
{
|
||||
throw new NotImplementedException($"FieldLoader: Missing field `{s}` on `{f.Name}`");
|
||||
};
|
||||
|
||||
static readonly ConcurrentCache<Type, FieldLoadInfo[]> TypeLoadInfo =
|
||||
new ConcurrentCache<Type, FieldLoadInfo[]>(BuildTypeLoadInfo);
|
||||
new(BuildTypeLoadInfo);
|
||||
static readonly ConcurrentCache<string, BooleanExpression> BooleanExpressionCache =
|
||||
new ConcurrentCache<string, BooleanExpression>(expression => new BooleanExpression(expression));
|
||||
new(expression => new BooleanExpression(expression));
|
||||
static readonly ConcurrentCache<string, IntegerExpression> IntegerExpressionCache =
|
||||
new ConcurrentCache<string, IntegerExpression>(expression => new IntegerExpression(expression));
|
||||
new(expression => new IntegerExpression(expression));
|
||||
|
||||
static readonly Dictionary<Type, Func<string, Type, string, MemberInfo, object>> TypeParsers =
|
||||
new Dictionary<Type, Func<string, Type, string, MemberInfo, object>>()
|
||||
new()
|
||||
{
|
||||
{ typeof(int), ParseInt },
|
||||
{ typeof(ushort), ParseUShort },
|
||||
@@ -107,7 +103,7 @@ namespace OpenRA
|
||||
};
|
||||
|
||||
static readonly Dictionary<Type, Func<string, Type, string, MiniYaml, MemberInfo, object>> GenericTypeParsers =
|
||||
new Dictionary<Type, Func<string, Type, string, MiniYaml, MemberInfo, object>>()
|
||||
new()
|
||||
{
|
||||
{ typeof(HashSet<>), ParseHashSetOrList },
|
||||
{ typeof(List<>), ParseHashSetOrList },
|
||||
@@ -116,10 +112,19 @@ namespace OpenRA
|
||||
{ typeof(Nullable<>), ParseNullable },
|
||||
};
|
||||
|
||||
static readonly object BoxedTrue = true;
|
||||
static readonly object BoxedFalse = false;
|
||||
static readonly object[] BoxedInts = Exts.MakeArray(33, i => (object)i);
|
||||
|
||||
static object ParseInt(string fieldName, Type fieldType, string value, MemberInfo field)
|
||||
{
|
||||
if (Exts.TryParseIntegerInvariant(value, out var res))
|
||||
{
|
||||
if (res >= 0 && res < BoxedInts.Length)
|
||||
return BoxedInts[res];
|
||||
return res;
|
||||
}
|
||||
|
||||
return InvalidValueAction(value, fieldType, fieldName);
|
||||
}
|
||||
|
||||
@@ -159,7 +164,7 @@ namespace OpenRA
|
||||
static object ParseColor(string fieldName, Type fieldType, string value, MemberInfo field)
|
||||
{
|
||||
if (value != null && Color.TryParse(value, out var color))
|
||||
return color;
|
||||
return color;
|
||||
|
||||
return InvalidValueAction(value, fieldType, fieldName);
|
||||
}
|
||||
@@ -365,7 +370,7 @@ namespace OpenRA
|
||||
static object ParseBool(string fieldName, Type fieldType, string value, MemberInfo field)
|
||||
{
|
||||
if (bool.TryParse(value.ToLowerInvariant(), out var result))
|
||||
return result;
|
||||
return result ? BoxedTrue : BoxedFalse;
|
||||
|
||||
return InvalidValueAction(value, fieldType, fieldName);
|
||||
}
|
||||
@@ -473,11 +478,11 @@ namespace OpenRA
|
||||
|
||||
static object ParseHashSetOrList(string fieldName, Type fieldType, string value, MiniYaml yaml, MemberInfo field)
|
||||
{
|
||||
var set = Activator.CreateInstance(fieldType);
|
||||
if (value == null)
|
||||
return set;
|
||||
return Activator.CreateInstance(fieldType);
|
||||
|
||||
var parts = value.Split(SplitComma, StringSplitOptions.RemoveEmptyEntries);
|
||||
var set = Activator.CreateInstance(fieldType, parts.Length);
|
||||
var arguments = fieldType.GetGenericArguments();
|
||||
var addMethod = fieldType.GetMethod(nameof(List<object>.Add), arguments);
|
||||
var addArgs = new object[1];
|
||||
@@ -492,7 +497,10 @@ namespace OpenRA
|
||||
|
||||
static object ParseDictionary(string fieldName, Type fieldType, string value, MiniYaml yaml, MemberInfo field)
|
||||
{
|
||||
var dict = Activator.CreateInstance(fieldType);
|
||||
if (yaml == null)
|
||||
return Activator.CreateInstance(fieldType);
|
||||
|
||||
var dict = Activator.CreateInstance(fieldType, yaml.Nodes.Count);
|
||||
var arguments = fieldType.GetGenericArguments();
|
||||
var addMethod = fieldType.GetMethod(nameof(Dictionary<object, object>.Add), arguments);
|
||||
var addArgs = new object[2];
|
||||
@@ -531,7 +539,7 @@ namespace OpenRA
|
||||
public static void Load(object self, MiniYaml my)
|
||||
{
|
||||
var loadInfo = TypeLoadInfo[self.GetType()];
|
||||
var missing = new List<string>();
|
||||
List<string> missing = null;
|
||||
|
||||
Dictionary<string, MiniYaml> md = null;
|
||||
|
||||
@@ -539,14 +547,14 @@ namespace OpenRA
|
||||
{
|
||||
object val;
|
||||
|
||||
if (md == null)
|
||||
md = my.ToDictionary();
|
||||
md ??= my.ToDictionary();
|
||||
if (fli.Loader != null)
|
||||
{
|
||||
if (!fli.Attribute.Required || md.ContainsKey(fli.YamlName))
|
||||
val = fli.Loader(my);
|
||||
else
|
||||
{
|
||||
missing ??= new List<string>();
|
||||
missing.Add(fli.YamlName);
|
||||
continue;
|
||||
}
|
||||
@@ -556,7 +564,11 @@ namespace OpenRA
|
||||
if (!TryGetValueFromYaml(fli.YamlName, fli.Field, md, out val))
|
||||
{
|
||||
if (fli.Attribute.Required)
|
||||
{
|
||||
missing ??= new List<string>();
|
||||
missing.Add(fli.YamlName);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -564,7 +576,7 @@ namespace OpenRA
|
||||
fli.Field.SetValue(self, val);
|
||||
}
|
||||
|
||||
if (missing.Count > 0)
|
||||
if (missing != null)
|
||||
throw new MissingFieldsException(missing.ToArray());
|
||||
}
|
||||
|
||||
@@ -625,12 +637,17 @@ namespace OpenRA
|
||||
|
||||
public static object GetValue(string fieldName, Type fieldType, string value, MemberInfo field)
|
||||
{
|
||||
return GetValue(fieldName, fieldType, new MiniYaml(value), field);
|
||||
return GetValue(fieldName, fieldType, value, null, field);
|
||||
}
|
||||
|
||||
public static object GetValue(string fieldName, Type fieldType, MiniYaml yaml, MemberInfo field)
|
||||
{
|
||||
var value = yaml.Value?.Trim();
|
||||
return GetValue(fieldName, fieldType, yaml.Value, yaml, field);
|
||||
}
|
||||
|
||||
static object GetValue(string fieldName, Type fieldType, string value, MiniYaml yaml, MemberInfo field)
|
||||
{
|
||||
value = value?.Trim();
|
||||
if (fieldType.IsGenericType)
|
||||
{
|
||||
if (GenericTypeParsers.TryGetValue(fieldType.GetGenericTypeDefinition(), out var parseFuncGeneric))
|
||||
@@ -754,7 +771,7 @@ namespace OpenRA
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public class SerializeAttribute : Attribute
|
||||
{
|
||||
public static readonly SerializeAttribute Default = new SerializeAttribute(true);
|
||||
public static readonly SerializeAttribute Default = new(true);
|
||||
|
||||
public bool IsDefault => this == Default;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -31,7 +31,7 @@ namespace OpenRA.FileFormats
|
||||
public Color[] Palette { get; }
|
||||
public byte[] Data { get; }
|
||||
public SpriteFrameType Type { get; }
|
||||
public Dictionary<string, string> EmbeddedData = new Dictionary<string, string>();
|
||||
public Dictionary<string, string> EmbeddedData = new();
|
||||
|
||||
public int PixelStride => Type == SpriteFrameType.Indexed8 ? 1 : Type == SpriteFrameType.Rgb24 ? 3 : 4;
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace OpenRA.FileFormats
|
||||
Height = IPAddress.NetworkToHostOrder(ms.ReadInt32());
|
||||
|
||||
var bitDepth = ms.ReadUInt8();
|
||||
var colorType = (PngColorType)ms.ReadByte();
|
||||
var colorType = (PngColorType)ms.ReadUInt8();
|
||||
if (IsPaletted(bitDepth, colorType))
|
||||
Type = SpriteFrameType.Indexed8;
|
||||
else if (colorType == PngColorType.Color)
|
||||
@@ -75,9 +75,9 @@ namespace OpenRA.FileFormats
|
||||
|
||||
Data = new byte[Width * Height * PixelStride];
|
||||
|
||||
var compression = ms.ReadByte();
|
||||
/*var filter = */ms.ReadByte();
|
||||
var interlace = ms.ReadByte();
|
||||
var compression = ms.ReadUInt8();
|
||||
/*var filter = */ms.ReadUInt8();
|
||||
var interlace = ms.ReadUInt8();
|
||||
|
||||
if (compression != 0)
|
||||
throw new InvalidDataException("Compression method not supported");
|
||||
@@ -95,7 +95,7 @@ namespace OpenRA.FileFormats
|
||||
Palette = new Color[256];
|
||||
for (var i = 0; i < length / 3; i++)
|
||||
{
|
||||
var r = ms.ReadByte(); var g = ms.ReadByte(); var b = ms.ReadByte();
|
||||
var r = ms.ReadUInt8(); var g = ms.ReadUInt8(); var b = ms.ReadUInt8();
|
||||
Palette[i] = Color.FromArgb(r, g, b);
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ namespace OpenRA.FileFormats
|
||||
throw new InvalidDataException("Non-Palette indexed PNG are not supported.");
|
||||
|
||||
for (var i = 0; i < length; i++)
|
||||
Palette[i] = Color.FromArgb(ms.ReadByte(), Palette[i]);
|
||||
Palette[i] = Color.FromArgb(ms.ReadUInt8(), Palette[i]);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -137,21 +137,56 @@ namespace OpenRA.FileFormats
|
||||
var pxStride = PixelStride;
|
||||
var rowStride = Width * pxStride;
|
||||
|
||||
var prevLine = new byte[rowStride];
|
||||
Span<byte> prevLine = new byte[rowStride];
|
||||
for (var y = 0; y < Height; y++)
|
||||
{
|
||||
var filter = (PngFilter)ds.ReadByte();
|
||||
var line = ds.ReadBytes(rowStride);
|
||||
var filter = (PngFilter)ds.ReadUInt8();
|
||||
ds.ReadBytes(Data, y * rowStride, rowStride);
|
||||
var line = Data.AsSpan(y * rowStride, rowStride);
|
||||
|
||||
for (var i = 0; i < rowStride; i++)
|
||||
line[i] = i < pxStride
|
||||
? UnapplyFilter(filter, line[i], 0, prevLine[i], 0)
|
||||
: UnapplyFilter(filter, line[i], line[i - pxStride], prevLine[i], prevLine[i - pxStride]);
|
||||
|
||||
Array.Copy(line, 0, Data, y * rowStride, rowStride);
|
||||
switch (filter)
|
||||
{
|
||||
case PngFilter.None:
|
||||
break;
|
||||
case PngFilter.Sub:
|
||||
for (var i = pxStride; i < rowStride; i++)
|
||||
line[i] += line[i - pxStride];
|
||||
break;
|
||||
case PngFilter.Up:
|
||||
for (var i = 0; i < rowStride; i++)
|
||||
line[i] += prevLine[i];
|
||||
break;
|
||||
case PngFilter.Average:
|
||||
for (var i = 0; i < pxStride; i++)
|
||||
line[i] += Average(0, prevLine[i]);
|
||||
for (var i = pxStride; i < rowStride; i++)
|
||||
line[i] += Average(line[i - pxStride], prevLine[i]);
|
||||
break;
|
||||
case PngFilter.Paeth:
|
||||
for (var i = 0; i < pxStride; i++)
|
||||
line[i] += Paeth(0, prevLine[i], 0);
|
||||
for (var i = pxStride; i < rowStride; i++)
|
||||
line[i] += Paeth(line[i - pxStride], prevLine[i], prevLine[i - pxStride]);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException("Unsupported Filter");
|
||||
}
|
||||
|
||||
prevLine = line;
|
||||
}
|
||||
|
||||
static byte Average(byte a, byte b) => (byte)((a + b) / 2);
|
||||
|
||||
static byte Paeth(byte a, byte b, byte c)
|
||||
{
|
||||
var p = a + b - c;
|
||||
var pa = Math.Abs(p - a);
|
||||
var pb = Math.Abs(p - b);
|
||||
var pc = Math.Abs(p - c);
|
||||
|
||||
return (pa <= pb && pa <= pc) ? a :
|
||||
(pb <= pc) ? b : c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,34 +263,9 @@ namespace OpenRA.FileFormats
|
||||
return isPng;
|
||||
}
|
||||
|
||||
static byte UnapplyFilter(PngFilter f, byte x, byte a, byte b, byte c)
|
||||
{
|
||||
switch (f)
|
||||
{
|
||||
case PngFilter.None: return x;
|
||||
case PngFilter.Sub: return (byte)(x + a);
|
||||
case PngFilter.Up: return (byte)(x + b);
|
||||
case PngFilter.Average: return (byte)(x + (a + b) / 2);
|
||||
case PngFilter.Paeth: return (byte)(x + Paeth(a, b, c));
|
||||
default:
|
||||
throw new InvalidOperationException("Unsupported Filter");
|
||||
}
|
||||
}
|
||||
|
||||
static byte Paeth(byte a, byte b, byte c)
|
||||
{
|
||||
var p = a + b - c;
|
||||
var pa = Math.Abs(p - a);
|
||||
var pb = Math.Abs(p - b);
|
||||
var pc = Math.Abs(p - c);
|
||||
|
||||
return (pa <= pb && pa <= pc) ? a :
|
||||
(pb <= pc) ? b : c;
|
||||
}
|
||||
|
||||
[Flags]
|
||||
enum PngColorType { Indexed = 1, Color = 2, Alpha = 4 }
|
||||
enum PngFilter { None, Sub, Up, Average, Paeth }
|
||||
enum PngColorType : byte { Indexed = 1, Color = 2, Alpha = 4 }
|
||||
enum PngFilter : byte { None, Sub, Up, Average, Paeth }
|
||||
|
||||
static bool IsPaletted(byte bitDepth, PngColorType colorType)
|
||||
{
|
||||
@@ -271,7 +281,7 @@ namespace OpenRA.FileFormats
|
||||
throw new InvalidDataException("Unknown pixel format");
|
||||
}
|
||||
|
||||
void WritePngChunk(Stream output, string type, Stream input)
|
||||
static void WritePngChunk(Stream output, string type, Stream input)
|
||||
{
|
||||
input.Position = 0;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -29,16 +29,16 @@ namespace OpenRA.FileSystem
|
||||
public class FileSystem : IReadOnlyFileSystem
|
||||
{
|
||||
public IEnumerable<IReadOnlyPackage> MountedPackages => mountedPackages.Keys;
|
||||
readonly Dictionary<IReadOnlyPackage, int> mountedPackages = new Dictionary<IReadOnlyPackage, int>();
|
||||
readonly Dictionary<string, IReadOnlyPackage> explicitMounts = new Dictionary<string, IReadOnlyPackage>();
|
||||
readonly Dictionary<IReadOnlyPackage, int> mountedPackages = new();
|
||||
readonly Dictionary<string, IReadOnlyPackage> explicitMounts = new();
|
||||
readonly string modID;
|
||||
|
||||
// Mod packages that should not be disposed
|
||||
readonly List<IReadOnlyPackage> modPackages = new List<IReadOnlyPackage>();
|
||||
readonly List<IReadOnlyPackage> modPackages = new();
|
||||
readonly IReadOnlyDictionary<string, Manifest> installedMods;
|
||||
readonly IPackageLoader[] packageLoaders;
|
||||
|
||||
Cache<string, List<IReadOnlyPackage>> fileIndex = new Cache<string, List<IReadOnlyPackage>>(_ => new List<IReadOnlyPackage>());
|
||||
Cache<string, List<IReadOnlyPackage>> fileIndex = new(_ => new List<IReadOnlyPackage>());
|
||||
|
||||
public FileSystem(string modID, IReadOnlyDictionary<string, Manifest> installedMods, IPackageLoader[] packageLoaders)
|
||||
{
|
||||
@@ -85,14 +85,14 @@ namespace OpenRA.FileSystem
|
||||
{
|
||||
var optional = name.StartsWith("~", StringComparison.Ordinal);
|
||||
if (optional)
|
||||
name = name.Substring(1);
|
||||
name = name[1..];
|
||||
|
||||
try
|
||||
{
|
||||
IReadOnlyPackage package;
|
||||
if (name.StartsWith("$", StringComparison.Ordinal))
|
||||
{
|
||||
name = name.Substring(1);
|
||||
name = name[1..];
|
||||
|
||||
if (!installedMods.TryGetValue(name, out var mod))
|
||||
throw new InvalidOperationException($"Could not load mod '{name}'. Available mods: {installedMods.Keys.JoinWith(", ")}");
|
||||
@@ -211,9 +211,9 @@ namespace OpenRA.FileSystem
|
||||
public bool TryGetPackageContaining(string path, out IReadOnlyPackage package, out string filename)
|
||||
{
|
||||
var explicitSplit = path.IndexOf('|');
|
||||
if (explicitSplit > 0 && explicitMounts.TryGetValue(path.Substring(0, explicitSplit), out package))
|
||||
if (explicitSplit > 0 && explicitMounts.TryGetValue(path[..explicitSplit], out package))
|
||||
{
|
||||
filename = path.Substring(explicitSplit + 1);
|
||||
filename = path[(explicitSplit + 1)..];
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -228,9 +228,9 @@ namespace OpenRA.FileSystem
|
||||
var explicitSplit = filename.IndexOf('|');
|
||||
if (explicitSplit > 0)
|
||||
{
|
||||
if (explicitMounts.TryGetValue(filename.Substring(0, explicitSplit), out var explicitPackage))
|
||||
if (explicitMounts.TryGetValue(filename[..explicitSplit], out var explicitPackage))
|
||||
{
|
||||
s = explicitPackage.GetStream(filename.Substring(explicitSplit + 1));
|
||||
s = explicitPackage.GetStream(filename[(explicitSplit + 1)..]);
|
||||
if (s != null)
|
||||
return true;
|
||||
}
|
||||
@@ -263,15 +263,15 @@ namespace OpenRA.FileSystem
|
||||
{
|
||||
var explicitSplit = filename.IndexOf('|');
|
||||
if (explicitSplit > 0)
|
||||
if (explicitMounts.TryGetValue(filename.Substring(0, explicitSplit), out var explicitPackage))
|
||||
if (explicitPackage.Contains(filename.Substring(explicitSplit + 1)))
|
||||
if (explicitMounts.TryGetValue(filename[..explicitSplit], out var explicitPackage))
|
||||
if (explicitPackage.Contains(filename[(explicitSplit + 1)..]))
|
||||
return true;
|
||||
|
||||
return fileIndex.ContainsKey(filename);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given filename references an external mod via an explicit mount
|
||||
/// Returns true if the given filename references an external mod via an explicit mount.
|
||||
/// </summary>
|
||||
public bool IsExternalModFile(string filename)
|
||||
{
|
||||
@@ -279,7 +279,7 @@ namespace OpenRA.FileSystem
|
||||
if (explicitSplit < 0)
|
||||
return false;
|
||||
|
||||
if (!explicitMounts.TryGetValue(filename.Substring(0, explicitSplit), out var explicitPackage))
|
||||
if (!explicitMounts.TryGetValue(filename[..explicitSplit], out var explicitPackage))
|
||||
return false;
|
||||
|
||||
if (installedMods[modID].Package == explicitPackage)
|
||||
@@ -297,8 +297,8 @@ namespace OpenRA.FileSystem
|
||||
var explicitSplit = path.IndexOf('|');
|
||||
if (explicitSplit > 0 && !path.StartsWith("^"))
|
||||
{
|
||||
var parent = path.Substring(0, explicitSplit);
|
||||
var filename = path.Substring(explicitSplit + 1);
|
||||
var parent = path[..explicitSplit];
|
||||
var filename = path[(explicitSplit + 1)..];
|
||||
|
||||
var parentPath = manifest.Packages.FirstOrDefault(kv => kv.Value == parent).Key;
|
||||
if (parentPath == null)
|
||||
@@ -306,10 +306,10 @@ namespace OpenRA.FileSystem
|
||||
|
||||
if (parentPath.StartsWith("$", StringComparison.Ordinal))
|
||||
{
|
||||
if (!installedMods.TryGetValue(parentPath.Substring(1), out var mod))
|
||||
if (!installedMods.TryGetValue(parentPath[1..], out var mod))
|
||||
return null;
|
||||
|
||||
if (!(mod.Package is Folder))
|
||||
if (mod.Package is not Folder)
|
||||
return null;
|
||||
|
||||
path = Path.Combine(mod.Package.Name, filename);
|
||||
@@ -322,6 +322,28 @@ namespace OpenRA.FileSystem
|
||||
return File.Exists(resolvedPath) ? resolvedPath : null;
|
||||
}
|
||||
|
||||
public static string ResolveCaseInsensitivePath(string path)
|
||||
{
|
||||
var resolved = Path.GetPathRoot(path);
|
||||
|
||||
if (resolved == null)
|
||||
return null;
|
||||
|
||||
foreach (var name in path[resolved.Length..].Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar))
|
||||
{
|
||||
// Filter out paths of the form /foo/bar/./baz
|
||||
if (name == ".")
|
||||
continue;
|
||||
|
||||
resolved = Directory.GetFileSystemEntries(resolved).FirstOrDefault(e => e.Equals(Path.Combine(resolved, name), StringComparison.InvariantCultureIgnoreCase));
|
||||
|
||||
if (resolved == null)
|
||||
return null;
|
||||
}
|
||||
|
||||
return resolved;
|
||||
}
|
||||
|
||||
public string GetPrefix(IReadOnlyPackage package)
|
||||
{
|
||||
return explicitMounts.ContainsValue(package) ? explicitMounts.First(f => f.Value == package).Key : null;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -18,24 +18,22 @@ namespace OpenRA.FileSystem
|
||||
{
|
||||
public sealed class Folder : IReadWritePackage
|
||||
{
|
||||
readonly string path;
|
||||
public string Name { get; }
|
||||
|
||||
public Folder(string path)
|
||||
{
|
||||
this.path = path;
|
||||
Name = path;
|
||||
if (!Directory.Exists(path))
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
|
||||
public string Name => path;
|
||||
|
||||
public IEnumerable<string> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
// Order may vary on different file systems and it matters for hashing.
|
||||
return Directory.GetFiles(path, "*", SearchOption.TopDirectoryOnly)
|
||||
.Concat(Directory.GetDirectories(path))
|
||||
return Directory.GetFiles(Name, "*", SearchOption.TopDirectoryOnly)
|
||||
.Concat(Directory.GetDirectories(Name))
|
||||
.Select(Path.GetFileName)
|
||||
.OrderBy(f => f);
|
||||
}
|
||||
@@ -43,14 +41,14 @@ namespace OpenRA.FileSystem
|
||||
|
||||
public Stream GetStream(string filename)
|
||||
{
|
||||
try { return File.OpenRead(Path.Combine(path, filename)); }
|
||||
try { return File.OpenRead(Path.Combine(Name, filename)); }
|
||||
catch { return null; }
|
||||
}
|
||||
|
||||
public bool Contains(string filename)
|
||||
{
|
||||
var combined = Path.Combine(path, filename);
|
||||
return combined.StartsWith(path, StringComparison.Ordinal) && File.Exists(combined);
|
||||
var combined = Path.Combine(Name, filename);
|
||||
return combined.StartsWith(Name, StringComparison.Ordinal) && File.Exists(combined);
|
||||
}
|
||||
|
||||
public IReadOnlyPackage OpenPackage(string filename, FileSystem context)
|
||||
@@ -82,7 +80,7 @@ namespace OpenRA.FileSystem
|
||||
// in FileSystem.OpenPackage. Their internal name therefore contains the
|
||||
// full parent path too. We need to be careful to not add a second path
|
||||
// prefix to these hacked packages.
|
||||
var filePath = filename.StartsWith(path) ? filename : Path.Combine(path, filename);
|
||||
var filePath = filename.StartsWith(Name) ? filename : Path.Combine(Name, filename);
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(filePath));
|
||||
using (var s = File.Create(filePath))
|
||||
@@ -96,7 +94,7 @@ namespace OpenRA.FileSystem
|
||||
// in FileSystem.OpenPackage. Their internal name therefore contains the
|
||||
// full parent path too. We need to be careful to not add a second path
|
||||
// prefix to these hacked packages.
|
||||
var filePath = filename.StartsWith(path) ? filename : Path.Combine(path, filename);
|
||||
var filePath = filename.StartsWith(Name) ? filename : Path.Combine(Name, filename);
|
||||
if (Directory.Exists(filePath))
|
||||
Directory.Delete(filePath, true);
|
||||
else if (File.Exists(filePath))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -19,7 +19,7 @@ namespace OpenRA.FileSystem
|
||||
{
|
||||
public class ZipFileLoader : IPackageLoader
|
||||
{
|
||||
static readonly string[] Extensions = { ".zip", ".oramap" };
|
||||
const uint ZipSignature = 0x04034b50;
|
||||
|
||||
class ReadOnlyZipFile : IReadOnlyPackage
|
||||
{
|
||||
@@ -55,7 +55,8 @@ namespace OpenRA.FileSystem
|
||||
get
|
||||
{
|
||||
foreach (ZipEntry entry in pkg)
|
||||
yield return entry.Name;
|
||||
if (entry.IsFile)
|
||||
yield return entry.Name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +95,7 @@ namespace OpenRA.FileSystem
|
||||
|
||||
sealed class ReadWriteZipFile : ReadOnlyZipFile, IReadWritePackage
|
||||
{
|
||||
readonly MemoryStream pkgStream = new MemoryStream();
|
||||
readonly MemoryStream pkgStream = new();
|
||||
|
||||
public ReadWriteZipFile(string filename, bool create = false)
|
||||
{
|
||||
@@ -141,23 +142,22 @@ namespace OpenRA.FileSystem
|
||||
|
||||
sealed class ZipFolder : IReadOnlyPackage
|
||||
{
|
||||
public string Name => path;
|
||||
public string Name { get; }
|
||||
public ReadOnlyZipFile Parent { get; }
|
||||
readonly string path;
|
||||
|
||||
public ZipFolder(ReadOnlyZipFile parent, string path)
|
||||
{
|
||||
if (path.EndsWith("/", StringComparison.Ordinal))
|
||||
path = path.Substring(0, path.Length - 1);
|
||||
path = path[..^1];
|
||||
|
||||
Name = path;
|
||||
Parent = parent;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public Stream GetStream(string filename)
|
||||
{
|
||||
// Zip files use '/' as a path separator
|
||||
return Parent.GetStream(path + '/' + filename);
|
||||
return Parent.GetStream(Name + '/' + filename);
|
||||
}
|
||||
|
||||
public IEnumerable<string> Contents
|
||||
@@ -166,9 +166,9 @@ namespace OpenRA.FileSystem
|
||||
{
|
||||
foreach (var entry in Parent.Contents)
|
||||
{
|
||||
if (entry.StartsWith(path, StringComparison.Ordinal) && entry != path)
|
||||
if (entry.StartsWith(Name, StringComparison.Ordinal) && entry != Name)
|
||||
{
|
||||
var filename = entry.Substring(path.Length + 1);
|
||||
var filename = entry[(Name.Length + 1)..];
|
||||
var dirLevels = filename.Split('/').Count(c => !string.IsNullOrEmpty(c));
|
||||
if (dirLevels == 1)
|
||||
yield return filename;
|
||||
@@ -179,18 +179,18 @@ namespace OpenRA.FileSystem
|
||||
|
||||
public bool Contains(string filename)
|
||||
{
|
||||
return Parent.Contains(path + '/' + filename);
|
||||
return Parent.Contains(Name + '/' + filename);
|
||||
}
|
||||
|
||||
public IReadOnlyPackage OpenPackage(string filename, FileSystem context)
|
||||
{
|
||||
return Parent.OpenPackage(path + '/' + filename, context);
|
||||
return Parent.OpenPackage(Name + '/' + filename, context);
|
||||
}
|
||||
|
||||
public void Dispose() { /* nothing to do */ }
|
||||
}
|
||||
|
||||
class StaticStreamDataSource : IStaticDataSource
|
||||
sealed class StaticStreamDataSource : IStaticDataSource
|
||||
{
|
||||
readonly Stream s;
|
||||
public StaticStreamDataSource(Stream s)
|
||||
@@ -206,7 +206,10 @@ namespace OpenRA.FileSystem
|
||||
|
||||
public bool TryParsePackage(Stream s, string filename, FileSystem context, out IReadOnlyPackage package)
|
||||
{
|
||||
if (!Extensions.Any(e => filename.EndsWith(e, StringComparison.InvariantCultureIgnoreCase)))
|
||||
var readSignature = s.ReadUInt32();
|
||||
s.Position -= 4;
|
||||
|
||||
if (readSignature != ZipSignature)
|
||||
{
|
||||
package = null;
|
||||
return false;
|
||||
@@ -218,10 +221,13 @@ namespace OpenRA.FileSystem
|
||||
|
||||
public static bool TryParseReadWritePackage(string filename, out IReadWritePackage package)
|
||||
{
|
||||
if (!Extensions.Any(e => filename.EndsWith(e, StringComparison.InvariantCultureIgnoreCase)))
|
||||
using (var s = File.OpenRead(filename))
|
||||
{
|
||||
package = null;
|
||||
return false;
|
||||
if (s.ReadUInt32() != ZipSignature)
|
||||
{
|
||||
package = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
package = new ReadWriteZipFile(filename);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -29,6 +29,9 @@ namespace OpenRA
|
||||
{
|
||||
public static class Game
|
||||
{
|
||||
[TranslationReference("filename")]
|
||||
const string SavedScreenshot = "notification-saved-screenshot";
|
||||
|
||||
public const int TimestepJankThreshold = 250; // Don't catch up for delays larger than 250ms
|
||||
|
||||
public static InstalledMods Mods { get; private set; }
|
||||
@@ -45,7 +48,7 @@ namespace OpenRA
|
||||
internal static OrderManager OrderManager;
|
||||
static Server.Server server;
|
||||
|
||||
public static MersenneTwister CosmeticRandom = new MersenneTwister(); // not synced
|
||||
public static MersenneTwister CosmeticRandom = new(); // not synced
|
||||
|
||||
public static Renderer Renderer;
|
||||
public static Sound Sound;
|
||||
@@ -62,7 +65,7 @@ namespace OpenRA
|
||||
{
|
||||
var newConnection = new NetworkConnection(endpoint);
|
||||
if (recordReplay)
|
||||
newConnection.StartRecording(() => { return TimestampedFilename(); });
|
||||
newConnection.StartRecording(() => TimestampedFilename());
|
||||
|
||||
var om = new OrderManager(newConnection);
|
||||
JoinInner(om);
|
||||
@@ -184,13 +187,8 @@ namespace OpenRA
|
||||
Cursor.SetCursor(null);
|
||||
BeforeGameStart();
|
||||
|
||||
Map map;
|
||||
|
||||
using (new PerfTimer("PrepareMap"))
|
||||
map = ModData.PrepareMap(mapUID);
|
||||
|
||||
using (new PerfTimer("NewWorld"))
|
||||
OrderManager.World = new World(ModData, map, OrderManager, type);
|
||||
OrderManager.World = new World(mapUID, ModData, OrderManager, type);
|
||||
|
||||
OrderManager.World.GameOver += FinishBenchmark;
|
||||
|
||||
@@ -267,15 +265,14 @@ namespace OpenRA
|
||||
{
|
||||
OrderManager om = null;
|
||||
|
||||
Action lobbyReady = null;
|
||||
lobbyReady = () =>
|
||||
void LobbyReady()
|
||||
{
|
||||
LobbyInfoChanged -= lobbyReady;
|
||||
LobbyInfoChanged -= LobbyReady;
|
||||
foreach (var o in setupOrders)
|
||||
om.IssueOrder(o);
|
||||
};
|
||||
}
|
||||
|
||||
LobbyInfoChanged += lobbyReady;
|
||||
LobbyInfoChanged += LobbyReady;
|
||||
|
||||
om = JoinServer(CreateLocalServer(mapUID), "");
|
||||
}
|
||||
@@ -318,7 +315,7 @@ namespace OpenRA
|
||||
if (!string.IsNullOrEmpty(supportDirArg))
|
||||
Platform.OverrideSupportDir(supportDirArg);
|
||||
|
||||
Console.WriteLine($"Platform is {Platform.CurrentPlatform}");
|
||||
Console.WriteLine($"Platform is {Platform.CurrentPlatform} ({Platform.CurrentArchitecture})");
|
||||
|
||||
// Load the engine version as early as possible so it can be written to exception logs
|
||||
try
|
||||
@@ -419,7 +416,7 @@ namespace OpenRA
|
||||
// Sanitize input from platform-specific launchers
|
||||
// Process.Start requires paths to not be quoted, even if they contain spaces
|
||||
if (launchPath != null && launchPath.First() == '"' && launchPath.Last() == '"')
|
||||
launchPath = launchPath.Substring(1, launchPath.Length - 2);
|
||||
launchPath = launchPath[1..^1];
|
||||
|
||||
// Metadata registration requires an explicit launch path
|
||||
if (launchPath != null)
|
||||
@@ -566,14 +563,11 @@ namespace OpenRA
|
||||
|
||||
// Note: These delayed actions should only be used by widgets or disposing objects
|
||||
// - things that depend on a particular world should be queuing them on the world actor.
|
||||
static volatile ActionQueue delayedActions = new ActionQueue();
|
||||
static volatile ActionQueue delayedActions = new();
|
||||
|
||||
public static void RunAfterTick(Action a) { delayedActions.Add(a, RunTime); }
|
||||
public static void RunAfterDelay(int delayMilliseconds, Action a) { delayedActions.Add(a, RunTime + delayMilliseconds); }
|
||||
|
||||
[TranslationReference("filename")]
|
||||
static readonly string SavedScreenshot = "saved-screenshot";
|
||||
|
||||
static void TakeScreenshotInner()
|
||||
{
|
||||
using (new PerfTimer("Renderer.SaveScreenshot"))
|
||||
@@ -587,7 +581,7 @@ namespace OpenRA
|
||||
Log.Write("debug", "Taking screenshot " + path);
|
||||
|
||||
Renderer.SaveScreenshot(path);
|
||||
TextNotificationsManager.Debug(ModData.Translation.GetString(SavedScreenshot, Translation.Arguments("filename", filename)));
|
||||
TextNotificationsManager.Debug(TranslationProvider.GetString(SavedScreenshot, Translation.Arguments("filename", filename)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -619,10 +613,7 @@ namespace OpenRA
|
||||
|
||||
if (orderManager.TryTick())
|
||||
{
|
||||
Sync.RunUnsynced(world, () =>
|
||||
{
|
||||
world.OrderGenerator.Tick(world);
|
||||
});
|
||||
Sync.RunUnsynced(world, () => world.OrderGenerator.Tick(world));
|
||||
|
||||
world.Tick();
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -36,7 +36,7 @@ namespace OpenRA
|
||||
public TimeSpan Duration => EndTimeUtc > StartTimeUtc ? EndTimeUtc - StartTimeUtc : TimeSpan.Zero;
|
||||
|
||||
public IList<Player> Players { get; }
|
||||
public HashSet<int> DisabledSpawnPoints = new HashSet<int>();
|
||||
public HashSet<int> DisabledSpawnPoints = new();
|
||||
public MapPreview MapPreview => Game.ModData.MapCache[MapUid];
|
||||
public IEnumerable<Player> HumanPlayers { get { return Players.Where(p => p.IsHuman); } }
|
||||
public bool IsSinglePlayer => HumanPlayers.Count() == 1;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -32,7 +32,7 @@ namespace OpenRA
|
||||
/// You can remove inherited traits by adding a - in front of them as in -TraitName: to inherit everything, but this trait.
|
||||
/// </summary>
|
||||
public readonly string Name;
|
||||
readonly TypeDictionary traits = new TypeDictionary();
|
||||
readonly TypeDictionary traits = new();
|
||||
List<TraitInfo> constructOrderCache = null;
|
||||
|
||||
public ActorInfo(ObjectCreator creator, string name, MiniYaml node)
|
||||
@@ -115,39 +115,46 @@ namespace OpenRA
|
||||
}).ToList();
|
||||
|
||||
var resolved = source.Where(s => s.Dependencies.Count == 0 && s.OptionalDependencies.Count == 0).ToList();
|
||||
var unresolved = source.Except(resolved);
|
||||
var unresolved = source.ToHashSet();
|
||||
unresolved.ExceptWith(resolved);
|
||||
|
||||
var testResolve = new Func<Type, Type, bool>((a, b) => a == b || a.IsAssignableFrom(b));
|
||||
static bool AreResolvable(Type a, Type b) => a.IsAssignableFrom(b);
|
||||
|
||||
// This query detects which unresolved traits can be immediately resolved as all their direct dependencies are met.
|
||||
var more = unresolved.Where(u =>
|
||||
u.Dependencies.All(d => // To be resolvable, all dependencies must be satisfied according to the following conditions:
|
||||
resolved.Exists(r => testResolve(d, r.Type)) && // There must exist a resolved trait that meets the dependency.
|
||||
!unresolved.Any(u1 => testResolve(d, u1.Type))) && // All matching traits that meet this dependency must be resolved first.
|
||||
resolved.Exists(r => AreResolvable(d, r.Type)) && // There must exist a resolved trait that meets the dependency.
|
||||
!unresolved.Any(u1 => AreResolvable(d, u1.Type))) && // All matching traits that meet this dependency must be resolved first.
|
||||
u.OptionalDependencies.All(d => // To be resolvable, all optional dependencies must be satisfied according to the following condition:
|
||||
!unresolved.Any(u1 => testResolve(d, u1.Type)))); // All matching traits that meet this optional dependencies must be resolved first.
|
||||
!unresolved.Any(u1 => AreResolvable(d, u1.Type)))); // All matching traits that meet this optional dependencies must be resolved first.
|
||||
|
||||
// Continue resolving traits as long as possible.
|
||||
// Each time we resolve some traits, this means dependencies for other traits may then be possible to satisfy in the next pass.
|
||||
while (more.Any())
|
||||
resolved.AddRange(more);
|
||||
|
||||
if (unresolved.Any())
|
||||
var readyToResolve = more.ToList();
|
||||
while (readyToResolve.Count != 0)
|
||||
{
|
||||
var exceptionString = "ActorInfo(\"" + Name + "\") failed to initialize because of the following:\r\n";
|
||||
var missing = unresolved.SelectMany(u => u.Dependencies.Where(d => !source.Any(s => testResolve(d, s.Type)))).Distinct();
|
||||
resolved.AddRange(readyToResolve);
|
||||
unresolved.ExceptWith(readyToResolve);
|
||||
readyToResolve.Clear();
|
||||
readyToResolve.AddRange(more);
|
||||
}
|
||||
|
||||
exceptionString += "Missing:\r\n";
|
||||
if (unresolved.Count != 0)
|
||||
{
|
||||
var exceptionString = "ActorInfo(\"" + Name + "\") failed to initialize because of the following:\n";
|
||||
var missing = unresolved.SelectMany(u => u.Dependencies.Where(d => !source.Any(s => AreResolvable(d, s.Type)))).Distinct();
|
||||
|
||||
exceptionString += "Missing:\n";
|
||||
foreach (var m in missing)
|
||||
exceptionString += m + " \r\n";
|
||||
exceptionString += m + " \n";
|
||||
|
||||
exceptionString += "Unresolved:\r\n";
|
||||
exceptionString += "Unresolved:\n";
|
||||
foreach (var u in unresolved)
|
||||
{
|
||||
var deps = u.Dependencies.Where(d => !resolved.Exists(r => r.Type == d));
|
||||
var optDeps = u.OptionalDependencies.Where(d => !resolved.Exists(r => r.Type == d));
|
||||
var allDeps = string.Join(", ", deps.Select(o => o.ToString()).Concat(optDeps.Select(o => $"[{o}]")));
|
||||
exceptionString += $"{u.Type}: {{ {allDeps} }}\r\n";
|
||||
exceptionString += $"{u.Type}: {{ {allDeps} }}\n";
|
||||
}
|
||||
|
||||
throw new YamlException(exceptionString);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -28,14 +28,14 @@ namespace OpenRA.GameRules
|
||||
Title = value.Value;
|
||||
|
||||
var nd = value.ToDictionary();
|
||||
if (nd.ContainsKey("Hidden"))
|
||||
bool.TryParse(nd["Hidden"].Value, out Hidden);
|
||||
if (nd.TryGetValue("Hidden", out var yaml))
|
||||
bool.TryParse(yaml.Value, out Hidden);
|
||||
|
||||
if (nd.ContainsKey("VolumeModifier"))
|
||||
VolumeModifier = FieldLoader.GetValue<float>("VolumeModifier", nd["VolumeModifier"].Value);
|
||||
if (nd.TryGetValue("VolumeModifier", out yaml))
|
||||
VolumeModifier = FieldLoader.GetValue<float>("VolumeModifier", yaml.Value);
|
||||
|
||||
var ext = nd.ContainsKey("Extension") ? nd["Extension"].Value : "aud";
|
||||
Filename = (nd.ContainsKey("Filename") ? nd["Filename"].Value : key) + "." + ext;
|
||||
var ext = nd.TryGetValue("Extension", out yaml) ? yaml.Value : "aud";
|
||||
Filename = (nd.TryGetValue("Filename", out yaml) ? yaml.Value : key) + "." + ext;
|
||||
}
|
||||
|
||||
public void Load(IReadOnlyFileSystem fileSystem)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -15,7 +15,6 @@ using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using OpenRA.FileSystem;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA
|
||||
@@ -28,7 +27,6 @@ namespace OpenRA
|
||||
public readonly IReadOnlyDictionary<string, SoundInfo> Notifications;
|
||||
public readonly IReadOnlyDictionary<string, MusicInfo> Music;
|
||||
public readonly ITerrainInfo TerrainInfo;
|
||||
public readonly SequenceProvider Sequences;
|
||||
public readonly IReadOnlyDictionary<string, MiniYamlNode> ModelSequences;
|
||||
|
||||
public Ruleset(
|
||||
@@ -38,7 +36,6 @@ namespace OpenRA
|
||||
IReadOnlyDictionary<string, SoundInfo> notifications,
|
||||
IReadOnlyDictionary<string, MusicInfo> music,
|
||||
ITerrainInfo terrainInfo,
|
||||
SequenceProvider sequences,
|
||||
IReadOnlyDictionary<string, MiniYamlNode> modelSequences)
|
||||
{
|
||||
Actors = new ActorInfoDictionary(actors);
|
||||
@@ -47,7 +44,6 @@ namespace OpenRA
|
||||
Notifications = notifications;
|
||||
Music = music;
|
||||
TerrainInfo = terrainInfo;
|
||||
Sequences = sequences;
|
||||
ModelSequences = modelSequences;
|
||||
|
||||
foreach (var a in Actors.Values)
|
||||
@@ -124,7 +120,7 @@ namespace OpenRA
|
||||
var fs = modData.DefaultFileSystem;
|
||||
|
||||
Ruleset ruleset = null;
|
||||
Action f = () =>
|
||||
void LoadRuleset()
|
||||
{
|
||||
var actors = MergeOrDefault("Manifest,Rules", fs, m.Rules, null, null,
|
||||
k => new ActorInfo(modData.ObjectCreator, k.Key.ToLowerInvariant(), k.Value),
|
||||
@@ -145,15 +141,15 @@ namespace OpenRA
|
||||
var modelSequences = MergeOrDefault("Manifest,ModelSequences", fs, m.ModelSequences, null, null,
|
||||
k => k);
|
||||
|
||||
// The default ruleset does not include a preferred tileset or sequence set
|
||||
ruleset = new Ruleset(actors, weapons, voices, notifications, music, null, null, modelSequences);
|
||||
};
|
||||
// The default ruleset does not include a preferred tileset
|
||||
ruleset = new Ruleset(actors, weapons, voices, notifications, music, null, modelSequences);
|
||||
}
|
||||
|
||||
if (modData.IsOnMainThread)
|
||||
{
|
||||
modData.HandleLoadingProgress();
|
||||
|
||||
var loader = new Task(f);
|
||||
var loader = new Task(LoadRuleset);
|
||||
loader.Start();
|
||||
|
||||
// Animate the loadscreen while we wait
|
||||
@@ -161,7 +157,7 @@ namespace OpenRA
|
||||
modData.HandleLoadingProgress();
|
||||
}
|
||||
else
|
||||
f();
|
||||
LoadRuleset();
|
||||
|
||||
return ruleset;
|
||||
}
|
||||
@@ -170,20 +166,19 @@ namespace OpenRA
|
||||
{
|
||||
var dr = modData.DefaultRules;
|
||||
var terrainInfo = modData.DefaultTerrainInfo[tileSet];
|
||||
var sequences = modData.DefaultSequences[tileSet];
|
||||
|
||||
return new Ruleset(dr.Actors, dr.Weapons, dr.Voices, dr.Notifications, dr.Music, terrainInfo, sequences, dr.ModelSequences);
|
||||
return new Ruleset(dr.Actors, dr.Weapons, dr.Voices, dr.Notifications, dr.Music, terrainInfo, dr.ModelSequences);
|
||||
}
|
||||
|
||||
public static Ruleset Load(ModData modData, IReadOnlyFileSystem fileSystem, string tileSet,
|
||||
MiniYaml mapRules, MiniYaml mapWeapons, MiniYaml mapVoices, MiniYaml mapNotifications,
|
||||
MiniYaml mapMusic, MiniYaml mapSequences, MiniYaml mapModelSequences)
|
||||
MiniYaml mapMusic, MiniYaml mapModelSequences)
|
||||
{
|
||||
var m = modData.Manifest;
|
||||
var dr = modData.DefaultRules;
|
||||
|
||||
Ruleset ruleset = null;
|
||||
Action f = () =>
|
||||
void LoadRuleset()
|
||||
{
|
||||
var actors = MergeOrDefault("Rules", fileSystem, m.Rules, mapRules, dr.Actors,
|
||||
k => new ActorInfo(modData.ObjectCreator, k.Key.ToLowerInvariant(), k.Value),
|
||||
@@ -204,23 +199,19 @@ namespace OpenRA
|
||||
// TODO: Add support for merging custom terrain modifications
|
||||
var terrainInfo = modData.DefaultTerrainInfo[tileSet];
|
||||
|
||||
// TODO: Top-level dictionary should be moved into the Ruleset instead of in its own object
|
||||
var sequences = mapSequences == null ? modData.DefaultSequences[tileSet] :
|
||||
new SequenceProvider(fileSystem, modData, tileSet, mapSequences);
|
||||
|
||||
var modelSequences = dr.ModelSequences;
|
||||
if (mapModelSequences != null)
|
||||
modelSequences = MergeOrDefault("ModelSequences", fileSystem, m.ModelSequences, mapModelSequences, dr.ModelSequences,
|
||||
k => k);
|
||||
|
||||
ruleset = new Ruleset(actors, weapons, voices, notifications, music, terrainInfo, sequences, modelSequences);
|
||||
};
|
||||
ruleset = new Ruleset(actors, weapons, voices, notifications, music, terrainInfo, modelSequences);
|
||||
}
|
||||
|
||||
if (modData.IsOnMainThread)
|
||||
{
|
||||
modData.HandleLoadingProgress();
|
||||
|
||||
var loader = new Task(f);
|
||||
var loader = new Task(LoadRuleset);
|
||||
loader.Start();
|
||||
|
||||
// Animate the loadscreen while we wait
|
||||
@@ -228,7 +219,7 @@ namespace OpenRA
|
||||
modData.HandleLoadingProgress();
|
||||
}
|
||||
else
|
||||
f();
|
||||
LoadRuleset();
|
||||
|
||||
return ruleset;
|
||||
}
|
||||
@@ -253,7 +244,7 @@ namespace OpenRA
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Write("debug", "Error in AnyFlaggedTraits\r\n" + ex.ToString());
|
||||
Log.Write("debug", "Error in AnyFlaggedTraits\n" + ex.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -17,14 +17,14 @@ namespace OpenRA.GameRules
|
||||
{
|
||||
public class SoundInfo
|
||||
{
|
||||
public readonly Dictionary<string, string[]> Variants = new Dictionary<string, string[]>();
|
||||
public readonly Dictionary<string, string[]> Prefixes = new Dictionary<string, string[]>();
|
||||
public readonly Dictionary<string, string[]> Voices = new Dictionary<string, string[]>();
|
||||
public readonly Dictionary<string, string[]> Notifications = new Dictionary<string, string[]>();
|
||||
public readonly Dictionary<string, string[]> Variants = new();
|
||||
public readonly Dictionary<string, string[]> Prefixes = new();
|
||||
public readonly Dictionary<string, string[]> Voices = new();
|
||||
public readonly Dictionary<string, string[]> Notifications = new();
|
||||
public readonly string DefaultVariant = ".aud";
|
||||
public readonly string DefaultPrefix = "";
|
||||
public readonly HashSet<string> DisableVariants = new HashSet<string>();
|
||||
public readonly HashSet<string> DisablePrefixes = new HashSet<string>();
|
||||
public readonly HashSet<string> DisableVariants = new();
|
||||
public readonly HashSet<string> DisablePrefixes = new();
|
||||
|
||||
public readonly Lazy<Dictionary<string, SoundPool>> VoicePools;
|
||||
public readonly Lazy<Dictionary<string, SoundPool>> NotificationsPools;
|
||||
@@ -69,7 +69,7 @@ namespace OpenRA.GameRules
|
||||
public readonly float VolumeModifier;
|
||||
public readonly InterruptType Type;
|
||||
readonly string[] clips;
|
||||
readonly List<string> liveclips = new List<string>();
|
||||
readonly List<string> liveclips = new();
|
||||
|
||||
public SoundPool(float volumeModifier, InterruptType interruptType, params string[] clips)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -99,17 +99,20 @@ namespace OpenRA.GameRules
|
||||
[Desc("Number of shots in a single ammo magazine.")]
|
||||
public readonly int Burst = 1;
|
||||
|
||||
[Desc("Can this weapon target the attacker itself?")]
|
||||
public readonly bool CanTargetSelf = false;
|
||||
|
||||
[Desc("What types of targets are affected.")]
|
||||
public readonly BitSet<TargetableType> ValidTargets = new BitSet<TargetableType>("Ground", "Water");
|
||||
public readonly BitSet<TargetableType> ValidTargets = new("Ground", "Water");
|
||||
|
||||
[Desc("What types of targets are unaffected.", "Overrules ValidTargets.")]
|
||||
public readonly BitSet<TargetableType> InvalidTargets;
|
||||
|
||||
static readonly BitSet<TargetableType> TargetTypeAir = new BitSet<TargetableType>("Air");
|
||||
static readonly BitSet<TargetableType> TargetTypeAir = new("Air");
|
||||
|
||||
[Desc("If weapon is not directly targeting an actor and targeted position is above this altitude,",
|
||||
"the weapon will ignore terrain target types and only check TargetTypeAir for validity.")]
|
||||
public readonly WDist AirThreshold = new WDist(128);
|
||||
public readonly WDist AirThreshold = new(128);
|
||||
|
||||
[Desc("Delay in ticks between firing shots from the same ammo magazine. If one entry, it will be used for all bursts.",
|
||||
"If multiple entries, their number needs to match Burst - 1.")]
|
||||
@@ -125,10 +128,10 @@ namespace OpenRA.GameRules
|
||||
public readonly IProjectileInfo Projectile;
|
||||
|
||||
[FieldLoader.LoadUsing(nameof(LoadWarheads))]
|
||||
public readonly List<IWarhead> Warheads = new List<IWarhead>();
|
||||
public readonly List<IWarhead> Warheads = new();
|
||||
|
||||
/// <summary>
|
||||
/// This constructor is used solely for documentation generation!
|
||||
/// This constructor is used solely for documentation generation.
|
||||
/// </summary>
|
||||
public WeaponInfo() { }
|
||||
|
||||
@@ -206,29 +209,24 @@ namespace OpenRA.GameRules
|
||||
/// <summary>Checks if the weapon is valid against (can target) the actor.</summary>
|
||||
public bool IsValidAgainst(Actor victim, Actor firedBy)
|
||||
{
|
||||
var targetTypes = victim.GetEnabledTargetTypes();
|
||||
|
||||
if (!IsValidTarget(targetTypes))
|
||||
if (!CanTargetSelf && victim == firedBy)
|
||||
return false;
|
||||
|
||||
// PERF: Avoid LINQ.
|
||||
foreach (var warhead in Warheads)
|
||||
if (warhead.IsValidAgainst(victim, firedBy))
|
||||
return true;
|
||||
var targetTypes = victim.GetEnabledTargetTypes();
|
||||
|
||||
return false;
|
||||
return IsValidTarget(targetTypes);
|
||||
}
|
||||
|
||||
/// <summary>Checks if the weapon is valid against (can target) the frozen actor.</summary>
|
||||
public bool IsValidAgainst(FrozenActor victim, Actor firedBy)
|
||||
{
|
||||
if (!IsValidTarget(victim.TargetTypes))
|
||||
if (!victim.IsValid)
|
||||
return false;
|
||||
|
||||
if (!Warheads.Any(w => w.IsValidAgainst(victim, firedBy)))
|
||||
if (!CanTargetSelf && victim.Actor == firedBy)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return IsValidTarget(victim.TargetTypes);
|
||||
}
|
||||
|
||||
/// <summary>Applies all the weapon's warheads to the target.</summary>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -16,6 +16,7 @@ namespace OpenRA
|
||||
{
|
||||
public class GameSpeed
|
||||
{
|
||||
[TranslationReference]
|
||||
[FieldLoader.Require]
|
||||
public readonly string Name;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -22,7 +22,7 @@ namespace OpenRA.Graphics
|
||||
public string Name { get; private set; }
|
||||
public bool IsDecoration { get; set; }
|
||||
|
||||
readonly SequenceProvider sequenceProvider;
|
||||
readonly SequenceSet sequences;
|
||||
readonly Func<WAngle> facingFunc;
|
||||
readonly Func<bool> paused;
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace OpenRA.Graphics
|
||||
bool backwards;
|
||||
bool tickAlways;
|
||||
int timeUntilNextFrame;
|
||||
Action tickFunc = () => { };
|
||||
Action tickFunc;
|
||||
|
||||
public Animation(World world, string name)
|
||||
: this(world, name, () => WAngle.Zero) { }
|
||||
@@ -43,7 +43,7 @@ namespace OpenRA.Graphics
|
||||
|
||||
public Animation(World world, string name, Func<WAngle> facingFunc, Func<bool> paused)
|
||||
{
|
||||
sequenceProvider = world.Map.Rules.Sequences;
|
||||
sequences = world.Map.Sequences;
|
||||
Name = name.ToLowerInvariant();
|
||||
this.facingFunc = facingFunc;
|
||||
this.paused = paused;
|
||||
@@ -61,9 +61,9 @@ namespace OpenRA.Graphics
|
||||
var imageRenderable = new SpriteRenderable(image, pos, offset, CurrentSequence.ZOffset + zOffset, palette, CurrentSequence.Scale, alpha, float3.Ones, tintModifiers, IsDecoration,
|
||||
rotation);
|
||||
|
||||
if (CurrentSequence.ShadowStart >= 0)
|
||||
var shadow = CurrentSequence.GetShadow(CurrentFrame, facingFunc());
|
||||
if (shadow != null)
|
||||
{
|
||||
var shadow = CurrentSequence.GetShadow(CurrentFrame, facingFunc());
|
||||
var shadowRenderable = new SpriteRenderable(shadow, pos, offset, CurrentSequence.ShadowZOffset + zOffset, palette, CurrentSequence.Scale, 1f, float3.Ones, tintModifiers,
|
||||
true, rotation);
|
||||
return new IRenderable[] { shadowRenderable, imageRenderable };
|
||||
@@ -80,9 +80,9 @@ namespace OpenRA.Graphics
|
||||
var alpha = CurrentSequence.GetAlpha(CurrentFrame);
|
||||
var imageRenderable = new UISpriteRenderable(Image, WPos.Zero + offset, imagePos, CurrentSequence.ZOffset + zOffset, palette, scale, alpha, rotation);
|
||||
|
||||
if (CurrentSequence.ShadowStart >= 0)
|
||||
var shadow = CurrentSequence.GetShadow(CurrentFrame, facingFunc());
|
||||
if (shadow != null)
|
||||
{
|
||||
var shadow = CurrentSequence.GetShadow(CurrentFrame, facingFunc());
|
||||
var shadowPos = pos - new int2((int)(scale * shadow.Size.X / 2), (int)(scale * shadow.Size.Y / 2));
|
||||
var shadowRenderable = new UISpriteRenderable(shadow, WPos.Zero + offset, shadowPos, CurrentSequence.ShadowZOffset + zOffset, palette, scale, 1f, rotation);
|
||||
return new IRenderable[] { shadowRenderable, imageRenderable };
|
||||
@@ -164,7 +164,7 @@ namespace OpenRA.Graphics
|
||||
if (frame >= CurrentSequence.Length)
|
||||
{
|
||||
frame = CurrentSequence.Length - 1;
|
||||
tickFunc = () => { };
|
||||
tickFunc = null;
|
||||
after?.Invoke();
|
||||
}
|
||||
};
|
||||
@@ -212,13 +212,13 @@ namespace OpenRA.Graphics
|
||||
public void Tick(int t)
|
||||
{
|
||||
if (tickAlways)
|
||||
tickFunc();
|
||||
tickFunc?.Invoke();
|
||||
else
|
||||
{
|
||||
timeUntilNextFrame -= t;
|
||||
while (timeUntilNextFrame <= 0)
|
||||
{
|
||||
tickFunc();
|
||||
tickFunc?.Invoke();
|
||||
timeUntilNextFrame += CurrentSequenceTickOrDefault();
|
||||
}
|
||||
}
|
||||
@@ -236,11 +236,11 @@ namespace OpenRA.Graphics
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasSequence(string seq) { return sequenceProvider.HasSequence(Name, seq); }
|
||||
public bool HasSequence(string seq) { return sequences.HasSequence(Name, seq); }
|
||||
|
||||
public ISpriteSequence GetSequence(string sequenceName)
|
||||
{
|
||||
return sequenceProvider.GetSequence(Name, sequenceName);
|
||||
return sequences.GetSequence(Name, sequenceName);
|
||||
}
|
||||
|
||||
public string GetRandomExistingSequence(string[] sequences, MersenneTwister random)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -49,7 +49,7 @@ namespace OpenRA.Graphics
|
||||
|
||||
public readonly int[] PanelRegion = null;
|
||||
public readonly PanelSides PanelSides = PanelSides.All;
|
||||
public readonly Dictionary<string, Rectangle> Regions = new Dictionary<string, Rectangle>();
|
||||
public readonly Dictionary<string, Rectangle> Regions = new();
|
||||
}
|
||||
|
||||
public static IReadOnlyDictionary<string, Collection> Collections => collections;
|
||||
@@ -100,9 +100,7 @@ namespace OpenRA.Graphics
|
||||
|
||||
static void LoadCollection(string name, MiniYaml yaml)
|
||||
{
|
||||
if (Game.ModData.LoadScreen != null)
|
||||
Game.ModData.LoadScreen.Display();
|
||||
|
||||
Game.ModData.LoadScreen?.Display();
|
||||
collections.Add(name, FieldLoader.Load<Collection>(yaml));
|
||||
}
|
||||
|
||||
@@ -265,13 +263,13 @@ namespace OpenRA.Graphics
|
||||
|
||||
if (!collections.TryGetValue(collectionName, out var collection))
|
||||
{
|
||||
Log.Write("debug", "Could not find collection '{0}'", collectionName);
|
||||
Log.Write("debug", $"Could not find collection '{collectionName}'");
|
||||
return new Size(0, 0);
|
||||
}
|
||||
|
||||
if (collection.PanelRegion == null || collection.PanelRegion.Length != 8)
|
||||
{
|
||||
Log.Write("debug", "Collection '{0}' does not define a valid PanelRegion", collectionName);
|
||||
Log.Write("debug", $"Collection '{collectionName}' does not define a valid PanelRegion");
|
||||
return new Size(0, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -17,7 +17,7 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
public sealed class CursorManager
|
||||
{
|
||||
class Cursor
|
||||
sealed class Cursor
|
||||
{
|
||||
public string Name;
|
||||
public int2 PaddedSize;
|
||||
@@ -28,7 +28,7 @@ namespace OpenRA.Graphics
|
||||
public IHardwareCursor[] Cursors;
|
||||
}
|
||||
|
||||
readonly Dictionary<string, Cursor> cursors = new Dictionary<string, Cursor>();
|
||||
readonly Dictionary<string, Cursor> cursors = new();
|
||||
readonly SheetBuilder sheetBuilder;
|
||||
readonly GraphicSettings graphicSettings;
|
||||
|
||||
@@ -111,8 +111,7 @@ namespace OpenRA.Graphics
|
||||
var template = kv.Value;
|
||||
for (var i = 0; i < template.Sprites.Length; i++)
|
||||
{
|
||||
if (template.Cursors[i] != null)
|
||||
template.Cursors[i].Dispose();
|
||||
template.Cursors[i]?.Dispose();
|
||||
|
||||
// Calculate the padding to position the frame within sequenceBounds
|
||||
var paddingTL = -(template.Bounds.Location - template.Sprites[i].Offset.XY.ToInt2());
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -31,28 +31,36 @@ namespace OpenRA.Graphics
|
||||
Palette = palette;
|
||||
Name = name;
|
||||
|
||||
Frames = cache[cursorSrc].Skip(Start).ToArray();
|
||||
var cursorSprites = cache[cursorSrc];
|
||||
Frames = cursorSprites.Skip(Start).ToArray();
|
||||
|
||||
if ((d.ContainsKey("Length") && d["Length"].Value == "*") || (d.ContainsKey("End") && d["End"].Value == "*"))
|
||||
if ((d.TryGetValue("Length", out var yaml) && yaml.Value == "*") ||
|
||||
(d.TryGetValue("End", out yaml) && yaml.Value == "*"))
|
||||
Length = Frames.Length;
|
||||
else if (d.ContainsKey("Length"))
|
||||
Length = Exts.ParseIntegerInvariant(d["Length"].Value);
|
||||
else if (d.ContainsKey("End"))
|
||||
Length = Exts.ParseIntegerInvariant(d["End"].Value) - Start;
|
||||
else if (d.TryGetValue("Length", out yaml))
|
||||
Length = Exts.ParseIntegerInvariant(yaml.Value);
|
||||
else if (d.TryGetValue("End", out yaml))
|
||||
Length = Exts.ParseIntegerInvariant(yaml.Value) - Start;
|
||||
else
|
||||
Length = 1;
|
||||
|
||||
Frames = Frames.Take(Length).ToArray();
|
||||
|
||||
if (d.ContainsKey("X"))
|
||||
if (Start > cursorSprites.Length)
|
||||
throw new YamlException($"Cursor {name}: {nameof(Start)} is greater than the length of the sprite sequence.");
|
||||
|
||||
if (Length > cursorSprites.Length)
|
||||
throw new YamlException($"Cursor {name}: {nameof(Length)} is greater than the length of the sprite sequence.");
|
||||
|
||||
if (d.TryGetValue("X", out yaml))
|
||||
{
|
||||
Exts.TryParseIntegerInvariant(d["X"].Value, out var x);
|
||||
Exts.TryParseIntegerInvariant(yaml.Value, out var x);
|
||||
Hotspot = Hotspot.WithX(x);
|
||||
}
|
||||
|
||||
if (d.ContainsKey("Y"))
|
||||
if (d.TryGetValue("Y", out yaml))
|
||||
{
|
||||
Exts.TryParseIntegerInvariant(d["Y"].Value, out var y);
|
||||
Exts.TryParseIntegerInvariant(yaml.Value, out var y);
|
||||
Hotspot = Hotspot.WithY(y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -21,9 +21,9 @@ namespace OpenRA.Graphics
|
||||
public ITexture ColorShifts { get; }
|
||||
|
||||
public int Height { get; private set; }
|
||||
readonly Dictionary<string, ImmutablePalette> palettes = new Dictionary<string, ImmutablePalette>();
|
||||
readonly Dictionary<string, MutablePalette> mutablePalettes = new Dictionary<string, MutablePalette>();
|
||||
readonly Dictionary<string, int> indices = new Dictionary<string, int>();
|
||||
readonly Dictionary<string, ImmutablePalette> palettes = new();
|
||||
readonly Dictionary<string, MutablePalette> mutablePalettes = new();
|
||||
readonly Dictionary<string, int> indices = new();
|
||||
byte[] buffer = Array.Empty<byte>();
|
||||
float[] colorShiftBuffer = Array.Empty<float>();
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
Height = Exts.NextPowerOf2(index + 1);
|
||||
Array.Resize(ref buffer, Height * Palette.Size * 4);
|
||||
Array.Resize(ref colorShiftBuffer, Height * 4);
|
||||
Array.Resize(ref colorShiftBuffer, Height * 8);
|
||||
}
|
||||
|
||||
if (allowModifiers)
|
||||
@@ -79,6 +79,9 @@ namespace OpenRA.Graphics
|
||||
CopyPaletteToBuffer(index, p);
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage(
|
||||
"Performance", "CA1854:Prefer the 'IDictionary.TryGetValue(TKey, out TValue)' method",
|
||||
Justification = "False positive - indexer is a set not a get.")]
|
||||
public void ReplacePalette(string name, IPalette p)
|
||||
{
|
||||
if (mutablePalettes.ContainsKey(name))
|
||||
@@ -90,19 +93,20 @@ namespace OpenRA.Graphics
|
||||
CopyBufferToTexture();
|
||||
}
|
||||
|
||||
public void SetColorShift(string name, float hueOffset, float satOffset, float minHue, float maxHue)
|
||||
public void SetColorShift(string name, float hueOffset, float satOffset, float valueMultiplier, float minHue, float maxHue)
|
||||
{
|
||||
var index = GetPaletteIndex(name);
|
||||
colorShiftBuffer[4 * index + 0] = hueOffset;
|
||||
colorShiftBuffer[4 * index + 1] = satOffset;
|
||||
colorShiftBuffer[4 * index + 2] = minHue;
|
||||
colorShiftBuffer[4 * index + 3] = maxHue;
|
||||
colorShiftBuffer[8 * index + 0] = minHue;
|
||||
colorShiftBuffer[8 * index + 1] = maxHue;
|
||||
colorShiftBuffer[8 * index + 4] = hueOffset;
|
||||
colorShiftBuffer[8 * index + 5] = satOffset;
|
||||
colorShiftBuffer[8 * index + 6] = valueMultiplier;
|
||||
}
|
||||
|
||||
public bool HasColorShift(string name)
|
||||
{
|
||||
var index = GetPaletteIndex(name);
|
||||
return colorShiftBuffer[4 * index + 2] != 0 || colorShiftBuffer[4 * index + 3] != 0;
|
||||
return colorShiftBuffer[8 * index] != 0 || colorShiftBuffer[8 * index + 1] != 0;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
@@ -125,7 +129,7 @@ namespace OpenRA.Graphics
|
||||
void CopyBufferToTexture()
|
||||
{
|
||||
Texture.SetData(buffer, Palette.Size, Height);
|
||||
ColorShifts.SetFloatData(colorShiftBuffer, 1, Height);
|
||||
ColorShifts.SetFloatData(colorShiftBuffer, 2, Height);
|
||||
}
|
||||
|
||||
public void ApplyModifiers(IEnumerable<IPaletteModifier> paletteMods)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -26,7 +26,7 @@ namespace OpenRA.Graphics
|
||||
float[] Bounds(uint frame);
|
||||
ModelRenderData RenderData(uint section);
|
||||
|
||||
/// <summary>Returns the smallest rectangle that covers all rotations of all frames in a model</summary>
|
||||
/// <summary>Returns the smallest rectangle that covers all rotations of all frames in a model.</summary>
|
||||
Rectangle AggregateBounds { get; }
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
public Action<string> OnMissingModelError { get; set; }
|
||||
|
||||
class PlaceholderModelCache : IModelCache
|
||||
sealed class PlaceholderModelCache : IModelCache
|
||||
{
|
||||
public IVertexBuffer<Vertex> VertexBuffer => throw new NotImplementedException();
|
||||
|
||||
@@ -84,7 +84,6 @@ namespace OpenRA.Graphics
|
||||
}
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "IDE0060:Remove unused parameter", Justification = "Load game API")]
|
||||
public PlaceholderModelSequenceLoader(ModData modData) { }
|
||||
|
||||
public IModelCache CacheModels(IReadOnlyFileSystem fileSystem, ModData modData, IReadOnlyDictionary<string, MiniYamlNode> modelDefinitions)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -37,7 +37,7 @@ namespace OpenRA.Graphics
|
||||
// Static constants
|
||||
static readonly float[] ShadowDiffuse = new float[] { 0, 0, 0 };
|
||||
static readonly float[] ShadowAmbient = new float[] { 1, 1, 1 };
|
||||
static readonly float2 SpritePadding = new float2(2, 2);
|
||||
static readonly float2 SpritePadding = new(2, 2);
|
||||
static readonly float[] ZeroVector = new float[] { 0, 0, 0, 1 };
|
||||
static readonly float[] ZVector = new float[] { 0, 0, 1, 1 };
|
||||
static readonly float[] FlipMtx = Util.ScaleMatrix(1, -1, 1);
|
||||
@@ -47,9 +47,9 @@ namespace OpenRA.Graphics
|
||||
readonly Renderer renderer;
|
||||
readonly IShader shader;
|
||||
|
||||
readonly Dictionary<Sheet, IFrameBuffer> mappedBuffers = new Dictionary<Sheet, IFrameBuffer>();
|
||||
readonly Stack<KeyValuePair<Sheet, IFrameBuffer>> unmappedBuffers = new Stack<KeyValuePair<Sheet, IFrameBuffer>>();
|
||||
readonly List<(Sheet Sheet, Action Func)> doRender = new List<(Sheet, Action)>();
|
||||
readonly Dictionary<Sheet, IFrameBuffer> mappedBuffers = new();
|
||||
readonly Stack<KeyValuePair<Sheet, IFrameBuffer>> unmappedBuffers = new();
|
||||
readonly List<(Sheet Sheet, Action Func)> doRender = new();
|
||||
|
||||
SheetBuilder sheetBuilderForFrame;
|
||||
bool isInFrame;
|
||||
@@ -167,8 +167,7 @@ namespace OpenRA.Graphics
|
||||
CalculateSpriteGeometry(tl, br, 1, out var spriteSize, out var spriteOffset);
|
||||
CalculateSpriteGeometry(stl, sbr, 2, out var shadowSpriteSize, out var shadowSpriteOffset);
|
||||
|
||||
if (sheetBuilderForFrame == null)
|
||||
sheetBuilderForFrame = new SheetBuilder(SheetType.BGRA, AllocateSheet);
|
||||
sheetBuilderForFrame ??= new SheetBuilder(SheetType.BGRA, AllocateSheet);
|
||||
|
||||
var sprite = sheetBuilderForFrame.Allocate(spriteSize, 0, spriteOffset);
|
||||
var shadowSprite = sheetBuilderForFrame.Allocate(shadowSpriteSize, 0, shadowSpriteOffset);
|
||||
@@ -303,7 +302,7 @@ namespace OpenRA.Graphics
|
||||
return fbo;
|
||||
}
|
||||
|
||||
void DisableFrameBuffer(IFrameBuffer fbo)
|
||||
static void DisableFrameBuffer(IFrameBuffer fbo)
|
||||
{
|
||||
Game.Renderer.Flush();
|
||||
Game.Renderer.Context.DisableDepthBuffer();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -40,7 +40,7 @@ namespace OpenRA.Graphics
|
||||
return new ReadOnlyPalette(palette);
|
||||
}
|
||||
|
||||
class ReadOnlyPalette : IPalette
|
||||
sealed class ReadOnlyPalette : IPalette
|
||||
{
|
||||
readonly IPalette palette;
|
||||
public ReadOnlyPalette(IPalette palette) { this.palette = palette; }
|
||||
@@ -108,7 +108,7 @@ namespace OpenRA.Graphics
|
||||
|
||||
public ImmutablePalette(IPalette p)
|
||||
{
|
||||
for (int i = 0; i < Palette.Size; i++)
|
||||
for (var i = 0; i < Palette.Size; i++)
|
||||
colors[i] = p[i];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -20,12 +20,14 @@ namespace OpenRA.Graphics
|
||||
readonly int[] remapIndices;
|
||||
readonly float hue;
|
||||
readonly float saturation;
|
||||
readonly float value;
|
||||
|
||||
public PlayerColorRemap(int[] remapIndices, float hue, float saturation)
|
||||
public PlayerColorRemap(int[] remapIndices, Color color)
|
||||
{
|
||||
this.remapIndices = remapIndices;
|
||||
this.hue = hue;
|
||||
this.saturation = saturation;
|
||||
|
||||
var (r, g, b) = color.ToLinear();
|
||||
(hue, saturation, value) = Color.RgbToHsv(r, g, b);
|
||||
}
|
||||
|
||||
public Color GetRemappedColor(Color original, int index)
|
||||
@@ -42,7 +44,7 @@ namespace OpenRA.Graphics
|
||||
var value = Math.Max(Math.Max(r, g), b);
|
||||
|
||||
// Construct the new RGB color
|
||||
(r, g, b) = Color.HsvToRgb(hue, saturation, value);
|
||||
(r, g, b) = Color.HsvToRgb(hue, saturation, value * this.value);
|
||||
|
||||
// Convert linear back to SRGB and pre-multiply by the alpha
|
||||
return Color.FromLinear(original.A, r, g, b);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -18,7 +18,7 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
public class RgbaColorRenderer
|
||||
{
|
||||
static readonly float3 Offset = new float3(0.5f, 0.5f, 0f);
|
||||
static readonly float3 Offset = new(0.5f, 0.5f, 0f);
|
||||
|
||||
readonly SpriteRenderer parent;
|
||||
readonly Vertex[] vertices = new Vertex[6];
|
||||
@@ -78,9 +78,9 @@ namespace OpenRA.Graphics
|
||||
/// <summary>
|
||||
/// Calculate the 2D intersection of two lines.
|
||||
/// Will behave badly if the lines are parallel.
|
||||
/// Z position is the average of a and b (ignores actual intersection point if it exists)
|
||||
/// Z position is the average of a and b (ignores actual intersection point if it exists).
|
||||
/// </summary>
|
||||
float3 IntersectionOf(in float3 a, in float3 da, in float3 b, in float3 db)
|
||||
static float3 IntersectionOf(in float3 a, in float3 da, in float3 b, in float3 db)
|
||||
{
|
||||
var crossA = a.X * (a.Y + da.Y) - a.Y * (a.X + da.X);
|
||||
var crossB = b.X * (b.Y + db.Y) - b.Y * (b.X + db.X);
|
||||
@@ -138,7 +138,7 @@ namespace OpenRA.Graphics
|
||||
// Segment is part of closed loop
|
||||
if (closed)
|
||||
{
|
||||
var prev = points[points.Length - 1];
|
||||
var prev = points[^1];
|
||||
var prevDir = (start - prev) / (start - prev).XY.Length;
|
||||
var prevCorner = width / 2 * new float3(-prevDir.Y, prevDir.X, prevDir.Z);
|
||||
ca = IntersectionOf(start - prevCorner, prevDir, start - corner, dir);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
|
||||
@@ -1,152 +0,0 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenRA.FileSystem;
|
||||
using OpenRA.Primitives;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
using Sequences = IReadOnlyDictionary<string, Lazy<IReadOnlyDictionary<string, ISpriteSequence>>>;
|
||||
using UnitSequences = Lazy<IReadOnlyDictionary<string, ISpriteSequence>>;
|
||||
|
||||
public interface ISpriteSequence
|
||||
{
|
||||
string Name { get; }
|
||||
int Start { get; }
|
||||
int Length { get; }
|
||||
int Stride { get; }
|
||||
int Facings { get; }
|
||||
int InterpolatedFacings { get; }
|
||||
int Tick { get; }
|
||||
int ZOffset { get; }
|
||||
int ShadowStart { get; }
|
||||
int ShadowZOffset { get; }
|
||||
int[] Frames { get; }
|
||||
Rectangle Bounds { get; }
|
||||
bool IgnoreWorldTint { get; }
|
||||
float Scale { get; }
|
||||
|
||||
Sprite GetSprite(int frame);
|
||||
Sprite GetSprite(int frame, WAngle facing);
|
||||
(Sprite, WAngle) GetSpriteWithRotation(int frame, WAngle facing);
|
||||
Sprite GetShadow(int frame, WAngle facing);
|
||||
float GetAlpha(int frame);
|
||||
}
|
||||
|
||||
public interface ISpriteSequenceLoader
|
||||
{
|
||||
IReadOnlyDictionary<string, ISpriteSequence> ParseSequences(ModData modData, string tileSet, SpriteCache cache, MiniYamlNode node);
|
||||
}
|
||||
|
||||
public class SequenceProvider : IDisposable
|
||||
{
|
||||
readonly ModData modData;
|
||||
readonly string tileSet;
|
||||
readonly Lazy<Sequences> sequences;
|
||||
readonly Lazy<SpriteCache> spriteCache;
|
||||
public SpriteCache SpriteCache => spriteCache.Value;
|
||||
|
||||
readonly Dictionary<string, UnitSequences> sequenceCache = new Dictionary<string, UnitSequences>();
|
||||
|
||||
public SequenceProvider(IReadOnlyFileSystem fileSystem, ModData modData, string tileSet, MiniYaml additionalSequences)
|
||||
{
|
||||
this.modData = modData;
|
||||
this.tileSet = tileSet;
|
||||
sequences = Exts.Lazy(() =>
|
||||
{
|
||||
using (new Support.PerfTimer("LoadSequences"))
|
||||
return Load(fileSystem, additionalSequences);
|
||||
});
|
||||
|
||||
spriteCache = Exts.Lazy(() => new SpriteCache(fileSystem, modData.SpriteLoaders));
|
||||
}
|
||||
|
||||
public ISpriteSequence GetSequence(string unitName, string sequenceName)
|
||||
{
|
||||
if (!sequences.Value.TryGetValue(unitName, out var unitSeq))
|
||||
throw new InvalidOperationException($"Unit `{unitName}` does not have any sequences defined.");
|
||||
|
||||
if (!unitSeq.Value.TryGetValue(sequenceName, out var seq))
|
||||
throw new InvalidOperationException($"Unit `{unitName}` does not have a sequence named `{sequenceName}`");
|
||||
|
||||
return seq;
|
||||
}
|
||||
|
||||
public IEnumerable<string> Images => sequences.Value.Keys;
|
||||
|
||||
public bool HasSequence(string unitName)
|
||||
{
|
||||
return sequences.Value.ContainsKey(unitName);
|
||||
}
|
||||
|
||||
public bool HasSequence(string unitName, string sequenceName)
|
||||
{
|
||||
if (!sequences.Value.TryGetValue(unitName, out var unitSeq))
|
||||
throw new InvalidOperationException($"Unit `{unitName}` does not have any sequences defined.");
|
||||
|
||||
return unitSeq.Value.ContainsKey(sequenceName);
|
||||
}
|
||||
|
||||
public IEnumerable<string> Sequences(string unitName)
|
||||
{
|
||||
if (!sequences.Value.TryGetValue(unitName, out var unitSeq))
|
||||
throw new InvalidOperationException($"Unit `{unitName}` does not have any sequences defined.");
|
||||
|
||||
return unitSeq.Value.Keys;
|
||||
}
|
||||
|
||||
Sequences Load(IReadOnlyFileSystem fileSystem, MiniYaml additionalSequences)
|
||||
{
|
||||
var nodes = MiniYaml.Load(fileSystem, modData.Manifest.Sequences, additionalSequences);
|
||||
var items = new Dictionary<string, UnitSequences>();
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
// Nodes starting with ^ are inheritable but never loaded directly
|
||||
if (node.Key.StartsWith(ActorInfo.AbstractActorPrefix, StringComparison.Ordinal))
|
||||
continue;
|
||||
|
||||
var key = node.Value.ToLines(node.Key).JoinWith("|");
|
||||
|
||||
if (sequenceCache.TryGetValue(key, out var t))
|
||||
items.Add(node.Key, t);
|
||||
else
|
||||
{
|
||||
t = Exts.Lazy(() => modData.SpriteSequenceLoader.ParseSequences(modData, tileSet, SpriteCache, node));
|
||||
sequenceCache.Add(key, t);
|
||||
items.Add(node.Key, t);
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
public void Preload()
|
||||
{
|
||||
foreach (var sb in SpriteCache.SheetBuilders.Values)
|
||||
sb.Current.CreateBuffer();
|
||||
|
||||
foreach (var unitSeq in sequences.Value.Values)
|
||||
foreach (var seq in unitSeq.Value.Values) { }
|
||||
|
||||
foreach (var sb in SpriteCache.SheetBuilders.Values)
|
||||
sb.Current.ReleaseBuffer();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (spriteCache.IsValueCreated)
|
||||
foreach (var sb in SpriteCache.SheetBuilders.Values)
|
||||
sb.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
119
OpenRA.Game/Graphics/SequenceSet.cs
Normal file
119
OpenRA.Game/Graphics/SequenceSet.cs
Normal file
@@ -0,0 +1,119 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenRA.FileSystem;
|
||||
using OpenRA.Primitives;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
public interface ISpriteSequence
|
||||
{
|
||||
string Name { get; }
|
||||
int Length { get; }
|
||||
int Facings { get; }
|
||||
int Tick { get; }
|
||||
int ZOffset { get; }
|
||||
int ShadowZOffset { get; }
|
||||
Rectangle Bounds { get; }
|
||||
bool IgnoreWorldTint { get; }
|
||||
float Scale { get; }
|
||||
void ResolveSprites(SpriteCache cache);
|
||||
Sprite GetSprite(int frame);
|
||||
Sprite GetSprite(int frame, WAngle facing);
|
||||
(Sprite Sprite, WAngle Rotation) GetSpriteWithRotation(int frame, WAngle facing);
|
||||
Sprite GetShadow(int frame, WAngle facing);
|
||||
float GetAlpha(int frame);
|
||||
}
|
||||
|
||||
public interface ISpriteSequenceLoader
|
||||
{
|
||||
int BgraSheetSize { get; }
|
||||
int IndexedSheetSize { get; }
|
||||
IReadOnlyDictionary<string, ISpriteSequence> ParseSequences(ModData modData, string tileSet, SpriteCache cache, MiniYamlNode node);
|
||||
}
|
||||
|
||||
public sealed class SequenceSet : IDisposable
|
||||
{
|
||||
readonly ModData modData;
|
||||
readonly string tileSet;
|
||||
readonly IReadOnlyDictionary<string, IReadOnlyDictionary<string, ISpriteSequence>> images;
|
||||
public SpriteCache SpriteCache { get; }
|
||||
|
||||
public SequenceSet(IReadOnlyFileSystem fileSystem, ModData modData, string tileSet, MiniYaml additionalSequences)
|
||||
{
|
||||
this.modData = modData;
|
||||
this.tileSet = tileSet;
|
||||
SpriteCache = new SpriteCache(fileSystem, modData.SpriteLoaders, modData.SpriteSequenceLoader.BgraSheetSize, modData.SpriteSequenceLoader.IndexedSheetSize);
|
||||
using (new Support.PerfTimer("LoadSequences"))
|
||||
images = Load(fileSystem, additionalSequences);
|
||||
}
|
||||
|
||||
public ISpriteSequence GetSequence(string image, string sequence)
|
||||
{
|
||||
if (!images.TryGetValue(image, out var sequences))
|
||||
throw new InvalidOperationException($"Image `{image}` does not have any sequences defined.");
|
||||
|
||||
if (!sequences.TryGetValue(sequence, out var seq))
|
||||
throw new InvalidOperationException($"Image `{image}` does not have a sequence named `{sequence}`.");
|
||||
|
||||
return seq;
|
||||
}
|
||||
|
||||
public IEnumerable<string> Images => images.Keys;
|
||||
|
||||
public bool HasSequence(string image, string sequence)
|
||||
{
|
||||
if (!images.TryGetValue(image, out var sequences))
|
||||
throw new InvalidOperationException($"Image `{image}` does not have any sequences defined.");
|
||||
|
||||
return sequences.ContainsKey(sequence);
|
||||
}
|
||||
|
||||
public IEnumerable<string> Sequences(string image)
|
||||
{
|
||||
if (!images.TryGetValue(image, out var sequences))
|
||||
throw new InvalidOperationException($"Image `{image}` does not have any sequences defined.");
|
||||
|
||||
return sequences.Keys;
|
||||
}
|
||||
|
||||
IReadOnlyDictionary<string, IReadOnlyDictionary<string, ISpriteSequence>> Load(IReadOnlyFileSystem fileSystem, MiniYaml additionalSequences)
|
||||
{
|
||||
var nodes = MiniYaml.Load(fileSystem, modData.Manifest.Sequences, additionalSequences);
|
||||
var images = new Dictionary<string, IReadOnlyDictionary<string, ISpriteSequence>>();
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
// Nodes starting with ^ are inheritable but never loaded directly
|
||||
if (node.Key.StartsWith(ActorInfo.AbstractActorPrefix, StringComparison.Ordinal))
|
||||
continue;
|
||||
|
||||
images[node.Key] = modData.SpriteSequenceLoader.ParseSequences(modData, tileSet, SpriteCache, node);
|
||||
}
|
||||
|
||||
return images;
|
||||
}
|
||||
|
||||
public void LoadSprites()
|
||||
{
|
||||
SpriteCache.LoadReservations(modData);
|
||||
foreach (var sequences in images.Values)
|
||||
foreach (var sequence in sequences)
|
||||
sequence.Value.ResolveSprites(SpriteCache);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
SpriteCache.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -34,15 +34,16 @@ namespace OpenRA.Graphics
|
||||
public sealed class SheetBuilder : IDisposable
|
||||
{
|
||||
public readonly SheetType Type;
|
||||
readonly List<Sheet> sheets = new List<Sheet>();
|
||||
readonly List<Sheet> sheets = new();
|
||||
readonly Func<Sheet> allocateSheet;
|
||||
readonly int margin;
|
||||
|
||||
Sheet current;
|
||||
TextureChannel channel;
|
||||
int rowHeight = 0;
|
||||
int2 p;
|
||||
|
||||
public Sheet Current { get; private set; }
|
||||
public TextureChannel CurrentChannel { get; private set; }
|
||||
public IEnumerable<Sheet> AllSheets => sheets;
|
||||
|
||||
public static Sheet AllocateSheet(SheetType type, int sheetSize)
|
||||
{
|
||||
return new Sheet(type, new Size(sheetSize, sheetSize));
|
||||
@@ -73,10 +74,10 @@ namespace OpenRA.Graphics
|
||||
|
||||
public SheetBuilder(SheetType t, Func<Sheet> allocateSheet, int margin = 1)
|
||||
{
|
||||
channel = t == SheetType.Indexed ? TextureChannel.Red : TextureChannel.RGBA;
|
||||
CurrentChannel = t == SheetType.Indexed ? TextureChannel.Red : TextureChannel.RGBA;
|
||||
Type = t;
|
||||
current = allocateSheet();
|
||||
sheets.Add(current);
|
||||
Current = allocateSheet();
|
||||
sheets.Add(Current);
|
||||
this.allocateSheet = allocateSheet;
|
||||
this.margin = margin;
|
||||
}
|
||||
@@ -87,19 +88,19 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
// Don't bother allocating empty sprites
|
||||
if (size.Width == 0 || size.Height == 0)
|
||||
return new Sprite(current, Rectangle.Empty, 0, spriteOffset, channel, BlendMode.Alpha);
|
||||
return new Sprite(Current, Rectangle.Empty, 0, spriteOffset, CurrentChannel, BlendMode.Alpha);
|
||||
|
||||
var rect = Allocate(size, zRamp, spriteOffset);
|
||||
Util.FastCopyIntoChannel(rect, src, type);
|
||||
current.CommitBufferedData();
|
||||
Current.CommitBufferedData();
|
||||
return rect;
|
||||
}
|
||||
|
||||
public Sprite Add(Png src, float scale = 1f)
|
||||
{
|
||||
var rect = Allocate(new Size(src.Width, src.Height), scale);
|
||||
var rect = Allocate(new Size(src.Width, src.Height), scale);
|
||||
Util.FastCopyIntoSprite(rect, src);
|
||||
current.CommitBufferedData();
|
||||
Current.CommitBufferedData();
|
||||
return rect;
|
||||
}
|
||||
|
||||
@@ -115,7 +116,7 @@ namespace OpenRA.Graphics
|
||||
public Sprite Allocate(Size imageSize, float scale = 1f) { return Allocate(imageSize, 0, float3.Zero, scale); }
|
||||
public Sprite Allocate(Size imageSize, float zRamp, in float3 spriteOffset, float scale = 1f)
|
||||
{
|
||||
if (imageSize.Width + p.X + margin > current.Size.Width)
|
||||
if (imageSize.Width + p.X + margin > Current.Size.Width)
|
||||
{
|
||||
p = new int2(0, p.Y + rowHeight + margin);
|
||||
rowHeight = imageSize.Height;
|
||||
@@ -124,33 +125,29 @@ namespace OpenRA.Graphics
|
||||
if (imageSize.Height > rowHeight)
|
||||
rowHeight = imageSize.Height;
|
||||
|
||||
if (p.Y + imageSize.Height + margin > current.Size.Height)
|
||||
if (p.Y + imageSize.Height + margin > Current.Size.Height)
|
||||
{
|
||||
var next = NextChannel(channel);
|
||||
var next = NextChannel(CurrentChannel);
|
||||
if (next == null)
|
||||
{
|
||||
current.ReleaseBuffer();
|
||||
current = allocateSheet();
|
||||
sheets.Add(current);
|
||||
channel = Type == SheetType.Indexed ? TextureChannel.Red : TextureChannel.RGBA;
|
||||
Current.ReleaseBuffer();
|
||||
Current = allocateSheet();
|
||||
sheets.Add(Current);
|
||||
CurrentChannel = Type == SheetType.Indexed ? TextureChannel.Red : TextureChannel.RGBA;
|
||||
}
|
||||
else
|
||||
channel = next.Value;
|
||||
CurrentChannel = next.Value;
|
||||
|
||||
rowHeight = imageSize.Height;
|
||||
p = int2.Zero;
|
||||
}
|
||||
|
||||
var rect = new Sprite(current, new Rectangle(p.X + margin, p.Y + margin, imageSize.Width, imageSize.Height), zRamp, spriteOffset, channel, BlendMode.Alpha, scale);
|
||||
var rect = new Sprite(Current, new Rectangle(p.X + margin, p.Y + margin, imageSize.Width, imageSize.Height), zRamp, spriteOffset, CurrentChannel, BlendMode.Alpha, scale);
|
||||
p += new int2(imageSize.Width + margin, 0);
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
public Sheet Current => current;
|
||||
public TextureChannel CurrentChannel => channel;
|
||||
public IEnumerable<Sheet> AllSheets => sheets;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var sheet in sheets)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
|
||||
174
OpenRA.Game/Graphics/SpriteCache.cs
Normal file
174
OpenRA.Game/Graphics/SpriteCache.cs
Normal file
@@ -0,0 +1,174 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using OpenRA.FileSystem;
|
||||
using OpenRA.Primitives;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
public sealed class SpriteCache : IDisposable
|
||||
{
|
||||
public readonly Dictionary<SheetType, SheetBuilder> SheetBuilders;
|
||||
readonly ISpriteLoader[] loaders;
|
||||
readonly IReadOnlyFileSystem fileSystem;
|
||||
|
||||
readonly Dictionary<int, (int[] Frames, MiniYamlNode.SourceLocation Location)> spriteReservations = new();
|
||||
readonly Dictionary<int, (int[] Frames, MiniYamlNode.SourceLocation Location)> frameReservations = new();
|
||||
readonly Dictionary<string, List<int>> reservationsByFilename = new();
|
||||
|
||||
readonly Dictionary<int, ISpriteFrame[]> resolvedFrames = new();
|
||||
readonly Dictionary<int, Sprite[]> resolvedSprites = new();
|
||||
|
||||
readonly Dictionary<int, (string Filename, MiniYamlNode.SourceLocation Location)> missingFiles = new();
|
||||
|
||||
int nextReservationToken = 1;
|
||||
|
||||
public SpriteCache(IReadOnlyFileSystem fileSystem, ISpriteLoader[] loaders, int bgraSheetSize, int indexedSheetSize, int bgraSheetMargin = 1, int indexedSheetMargin = 1)
|
||||
{
|
||||
SheetBuilders = new Dictionary<SheetType, SheetBuilder>
|
||||
{
|
||||
{ SheetType.Indexed, new SheetBuilder(SheetType.Indexed, indexedSheetSize, indexedSheetMargin) },
|
||||
{ SheetType.BGRA, new SheetBuilder(SheetType.BGRA, bgraSheetSize, bgraSheetMargin) }
|
||||
};
|
||||
|
||||
this.fileSystem = fileSystem;
|
||||
this.loaders = loaders;
|
||||
}
|
||||
|
||||
public int ReserveSprites(string filename, IEnumerable<int> frames, MiniYamlNode.SourceLocation location)
|
||||
{
|
||||
var token = nextReservationToken++;
|
||||
spriteReservations[token] = (frames?.ToArray(), location);
|
||||
reservationsByFilename.GetOrAdd(filename, _ => new List<int>()).Add(token);
|
||||
return token;
|
||||
}
|
||||
|
||||
public int ReserveFrames(string filename, IEnumerable<int> frames, MiniYamlNode.SourceLocation location)
|
||||
{
|
||||
var token = nextReservationToken++;
|
||||
frameReservations[token] = (frames?.ToArray(), location);
|
||||
reservationsByFilename.GetOrAdd(filename, _ => new List<int>()).Add(token);
|
||||
return token;
|
||||
}
|
||||
|
||||
static ISpriteFrame[] GetFrames(IReadOnlyFileSystem fileSystem, string filename, ISpriteLoader[] loaders, out TypeDictionary metadata)
|
||||
{
|
||||
metadata = null;
|
||||
if (!fileSystem.TryOpen(filename, out var stream))
|
||||
return null;
|
||||
|
||||
using (stream)
|
||||
{
|
||||
foreach (var loader in loaders)
|
||||
if (loader.TryParseSprite(stream, filename, out var frames, out metadata))
|
||||
return frames;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void LoadReservations(ModData modData)
|
||||
{
|
||||
foreach (var sb in SheetBuilders.Values)
|
||||
sb.Current.CreateBuffer();
|
||||
|
||||
var spriteCache = new Dictionary<int, Sprite>();
|
||||
foreach (var (filename, tokens) in reservationsByFilename)
|
||||
{
|
||||
modData.LoadScreen?.Display();
|
||||
var loadedFrames = GetFrames(fileSystem, filename, loaders, out _);
|
||||
foreach (var token in tokens)
|
||||
{
|
||||
if (frameReservations.TryGetValue(token, out var r))
|
||||
{
|
||||
if (loadedFrames != null)
|
||||
{
|
||||
if (r.Frames != null)
|
||||
{
|
||||
var resolved = new ISpriteFrame[loadedFrames.Length];
|
||||
foreach (var i in r.Frames)
|
||||
resolved[i] = loadedFrames[i];
|
||||
resolvedFrames[token] = resolved;
|
||||
}
|
||||
else
|
||||
resolvedFrames[token] = loadedFrames;
|
||||
}
|
||||
else
|
||||
{
|
||||
resolvedFrames[token] = null;
|
||||
missingFiles[token] = (filename, r.Location);
|
||||
}
|
||||
}
|
||||
|
||||
if (spriteReservations.TryGetValue(token, out r))
|
||||
{
|
||||
if (loadedFrames != null)
|
||||
{
|
||||
var resolved = new Sprite[loadedFrames.Length];
|
||||
var frames = r.Frames ?? Enumerable.Range(0, loadedFrames.Length);
|
||||
foreach (var i in frames)
|
||||
resolved[i] = spriteCache.GetOrAdd(i,
|
||||
f => SheetBuilders[SheetBuilder.FrameTypeToSheetType(loadedFrames[f].Type)].Add(loadedFrames[f]));
|
||||
|
||||
resolvedSprites[token] = resolved;
|
||||
}
|
||||
else
|
||||
{
|
||||
resolvedSprites[token] = null;
|
||||
missingFiles[token] = (filename, r.Location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spriteCache.Clear();
|
||||
}
|
||||
|
||||
spriteReservations.Clear();
|
||||
frameReservations.Clear();
|
||||
reservationsByFilename.Clear();
|
||||
|
||||
foreach (var sb in SheetBuilders.Values)
|
||||
sb.Current.ReleaseBuffer();
|
||||
}
|
||||
|
||||
public Sprite[] ResolveSprites(int token)
|
||||
{
|
||||
var resolved = resolvedSprites[token];
|
||||
resolvedSprites.Remove(token);
|
||||
if (missingFiles.TryGetValue(token, out var r))
|
||||
throw new FileNotFoundException($"{r.Location}: {r.Filename} not found", r.Filename);
|
||||
|
||||
return resolved;
|
||||
}
|
||||
|
||||
public ISpriteFrame[] ResolveFrames(int token)
|
||||
{
|
||||
var resolved = resolvedFrames[token];
|
||||
resolvedFrames.Remove(token);
|
||||
if (missingFiles.TryGetValue(token, out var r))
|
||||
throw new FileNotFoundException($"{r.Location}: {r.Filename} not found", r.Filename);
|
||||
|
||||
return resolved;
|
||||
}
|
||||
|
||||
public IEnumerable<(string Filename, MiniYamlNode.SourceLocation Location)> MissingFiles => missingFiles.Values.ToHashSet();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var sb in SheetBuilders.Values)
|
||||
sb.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -123,7 +123,7 @@ namespace OpenRA.Graphics
|
||||
}
|
||||
}
|
||||
|
||||
float2 Rotate(float2 v, float sina, float cosa, float2 offset)
|
||||
static float2 Rotate(float2 v, float sina, float cosa, float2 offset)
|
||||
{
|
||||
return new float2(
|
||||
v.X * cosa - v.Y * sina + offset.X,
|
||||
@@ -427,7 +427,7 @@ namespace OpenRA.Graphics
|
||||
}
|
||||
}
|
||||
|
||||
class GlyphInfo
|
||||
sealed class GlyphInfo
|
||||
{
|
||||
public float Advance;
|
||||
public int2 Offset;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -9,10 +9,7 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using OpenRA.FileSystem;
|
||||
using OpenRA.Primitives;
|
||||
|
||||
@@ -21,7 +18,7 @@ namespace OpenRA.Graphics
|
||||
/// <summary>
|
||||
/// Describes the format of the pixel data in a ISpriteFrame.
|
||||
/// Note that the channel order is defined for little-endian bytes, so BGRA corresponds
|
||||
/// to a 32bit ARGB value, such as that returned by Color.ToArgb()!
|
||||
/// to a 32bit ARGB value, such as that returned by Color.ToArgb().
|
||||
/// </summary>
|
||||
public enum SpriteFrameType
|
||||
{
|
||||
@@ -67,94 +64,6 @@ namespace OpenRA.Graphics
|
||||
bool DisableExportPadding { get; }
|
||||
}
|
||||
|
||||
public class SpriteCache
|
||||
{
|
||||
public readonly Cache<SheetType, SheetBuilder> SheetBuilders;
|
||||
readonly ISpriteLoader[] loaders;
|
||||
readonly IReadOnlyFileSystem fileSystem;
|
||||
|
||||
readonly Dictionary<string, List<Sprite[]>> sprites = new Dictionary<string, List<Sprite[]>>();
|
||||
readonly Dictionary<string, ISpriteFrame[]> unloadedFrames = new Dictionary<string, ISpriteFrame[]>();
|
||||
readonly Dictionary<string, TypeDictionary> metadata = new Dictionary<string, TypeDictionary>();
|
||||
|
||||
public SpriteCache(IReadOnlyFileSystem fileSystem, ISpriteLoader[] loaders)
|
||||
{
|
||||
SheetBuilders = new Cache<SheetType, SheetBuilder>(t => new SheetBuilder(t));
|
||||
|
||||
this.fileSystem = fileSystem;
|
||||
this.loaders = loaders;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the first set of sprites with the given filename.
|
||||
/// If getUsedFrames is defined then the indices returned by the function call
|
||||
/// are guaranteed to be loaded. The value of other indices in the returned
|
||||
/// array are undefined and should never be accessed.
|
||||
/// </summary>
|
||||
public Sprite[] this[string filename, Func<int, IEnumerable<int>> getUsedFrames = null]
|
||||
{
|
||||
get
|
||||
{
|
||||
var allSprites = sprites.GetOrAdd(filename);
|
||||
var sprite = allSprites.FirstOrDefault();
|
||||
|
||||
if (!unloadedFrames.TryGetValue(filename, out var unloaded))
|
||||
unloaded = null;
|
||||
|
||||
// This is the first time that the file has been requested
|
||||
// Load all of the frames into the unused buffer and initialize
|
||||
// the loaded cache (initially empty)
|
||||
if (sprite == null)
|
||||
{
|
||||
unloaded = FrameLoader.GetFrames(fileSystem, filename, loaders, out var fileMetadata);
|
||||
unloadedFrames[filename] = unloaded;
|
||||
metadata[filename] = fileMetadata;
|
||||
|
||||
sprite = new Sprite[unloaded.Length];
|
||||
allSprites.Add(sprite);
|
||||
}
|
||||
|
||||
// HACK: The sequence code relies on side-effects from getUsedFrames
|
||||
var indices = getUsedFrames != null ? getUsedFrames(sprite.Length) :
|
||||
Enumerable.Range(0, sprite.Length);
|
||||
|
||||
// Load any unused frames into the SheetBuilder
|
||||
if (unloaded != null)
|
||||
{
|
||||
foreach (var i in indices)
|
||||
{
|
||||
if (unloaded[i] != null)
|
||||
{
|
||||
sprite[i] = SheetBuilders[SheetBuilder.FrameTypeToSheetType(unloaded[i].Type)].Add(unloaded[i]);
|
||||
unloaded[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
// All frames have been loaded
|
||||
if (unloaded.All(f => f == null))
|
||||
unloadedFrames.Remove(filename);
|
||||
}
|
||||
|
||||
return sprite;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a TypeDictionary containing any metadata defined by the frame
|
||||
/// or null if the frame does not define metadata.
|
||||
/// </summary>
|
||||
public TypeDictionary FrameMetadata(string filename)
|
||||
{
|
||||
if (!metadata.TryGetValue(filename, out var fileMetadata))
|
||||
{
|
||||
FrameLoader.GetFrames(fileSystem, filename, loaders, out fileMetadata);
|
||||
metadata[filename] = fileMetadata;
|
||||
}
|
||||
|
||||
return fileMetadata;
|
||||
}
|
||||
}
|
||||
|
||||
public class FrameCache
|
||||
{
|
||||
readonly Cache<string, ISpriteFrame[]> frames;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -21,102 +21,95 @@ namespace OpenRA.Graphics
|
||||
|
||||
readonly Sprite sprite;
|
||||
readonly WPos pos;
|
||||
readonly WVec offset;
|
||||
readonly int zOffset;
|
||||
readonly PaletteReference palette;
|
||||
readonly float scale;
|
||||
readonly WAngle rotation = WAngle.Zero;
|
||||
readonly float3 tint;
|
||||
readonly TintModifiers tintModifiers;
|
||||
readonly float alpha;
|
||||
readonly bool isDecoration;
|
||||
|
||||
public SpriteRenderable(Sprite sprite, WPos pos, WVec offset, int zOffset, PaletteReference palette, float scale, float alpha,
|
||||
float3 tint, TintModifiers tintModifiers, bool isDecoration, WAngle rotation)
|
||||
{
|
||||
this.sprite = sprite;
|
||||
this.pos = pos;
|
||||
this.offset = offset;
|
||||
this.zOffset = zOffset;
|
||||
this.palette = palette;
|
||||
Offset = offset;
|
||||
ZOffset = zOffset;
|
||||
Palette = palette;
|
||||
this.scale = scale;
|
||||
this.rotation = rotation;
|
||||
this.tint = tint;
|
||||
this.isDecoration = isDecoration;
|
||||
this.tintModifiers = tintModifiers;
|
||||
this.alpha = alpha;
|
||||
Tint = tint;
|
||||
IsDecoration = isDecoration;
|
||||
TintModifiers = tintModifiers;
|
||||
Alpha = alpha;
|
||||
|
||||
// PERF: Remove useless palette assignments for RGBA sprites
|
||||
// HACK: This is working around the fact that palettes are defined on traits rather than sequences
|
||||
// and can be removed once this has been fixed
|
||||
if (sprite.Channel == TextureChannel.RGBA && !(palette?.HasColorShift ?? false))
|
||||
this.palette = null;
|
||||
Palette = null;
|
||||
}
|
||||
|
||||
public SpriteRenderable(Sprite sprite, WPos pos, WVec offset, int zOffset, PaletteReference palette, float scale, float alpha,
|
||||
float3 tint, TintModifiers tintModifiers, bool isDecoration)
|
||||
: this(sprite, pos, offset, zOffset, palette, scale, alpha, tint, tintModifiers, isDecoration, WAngle.Zero) { }
|
||||
|
||||
public WPos Pos => pos + offset;
|
||||
public WVec Offset => offset;
|
||||
public PaletteReference Palette => palette;
|
||||
public int ZOffset => zOffset;
|
||||
public bool IsDecoration => isDecoration;
|
||||
public WPos Pos => pos + Offset;
|
||||
public WVec Offset { get; }
|
||||
public PaletteReference Palette { get; }
|
||||
public int ZOffset { get; }
|
||||
public bool IsDecoration { get; }
|
||||
|
||||
public float Alpha => alpha;
|
||||
public float3 Tint => tint;
|
||||
public TintModifiers TintModifiers => tintModifiers;
|
||||
public float Alpha { get; }
|
||||
public float3 Tint { get; }
|
||||
public TintModifiers TintModifiers { get; }
|
||||
|
||||
public IPalettedRenderable WithPalette(PaletteReference newPalette)
|
||||
{
|
||||
return new SpriteRenderable(sprite, pos, offset, zOffset, newPalette, scale, alpha, tint, tintModifiers, isDecoration, rotation);
|
||||
return new SpriteRenderable(sprite, pos, Offset, ZOffset, newPalette, scale, Alpha, Tint, TintModifiers, IsDecoration, rotation);
|
||||
}
|
||||
|
||||
public IRenderable WithZOffset(int newOffset)
|
||||
{
|
||||
return new SpriteRenderable(sprite, pos, offset, newOffset, palette, scale, alpha, tint, tintModifiers, isDecoration, rotation);
|
||||
return new SpriteRenderable(sprite, pos, Offset, newOffset, Palette, scale, Alpha, Tint, TintModifiers, IsDecoration, rotation);
|
||||
}
|
||||
|
||||
public IRenderable OffsetBy(in WVec vec)
|
||||
{
|
||||
return new SpriteRenderable(sprite, pos + vec, offset, zOffset, palette, scale, alpha, tint, tintModifiers, isDecoration, rotation);
|
||||
return new SpriteRenderable(sprite, pos + vec, Offset, ZOffset, Palette, scale, Alpha, Tint, TintModifiers, IsDecoration, rotation);
|
||||
}
|
||||
|
||||
public IRenderable AsDecoration()
|
||||
{
|
||||
return new SpriteRenderable(sprite, pos, offset, zOffset, palette, scale, alpha, tint, tintModifiers, true, rotation);
|
||||
return new SpriteRenderable(sprite, pos, Offset, ZOffset, Palette, scale, Alpha, Tint, TintModifiers, true, rotation);
|
||||
}
|
||||
|
||||
public IModifyableRenderable WithAlpha(float newAlpha)
|
||||
{
|
||||
return new SpriteRenderable(sprite, pos, offset, zOffset, palette, scale, newAlpha, tint, tintModifiers, isDecoration, rotation);
|
||||
return new SpriteRenderable(sprite, pos, Offset, ZOffset, Palette, scale, newAlpha, Tint, TintModifiers, IsDecoration, rotation);
|
||||
}
|
||||
|
||||
public IModifyableRenderable WithTint(in float3 newTint, TintModifiers newTintModifiers)
|
||||
{
|
||||
return new SpriteRenderable(sprite, pos, offset, zOffset, palette, scale, alpha, newTint, newTintModifiers, isDecoration, rotation);
|
||||
return new SpriteRenderable(sprite, pos, Offset, ZOffset, Palette, scale, Alpha, newTint, newTintModifiers, IsDecoration, rotation);
|
||||
}
|
||||
|
||||
float3 ScreenPosition(WorldRenderer wr)
|
||||
{
|
||||
var s = 0.5f * scale * sprite.Size;
|
||||
return wr.Screen3DPxPosition(pos) + wr.ScreenPxOffset(offset) - new float3((int)s.X, (int)s.Y, s.Z);
|
||||
return wr.Screen3DPxPosition(pos) + wr.ScreenPxOffset(Offset) - new float3((int)s.X, (int)s.Y, s.Z);
|
||||
}
|
||||
|
||||
public IFinalizedRenderable PrepareRender(WorldRenderer wr) { return this; }
|
||||
public void Render(WorldRenderer wr)
|
||||
{
|
||||
var wsr = Game.Renderer.WorldSpriteRenderer;
|
||||
var t = alpha * tint;
|
||||
if (wr.TerrainLighting != null && (tintModifiers & TintModifiers.IgnoreWorldTint) == 0)
|
||||
var t = Alpha * Tint;
|
||||
if (wr.TerrainLighting != null && (TintModifiers & TintModifiers.IgnoreWorldTint) == 0)
|
||||
t *= wr.TerrainLighting.TintAt(pos);
|
||||
|
||||
// Shader interprets negative alpha as a flag to use the tint colour directly instead of multiplying the sprite colour
|
||||
var a = alpha;
|
||||
if ((tintModifiers & TintModifiers.ReplaceColor) != 0)
|
||||
var a = Alpha;
|
||||
if ((TintModifiers & TintModifiers.ReplaceColor) != 0)
|
||||
a *= -1;
|
||||
|
||||
wsr.DrawSprite(sprite, palette, ScreenPosition(wr), scale, t, a, rotation.RendererRadians());
|
||||
wsr.DrawSprite(sprite, Palette, ScreenPosition(wr), scale, t, a, rotation.RendererRadians());
|
||||
}
|
||||
|
||||
public void RenderDebugGeometry(WorldRenderer wr)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -114,7 +114,7 @@ namespace OpenRA.Graphics
|
||||
return new int2(sheetIndex, secondarySheetIndex);
|
||||
}
|
||||
|
||||
float ResolveTextureIndex(Sprite s, PaletteReference pal)
|
||||
static float ResolveTextureIndex(Sprite s, PaletteReference pal)
|
||||
{
|
||||
if (pal == null)
|
||||
return 0;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -27,7 +27,7 @@ namespace OpenRA.Graphics
|
||||
readonly IVertexBuffer<Vertex> vertexBuffer;
|
||||
readonly Vertex[] vertices;
|
||||
readonly bool[] ignoreTint;
|
||||
readonly HashSet<int> dirtyRows = new HashSet<int>();
|
||||
readonly HashSet<int> dirtyRows = new();
|
||||
readonly int rowStride;
|
||||
readonly bool restrictToBounds;
|
||||
|
||||
@@ -114,7 +114,7 @@ namespace OpenRA.Graphics
|
||||
// transparent for isometric tiles
|
||||
var tl = worldRenderer.TerrainLighting;
|
||||
var pos = map.CenterOfCell(uv.ToCPos(map));
|
||||
var step = map.Grid.Type == MapGridType.RectangularIsometric ? 724 : 512;
|
||||
var step = map.Grid.TileScale / 2;
|
||||
var weights = new[]
|
||||
{
|
||||
tl.TintAt(pos + new WVec(-step, -step, 0)),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -16,10 +16,7 @@ namespace OpenRA.Graphics
|
||||
public class UISpriteRenderable : IRenderable, IPalettedRenderable, IFinalizedRenderable
|
||||
{
|
||||
readonly Sprite sprite;
|
||||
readonly WPos effectiveWorldPos;
|
||||
readonly int2 screenPos;
|
||||
readonly int zOffset;
|
||||
readonly PaletteReference palette;
|
||||
readonly float scale;
|
||||
readonly float alpha;
|
||||
readonly float rotation = 0f;
|
||||
@@ -27,10 +24,10 @@ namespace OpenRA.Graphics
|
||||
public UISpriteRenderable(Sprite sprite, WPos effectiveWorldPos, int2 screenPos, int zOffset, PaletteReference palette, float scale = 1f, float alpha = 1f, float rotation = 0f)
|
||||
{
|
||||
this.sprite = sprite;
|
||||
this.effectiveWorldPos = effectiveWorldPos;
|
||||
Pos = effectiveWorldPos;
|
||||
this.screenPos = screenPos;
|
||||
this.zOffset = zOffset;
|
||||
this.palette = palette;
|
||||
ZOffset = zOffset;
|
||||
Palette = palette;
|
||||
this.scale = scale;
|
||||
this.alpha = alpha;
|
||||
this.rotation = rotation;
|
||||
@@ -39,18 +36,18 @@ namespace OpenRA.Graphics
|
||||
// HACK: This is working around the fact that palettes are defined on traits rather than sequences
|
||||
// and can be removed once this has been fixed
|
||||
if (sprite.Channel == TextureChannel.RGBA && !(palette?.HasColorShift ?? false))
|
||||
this.palette = null;
|
||||
Palette = null;
|
||||
}
|
||||
|
||||
// Does not exist in the world, so a world positions don't make sense
|
||||
public WPos Pos => effectiveWorldPos;
|
||||
public WPos Pos { get; }
|
||||
public WVec Offset => WVec.Zero;
|
||||
public bool IsDecoration => true;
|
||||
|
||||
public PaletteReference Palette => palette;
|
||||
public int ZOffset => zOffset;
|
||||
public PaletteReference Palette { get; }
|
||||
public int ZOffset { get; }
|
||||
|
||||
public IPalettedRenderable WithPalette(PaletteReference newPalette) { return new UISpriteRenderable(sprite, effectiveWorldPos, screenPos, zOffset, newPalette, scale, alpha, rotation); }
|
||||
public IPalettedRenderable WithPalette(PaletteReference newPalette) { return new UISpriteRenderable(sprite, Pos, screenPos, ZOffset, newPalette, scale, alpha, rotation); }
|
||||
public IRenderable WithZOffset(int newOffset) { return this; }
|
||||
public IRenderable OffsetBy(in WVec vec) { return this; }
|
||||
public IRenderable AsDecoration() { return this; }
|
||||
@@ -58,7 +55,7 @@ namespace OpenRA.Graphics
|
||||
public IFinalizedRenderable PrepareRender(WorldRenderer wr) { return this; }
|
||||
public void Render(WorldRenderer wr)
|
||||
{
|
||||
Game.Renderer.SpriteRenderer.DrawSprite(sprite, palette, screenPos, scale, float3.Ones, alpha, rotation);
|
||||
Game.Renderer.SpriteRenderer.DrawSprite(sprite, Palette, screenPos, scale, float3.Ones, alpha, rotation);
|
||||
}
|
||||
|
||||
public void RenderDebugGeometry(WorldRenderer wr)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -224,10 +224,10 @@ namespace OpenRA.Graphics
|
||||
}
|
||||
|
||||
/// <summary>Rotates a quad about its center in the x-y plane.</summary>
|
||||
/// <param name="tl">The top left vertex of the quad</param>
|
||||
/// <param name="size">A float3 containing the X, Y, and Z lengths of the quad</param>
|
||||
/// <param name="rotation">The number of radians to rotate by</param>
|
||||
/// <returns>An array of four vertices representing the rotated quad (top-left, top-right, bottom-right, bottom-left)</returns>
|
||||
/// <param name="tl">The top left vertex of the quad.</param>
|
||||
/// <param name="size">A float3 containing the X, Y, and Z lengths of the quad.</param>
|
||||
/// <param name="rotation">The number of radians to rotate by.</param>
|
||||
/// <returns>An array of four vertices representing the rotated quad (top-left, top-right, bottom-right, bottom-left).</returns>
|
||||
public static float3[] RotateQuad(float3 tl, float3 size, float rotation)
|
||||
{
|
||||
var center = tl + 0.5f * size;
|
||||
@@ -258,15 +258,15 @@ namespace OpenRA.Graphics
|
||||
/// <summary>
|
||||
/// Returns the bounds of an object. Used for determining which objects need to be rendered on screen, and which do not.
|
||||
/// </summary>
|
||||
/// <param name="offset">The top left vertex of the object</param>
|
||||
/// <param name="size">A float 3 containing the X, Y, and Z lengths of the object</param>
|
||||
/// <param name="rotation">The angle to rotate the object by (use 0f if there is no rotation)</param>
|
||||
/// <param name="offset">The top left vertex of the object.</param>
|
||||
/// <param name="size">A float 3 containing the X, Y, and Z lengths of the object.</param>
|
||||
/// <param name="rotation">The angle to rotate the object by (use 0f if there is no rotation).</param>
|
||||
public static Rectangle BoundingRectangle(float3 offset, float3 size, float rotation)
|
||||
{
|
||||
if (rotation == 0f)
|
||||
return new Rectangle((int)offset.X, (int)offset.Y, (int)size.X, (int)size.Y);
|
||||
|
||||
var rotatedQuad = Util.RotateQuad(offset, size, rotation);
|
||||
var rotatedQuad = RotateQuad(offset, size, rotation);
|
||||
var minX = rotatedQuad[0].X;
|
||||
var maxX = rotatedQuad[0].X;
|
||||
var minY = rotatedQuad[0].Y;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -53,7 +53,7 @@ namespace OpenRA.Graphics
|
||||
|
||||
public WPos CenterPosition => worldRenderer.ProjectedPosition(CenterLocation);
|
||||
|
||||
public Rectangle Rectangle => new Rectangle(TopLeft, new Size(viewportSize.X, viewportSize.Y));
|
||||
public Rectangle Rectangle => new(TopLeft, new Size(viewportSize.X, viewportSize.Y));
|
||||
public int2 TopLeft => CenterLocation - viewportSize / 2;
|
||||
public int2 BottomRight => CenterLocation + viewportSize / 2;
|
||||
int2 viewportSize;
|
||||
@@ -66,9 +66,6 @@ namespace OpenRA.Graphics
|
||||
WorldViewport lastViewportDistance;
|
||||
|
||||
float zoom = 1f;
|
||||
float minZoom = 1f;
|
||||
float maxZoom = 2f;
|
||||
|
||||
bool unlockMinZoom;
|
||||
float unlockedMinZoomScale;
|
||||
float unlockedMinZoom = 1f;
|
||||
@@ -86,12 +83,13 @@ namespace OpenRA.Graphics
|
||||
}
|
||||
}
|
||||
|
||||
public float MinZoom => minZoom;
|
||||
public float MinZoom { get; private set; } = 1f;
|
||||
public float MaxZoom { get; private set; } = 2f;
|
||||
|
||||
public void AdjustZoom(float dz)
|
||||
{
|
||||
// Exponential ensures that equal positive and negative steps have the same effect
|
||||
Zoom = (zoom * (float)Math.Exp(dz)).Clamp(unlockMinZoom ? unlockedMinZoom : minZoom, maxZoom);
|
||||
Zoom = (zoom * (float)Math.Exp(dz)).Clamp(unlockMinZoom ? unlockedMinZoom : MinZoom, MaxZoom);
|
||||
}
|
||||
|
||||
public void AdjustZoom(float dz, int2 center)
|
||||
@@ -105,10 +103,10 @@ namespace OpenRA.Graphics
|
||||
public void ToggleZoom()
|
||||
{
|
||||
// Unlocked zooms always reset to the default zoom
|
||||
if (zoom < minZoom)
|
||||
Zoom = minZoom;
|
||||
if (zoom < MinZoom)
|
||||
Zoom = MinZoom;
|
||||
else
|
||||
Zoom = zoom > minZoom ? minZoom : maxZoom;
|
||||
Zoom = zoom > MinZoom ? MinZoom : MaxZoom;
|
||||
}
|
||||
|
||||
public void UnlockMinimumZoom(float scale)
|
||||
@@ -121,23 +119,6 @@ namespace OpenRA.Graphics
|
||||
public static long LastMoveRunTime = 0;
|
||||
public static int2 LastMousePos;
|
||||
|
||||
float ClosestTo(float[] collection, float target)
|
||||
{
|
||||
var closestValue = collection.First();
|
||||
var subtractResult = Math.Abs(closestValue - target);
|
||||
|
||||
foreach (var element in collection)
|
||||
{
|
||||
if (Math.Abs(element - target) < subtractResult)
|
||||
{
|
||||
subtractResult = Math.Abs(element - target);
|
||||
closestValue = element;
|
||||
}
|
||||
}
|
||||
|
||||
return closestValue;
|
||||
}
|
||||
|
||||
public ScrollDirection GetBlockedDirections()
|
||||
{
|
||||
var ret = ScrollDirection.None;
|
||||
@@ -191,7 +172,7 @@ namespace OpenRA.Graphics
|
||||
UpdateViewportZooms();
|
||||
}
|
||||
|
||||
float CalculateMinimumZoom(float minHeight, float maxHeight)
|
||||
static float CalculateMinimumZoom(float minHeight, float maxHeight)
|
||||
{
|
||||
var h = Game.Renderer.NativeResolution.Height;
|
||||
|
||||
@@ -227,14 +208,14 @@ namespace OpenRA.Graphics
|
||||
|
||||
var vd = graphicSettings.ViewportDistance;
|
||||
if (viewportSizes.AllowNativeZoom && vd == WorldViewport.Native)
|
||||
minZoom = 1;
|
||||
MinZoom = viewportSizes.DefaultScale;
|
||||
else
|
||||
{
|
||||
var range = viewportSizes.GetSizeRange(vd);
|
||||
minZoom = CalculateMinimumZoom(range.X, range.Y);
|
||||
MinZoom = CalculateMinimumZoom(range.X, range.Y) * viewportSizes.DefaultScale;
|
||||
}
|
||||
|
||||
maxZoom = Math.Min(minZoom * viewportSizes.MaxZoomScale, Game.Renderer.NativeResolution.Height * 1f / viewportSizes.MaxZoomWindowHeight);
|
||||
MaxZoom = Math.Min(MinZoom * viewportSizes.MaxZoomScale, Game.Renderer.NativeResolution.Height * viewportSizes.DefaultScale / viewportSizes.MaxZoomWindowHeight);
|
||||
|
||||
if (unlockMinZoom)
|
||||
{
|
||||
@@ -242,19 +223,19 @@ namespace OpenRA.Graphics
|
||||
// TODO: Allow zooming out until the full map is visible
|
||||
// We need to improve our viewport scroll handling to center the map as we zoom out
|
||||
// before this will work well enough to enable
|
||||
unlockedMinZoom = minZoom * unlockedMinZoomScale;
|
||||
unlockedMinZoom = MinZoom * unlockedMinZoomScale;
|
||||
}
|
||||
|
||||
if (resetCurrentZoom)
|
||||
Zoom = minZoom;
|
||||
Zoom = MinZoom;
|
||||
else
|
||||
Zoom = Zoom.Clamp(minZoom, maxZoom);
|
||||
Zoom = Zoom.Clamp(MinZoom, MaxZoom);
|
||||
|
||||
var maxSize = (1f / (unlockMinZoom ? unlockedMinZoom : minZoom) * new float2(Game.Renderer.NativeResolution));
|
||||
var maxSize = 1f / (unlockMinZoom ? unlockedMinZoom : MinZoom) * new float2(Game.Renderer.NativeResolution);
|
||||
Game.Renderer.SetMaximumViewportSize(new Size((int)maxSize.X, (int)maxSize.Y));
|
||||
|
||||
foreach (var t in worldRenderer.World.WorldActor.TraitsImplementing<INotifyViewportZoomExtentsChanged>())
|
||||
t.ViewportZoomExtentsChanged(minZoom, maxZoom);
|
||||
t.ViewportZoomExtentsChanged(MinZoom, MaxZoom);
|
||||
}
|
||||
|
||||
public CPos ViewToWorld(int2 view)
|
||||
@@ -297,7 +278,7 @@ namespace OpenRA.Graphics
|
||||
return worldRenderer.World.Map.CellContaining(worldRenderer.ProjectedPosition(ViewToWorldPx(view)));
|
||||
}
|
||||
|
||||
/// <summary> Returns an unfiltered list of all cells that could potentially contain the mouse cursor</summary>
|
||||
/// <summary>Returns an unfiltered list of all cells that could potentially contain the mouse cursor.</summary>
|
||||
IEnumerable<MPos> CandidateMouseoverCells(int2 world)
|
||||
{
|
||||
var map = worldRenderer.World.Map;
|
||||
@@ -313,8 +294,8 @@ namespace OpenRA.Graphics
|
||||
}
|
||||
|
||||
public int2 ViewToWorldPx(int2 view) { return (graphicSettings.UIScale / Zoom * view.ToFloat2()).ToInt2() + TopLeft; }
|
||||
public int2 WorldToViewPx(int2 world) { return ((Zoom / graphicSettings.UIScale) * (world - TopLeft).ToFloat2()).ToInt2(); }
|
||||
public int2 WorldToViewPx(in float3 world) { return ((Zoom / graphicSettings.UIScale) * (world - TopLeft).XY).ToInt2(); }
|
||||
public int2 WorldToViewPx(int2 world) { return (Zoom / graphicSettings.UIScale * (world - TopLeft).ToFloat2()).ToInt2(); }
|
||||
public int2 WorldToViewPx(in float3 world) { return (Zoom / graphicSettings.UIScale * (world - TopLeft).XY).ToInt2(); }
|
||||
|
||||
public void Center(IEnumerable<Actor> actors)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -31,25 +31,25 @@ namespace OpenRA.Graphics
|
||||
|
||||
public event Action PaletteInvalidated = null;
|
||||
|
||||
readonly HashSet<Actor> onScreenActors = new HashSet<Actor>();
|
||||
readonly HardwarePalette palette = new HardwarePalette();
|
||||
readonly Dictionary<string, PaletteReference> palettes = new Dictionary<string, PaletteReference>();
|
||||
readonly HashSet<Actor> onScreenActors = new();
|
||||
readonly HardwarePalette palette = new();
|
||||
readonly Dictionary<string, PaletteReference> palettes = new();
|
||||
readonly IRenderTerrain terrainRenderer;
|
||||
readonly Lazy<DebugVisualizations> debugVis;
|
||||
readonly Func<string, PaletteReference> createPaletteReference;
|
||||
readonly bool enableDepthBuffer;
|
||||
|
||||
readonly List<IFinalizedRenderable> preparedRenderables = new List<IFinalizedRenderable>();
|
||||
readonly List<IFinalizedRenderable> preparedOverlayRenderables = new List<IFinalizedRenderable>();
|
||||
readonly List<IFinalizedRenderable> preparedAnnotationRenderables = new List<IFinalizedRenderable>();
|
||||
readonly List<IFinalizedRenderable> preparedRenderables = new();
|
||||
readonly List<IFinalizedRenderable> preparedOverlayRenderables = new();
|
||||
readonly List<IFinalizedRenderable> preparedAnnotationRenderables = new();
|
||||
|
||||
readonly List<IRenderable> renderablesBuffer = new List<IRenderable>();
|
||||
readonly List<IRenderable> renderablesBuffer = new();
|
||||
|
||||
internal WorldRenderer(ModData modData, World world)
|
||||
{
|
||||
World = world;
|
||||
TileSize = World.Map.Grid.TileSize;
|
||||
TileScale = World.Map.Grid.Type == MapGridType.RectangularIsometric ? 1448 : 1024;
|
||||
TileScale = World.Map.Grid.TileScale;
|
||||
Viewport = new Viewport(this, world.Map);
|
||||
|
||||
createPaletteReference = CreatePaletteReference;
|
||||
@@ -87,7 +87,7 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
// HACK: This is working around the fact that palettes are defined on traits rather than sequences
|
||||
// and can be removed once this has been fixed.
|
||||
return name == null ? null : palettes.GetOrAdd(name, createPaletteReference);
|
||||
return string.IsNullOrEmpty(name) ? null : palettes.GetOrAdd(name, createPaletteReference);
|
||||
}
|
||||
|
||||
public void AddPalette(string name, ImmutablePalette pal, bool allowModifiers = false, bool allowOverwrite = false)
|
||||
@@ -109,13 +109,13 @@ namespace OpenRA.Graphics
|
||||
palette.ReplacePalette(name, pal);
|
||||
|
||||
// Update cached PlayerReference if one exists
|
||||
if (palettes.ContainsKey(name))
|
||||
palettes[name].Palette = pal;
|
||||
if (palettes.TryGetValue(name, out var paletteReference))
|
||||
paletteReference.Palette = pal;
|
||||
}
|
||||
|
||||
public void SetPaletteColorShift(string name, float hueOffset, float satOffset, float minHue, float maxHue)
|
||||
public void SetPaletteColorShift(string name, float hueOffset, float satOffset, float valueModifier, float minHue, float maxHue)
|
||||
{
|
||||
palette.SetColorShift(name, hueOffset, satOffset, minHue, maxHue);
|
||||
palette.SetColorShift(name, hueOffset, satOffset, valueModifier, minHue, maxHue);
|
||||
}
|
||||
|
||||
// PERF: Avoid LINQ.
|
||||
@@ -177,7 +177,7 @@ namespace OpenRA.Graphics
|
||||
|
||||
foreach (var e in World.Effects)
|
||||
{
|
||||
if (!(e is IEffectAboveShroud ea))
|
||||
if (e is not IEffectAboveShroud ea)
|
||||
continue;
|
||||
|
||||
foreach (var renderable in ea.RenderAboveShroud(this))
|
||||
@@ -218,7 +218,7 @@ namespace OpenRA.Graphics
|
||||
|
||||
foreach (var e in World.Effects)
|
||||
{
|
||||
if (!(e is IEffectAnnotation ea))
|
||||
if (e is not IEffectAnnotation ea)
|
||||
continue;
|
||||
|
||||
foreach (var renderAnnotation in ea.RenderAnnotation(this))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -19,8 +19,8 @@ namespace OpenRA
|
||||
public readonly string Name;
|
||||
public readonly Hotkey Default = Hotkey.Invalid;
|
||||
public readonly string Description = "";
|
||||
public readonly HashSet<string> Types = new HashSet<string>();
|
||||
public readonly HashSet<string> Contexts = new HashSet<string>();
|
||||
public readonly HashSet<string> Types = new();
|
||||
public readonly HashSet<string> Contexts = new();
|
||||
public readonly bool Readonly = false;
|
||||
public bool HasDuplicates { get; internal set; }
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -18,8 +18,8 @@ namespace OpenRA
|
||||
public sealed class HotkeyManager
|
||||
{
|
||||
readonly Dictionary<string, Hotkey> settings;
|
||||
readonly Dictionary<string, HotkeyDefinition> definitions = new Dictionary<string, HotkeyDefinition>();
|
||||
readonly Dictionary<string, Hotkey> keys = new Dictionary<string, Hotkey>();
|
||||
readonly Dictionary<string, HotkeyDefinition> definitions = new();
|
||||
readonly Dictionary<string, Hotkey> keys = new();
|
||||
|
||||
public HotkeyManager(IReadOnlyFileSystem fileSystem, Dictionary<string, Hotkey> settings, Manifest manifest)
|
||||
{
|
||||
@@ -35,7 +35,7 @@ namespace OpenRA
|
||||
|
||||
foreach (var kv in settings)
|
||||
{
|
||||
if (definitions.ContainsKey(kv.Key) && !definitions[kv.Key].Readonly)
|
||||
if (definitions.TryGetValue(kv.Key, out var definition) && !definition.Readonly)
|
||||
keys[kv.Key] = kv.Value;
|
||||
}
|
||||
|
||||
@@ -43,6 +43,9 @@ namespace OpenRA
|
||||
hd.Value.HasDuplicates = GetFirstDuplicate(hd.Value, this[hd.Value.Name].GetValue()) != null;
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage(
|
||||
"Performance", "CA1854:Prefer the 'IDictionary.TryGetValue(TKey, out TValue)' method",
|
||||
Justification = "Func must perform a live lookup in the collection, as the lookup value can change.")]
|
||||
internal Func<Hotkey> GetHotkeyReference(string name)
|
||||
{
|
||||
// Is this a mod-defined hotkey?
|
||||
@@ -102,7 +105,7 @@ namespace OpenRA
|
||||
return null;
|
||||
}
|
||||
|
||||
public HotkeyReference this[string name] => new HotkeyReference(GetHotkeyReference(name));
|
||||
public HotkeyReference this[string name] => new(GetHotkeyReference(name));
|
||||
|
||||
public IEnumerable<HotkeyDefinition> Definitions => definitions.Values;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -9,12 +9,41 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
public class Utility
|
||||
{
|
||||
static readonly ConcurrentCache<Type, FieldInfo[]> TypeFields =
|
||||
new(type => type.GetFields());
|
||||
|
||||
static readonly ConcurrentCache<(MemberInfo Member, Type AttributeType), bool> MemberHasAttribute =
|
||||
new(x => Attribute.IsDefined(x.Member, x.AttributeType));
|
||||
|
||||
static readonly ConcurrentCache<(MemberInfo Member, Type AttributeType, bool Inherit), object[]> MemberCustomAttributes =
|
||||
new(x => x.Member.GetCustomAttributes(x.AttributeType, x.Inherit));
|
||||
|
||||
public static FieldInfo[] GetFields(Type type)
|
||||
{
|
||||
return TypeFields[type];
|
||||
}
|
||||
|
||||
public static bool HasAttribute<TAttribute>(MemberInfo member)
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
return MemberHasAttribute[(member, typeof(TAttribute))];
|
||||
}
|
||||
|
||||
public static TAttribute[] GetCustomAttributes<TAttribute>(MemberInfo member, bool inherit)
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
return (TAttribute[])MemberCustomAttributes[(member, typeof(TAttribute), inherit)];
|
||||
}
|
||||
|
||||
public readonly ModData ModData;
|
||||
public readonly InstalledMods Mods;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -15,7 +15,7 @@ namespace OpenRA
|
||||
{
|
||||
public readonly struct Hotkey : IEquatable<Hotkey>
|
||||
{
|
||||
public static Hotkey Invalid = new Hotkey(Keycode.UNKNOWN, Modifiers.None);
|
||||
public static Hotkey Invalid = new(Keycode.UNKNOWN, Modifiers.None);
|
||||
public bool IsValid()
|
||||
{
|
||||
return Key != Keycode.UNKNOWN;
|
||||
@@ -42,7 +42,7 @@ namespace OpenRA
|
||||
var mods = Modifiers.None;
|
||||
if (parts.Length >= 2)
|
||||
{
|
||||
var modString = s.Substring(s.IndexOf(' '));
|
||||
var modString = s[s.IndexOf(' ')..];
|
||||
if (!Enum<Modifiers>.TryParse(modString, true, out mods))
|
||||
return false;
|
||||
}
|
||||
@@ -84,7 +84,7 @@ namespace OpenRA
|
||||
return obj is Hotkey o && (Hotkey?)o == this;
|
||||
}
|
||||
|
||||
public override string ToString() { return $"{Key} {Modifiers.ToString("F")}"; }
|
||||
public override string ToString() { return $"{Key} {Modifiers:F}"; }
|
||||
|
||||
public string DisplayString()
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -14,7 +14,7 @@ using System;
|
||||
namespace OpenRA
|
||||
{
|
||||
/// <summary>
|
||||
/// A reference to either a named hotkey (defined in the game settings) or a statically assigned hotkey
|
||||
/// A reference to either a named hotkey (defined in the game settings) or a statically assigned hotkey.
|
||||
/// </summary>
|
||||
public class HotkeyReference
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -13,7 +13,8 @@ using System.Collections.Generic;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
// List of keycodes, duplicated from SDL 2.0.1
|
||||
// List of keycodes. Duplicated from SDL 2.0.1, with the addition
|
||||
// of MOUSE4 and MOUSE5.
|
||||
public enum Keycode
|
||||
{
|
||||
UNKNOWN = 0,
|
||||
@@ -252,11 +253,13 @@ namespace OpenRA
|
||||
KBDILLUMUP = 280 | (1 << 30),
|
||||
EJECT = 281 | (1 << 30),
|
||||
SLEEP = 282 | (1 << 30),
|
||||
MOUSE4 = 283 | (1 << 30),
|
||||
MOUSE5 = 284 | (1 << 30)
|
||||
}
|
||||
|
||||
public static class KeycodeExts
|
||||
{
|
||||
static readonly Dictionary<Keycode, string> KeyNames = new Dictionary<Keycode, string>
|
||||
static readonly Dictionary<Keycode, string> KeyNames = new()
|
||||
{
|
||||
{ Keycode.UNKNOWN, "Undefined" },
|
||||
{ Keycode.RETURN, "Return" },
|
||||
@@ -494,6 +497,8 @@ namespace OpenRA
|
||||
{ Keycode.KBDILLUMUP, "KBDIllumUp" },
|
||||
{ Keycode.EJECT, "Eject" },
|
||||
{ Keycode.SLEEP, "Sleep" },
|
||||
{ Keycode.MOUSE4, "Mouse 4" },
|
||||
{ Keycode.MOUSE5, "Mouse 5" },
|
||||
};
|
||||
|
||||
public static string DisplayString(Keycode k)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -54,7 +54,7 @@ namespace OpenRA
|
||||
return mods;
|
||||
}
|
||||
|
||||
Manifest LoadMod(string id, string path)
|
||||
static Manifest LoadMod(string id, string path)
|
||||
{
|
||||
IReadOnlyPackage package = null;
|
||||
try
|
||||
@@ -79,7 +79,7 @@ namespace OpenRA
|
||||
return null;
|
||||
}
|
||||
|
||||
Dictionary<string, Manifest> GetInstalledMods(IEnumerable<string> searchPaths, IEnumerable<string> explicitPaths)
|
||||
static Dictionary<string, Manifest> GetInstalledMods(IEnumerable<string> searchPaths, IEnumerable<string> explicitPaths)
|
||||
{
|
||||
var ret = new Dictionary<string, Manifest>();
|
||||
var candidates = GetCandidateMods(searchPaths)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -66,8 +66,10 @@ namespace OpenRA
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine("Failed to load keys: {0}", e);
|
||||
Log.Write("debug", "Failed to load player keypair from `{0}` with exception: {1}", filePath, e);
|
||||
Console.WriteLine("Failed to load keys:");
|
||||
Console.WriteLine(e);
|
||||
Log.Write("debug", $"Failed to load player keypair from `{filePath}` with exception:");
|
||||
Log.Write("debug", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +93,7 @@ namespace OpenRA
|
||||
innerData = FieldLoader.Load<PlayerProfile>(yaml.Value);
|
||||
if (innerData.KeyRevoked)
|
||||
{
|
||||
Log.Write("debug", "Revoking key with fingerprint {0}", Fingerprint);
|
||||
Log.Write("debug", $"Revoking key with fingerprint {Fingerprint}");
|
||||
DeleteKeypair();
|
||||
}
|
||||
else
|
||||
@@ -102,7 +104,8 @@ namespace OpenRA
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Write("debug", "Failed to parse player data result with exception: {0}", e);
|
||||
Log.Write("debug", "Failed to parse player data result with exception:");
|
||||
Log.Write("debug", e);
|
||||
innerState = LinkState.ConnectionFailed;
|
||||
}
|
||||
finally
|
||||
@@ -136,8 +139,10 @@ namespace OpenRA
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Write("debug", "Failed to generate keypair with exception: {1}", e);
|
||||
Console.WriteLine("Key generation failed: {0}", e);
|
||||
Log.Write("debug", "Failed to generate keypair with exception:");
|
||||
Log.Write("debug", e);
|
||||
Console.WriteLine("Key generation failed:");
|
||||
Console.WriteLine(e);
|
||||
|
||||
innerState = LinkState.Uninitialized;
|
||||
}
|
||||
@@ -152,8 +157,10 @@ namespace OpenRA
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Write("debug", "Failed to delete keypair with exception: {1}", e);
|
||||
Console.WriteLine("Key deletion failed: {0}", e);
|
||||
Log.Write("debug", "Failed to delete keypair with exception:");
|
||||
Log.Write("debug", e);
|
||||
Console.WriteLine("Key deletion failed:");
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
|
||||
innerState = LinkState.Uninitialized;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -19,7 +19,7 @@ namespace OpenRA
|
||||
public readonly int U, V;
|
||||
|
||||
public MPos(int u, int v) { U = u; V = v; }
|
||||
public static readonly MPos Zero = new MPos(0, 0);
|
||||
public static readonly MPos Zero = new(0, 0);
|
||||
|
||||
public static bool operator ==(MPos me, MPos other) { return me.U == other.U && me.V == other.V; }
|
||||
public static bool operator !=(MPos me, MPos other) { return !(me == other); }
|
||||
@@ -27,7 +27,7 @@ namespace OpenRA
|
||||
public override int GetHashCode() { return U.GetHashCode() ^ V.GetHashCode(); }
|
||||
|
||||
public bool Equals(MPos other) { return other == this; }
|
||||
public override bool Equals(object obj) { return obj is MPos && Equals((MPos)obj); }
|
||||
public override bool Equals(object obj) { return obj is MPos uv && Equals(uv); }
|
||||
|
||||
public MPos Clamp(Rectangle r)
|
||||
{
|
||||
@@ -64,14 +64,14 @@ namespace OpenRA
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Projected map position
|
||||
/// Projected map position.
|
||||
/// </summary>
|
||||
public readonly struct PPos : IEquatable<PPos>
|
||||
{
|
||||
public readonly int U, V;
|
||||
|
||||
public PPos(int u, int v) { U = u; V = v; }
|
||||
public static readonly PPos Zero = new PPos(0, 0);
|
||||
public static readonly PPos Zero = new(0, 0);
|
||||
|
||||
public static bool operator ==(PPos me, PPos other) { return me.U == other.U && me.V == other.V; }
|
||||
public static bool operator !=(PPos me, PPos other) { return !(me == other); }
|
||||
@@ -88,7 +88,7 @@ namespace OpenRA
|
||||
public override int GetHashCode() { return U.GetHashCode() ^ V.GetHashCode(); }
|
||||
|
||||
public bool Equals(PPos other) { return other == this; }
|
||||
public override bool Equals(object obj) { return obj is PPos && Equals((PPos)obj); }
|
||||
public override bool Equals(object obj) { return obj is PPos puv && Equals(puv); }
|
||||
|
||||
public override string ToString() { return U + "," + V; }
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -64,8 +64,8 @@ namespace OpenRA
|
||||
public bool Hidden;
|
||||
}
|
||||
|
||||
/// <summary> Describes what is to be loaded in order to run a mod. </summary>
|
||||
public class Manifest : IDisposable
|
||||
/// <summary>Describes what is to be loaded in order to run a mod.</summary>
|
||||
public sealed class Manifest : IDisposable
|
||||
{
|
||||
public readonly string Id;
|
||||
public readonly IReadOnlyPackage Package;
|
||||
@@ -95,7 +95,7 @@ namespace OpenRA
|
||||
"RequiresMods", "PackageFormats"
|
||||
};
|
||||
|
||||
readonly TypeDictionary modules = new TypeDictionary();
|
||||
readonly TypeDictionary modules = new();
|
||||
readonly Dictionary<string, MiniYaml> yaml;
|
||||
|
||||
bool customDataLoaded;
|
||||
@@ -157,25 +157,25 @@ namespace OpenRA
|
||||
// Allow inherited mods to import parent maps.
|
||||
var compat = new List<string> { Id };
|
||||
|
||||
if (yaml.ContainsKey("SupportsMapsFrom"))
|
||||
compat.AddRange(yaml["SupportsMapsFrom"].Value.Split(',').Select(c => c.Trim()));
|
||||
if (yaml.TryGetValue("SupportsMapsFrom", out var entry))
|
||||
compat.AddRange(entry.Value.Split(',').Select(c => c.Trim()));
|
||||
|
||||
MapCompatibility = compat.ToArray();
|
||||
|
||||
if (yaml.ContainsKey("DefaultOrderGenerator"))
|
||||
DefaultOrderGenerator = yaml["DefaultOrderGenerator"].Value;
|
||||
if (yaml.TryGetValue("DefaultOrderGenerator", out entry))
|
||||
DefaultOrderGenerator = entry.Value;
|
||||
|
||||
if (yaml.ContainsKey("PackageFormats"))
|
||||
PackageFormats = FieldLoader.GetValue<string[]>("PackageFormats", yaml["PackageFormats"].Value);
|
||||
if (yaml.TryGetValue("PackageFormats", out entry))
|
||||
PackageFormats = FieldLoader.GetValue<string[]>("PackageFormats", entry.Value);
|
||||
|
||||
if (yaml.ContainsKey("SoundFormats"))
|
||||
SoundFormats = FieldLoader.GetValue<string[]>("SoundFormats", yaml["SoundFormats"].Value);
|
||||
if (yaml.TryGetValue("SoundFormats", out entry))
|
||||
SoundFormats = FieldLoader.GetValue<string[]>("SoundFormats", entry.Value);
|
||||
|
||||
if (yaml.ContainsKey("SpriteFormats"))
|
||||
SpriteFormats = FieldLoader.GetValue<string[]>("SpriteFormats", yaml["SpriteFormats"].Value);
|
||||
if (yaml.TryGetValue("SpriteFormats", out entry))
|
||||
SpriteFormats = FieldLoader.GetValue<string[]>("SpriteFormats", entry.Value);
|
||||
|
||||
if (yaml.ContainsKey("VideoFormats"))
|
||||
VideoFormats = FieldLoader.GetValue<string[]>("VideoFormats", yaml["VideoFormats"].Value);
|
||||
if (yaml.TryGetValue("VideoFormats", out entry))
|
||||
VideoFormats = FieldLoader.GetValue<string[]>("VideoFormats", entry.Value);
|
||||
}
|
||||
|
||||
public void LoadCustomData(ObjectCreator oc)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -54,7 +54,7 @@ namespace OpenRA
|
||||
// Traits tagged with an instance name prefer inits with the same name.
|
||||
// If a more specific init is not available, fall back to an unnamed init.
|
||||
// If duplicate inits are defined, take the last to match standard yaml override expectations
|
||||
if (info != null && !string.IsNullOrEmpty(info.InstanceName))
|
||||
if (!string.IsNullOrEmpty(info?.InstanceName))
|
||||
return inits.LastOrDefault(i => i.InstanceName == info.InstanceName) ??
|
||||
inits.LastOrDefault(i => string.IsNullOrEmpty(i.InstanceName));
|
||||
|
||||
@@ -159,9 +159,9 @@ namespace OpenRA
|
||||
|
||||
public virtual void Initialize(T value)
|
||||
{
|
||||
var field = typeof(ValueActorInit<T>).GetField(nameof(value), BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
if (field != null)
|
||||
field.SetValue(this, value);
|
||||
typeof(ValueActorInit<T>)
|
||||
.GetField(nameof(value), BindingFlags.NonPublic | BindingFlags.Instance)
|
||||
?.SetValue(this, value);
|
||||
}
|
||||
|
||||
public override MiniYaml Save()
|
||||
@@ -246,16 +246,16 @@ namespace OpenRA
|
||||
|
||||
public void Initialize(MiniYaml yaml)
|
||||
{
|
||||
var field = typeof(OwnerInit).GetField(nameof(InternalName), BindingFlags.Public | BindingFlags.Instance);
|
||||
if (field != null)
|
||||
field.SetValue(this, yaml.Value);
|
||||
typeof(OwnerInit)
|
||||
.GetField(nameof(InternalName), BindingFlags.Public | BindingFlags.Instance)
|
||||
?.SetValue(this, yaml.Value);
|
||||
}
|
||||
|
||||
public void Initialize(Player player)
|
||||
{
|
||||
var field = typeof(OwnerInit).GetField(nameof(value), BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
if (field != null)
|
||||
field.SetValue(this, player);
|
||||
typeof(OwnerInit)
|
||||
.GetField(nameof(value), BindingFlags.NonPublic | BindingFlags.Instance)
|
||||
?.SetValue(this, player);
|
||||
}
|
||||
|
||||
public override MiniYaml Save()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -22,7 +22,7 @@ namespace OpenRA
|
||||
{
|
||||
public interface ISuppressInitExport { }
|
||||
|
||||
public class ActorReference : IEnumerable
|
||||
public class ActorReference : IEnumerable<object>
|
||||
{
|
||||
public string Type;
|
||||
readonly Lazy<TypeDictionary> initDict;
|
||||
@@ -87,14 +87,14 @@ namespace OpenRA
|
||||
var ret = new MiniYaml(Type);
|
||||
foreach (var o in initDict.Value)
|
||||
{
|
||||
if (!(o is ActorInit init) || o is ISuppressInitExport)
|
||||
if (o is not ActorInit init || o is ISuppressInitExport)
|
||||
continue;
|
||||
|
||||
if (initFilter != null && !initFilter(init))
|
||||
continue;
|
||||
|
||||
var initTypeName = init.GetType().Name;
|
||||
var initName = initTypeName.Substring(0, initTypeName.Length - 4);
|
||||
var initName = initTypeName[..^4];
|
||||
if (!string.IsNullOrEmpty(init.InstanceName))
|
||||
initName += ActorInfo.TraitInstanceSeparator + init.InstanceName;
|
||||
|
||||
@@ -104,7 +104,9 @@ namespace OpenRA
|
||||
return ret;
|
||||
}
|
||||
|
||||
public IEnumerator GetEnumerator() { return initDict.Value.GetEnumerator(); }
|
||||
public IEnumerator<object> GetEnumerator() { return initDict.Value.GetEnumerator(); }
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
|
||||
|
||||
public ActorReference Clone()
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -72,7 +72,7 @@ namespace OpenRA
|
||||
return uv.V * Size.Width + uv.U;
|
||||
}
|
||||
|
||||
/// <summary>Gets or sets the <see cref="CellLayer"/> using cell coordinates</summary>
|
||||
/// <summary>Gets or sets the <see cref="CellLayer"/> using cell coordinates.</summary>
|
||||
public T this[CPos cell]
|
||||
{
|
||||
get => Entries[Index(cell)];
|
||||
@@ -85,7 +85,7 @@ namespace OpenRA
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Gets or sets the layer contents using raw map coordinates (not CPos!)</summary>
|
||||
/// <summary>Gets or sets the layer contents using raw map coordinates (not CPos!).</summary>
|
||||
public T this[MPos uv]
|
||||
{
|
||||
get => Entries[Index(uv)];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -24,10 +24,10 @@ namespace OpenRA
|
||||
protected readonly T[] Entries;
|
||||
protected readonly Rectangle Bounds;
|
||||
|
||||
public CellLayerBase(Map map)
|
||||
protected CellLayerBase(Map map)
|
||||
: this(map.Grid.Type, new Size(map.MapSize.X, map.MapSize.Y)) { }
|
||||
|
||||
public CellLayerBase(MapGridType gridType, Size size)
|
||||
protected CellLayerBase(MapGridType gridType, Size size)
|
||||
{
|
||||
Size = size;
|
||||
Bounds = new Rectangle(0, 0, Size.Width, Size.Height);
|
||||
@@ -43,13 +43,13 @@ namespace OpenRA
|
||||
Array.Copy(anotherLayer.Entries, Entries, Entries.Length);
|
||||
}
|
||||
|
||||
/// <summary>Clears the layer contents with their default value</summary>
|
||||
/// <summary>Clears the layer contents with their default value.</summary>
|
||||
public virtual void Clear()
|
||||
{
|
||||
Array.Clear(Entries, 0, Entries.Length);
|
||||
}
|
||||
|
||||
/// <summary>Clears the layer contents with a known value</summary>
|
||||
/// <summary>Clears the layer contents with a known value.</summary>
|
||||
public virtual void Clear(T clearValue)
|
||||
{
|
||||
Array.Fill(Entries, clearValue);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -102,7 +102,7 @@ namespace OpenRA
|
||||
return uv.U >= mapTopLeft.U && uv.U <= mapBottomRight.U && uv.V >= mapTopLeft.V && uv.V <= mapBottomRight.V;
|
||||
}
|
||||
|
||||
public MapCoordsRegion MapCoords => new MapCoordsRegion(mapTopLeft, mapBottomRight);
|
||||
public MapCoordsRegion MapCoords => new(mapTopLeft, mapBottomRight);
|
||||
|
||||
public CellRegionEnumerator GetEnumerator()
|
||||
{
|
||||
@@ -126,15 +126,12 @@ namespace OpenRA
|
||||
// Current position, in map coordinates
|
||||
int u, v;
|
||||
|
||||
// Current position, in cell coordinates
|
||||
CPos current;
|
||||
|
||||
public CellRegionEnumerator(CellRegion region)
|
||||
: this()
|
||||
{
|
||||
r = region;
|
||||
Reset();
|
||||
current = new MPos(u, v).ToCPos(r.gridType);
|
||||
Current = new MPos(u, v).ToCPos(r.gridType);
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
@@ -152,7 +149,8 @@ namespace OpenRA
|
||||
return false;
|
||||
}
|
||||
|
||||
current = new MPos(u, v).ToCPos(r.gridType);
|
||||
// Current position, in cell coordinates
|
||||
Current = new MPos(u, v).ToCPos(r.gridType);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -163,7 +161,7 @@ namespace OpenRA
|
||||
v = r.mapTopLeft.V;
|
||||
}
|
||||
|
||||
public CPos Current => current;
|
||||
public CPos Current { get; private set; }
|
||||
object IEnumerator.Current => Current;
|
||||
public void Dispose() { }
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -65,7 +65,7 @@ namespace OpenRA
|
||||
MissionSelector = 4
|
||||
}
|
||||
|
||||
class MapField
|
||||
sealed class MapField
|
||||
{
|
||||
enum Type { Normal, NodeList, MiniYaml }
|
||||
readonly FieldInfo field;
|
||||
@@ -149,13 +149,13 @@ namespace OpenRA
|
||||
}
|
||||
}
|
||||
|
||||
public class Map : IReadOnlyFileSystem
|
||||
public sealed class Map : IReadOnlyFileSystem, IDisposable
|
||||
{
|
||||
public const int SupportedMapFormat = 11;
|
||||
public const int CurrentMapFormat = 12;
|
||||
const short InvalidCachedTerrainIndex = -1;
|
||||
|
||||
/// <summary>Defines the order of the fields in map.yaml</summary>
|
||||
/// <summary>Defines the order of the fields in map.yaml.</summary>
|
||||
static readonly MapField[] YamlFields =
|
||||
{
|
||||
new MapField("MapFormat"),
|
||||
@@ -167,11 +167,11 @@ namespace OpenRA
|
||||
new MapField("Bounds"),
|
||||
new MapField("Visibility"),
|
||||
new MapField("Categories"),
|
||||
new MapField("Translations", required: false, ignoreIfValue: ""),
|
||||
new MapField("LockPreview", required: false, ignoreIfValue: "False"),
|
||||
new MapField("Players", "PlayerDefinitions"),
|
||||
new MapField("Actors", "ActorDefinitions"),
|
||||
new MapField("Rules", "RuleDefinitions", required: false),
|
||||
new MapField("Translations", "TranslationDefinitions", required: false),
|
||||
new MapField("Sequences", "SequenceDefinitions", required: false),
|
||||
new MapField("ModelSequences", "ModelSequenceDefinitions", required: false),
|
||||
new MapField("Weapons", "WeaponDefinitions", required: false),
|
||||
@@ -193,16 +193,16 @@ namespace OpenRA
|
||||
public Rectangle Bounds;
|
||||
public MapVisibility Visibility = MapVisibility.Lobby;
|
||||
public string[] Categories = { "Conquest" };
|
||||
public string[] Translations;
|
||||
|
||||
public int2 MapSize { get; private set; }
|
||||
|
||||
// Player and actor yaml. Public for access by the map importers and lint checks.
|
||||
public List<MiniYamlNode> PlayerDefinitions = new List<MiniYamlNode>();
|
||||
public List<MiniYamlNode> ActorDefinitions = new List<MiniYamlNode>();
|
||||
public List<MiniYamlNode> PlayerDefinitions = new();
|
||||
public List<MiniYamlNode> ActorDefinitions = new();
|
||||
|
||||
// Custom map yaml. Public for access by the map importers and lint checks
|
||||
public readonly MiniYaml RuleDefinitions;
|
||||
public readonly MiniYaml TranslationDefinitions;
|
||||
public readonly MiniYaml SequenceDefinitions;
|
||||
public readonly MiniYaml ModelSequenceDefinitions;
|
||||
public readonly MiniYaml WeaponDefinitions;
|
||||
@@ -210,7 +210,7 @@ namespace OpenRA
|
||||
public readonly MiniYaml MusicDefinitions;
|
||||
public readonly MiniYaml NotificationDefinitions;
|
||||
|
||||
public readonly Dictionary<CPos, TerrainTile> ReplacedInvalidTerrainTiles = new Dictionary<CPos, TerrainTile>();
|
||||
public readonly Dictionary<CPos, TerrainTile> ReplacedInvalidTerrainTiles = new();
|
||||
|
||||
// Generated data
|
||||
public readonly MapGrid Grid;
|
||||
@@ -218,6 +218,8 @@ namespace OpenRA
|
||||
public string Uid { get; private set; }
|
||||
|
||||
public Ruleset Rules { get; private set; }
|
||||
public SequenceSet Sequences { get; private set; }
|
||||
|
||||
public bool InvalidCustomRules { get; private set; }
|
||||
public Exception InvalidCustomRulesException { get; private set; }
|
||||
|
||||
@@ -243,6 +245,8 @@ namespace OpenRA
|
||||
public CellRegion AllCells { get; private set; }
|
||||
public List<CPos> AllEdgeCells { get; private set; }
|
||||
|
||||
public event Action<CPos> CellProjectionChanged;
|
||||
|
||||
// Internal data
|
||||
readonly ModData modData;
|
||||
CellLayer<short> cachedTerrainIndexes;
|
||||
@@ -252,8 +256,6 @@ namespace OpenRA
|
||||
CellLayer<byte> projectedHeight;
|
||||
Rectangle projectionSafeBounds;
|
||||
|
||||
internal Translation Translation;
|
||||
|
||||
public static string ComputeUID(IReadOnlyPackage package)
|
||||
{
|
||||
return ComputeUID(package, GetMapFormat(package));
|
||||
@@ -336,11 +338,12 @@ namespace OpenRA
|
||||
Height = new CellLayer<byte>(Grid.Type, size);
|
||||
Ramp = new CellLayer<byte>(Grid.Type, size);
|
||||
Tiles.Clear(terrainInfo.DefaultTerrainTile);
|
||||
|
||||
if (Grid.MaximumTerrainHeight > 0)
|
||||
{
|
||||
Height.CellEntryChanged += UpdateProjection;
|
||||
Tiles.CellEntryChanged += UpdateProjection;
|
||||
Tiles.CellEntryChanged += UpdateRamp;
|
||||
Tiles.CellEntryChanged += UpdateProjection;
|
||||
Height.CellEntryChanged += UpdateProjection;
|
||||
}
|
||||
|
||||
PostInit();
|
||||
@@ -387,7 +390,7 @@ namespace OpenRA
|
||||
|
||||
// TODO: Remember to remove this when rewriting tile variants / PickAny
|
||||
if (index == byte.MaxValue)
|
||||
index = (byte)(i % 4 + (j % 4) * 4);
|
||||
index = (byte)(i % 4 + j % 4 * 4);
|
||||
|
||||
Tiles[new MPos(i, j)] = new TerrainTile(tile, index);
|
||||
}
|
||||
@@ -434,19 +437,18 @@ namespace OpenRA
|
||||
try
|
||||
{
|
||||
Rules = Ruleset.Load(modData, this, Tileset, RuleDefinitions, WeaponDefinitions,
|
||||
VoiceDefinitions, NotificationDefinitions, MusicDefinitions, SequenceDefinitions, ModelSequenceDefinitions);
|
||||
VoiceDefinitions, NotificationDefinitions, MusicDefinitions, ModelSequenceDefinitions);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Write("debug", "Failed to load rules for {0} with error {1}", Title, e);
|
||||
Log.Write("debug", $"Failed to load rules for {Title} with error");
|
||||
Log.Write("debug", e);
|
||||
InvalidCustomRules = true;
|
||||
InvalidCustomRulesException = e;
|
||||
Rules = Ruleset.LoadDefaultsForTileSet(modData, Tileset);
|
||||
}
|
||||
|
||||
Rules.Sequences.Preload();
|
||||
|
||||
Translation = new Translation(Game.Settings.Player.Language, Translations, this);
|
||||
Sequences = new SequenceSet(this, modData, Tileset, SequenceDefinitions);
|
||||
|
||||
var tl = new MPos(0, 0).ToCPos(this);
|
||||
var br = new MPos(MapSize.X - 1, MapSize.Y - 1).ToCPos(this);
|
||||
@@ -477,17 +479,17 @@ namespace OpenRA
|
||||
AllEdgeCells = UpdateEdgeCells();
|
||||
|
||||
// Invalidate the entry for a cell if anything could cause the terrain index to change.
|
||||
Action<CPos> invalidateTerrainIndex = c =>
|
||||
void InvalidateTerrainIndex(CPos c)
|
||||
{
|
||||
if (cachedTerrainIndexes != null)
|
||||
cachedTerrainIndexes[c] = InvalidCachedTerrainIndex;
|
||||
};
|
||||
}
|
||||
|
||||
// Even though the cache is lazily initialized, we must attach these event handlers on init.
|
||||
// This ensures our handler to invalidate the cache runs first,
|
||||
// so other listeners to these same events will get correct data when calling GetTerrainIndex.
|
||||
CustomTerrain.CellEntryChanged += invalidateTerrainIndex;
|
||||
Tiles.CellEntryChanged += invalidateTerrainIndex;
|
||||
CustomTerrain.CellEntryChanged += InvalidateTerrainIndex;
|
||||
Tiles.CellEntryChanged += InvalidateTerrainIndex;
|
||||
}
|
||||
|
||||
void UpdateRamp(CPos cell)
|
||||
@@ -530,6 +532,7 @@ namespace OpenRA
|
||||
var inverse = inverseCellProjection[uv];
|
||||
inverse.Clear();
|
||||
inverse.Add(uv);
|
||||
CellProjectionChanged?.Invoke(cell);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -567,6 +570,8 @@ namespace OpenRA
|
||||
projectedHeight[temp] = height;
|
||||
}
|
||||
}
|
||||
|
||||
CellProjectionChanged?.Invoke(cell);
|
||||
}
|
||||
|
||||
byte ProjectedCellHeightInner(PPos puv)
|
||||
@@ -642,12 +647,21 @@ namespace OpenRA
|
||||
toPackage.Update(file, Package.GetStream(file).ReadAllBytes());
|
||||
|
||||
if (!LockPreview)
|
||||
toPackage.Update("map.png", SavePreview());
|
||||
{
|
||||
var previewData = SavePreview();
|
||||
if (Package != toPackage || !Enumerable.SequenceEqual(previewData, Package.GetStream("map.png").ReadAllBytes()))
|
||||
toPackage.Update("map.png", previewData);
|
||||
}
|
||||
|
||||
// Update the package with the new map data
|
||||
var s = root.WriteToString();
|
||||
toPackage.Update("map.yaml", Encoding.UTF8.GetBytes(s));
|
||||
toPackage.Update("map.bin", SaveBinaryData());
|
||||
var textData = Encoding.UTF8.GetBytes(root.WriteToString());
|
||||
if (Package != toPackage || !Enumerable.SequenceEqual(textData, Package.GetStream("map.yaml").ReadAllBytes()))
|
||||
toPackage.Update("map.yaml", textData);
|
||||
|
||||
var binaryData = SaveBinaryData();
|
||||
if (Package != toPackage || !Enumerable.SequenceEqual(binaryData, Package.GetStream("map.bin").ReadAllBytes()))
|
||||
toPackage.Update("map.bin", binaryData);
|
||||
|
||||
Package = toPackage;
|
||||
|
||||
// Update UID to match the newly saved data
|
||||
@@ -733,8 +747,8 @@ namespace OpenRA
|
||||
public byte[] SavePreview()
|
||||
{
|
||||
var actorTypes = Rules.Actors.Values.Where(a => a.HasTraitInfo<IMapPreviewSignatureInfo>());
|
||||
var actors = ActorDefinitions.Where(a => actorTypes.Where(ai => ai.Name == a.Value.Value).Any());
|
||||
var positions = new List<(MPos Position, Color Color)>();
|
||||
var actors = ActorDefinitions.Where(a => actorTypes.Any(ai => ai.Name == a.Value.Value));
|
||||
var positions = new List<(MPos Uv, Color Color)>();
|
||||
foreach (var actor in actors)
|
||||
{
|
||||
var s = new ActorReference(actor.Value.Value, actor.Value.ToDictionary());
|
||||
@@ -791,14 +805,17 @@ namespace OpenRA
|
||||
var minimapData = new byte[stride * height];
|
||||
(Color Left, Color Right) terrainColor = default;
|
||||
|
||||
var colorsByPosition = positions
|
||||
.GroupBy(p => p.Uv)
|
||||
.ToDictionary(g => g.Key, g => g.First().Color);
|
||||
for (var y = 0; y < height; y++)
|
||||
{
|
||||
for (var x = 0; x < width; x++)
|
||||
{
|
||||
var uv = new MPos(x + Bounds.Left, y + top);
|
||||
|
||||
// FirstOrDefault will return a (MPos.Zero, Color.Transparent) if positions is empty
|
||||
var actorColor = positions.FirstOrDefault(ap => ap.Position == uv).Color;
|
||||
// TryGetValue will return Color.Transparent if not found
|
||||
colorsByPosition.TryGetValue(uv, out var actorColor);
|
||||
if (actorColor.A == 0)
|
||||
terrainColor = GetTerrainColorPair(uv);
|
||||
|
||||
@@ -977,11 +994,11 @@ namespace OpenRA
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The size of the map Height step in world units
|
||||
/// The size of the map Height step in world units.
|
||||
/// </summary>
|
||||
/// RectangularIsometric defines 1024 units along the diagonal axis,
|
||||
/// giving a half-tile height step of sqrt(2) * 512
|
||||
public WDist CellHeightStep => new WDist(Grid.Type == MapGridType.RectangularIsometric ? 724 : 512);
|
||||
public WDist CellHeightStep => new(Grid.Type == MapGridType.RectangularIsometric ? 724 : 512);
|
||||
|
||||
public CPos CellContaining(WPos pos)
|
||||
{
|
||||
@@ -1191,7 +1208,7 @@ namespace OpenRA
|
||||
// This shouldn't happen. But if it does, return the original value and hope the caller doesn't explode.
|
||||
if (unProjected.Count == 0)
|
||||
{
|
||||
Log.Write("debug", "Failed to clamp map cell {0} to map bounds", uv);
|
||||
Log.Write("debug", $"Failed to clamp map cell {uv} to map bounds");
|
||||
return uv;
|
||||
}
|
||||
}
|
||||
@@ -1233,8 +1250,8 @@ namespace OpenRA
|
||||
if (allProjected.Length > 0)
|
||||
{
|
||||
var puv = allProjected.First();
|
||||
var horizontalBound = ((puv.U - Bounds.Left) < Bounds.Width / 2) ? Bounds.Left : Bounds.Right;
|
||||
var verticalBound = ((puv.V - Bounds.Top) < Bounds.Height / 2) ? Bounds.Top : Bounds.Bottom;
|
||||
var horizontalBound = (puv.U - Bounds.Left < Bounds.Width / 2) ? Bounds.Left : Bounds.Right;
|
||||
var verticalBound = (puv.V - Bounds.Top < Bounds.Height / 2) ? Bounds.Top : Bounds.Bottom;
|
||||
|
||||
var du = Math.Abs(horizontalBound - puv.U);
|
||||
var dv = Math.Abs(verticalBound - puv.V);
|
||||
@@ -1263,7 +1280,7 @@ namespace OpenRA
|
||||
// This shouldn't happen. But if it does, return the original value and hope the caller doesn't explode.
|
||||
if (unProjected.Count == 0)
|
||||
{
|
||||
Log.Write("debug", "Failed to find closest edge for map cell {0}", uv);
|
||||
Log.Write("debug", $"Failed to find closest edge for map cell {uv}");
|
||||
return uv;
|
||||
}
|
||||
}
|
||||
@@ -1394,12 +1411,9 @@ namespace OpenRA
|
||||
return false;
|
||||
}
|
||||
|
||||
public string Translate(string key, IDictionary<string, object> args = null)
|
||||
public void Dispose()
|
||||
{
|
||||
if (Translation.TryGetString(key, out var message, args))
|
||||
return message;
|
||||
|
||||
return modData.Translation.GetString(key, args);
|
||||
Sequences.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -25,32 +25,33 @@ namespace OpenRA
|
||||
{
|
||||
public sealed class MapCache : IEnumerable<MapPreview>, IDisposable
|
||||
{
|
||||
public static readonly MapPreview UnknownMap = new MapPreview(null, null, MapGridType.Rectangular, null);
|
||||
public static readonly MapPreview UnknownMap = new(null, null, MapGridType.Rectangular, null);
|
||||
public IReadOnlyDictionary<IReadOnlyPackage, MapClassification> MapLocations => mapLocations;
|
||||
readonly Dictionary<IReadOnlyPackage, MapClassification> mapLocations = new Dictionary<IReadOnlyPackage, MapClassification>();
|
||||
readonly Dictionary<IReadOnlyPackage, MapClassification> mapLocations = new();
|
||||
public bool LoadPreviewImages = true;
|
||||
|
||||
readonly Cache<string, MapPreview> previews;
|
||||
readonly ModData modData;
|
||||
readonly SheetBuilder sheetBuilder;
|
||||
Thread previewLoaderThread;
|
||||
bool previewLoaderThreadShutDown = true;
|
||||
readonly object syncRoot = new object();
|
||||
readonly Queue<MapPreview> generateMinimap = new Queue<MapPreview>();
|
||||
readonly object syncRoot = new();
|
||||
readonly Queue<MapPreview> generateMinimap = new();
|
||||
|
||||
public Dictionary<string, string> StringPool { get; } = new Dictionary<string, string>();
|
||||
|
||||
readonly List<MapDirectoryTracker> mapDirectoryTrackers = new List<MapDirectoryTracker>();
|
||||
readonly List<MapDirectoryTracker> mapDirectoryTrackers = new();
|
||||
|
||||
/// <summary>
|
||||
/// The most recenly modified or loaded map at runtime
|
||||
/// The most recently modified or loaded map at runtime.
|
||||
/// </summary>
|
||||
public string LastModifiedMap { get; private set; } = null;
|
||||
readonly Dictionary<string, string> mapUpdates = new Dictionary<string, string>();
|
||||
readonly Dictionary<string, string> mapUpdates = new();
|
||||
|
||||
string lastLoadedLastModifiedMap;
|
||||
|
||||
/// <summary>
|
||||
/// If LastModifiedMap was picked already, returns a null
|
||||
/// If LastModifiedMap was picked already, returns a null.
|
||||
/// </summary>
|
||||
public string PickLastModifiedMap(MapVisibility visibility)
|
||||
{
|
||||
@@ -98,7 +99,7 @@ namespace OpenRA
|
||||
IReadOnlyPackage package;
|
||||
var optional = name.StartsWith("~", StringComparison.Ordinal);
|
||||
if (optional)
|
||||
name = name.Substring(1);
|
||||
name = name[1..];
|
||||
|
||||
try
|
||||
{
|
||||
@@ -122,10 +123,12 @@ namespace OpenRA
|
||||
mapDirectoryTrackers.Add(new MapDirectoryTracker(mapGrid, package, classification));
|
||||
}
|
||||
|
||||
// PERF: Load the mod YAML once outside the loop, and reuse it when resolving each maps custom YAML.
|
||||
var modDataRules = modData.GetRulesYaml();
|
||||
foreach (var kv in MapLocations)
|
||||
{
|
||||
foreach (var map in kv.Key.Contents)
|
||||
LoadMap(map, kv.Key, kv.Value, mapGrid, null);
|
||||
LoadMapInternal(map, kv.Key, kv.Value, mapGrid, null, modDataRules);
|
||||
}
|
||||
|
||||
// We only want to track maps in runtime, not at loadtime
|
||||
@@ -133,17 +136,22 @@ namespace OpenRA
|
||||
}
|
||||
|
||||
public void LoadMap(string map, IReadOnlyPackage package, MapClassification classification, MapGrid mapGrid, string oldMap)
|
||||
{
|
||||
LoadMapInternal(map, package, classification, mapGrid, oldMap, null);
|
||||
}
|
||||
|
||||
void LoadMapInternal(string map, IReadOnlyPackage package, MapClassification classification, MapGrid mapGrid, string oldMap, IEnumerable<List<MiniYamlNode>> modDataRules)
|
||||
{
|
||||
IReadOnlyPackage mapPackage = null;
|
||||
try
|
||||
{
|
||||
using (new Support.PerfTimer(map))
|
||||
using (new PerfTimer(map))
|
||||
{
|
||||
mapPackage = package.OpenPackage(map, modData.ModFiles);
|
||||
if (mapPackage != null)
|
||||
{
|
||||
var uid = Map.ComputeUID(mapPackage);
|
||||
previews[uid].UpdateFromMap(mapPackage, package, classification, modData.Manifest.MapCompatibility, mapGrid.Type);
|
||||
previews[uid].UpdateFromMap(mapPackage, package, classification, modData.Manifest.MapCompatibility, mapGrid.Type, modDataRules);
|
||||
|
||||
if (oldMap != uid)
|
||||
{
|
||||
@@ -157,10 +165,12 @@ namespace OpenRA
|
||||
catch (Exception e)
|
||||
{
|
||||
mapPackage?.Dispose();
|
||||
Console.WriteLine("Failed to load map: {0}", map);
|
||||
Console.WriteLine("Details: {0}", e);
|
||||
Log.Write("debug", "Failed to load map: {0}", map);
|
||||
Log.Write("debug", "Details: {0}", e);
|
||||
Console.WriteLine($"Failed to load map: {map}");
|
||||
Console.WriteLine("Details:");
|
||||
Console.WriteLine(e);
|
||||
Log.Write("debug", $"Failed to load map: {map}");
|
||||
Log.Write("debug", "Details:");
|
||||
Log.Write("debug", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +192,7 @@ namespace OpenRA
|
||||
var name = kv.Key;
|
||||
var optional = name.StartsWith("~", StringComparison.Ordinal);
|
||||
if (optional)
|
||||
name = name.Substring(1);
|
||||
name = name[1..];
|
||||
|
||||
// Don't try to open the map directory in the support directory if it doesn't exist
|
||||
var resolved = Platform.ResolvePath(name);
|
||||
@@ -194,7 +204,7 @@ namespace OpenRA
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<(IReadWritePackage package, string map)> EnumerateMapDirPackagesAndNames(MapClassification classification = MapClassification.System)
|
||||
public IEnumerable<(IReadWritePackage Package, string Map)> EnumerateMapDirPackagesAndNames(MapClassification classification = MapClassification.System)
|
||||
{
|
||||
var mapDirPackages = EnumerateMapDirPackages(classification);
|
||||
|
||||
@@ -213,12 +223,6 @@ namespace OpenRA
|
||||
yield return mapPackage;
|
||||
}
|
||||
|
||||
public IEnumerable<Map> EnumerateMapsWithoutCaching(MapClassification classification = MapClassification.System)
|
||||
{
|
||||
foreach (var mapPackage in EnumerateMapPackagesWithoutCaching(classification))
|
||||
yield return new Map(modData, mapPackage);
|
||||
}
|
||||
|
||||
public void QueryRemoteMapDetails(string repositoryUrl, IEnumerable<string> uids, Action<MapPreview> mapDetailsReceived = null, Action<MapPreview> mapQueryFailed = null)
|
||||
{
|
||||
var queryUids = uids.Distinct()
|
||||
@@ -258,8 +262,9 @@ namespace OpenRA
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Write("debug", "Remote map query failed with error: {0}", e);
|
||||
Log.Write("debug", "URL was: {0}", url);
|
||||
Log.Write("debug", "Remote map query failed with error:");
|
||||
Log.Write("debug", e);
|
||||
Log.Write("debug", $"URL was: {url}");
|
||||
|
||||
foreach (var uid in batchUids)
|
||||
{
|
||||
@@ -320,7 +325,8 @@ namespace OpenRA
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Write("debug", "Failed to load minimap with exception: {0}", e);
|
||||
Log.Write("debug", "Failed to load minimap with exception:");
|
||||
Log.Write("debug", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -19,7 +19,6 @@ namespace OpenRA
|
||||
public struct MapCoordsEnumerator : IEnumerator<MPos>
|
||||
{
|
||||
readonly MapCoordsRegion r;
|
||||
MPos current;
|
||||
|
||||
public MapCoordsEnumerator(MapCoordsRegion region)
|
||||
: this()
|
||||
@@ -30,41 +29,38 @@ namespace OpenRA
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
var u = current.U + 1;
|
||||
var v = current.V;
|
||||
var u = Current.U + 1;
|
||||
var v = Current.V;
|
||||
|
||||
// Check for column overflow
|
||||
if (u > r.bottomRight.U)
|
||||
if (u > r.BottomRight.U)
|
||||
{
|
||||
v += 1;
|
||||
u = r.topLeft.U;
|
||||
u = r.TopLeft.U;
|
||||
|
||||
// Check for row overflow
|
||||
if (v > r.bottomRight.V)
|
||||
if (v > r.BottomRight.V)
|
||||
return false;
|
||||
}
|
||||
|
||||
current = new MPos(u, v);
|
||||
Current = new MPos(u, v);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
current = new MPos(r.topLeft.U - 1, r.topLeft.V);
|
||||
Current = new MPos(r.TopLeft.U - 1, r.TopLeft.V);
|
||||
}
|
||||
|
||||
public MPos Current => current;
|
||||
public MPos Current { get; private set; }
|
||||
object IEnumerator.Current => Current;
|
||||
public void Dispose() { }
|
||||
}
|
||||
|
||||
readonly MPos topLeft;
|
||||
readonly MPos bottomRight;
|
||||
|
||||
public MapCoordsRegion(MPos mapTopLeft, MPos mapBottomRight)
|
||||
{
|
||||
topLeft = mapTopLeft;
|
||||
bottomRight = mapBottomRight;
|
||||
TopLeft = mapTopLeft;
|
||||
BottomRight = mapBottomRight;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
@@ -87,7 +83,7 @@ namespace OpenRA
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public MPos TopLeft => topLeft;
|
||||
public MPos BottomRight => bottomRight;
|
||||
public MPos TopLeft { get; }
|
||||
public MPos BottomRight { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -25,7 +25,7 @@ namespace OpenRA
|
||||
readonly MapClassification classification;
|
||||
|
||||
enum MapAction { Add, Delete, Update }
|
||||
readonly Dictionary<string, MapAction> mapActionQueue = new Dictionary<string, MapAction>();
|
||||
readonly Dictionary<string, MapAction> mapActionQueue = new();
|
||||
|
||||
bool dirty = false;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -29,7 +29,10 @@ namespace OpenRA
|
||||
public readonly WVec[][] Polygons;
|
||||
public readonly WRot Orientation;
|
||||
|
||||
public CellRamp(MapGridType type, WRot orientation, RampCornerHeight tl = RampCornerHeight.Low, RampCornerHeight tr = RampCornerHeight.Low, RampCornerHeight br = RampCornerHeight.Low, RampCornerHeight bl = RampCornerHeight.Low, RampSplit split = RampSplit.Flat)
|
||||
public CellRamp(MapGridType type, WRot orientation,
|
||||
RampCornerHeight tl = RampCornerHeight.Low, RampCornerHeight tr = RampCornerHeight.Low,
|
||||
RampCornerHeight br = RampCornerHeight.Low, RampCornerHeight bl = RampCornerHeight.Low,
|
||||
RampSplit split = RampSplit.Flat)
|
||||
{
|
||||
Orientation = orientation;
|
||||
if (type == MapGridType.RectangularIsometric)
|
||||
@@ -103,7 +106,7 @@ namespace OpenRA
|
||||
public class MapGrid : IGlobalModData
|
||||
{
|
||||
public readonly MapGridType Type = MapGridType.Rectangular;
|
||||
public readonly Size TileSize = new Size(24, 24);
|
||||
public readonly Size TileSize = new(24, 24);
|
||||
public readonly byte MaximumTerrainHeight = 0;
|
||||
public readonly SubCell DefaultSubCell = (SubCell)byte.MaxValue;
|
||||
|
||||
@@ -125,10 +128,14 @@ namespace OpenRA
|
||||
|
||||
internal readonly CVec[][] TilesByDistance;
|
||||
|
||||
public int TileScale { get; }
|
||||
|
||||
public MapGrid(MiniYaml yaml)
|
||||
{
|
||||
FieldLoader.Load(this, yaml);
|
||||
|
||||
TileScale = Type == MapGridType.RectangularIsometric ? 1448 : 1024;
|
||||
|
||||
// The default subcell index defaults to the middle entry
|
||||
var defaultSubCellIndex = (byte)DefaultSubCell;
|
||||
if (defaultSubCellIndex == byte.MaxValue)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
@@ -61,10 +61,10 @@ namespace OpenRA
|
||||
public readonly int mapformat;
|
||||
}
|
||||
|
||||
public class MapPreview : IDisposable, IReadOnlyFileSystem
|
||||
public sealed class MapPreview : IDisposable, IReadOnlyFileSystem
|
||||
{
|
||||
/// <summary>Wrapper that enables map data to be replaced in an atomic fashion</summary>
|
||||
class InnerData
|
||||
/// <summary>Wrapper that enables map data to be replaced in an atomic fashion.</summary>
|
||||
sealed class InnerData
|
||||
{
|
||||
public int MapFormat;
|
||||
public string Title;
|
||||
@@ -90,6 +90,7 @@ namespace OpenRA
|
||||
public MiniYaml SequenceDefinitions;
|
||||
public MiniYaml ModelSequenceDefinitions;
|
||||
|
||||
public Translation Translation { get; private set; }
|
||||
public ActorInfo WorldActorInfo { get; private set; }
|
||||
public ActorInfo PlayerActorInfo { get; private set; }
|
||||
|
||||
@@ -110,7 +111,7 @@ namespace OpenRA
|
||||
return key == "world" || key == "player";
|
||||
}
|
||||
|
||||
public void SetCustomRules(ModData modData, IReadOnlyFileSystem fileSystem, Dictionary<string, MiniYaml> yaml)
|
||||
public void SetCustomRules(ModData modData, IReadOnlyFileSystem fileSystem, Dictionary<string, MiniYaml> yaml, IEnumerable<List<MiniYamlNode>> modDataRules)
|
||||
{
|
||||
RuleDefinitions = LoadRuleSection(yaml, "Rules");
|
||||
WeaponDefinitions = LoadRuleSection(yaml, "Weapons");
|
||||
@@ -120,20 +121,27 @@ namespace OpenRA
|
||||
SequenceDefinitions = LoadRuleSection(yaml, "Sequences");
|
||||
ModelSequenceDefinitions = LoadRuleSection(yaml, "ModelSequences");
|
||||
|
||||
Translation = yaml.TryGetValue("Translations", out var node) && node != null
|
||||
? new Translation(Game.Settings.Player.Language, FieldLoader.GetValue<string[]>("value", node.Value), fileSystem)
|
||||
: null;
|
||||
|
||||
try
|
||||
{
|
||||
// PERF: Implement a minimal custom loader for custom world and player actors to minimize loading time
|
||||
// This assumes/enforces that these actor types can only inherit abstract definitions (starting with ^)
|
||||
if (RuleDefinitions != null)
|
||||
{
|
||||
var files = modData.Manifest.Rules.AsEnumerable();
|
||||
modDataRules ??= modData.GetRulesYaml();
|
||||
var files = Enumerable.Empty<string>();
|
||||
if (RuleDefinitions.Value != null)
|
||||
{
|
||||
var mapFiles = FieldLoader.GetValue<string[]>("value", RuleDefinitions.Value);
|
||||
files = files.Append(mapFiles);
|
||||
}
|
||||
|
||||
var sources = files.Select(s => MiniYaml.FromStream(fileSystem.Open(s), s).Where(IsLoadableRuleDefinition).ToList());
|
||||
var sources =
|
||||
modDataRules.Select(x => x.Where(IsLoadableRuleDefinition).ToList())
|
||||
.Concat(files.Select(s => MiniYaml.FromStream(fileSystem.Open(s), s).Where(IsLoadableRuleDefinition).ToList()));
|
||||
if (RuleDefinitions.Nodes.Count > 0)
|
||||
sources = sources.Append(RuleDefinitions.Nodes.Where(IsLoadableRuleDefinition).ToList());
|
||||
|
||||
@@ -145,7 +153,8 @@ namespace OpenRA
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Write("debug", "Failed to load rules for `{0}` with error: {1}", Title, e.Message);
|
||||
Log.Write("debug", $"Failed to load rules for `{Title}` with error:");
|
||||
Log.Write("debug", e);
|
||||
}
|
||||
|
||||
WorldActorInfo = modData.DefaultRules.Actors[SystemActors.World];
|
||||
@@ -185,6 +194,7 @@ namespace OpenRA
|
||||
|
||||
public MiniYaml RuleDefinitions => innerData.RuleDefinitions;
|
||||
public MiniYaml WeaponDefinitions => innerData.WeaponDefinitions;
|
||||
public MiniYaml SequenceDefinitions => innerData.SequenceDefinitions;
|
||||
|
||||
public ActorInfo WorldActorInfo => innerData.WorldActorInfo;
|
||||
public ActorInfo PlayerActorInfo => innerData.PlayerActorInfo;
|
||||
@@ -193,6 +203,19 @@ namespace OpenRA
|
||||
public long DownloadBytes { get; private set; }
|
||||
public int DownloadPercentage { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Functionality mirrors <see cref="TranslationProvider.GetString"/>, except instead of using
|
||||
/// loaded <see cref="Map"/>'s translations as backup, we use this <see cref="MapPreview"/>'s.
|
||||
/// </summary>
|
||||
public string GetLocalisedString(string key, IDictionary<string, object> args = null)
|
||||
{
|
||||
// PERF: instead of loading mod level Translation per each MapPreview, reuse the already loaded one in TranslationProvider.
|
||||
if (TranslationProvider.TryGetModString(key, out var message, args))
|
||||
return message;
|
||||
|
||||
return innerData.Translation?.GetString(key, args) ?? key;
|
||||
}
|
||||
|
||||
Sprite minimap;
|
||||
bool generatingMinimap;
|
||||
public Sprite GetMinimap()
|
||||
@@ -226,7 +249,7 @@ namespace OpenRA
|
||||
{
|
||||
return Ruleset.Load(modData, this, TileSet, innerData.RuleDefinitions,
|
||||
innerData.WeaponDefinitions, innerData.VoiceDefinitions, innerData.NotificationDefinitions,
|
||||
innerData.MusicDefinitions, innerData.SequenceDefinitions, innerData.ModelSequenceDefinitions);
|
||||
innerData.MusicDefinitions, innerData.ModelSequenceDefinitions);
|
||||
}
|
||||
|
||||
public MapPreview(ModData modData, string uid, MapGridType gridType, MapCache cache)
|
||||
@@ -292,16 +315,17 @@ namespace OpenRA
|
||||
innerData.SetCustomRules(modData, this, new Dictionary<string, MiniYaml>()
|
||||
{
|
||||
{ "Rules", map.RuleDefinitions },
|
||||
{ "Translations", map.TranslationDefinitions },
|
||||
{ "Weapons", map.WeaponDefinitions },
|
||||
{ "Voices", map.VoiceDefinitions },
|
||||
{ "Music", map.MusicDefinitions },
|
||||
{ "Notifications", map.NotificationDefinitions },
|
||||
{ "Sequences", map.SequenceDefinitions },
|
||||
{ "ModelSequences", map.ModelSequenceDefinitions }
|
||||
});
|
||||
}, null);
|
||||
}
|
||||
|
||||
public void UpdateFromMap(IReadOnlyPackage p, IReadOnlyPackage parent, MapClassification classification, string[] mapCompatibility, MapGridType gridType)
|
||||
public void UpdateFromMap(IReadOnlyPackage p, IReadOnlyPackage parent, MapClassification classification, string[] mapCompatibility, MapGridType gridType, IEnumerable<List<MiniYamlNode>> modDataRules)
|
||||
{
|
||||
Dictionary<string, MiniYaml> yaml;
|
||||
using (var yamlStream = p.GetStream("map.yaml"))
|
||||
@@ -344,7 +368,7 @@ namespace OpenRA
|
||||
if (yaml.TryGetValue("Visibility", out temp))
|
||||
newData.Visibility = FieldLoader.GetValue<MapVisibility>("Visibility", temp.Value);
|
||||
|
||||
string requiresMod = string.Empty;
|
||||
var requiresMod = string.Empty;
|
||||
if (yaml.TryGetValue("RequiresMod", out temp))
|
||||
requiresMod = temp.Value;
|
||||
|
||||
@@ -391,9 +415,9 @@ namespace OpenRA
|
||||
newData.Status = MapStatus.Unavailable;
|
||||
}
|
||||
|
||||
newData.SetCustomRules(modData, this, yaml);
|
||||
newData.SetCustomRules(modData, this, yaml, modDataRules);
|
||||
|
||||
if (p.Contains("map.png"))
|
||||
if (cache.LoadPreviewImages && p.Contains("map.png"))
|
||||
using (var dataStream = p.GetStream("map.png"))
|
||||
newData.Preview = new Png(dataStream);
|
||||
|
||||
@@ -435,14 +459,18 @@ namespace OpenRA
|
||||
spawns[j / 2] = new CPos(r.spawnpoints[j], r.spawnpoints[j + 1]);
|
||||
newData.SpawnPoints = spawns;
|
||||
newData.GridType = r.map_grid_type;
|
||||
try
|
||||
if (cache.LoadPreviewImages)
|
||||
{
|
||||
newData.Preview = new Png(new MemoryStream(Convert.FromBase64String(r.minimap)));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Write("debug", "Failed parsing mapserver minimap response: {0}", e);
|
||||
newData.Preview = null;
|
||||
try
|
||||
{
|
||||
newData.Preview = new Png(new MemoryStream(Convert.FromBase64String(r.minimap)));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Write("debug", "Failed parsing mapserver minimap response:");
|
||||
Log.Write("debug", e);
|
||||
newData.Preview = null;
|
||||
}
|
||||
}
|
||||
|
||||
var playersString = Encoding.UTF8.GetString(Convert.FromBase64String(r.players_block));
|
||||
@@ -450,11 +478,12 @@ namespace OpenRA
|
||||
|
||||
var rulesString = Encoding.UTF8.GetString(Convert.FromBase64String(r.rules));
|
||||
var rulesYaml = new MiniYaml("", MiniYaml.FromString(rulesString)).ToDictionary();
|
||||
newData.SetCustomRules(modData, this, rulesYaml);
|
||||
newData.SetCustomRules(modData, this, rulesYaml, null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Write("debug", "Failed parsing mapserver response: {0}", e);
|
||||
Log.Write("debug", "Failed parsing mapserver response:");
|
||||
Log.Write("debug", e);
|
||||
}
|
||||
|
||||
// Commit updated data before running the callbacks
|
||||
@@ -477,7 +506,7 @@ namespace OpenRA
|
||||
|
||||
innerData.Status = MapStatus.Downloading;
|
||||
var installLocation = cache.MapLocations.FirstOrDefault(p => p.Value == MapClassification.User);
|
||||
if (!(installLocation.Key is IReadWritePackage mapInstallPackage))
|
||||
if (installLocation.Key is not IReadWritePackage mapInstallPackage)
|
||||
{
|
||||
Log.Write("debug", "Map install directory not found");
|
||||
innerData.Status = MapStatus.DownloadError;
|
||||
@@ -521,20 +550,21 @@ namespace OpenRA
|
||||
await response.ReadAsStreamWithProgress(fileStream, OnDownloadProgress, CancellationToken.None);
|
||||
|
||||
mapInstallPackage.Update(mapFilename, fileStream.ToArray());
|
||||
Log.Write("debug", "Downloaded map to '{0}'", mapFilename);
|
||||
Log.Write("debug", $"Downloaded map to '{mapFilename}'");
|
||||
|
||||
var package = mapInstallPackage.OpenPackage(mapFilename, modData.ModFiles);
|
||||
if (package == null)
|
||||
innerData.Status = MapStatus.DownloadError;
|
||||
else
|
||||
{
|
||||
UpdateFromMap(package, mapInstallPackage, MapClassification.User, null, GridType);
|
||||
UpdateFromMap(package, mapInstallPackage, MapClassification.User, null, GridType, null);
|
||||
Game.RunAfterTick(onSuccess);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Write("debug", "Map installation failed with error: {0}", e);
|
||||
Log.Write("debug", "Map installation failed with error:");
|
||||
Log.Write("debug", e);
|
||||
innerData.Status = MapStatus.DownloadError;
|
||||
}
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user