mirror of
https://github.com/gwdevhub/Daybreak.git
synced 2026-09-16 21:35:20 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9690d649fa | ||
|
|
821ce69547 | ||
|
|
4f524ada67 | ||
|
|
0c2234f31b | ||
|
|
70085efd39 | ||
|
|
bfa2128868 | ||
|
|
9b0da9b13c | ||
|
|
721ee8e494 | ||
|
|
5458db891f | ||
|
|
9d9c15d0f6 | ||
|
|
4f49fc1cdf | ||
|
|
7efc7ba698 | ||
|
|
a79a6eae98 | ||
|
|
0801256f4c | ||
|
|
e0799dd100 | ||
|
|
24f4607899 | ||
|
|
7aee0dfc16 | ||
|
|
5fcb2314bc | ||
|
|
f218b89f6c | ||
|
|
cc607b37c9 | ||
|
|
f80ea8cf0c | ||
|
|
39f6707d23 | ||
|
|
eb11029ece | ||
|
|
4583b5b2d3 | ||
|
|
8c01377667 | ||
|
|
9a130d71dd | ||
|
|
018ed6c5b5 | ||
|
|
cb48248c82 | ||
|
|
e1284375e2 | ||
|
|
d38d620a84 | ||
|
|
ce810dafab | ||
|
|
aabc98e4fc | ||
|
|
7eb0b7cc4f | ||
|
|
f1eb829ac4 | ||
|
|
4b03a5a16f | ||
|
|
71c90100be | ||
|
|
ee512d130d | ||
|
|
03d0759e57 | ||
|
|
0db7628d66 | ||
|
|
d1d1ba6c08 | ||
|
|
d16a88a9bc | ||
|
|
a9d93f4162 | ||
|
|
632b5a55ac | ||
|
|
6424505631 | ||
|
|
dfc1d3ba0a | ||
|
|
5bee88016d | ||
|
|
5a37250680 | ||
|
|
1c4ccb9fa3 | ||
|
|
8403dadca7 | ||
|
|
4ac4cb0886 | ||
|
|
74f13d2447 | ||
|
|
bf53793729 | ||
|
|
e69dbf6791 | ||
|
|
a0eafa8a13 | ||
|
|
b0a236beb4 | ||
|
|
c10b81f3a1 | ||
|
|
6cd51d6584 | ||
|
|
a283117cc8 | ||
|
|
329e64232c | ||
|
|
feb3c9042e | ||
|
|
71f15f56a4 | ||
|
|
d37951b832 | ||
|
|
908a149df4 | ||
|
|
38cf140dfa | ||
|
|
d13e1a2d08 | ||
|
|
a0c7842b84 | ||
|
|
de13b68633 | ||
|
|
f289602068 | ||
|
|
15f4ee8979 | ||
|
|
d826dea457 | ||
|
|
b89a6666a3 | ||
|
|
1dc69fd0c2 | ||
|
|
5005b07f09 | ||
|
|
0b692165e0 | ||
|
|
ffee0fdf4c | ||
|
|
72b4cd5470 | ||
|
|
dc9be53ace | ||
|
|
3a8a6b0f7f | ||
|
|
7cdd0534f6 | ||
|
|
4b14ab9312 | ||
|
|
57e1ddb8da | ||
|
|
c7609c0f7e | ||
|
|
1eca8021d2 | ||
|
|
0077f35c4d | ||
|
|
28b0a0a138 | ||
|
|
cc7ce92013 | ||
|
|
5bd02e56ee | ||
|
|
8c7cd0a562 | ||
|
|
3ab3f72366 | ||
|
|
733883a6c2 | ||
|
|
d1ed8aeaf6 | ||
|
|
66ad44b8ce | ||
|
|
18e51ae408 | ||
|
|
06940dbf38 | ||
|
|
875b29f8ba | ||
|
|
a953c3a0d3 | ||
|
|
ce198fcfc9 | ||
|
|
3d84648af2 | ||
|
|
38bb43bba3 | ||
|
|
cc00709016 | ||
|
|
ee02b3b49a | ||
|
|
d1d6b7d757 | ||
|
|
4e1c0c4f50 | ||
|
|
2a7e2c90fc | ||
|
|
0dc957a99d | ||
|
|
f3f0aeb97e | ||
|
|
d6dbe6f2cd | ||
|
|
79da1801bc | ||
|
|
2b692b2d88 | ||
|
|
a7a98f7288 | ||
|
|
5d27d9c380 | ||
|
|
fb4185b541 | ||
|
|
d2d6e87e12 | ||
|
|
354cdda109 | ||
|
|
83429e264a | ||
|
|
ffdf374cdd | ||
|
|
aed34608ee | ||
|
|
18981e131d | ||
|
|
fe0a77d89d | ||
|
|
dbfd555f0d | ||
|
|
85d4ac3a29 | ||
|
|
dcb983d3de | ||
|
|
ba1e4348ad | ||
|
|
04bc7cffc6 | ||
|
|
01b74a936b | ||
|
|
654b6bc10f | ||
|
|
c9e6b9f626 | ||
|
|
554f1aea9b | ||
|
|
6fb817855c | ||
|
|
b3f5fadfe3 | ||
|
|
9275b7a7f8 | ||
|
|
2d06ff85b8 | ||
|
|
07d06313d9 | ||
|
|
546409130c | ||
|
|
82436872f8 | ||
|
|
ad6f76af0c | ||
|
|
8f0ad91a22 | ||
|
|
6a70c5b7cc | ||
|
|
5f5d67fdf2 | ||
|
|
150b41647a | ||
|
|
66e52e7324 | ||
|
|
23328240a9 | ||
|
|
3f06e9486d | ||
|
|
52a8e912e9 | ||
|
|
641aa8250e | ||
|
|
faa47f32c7 | ||
|
|
e3dac780df | ||
|
|
dfc0f12150 | ||
|
|
638fb38fa0 | ||
|
|
4d6a06ccdf | ||
|
|
3228604876 | ||
|
|
44879924d6 | ||
|
|
6b7478f6ae | ||
|
|
f54d95c1e7 | ||
|
|
5315a45a98 | ||
|
|
8575d970a3 | ||
|
|
5c611eca4f | ||
|
|
71aa37b965 | ||
|
|
0f1b1cc83d | ||
|
|
198c1e6eb3 | ||
|
|
e7c9111a1f | ||
|
|
1191e996db | ||
|
|
19de3c99f9 | ||
|
|
d857b6dc26 | ||
|
|
68b5b79035 | ||
|
|
318032d998 | ||
|
|
483860532f | ||
|
|
694dbe82a9 | ||
|
|
a936f24e32 | ||
|
|
a2ec87ced2 | ||
|
|
48955a7dd7 | ||
|
|
9d7c6c29b0 | ||
|
|
902d210dfd | ||
|
|
57867851a9 | ||
|
|
ca82cc92bf | ||
|
|
569ce1e656 | ||
|
|
a96c6c3f66 | ||
|
|
28c3b2f8c1 | ||
|
|
deeccd81b4 | ||
|
|
6a27245ae8 | ||
|
|
6f4063abb7 | ||
|
|
f307bcd665 | ||
|
|
02ca41ba6d | ||
|
|
a0ebc87b7c | ||
|
|
d21c55deb0 | ||
|
|
50a8131ec2 | ||
|
|
e70cfa3d99 | ||
|
|
4c0c45f1c7 | ||
|
|
a9e819a83a | ||
|
|
65830f9125 | ||
|
|
3d9106addf | ||
|
|
2863032d9a | ||
|
|
aada189b1b | ||
|
|
22ea4de66e | ||
|
|
9859617a74 | ||
|
|
0629c1929d | ||
|
|
6ec45396c3 | ||
|
|
b76a9b80fb | ||
|
|
f4bc58bbf7 | ||
|
|
09fdbb6f95 | ||
|
|
8ee7ed23e4 | ||
|
|
8d8a78cf88 | ||
|
|
f0652231cb | ||
|
|
d9aa760256 | ||
|
|
a65f375255 | ||
|
|
3ee58e2711 | ||
|
|
9b3b083aec | ||
|
|
ecb9b8f172 | ||
|
|
5765c27240 | ||
|
|
c53456112a | ||
|
|
ccea21886e | ||
|
|
37be8de5ac | ||
|
|
107e43a15f | ||
|
|
17b3ed34db | ||
|
|
cce9cd34af | ||
|
|
6a80f8ee5d | ||
|
|
edb7f0d0bd | ||
|
|
8e69375338 | ||
|
|
d24ae98fb0 | ||
|
|
111b3ea632 | ||
|
|
cc1e759972 | ||
|
|
ad0527ed73 | ||
|
|
8ffbb918ea | ||
|
|
c27a0dba65 | ||
|
|
ad8305c66d | ||
|
|
29fe12f094 | ||
|
|
9dbe4c5eaf | ||
|
|
1e9aca3807 | ||
|
|
895da23f7d | ||
|
|
f788a10879 | ||
|
|
9fe4be0467 | ||
|
|
b1a7d3a111 | ||
|
|
8b9fdaaa30 | ||
|
|
60d5947535 | ||
|
|
0ba0e64a2a | ||
|
|
e1dfd1f0d0 | ||
|
|
cd2a529381 | ||
|
|
6ba8dcac49 | ||
|
|
f2e76b5459 | ||
|
|
cfbf6ed021 | ||
|
|
a372eb5125 | ||
|
|
76b89ca0e8 | ||
|
|
2c1721d52c | ||
|
|
324a77a625 | ||
|
|
88e59b8ec9 | ||
|
|
df71a17d9f | ||
|
|
8451f53e19 | ||
|
|
e795af5c11 | ||
|
|
efa3c5175c | ||
|
|
32efe42a61 | ||
|
|
97d2d09cdc | ||
|
|
ed90d567a4 | ||
|
|
51d6fb0f42 | ||
|
|
c10525708c | ||
|
|
0a69d795aa | ||
|
|
3b1d6831a5 | ||
|
|
b4c1dbcddb | ||
|
|
db5d62d7c0 | ||
|
|
ed5ccf38c6 | ||
|
|
7671e0c04c | ||
|
|
f3b8221b29 | ||
|
|
8fdc9a67c0 | ||
|
|
bb2e739876 | ||
|
|
852cbff5f3 | ||
|
|
6e1c111876 | ||
|
|
9f60839e40 | ||
|
|
dd37db18b5 | ||
|
|
793d60f7b5 | ||
|
|
08674cd7a6 | ||
|
|
dca3e39a6d | ||
|
|
8a1033d4b6 | ||
|
|
e4ebe558d7 | ||
|
|
70728cc5ed | ||
|
|
b49a0a5ff4 | ||
|
|
b48d959ffb | ||
|
|
b8e1ad89af | ||
|
|
b2bfbfcd86 | ||
|
|
062e28a6d2 | ||
|
|
dc0f833291 | ||
|
|
e598237916 | ||
|
|
6b96d3d9e9 | ||
|
|
1dbb610846 | ||
|
|
5c649b0c15 | ||
|
|
527ab041d9 | ||
|
|
ff94e90259 | ||
|
|
51efbcce1e | ||
|
|
87b2345105 | ||
|
|
5022d33ca9 | ||
|
|
141f949a63 | ||
|
|
3913c71fd8 | ||
|
|
5706652c40 | ||
|
|
768b6b20f5 | ||
|
|
7066b7dbb6 | ||
|
|
17e01fc7b9 | ||
|
|
ee9fcf38b7 | ||
|
|
5abb24bdd4 | ||
|
|
53f17d3f22 | ||
|
|
b728c38dc1 | ||
|
|
5e57b6ecd0 | ||
|
|
e9ffcdf7c3 | ||
|
|
118657de7c | ||
|
|
34c332504b | ||
|
|
d7a29d68a1 | ||
|
|
eefa02837d | ||
|
|
5b2812fa61 | ||
|
|
e3ddfb88c1 | ||
|
|
664d94aeaa | ||
|
|
e2baf63099 | ||
|
|
c1b7000139 | ||
|
|
6e8333d76f | ||
|
|
c67eddc9d4 | ||
|
|
292cf6fd94 | ||
|
|
69038bca43 | ||
|
|
f05d15ce36 | ||
|
|
98cb349d67 | ||
|
|
a4314ee4d5 | ||
|
|
96097bd25a | ||
|
|
14029e6af2 | ||
|
|
365777141d | ||
|
|
aaa5da8d9b | ||
|
|
b898ab5679 | ||
|
|
b896fa5cc7 | ||
|
|
bca9f6d66b | ||
|
|
d6f71cb2eb | ||
|
|
986d09867c | ||
|
|
97cb2151f9 | ||
|
|
338ac100a1 | ||
|
|
01badcee6a | ||
|
|
302cf1114c | ||
|
|
613e03dc75 | ||
|
|
4267359cb2 | ||
|
|
daac8ec787 | ||
|
|
857adec459 | ||
|
|
b46e10a1a6 | ||
|
|
10799b7e9c | ||
|
|
6bbeaa1738 | ||
|
|
1a0f1cbf9a | ||
|
|
68e708fe96 | ||
|
|
a2166f2327 | ||
|
|
6d55366bdc | ||
|
|
28fcaa81cf | ||
|
|
c5efc2990e | ||
|
|
597010b9a1 | ||
|
|
1f71816256 | ||
|
|
7c3618d2b5 | ||
|
|
df9038039c | ||
|
|
9a4b23976a | ||
|
|
8732e0fe5e | ||
|
|
c23b84c4d5 | ||
|
|
345b6a792a | ||
|
|
d9ae52165d | ||
|
|
4f40e8328b | ||
|
|
ebdd828b06 | ||
|
|
711acb55db | ||
|
|
7dfc21bfe0 | ||
|
|
78644a6eec | ||
|
|
30b1d77575 | ||
|
|
a9626d03a4 | ||
|
|
be731bbffb | ||
|
|
8cd40e2de3 | ||
|
|
7745594bb6 | ||
|
|
e43bedf1c2 | ||
|
|
d6623a8646 | ||
|
|
403ba51a7d | ||
|
|
b185a606e6 | ||
|
|
342a9a4826 | ||
|
|
2df2e8a65e | ||
|
|
2d5e9231a9 | ||
|
|
818e2bf1d0 | ||
|
|
f0a876f7cc | ||
|
|
3fae8f91cb | ||
|
|
8b08056ca7 | ||
|
|
39eaf53deb | ||
|
|
4674d1d7e5 | ||
|
|
b8b5cc8b1d | ||
|
|
dc987233a7 | ||
|
|
266b400c22 | ||
|
|
a4ac083fd0 | ||
|
|
320dd16838 | ||
|
|
5c05c636bc | ||
|
|
7103a8a83a | ||
|
|
ad749d801a | ||
|
|
747e9a0490 | ||
|
|
836402bd0f | ||
|
|
a3d5e1ce1f | ||
|
|
f2cc59a4ab | ||
|
|
6ea77f7e05 | ||
|
|
5ea8df7cb9 | ||
|
|
c70e8ec90d | ||
|
|
210e3a8cb1 | ||
|
|
a0c3bb094c | ||
|
|
b4d932692a | ||
|
|
667534a07a | ||
|
|
159928f24b | ||
|
|
8a91ded610 | ||
|
|
4226b7eb32 | ||
|
|
b61c99dd1c | ||
|
|
1ccb0d5334 | ||
|
|
7fa01353dd | ||
|
|
4f849d880b | ||
|
|
4b60c96aad | ||
|
|
a4dc0d65cf | ||
|
|
85e017423f | ||
|
|
b38488937b | ||
|
|
d291d5825a | ||
|
|
9d6162f65f | ||
|
|
f54ab42a92 | ||
|
|
78c8ae3e8f | ||
|
|
c64830c5b6 | ||
|
|
561c7cf7b1 | ||
|
|
2c6862de41 | ||
|
|
69842cbadf | ||
|
|
c7327e7bb2 | ||
|
|
de33ed7fc4 | ||
|
|
c99bb8d074 | ||
|
|
a98e54ebc6 | ||
|
|
a832aa1925 | ||
|
|
c7eb5debcb | ||
|
|
91f0cb4e31 | ||
|
|
5e8407a6ab | ||
|
|
243c2c1536 | ||
|
|
930aca4ffe | ||
|
|
1639cabe8e | ||
|
|
5961a57c5b | ||
|
|
75d9bc6dec | ||
|
|
4ccca32881 | ||
|
|
a7f5d9dd96 | ||
|
|
c8ba125abc | ||
|
|
7d290031f1 | ||
|
|
5220a8c7ac | ||
|
|
33e221f60f | ||
|
|
7f77547c50 | ||
|
|
c5964e33ac | ||
|
|
1c6f3ec797 | ||
|
|
8601f61739 | ||
|
|
91bac0d50b | ||
|
|
0bf03e0fb5 | ||
|
|
81401178a5 | ||
|
|
882357a8e5 | ||
|
|
abf629c5c6 | ||
|
|
758f9004cd | ||
|
|
f174f8cbb3 | ||
|
|
f2f6bde25d | ||
|
|
85f378b303 | ||
|
|
71ab3fdefb | ||
|
|
2f83d6c860 | ||
|
|
3db4975b48 | ||
|
|
6a6eea5d02 | ||
|
|
8fe9eeb32f | ||
|
|
4c1025243b | ||
|
|
f24eb02ca1 | ||
|
|
b01c09491f | ||
|
|
54ae742899 | ||
|
|
4c862463d7 | ||
|
|
b455c89ddc | ||
|
|
782b76cd8e | ||
|
|
230c2d9457 | ||
|
|
63531e3b8c | ||
|
|
ac430305f4 | ||
|
|
3d830cfc16 | ||
|
|
b529aa8861 | ||
|
|
3798daa54e | ||
|
|
624380ed86 | ||
|
|
2b025e225b | ||
|
|
15a67ea28c | ||
|
|
c6b62fd5fd | ||
|
|
3c0877c1a0 | ||
|
|
967b57b9a8 | ||
|
|
f47cc319b5 | ||
|
|
26da84c4e7 | ||
|
|
a39e8dc5c6 | ||
|
|
1bb4669135 | ||
|
|
0203eef006 | ||
|
|
4ab50ee191 | ||
|
|
06c1ec1ac2 | ||
|
|
ef4befdc38 | ||
|
|
33f49ddffa | ||
|
|
49aa249b5b | ||
|
|
c387d44890 | ||
|
|
d4d09e7267 | ||
|
|
dd7bf02a97 | ||
|
|
6d0eeb478f | ||
|
|
d4e9de48b1 | ||
|
|
6bd9877925 | ||
|
|
d38df6596f | ||
|
|
b4e31e859c | ||
|
|
1acd07c1be | ||
|
|
b9b25bb098 | ||
|
|
5ea2981dc7 | ||
|
|
4fb96ca3a4 | ||
|
|
6de52f5585 | ||
|
|
6622e41f64 | ||
|
|
8405e4d1e5 | ||
|
|
0edc3f1560 | ||
|
|
c109fe7561 | ||
|
|
b5413dca5c | ||
|
|
6c2d4a1e70 | ||
|
|
be03f1a32d | ||
|
|
3ed1cc453a | ||
|
|
16030063ed | ||
|
|
458696ad8f | ||
|
|
6201702563 | ||
|
|
c5bea23a8f | ||
|
|
e5f38f77ef | ||
|
|
1d774ab8de | ||
|
|
bc66ca9948 | ||
|
|
524cd21fd4 | ||
|
|
132cb0e1f4 | ||
|
|
09c99e7731 | ||
|
|
c9d0be1117 | ||
|
|
965055c8d7 | ||
|
|
f6bb21d0ef | ||
|
|
465e0a4ce0 | ||
|
|
55f304b885 | ||
|
|
0cb1d97332 | ||
|
|
e2091cd82f | ||
|
|
d2bada4159 | ||
|
|
b27998d7f2 | ||
|
|
98d3e21db9 | ||
|
|
0683504330 | ||
|
|
98bd1b2de6 | ||
|
|
c169ca1684 | ||
|
|
88214ea166 | ||
|
|
4bdcd1a811 | ||
|
|
fa4f665a3e | ||
|
|
e59e022c0a | ||
|
|
d096dc696a | ||
|
|
071007c3e5 | ||
|
|
57192d5043 | ||
|
|
6af72683a8 | ||
|
|
3af9567506 | ||
|
|
1d7adf3944 | ||
|
|
fb7399adf8 | ||
|
|
6ebbffdda1 | ||
|
|
2c35333cac | ||
|
|
fe5e38b216 |
+137
@@ -0,0 +1,137 @@
|
||||
[*.cs]
|
||||
|
||||
# CA2254: Template should be a static expression
|
||||
dotnet_diagnostic.CA2254.severity = none
|
||||
csharp_indent_labels = one_less_than_current
|
||||
csharp_using_directive_placement = outside_namespace:error
|
||||
csharp_prefer_simple_using_statement = true:error
|
||||
csharp_prefer_braces = true:silent
|
||||
csharp_style_namespace_declarations = file_scoped:error
|
||||
csharp_style_prefer_method_group_conversion = true:suggestion
|
||||
csharp_style_expression_bodied_methods = false:silent
|
||||
csharp_style_expression_bodied_constructors = false:silent
|
||||
csharp_style_expression_bodied_operators = false:silent
|
||||
csharp_style_expression_bodied_properties = true:silent
|
||||
csharp_style_expression_bodied_indexers = true:silent
|
||||
csharp_style_expression_bodied_accessors = true:silent
|
||||
csharp_style_expression_bodied_lambdas = true:silent
|
||||
csharp_style_expression_bodied_local_functions = false:silent
|
||||
csharp_indent_braces = false
|
||||
insert_final_newline = true
|
||||
csharp_space_around_binary_operators = before_and_after
|
||||
csharp_style_throw_expression = true:suggestion
|
||||
csharp_style_prefer_null_check_over_type_check = true:suggestion
|
||||
csharp_prefer_simple_default_expression = true:suggestion
|
||||
csharp_style_prefer_local_over_anonymous_function = true:error
|
||||
csharp_style_prefer_index_operator = true:suggestion
|
||||
csharp_style_prefer_range_operator = true:suggestion
|
||||
csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
|
||||
csharp_style_prefer_tuple_swap = true:suggestion
|
||||
csharp_style_inlined_variable_declaration = true:suggestion
|
||||
csharp_style_deconstructed_variable_declaration = true:error
|
||||
csharp_style_unused_value_assignment_preference = discard_variable:error
|
||||
csharp_style_unused_value_expression_statement_preference = discard_variable:silent
|
||||
csharp_prefer_static_local_function = true:suggestion
|
||||
csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent
|
||||
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent
|
||||
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false:suggestion
|
||||
csharp_style_conditional_delegate_call = true:suggestion
|
||||
csharp_style_prefer_parameter_null_checking = true:suggestion
|
||||
csharp_style_prefer_switch_expression = true:suggestion
|
||||
csharp_style_prefer_pattern_matching = true:silent
|
||||
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
|
||||
csharp_style_prefer_not_pattern = true:suggestion
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
|
||||
csharp_style_prefer_extended_property_pattern = true:suggestion
|
||||
csharp_style_var_for_built_in_types = false:silent
|
||||
csharp_style_var_when_type_is_apparent = false:silent
|
||||
csharp_style_var_elsewhere = false:silent
|
||||
csharp_style_prefer_top_level_statements = true:suggestion
|
||||
csharp_style_prefer_utf8_string_literals = true:suggestion
|
||||
csharp_style_prefer_readonly_struct = true:suggestion
|
||||
|
||||
[*.{cs,vb}]
|
||||
#### Naming styles ####
|
||||
|
||||
# Naming rules
|
||||
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.severity = error
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
|
||||
|
||||
dotnet_naming_rule.types_should_be_pascal_case.severity = error
|
||||
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
|
||||
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
|
||||
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = error
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
|
||||
|
||||
# Symbol specifications
|
||||
|
||||
dotnet_naming_symbols.interface.applicable_kinds = interface
|
||||
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.interface.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
|
||||
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.types.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
|
||||
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.non_field_members.required_modifiers =
|
||||
|
||||
# Naming styles
|
||||
|
||||
dotnet_naming_style.begins_with_i.required_prefix = I
|
||||
dotnet_naming_style.begins_with_i.required_suffix =
|
||||
dotnet_naming_style.begins_with_i.word_separator =
|
||||
dotnet_naming_style.begins_with_i.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
dotnet_style_operator_placement_when_wrapping = beginning_of_line
|
||||
tab_width = 4
|
||||
indent_size = 4
|
||||
end_of_line = crlf
|
||||
dotnet_style_coalesce_expression = true:suggestion
|
||||
dotnet_style_null_propagation = true:suggestion
|
||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:error
|
||||
dotnet_style_prefer_auto_properties = true:error
|
||||
dotnet_style_object_initializer = true:suggestion
|
||||
dotnet_style_collection_initializer = true:suggestion
|
||||
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
|
||||
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
|
||||
dotnet_style_prefer_conditional_expression_over_return = true:silent
|
||||
dotnet_style_explicit_tuple_names = true:suggestion
|
||||
dotnet_style_prefer_inferred_tuple_names = true:suggestion
|
||||
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
|
||||
dotnet_style_prefer_compound_assignment = true:suggestion
|
||||
dotnet_style_prefer_simplified_interpolation = true:suggestion
|
||||
dotnet_style_namespace_match_folder = true:suggestion
|
||||
dotnet_style_readonly_field = true:suggestion
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
|
||||
dotnet_style_predefined_type_for_member_access = true:silent
|
||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
|
||||
dotnet_style_allow_multiple_blank_lines_experimental = true:silent
|
||||
dotnet_style_allow_statement_immediately_after_block_experimental = false:suggestion
|
||||
dotnet_code_quality_unused_parameters = all:error
|
||||
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:suggestion
|
||||
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:suggestion
|
||||
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:suggestion
|
||||
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:suggestion
|
||||
dotnet_style_qualification_for_field = true:error
|
||||
dotnet_style_qualification_for_property = true:error
|
||||
dotnet_style_qualification_for_method = true:error
|
||||
dotnet_style_qualification_for_event = true:error
|
||||
dotnet_diagnostic.CA1000.severity = error
|
||||
|
||||
[*.vb]
|
||||
dotnet_diagnostic.CA1047.severity = error
|
||||
@@ -0,0 +1 @@
|
||||
* amacocian@yahoo.com
|
||||
@@ -0,0 +1,16 @@
|
||||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions" # See documentation for possible values
|
||||
directory: "/" # Location of package manifests
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
- package-ecosystem: "nuget"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
@@ -0,0 +1,169 @@
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
# Licensed under the MIT license.
|
||||
|
||||
# This continuous integration pipeline is triggered anytime a user pushes code to the repo.
|
||||
# This pipeline builds the Wpf project, runs unit tests, then saves the MSIX build artifact.
|
||||
name: Daybreak CD Pipeline
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- "Daybreak/**"
|
||||
- "Daybreak.Installer/**"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
targetplatform: [x86]
|
||||
|
||||
runs-on: windows-latest
|
||||
|
||||
env:
|
||||
Configuration: Release
|
||||
Solution_Path: Daybreak.sln
|
||||
Test_Project_Path: Daybreak.Tests\Daybreak.Tests.csproj
|
||||
Wpf_Project_Path: Daybreak\Daybreak.csproj
|
||||
Actions_Allow_Unsecure_Commands: true
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Get Latest Tag
|
||||
id: getLatestTag
|
||||
uses: WyriHaximus/github-action-get-previous-tag@v1
|
||||
|
||||
- name: Generate changelog
|
||||
id: gen_changelog
|
||||
run: |
|
||||
$changeLog = git log --no-merges --pretty="%h - %s (%an)<br />" ${{ env.LatestReleaseTag }}..HEAD
|
||||
echo "::set-env name=Changelog::$changeLog"
|
||||
mkdir Publish
|
||||
echo $changeLog > .\Publish\changelog.txt
|
||||
env:
|
||||
LatestReleaseTag: ${{steps.getLatestTag.outputs.tag}}
|
||||
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '9.x'
|
||||
|
||||
- name: Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v2.0.0
|
||||
|
||||
- name: Setup project secrets
|
||||
run: |
|
||||
dotnet user-secrets --project Daybreak\Daybreak.csproj set AadApplicationId "${{ secrets.AadApplicationId }}"
|
||||
dotnet user-secrets --project Daybreak\Daybreak.csproj set AadTenantId "${{ secrets.AadTenantId }}"
|
||||
|
||||
- name: Restore project
|
||||
run: msbuild $env:Solution_Path /t:Restore /p:Configuration=$env:Configuration /p:RuntimeIdentifier=$env:RuntimeIdentifier --property:SolutionDir=$GITHUB_WORKSPACE
|
||||
env:
|
||||
RuntimeIdentifier: win-${{ matrix.targetplatform }}
|
||||
|
||||
- name: Build Daybreak project
|
||||
run: dotnet build Daybreak -c $env:Configuration --property:SolutionDir=$env:GITHUB_WORKSPACE
|
||||
|
||||
- name: Set version variable
|
||||
run: |
|
||||
$version = .\Scripts\GetBuildVersion.ps1
|
||||
echo "::set-env name=Version::$version"
|
||||
|
||||
- name: Create publish launcher files
|
||||
run: dotnet publish .\Daybreak\Daybreak.csproj -c $env:Configuration -r $env:RuntimeIdentifier --property:SolutionDir=$env:GITHUB_WORKSPACE -p:PublishReadyToRun=true -p:PublishSingleFile=false --self-contained true -o .\Publish
|
||||
env:
|
||||
RuntimeIdentifier: win-${{ matrix.targetplatform }}
|
||||
|
||||
- name: Create publish installer files
|
||||
run: dotnet publish .\Daybreak.Installer\Daybreak.Installer.csproj -c $env:Configuration -r $env:RuntimeIdentifier --property:SolutionDir=$env:GITHUB_WORKSPACE -p:PublishReadyToRun=true -p:PublishSingleFile=true --self-contained true -o .\Publish
|
||||
env:
|
||||
RuntimeIdentifier: win-${{ matrix.targetplatform }}
|
||||
|
||||
- name: Create publish extractor files
|
||||
run: dotnet publish .\Daybreak.7ZipExtractor\Daybreak.7ZipExtractor.csproj -c $env:Configuration -r $env:RuntimeIdentifier --property:SolutionDir=$env:GITHUB_WORKSPACE -p:PublishReadyToRun=true -p:PublishSingleFile=false --self-contained true -o .\Publish
|
||||
env:
|
||||
RuntimeIdentifier: win-${{ matrix.targetplatform }}
|
||||
|
||||
- name: Create publish API files
|
||||
run: dotnet publish .\Daybreak.API\Daybreak.API.csproj -c $env:Configuration -r $env:RuntimeIdentifier --property:SolutionDir=$env:GITHUB_WORKSPACE -p:PublishSingleFile=false --self-contained true -o .\Publish
|
||||
env:
|
||||
RuntimeIdentifier: win-${{ matrix.targetplatform }}
|
||||
|
||||
- name: Pack publish files
|
||||
run: |
|
||||
Write-Host $env
|
||||
.\Scripts\BuildRelease.ps1 -version $env:Version
|
||||
shell: pwsh
|
||||
|
||||
- name: Submit virustotal scan
|
||||
shell: pwsh
|
||||
run: |
|
||||
cd Publish
|
||||
$apiKey = "${{ secrets.VIRUSTOTAL_APIKEY }}"
|
||||
$archiveName = "daybreakv${{ env.Version }}.zip"
|
||||
$uploadUrlResponse = curl https://www.virustotal.com/api/v3/files/upload_url -H x-apikey:"$apiKey"
|
||||
$uploadUrlResponse
|
||||
$uploadUrlJson = $uploadUrlResponse | ConvertFrom-Json
|
||||
$uploadUrl = $uploadUrlJson.data
|
||||
$uploadResponse = curl --request POST --header x-apikey:"$apiKey" --header 'content-type: multipart/form-data' --form file="@$archiveName" --url $uploadUrl
|
||||
$uploadResponse
|
||||
$uploadResponseJson = $uploadResponse | ConvertFrom-Json
|
||||
$resultsUrl = "https://www.virustotal.com/api/v3/analyses/$($uploadResponseJson.data.id)"
|
||||
$resultsUrl
|
||||
# Poll the results until the status is "completed"
|
||||
$status = ""
|
||||
while ($status -ne "completed") {
|
||||
Start-Sleep -Seconds 10 # Wait for 10 seconds between checks
|
||||
$results = curl --header x-apikey:"$apiKey" --url $resultsUrl
|
||||
$results
|
||||
$resultsJson = $results | ConvertFrom-Json
|
||||
$status = $resultsJson.data.attributes.status
|
||||
Write-Host "Current status: $status"
|
||||
}
|
||||
|
||||
$resultsJson.data.attributes.results | ConvertTo-Json | Out-File -FilePath "VirusTotal.Results.json" -Encoding UTF8
|
||||
$resultsJson.data.attributes.stats | ConvertTo-Json | Out-File -FilePath "VirusTotal.Stats.json" -Encoding UTF8
|
||||
$stats = $resultsJson.data.attributes.stats
|
||||
echo "::set-env name=VirusTotalStats::$stats"
|
||||
|
||||
- name: Publish blob files
|
||||
run: |
|
||||
Write-Host $env
|
||||
.\Scripts\PushFilesToBlobStorage.ps1 -version $env:Version -sourcePath .\Publish\ -connectionString "${{ secrets.BLOBSTORAGE_CONNECTIONSTRING }}"
|
||||
shell: pwsh
|
||||
|
||||
- name: Create release draft
|
||||
uses: Xotl/cool-github-releases@v1.1.10
|
||||
with:
|
||||
mode: update
|
||||
tag_name: v${{ env.Version }}
|
||||
release_name: Daybreak v${{ env.Version }}
|
||||
assets: .\Publish\daybreakv${{ env.Version }}.zip;.\Publish\VirusTotal.Results.json;.\Publish\VirusTotal.Stats.json
|
||||
github_token: ${{ env.GITHUB_TOKEN }}
|
||||
replace_assets: true
|
||||
body_mrkdwn: |
|
||||
${{ env.Changelog }}
|
||||
|
||||
** VirustTotal Stats: **
|
||||
```
|
||||
${{ env.VirusTotalStats }}
|
||||
```
|
||||
isDraft: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Publish release
|
||||
run: |
|
||||
gh release edit v${{ env.Version }} --draft=false
|
||||
shell: powershell
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
# Licensed under the MIT license.
|
||||
|
||||
# This continuous integration pipeline is triggered anytime a user pushes code to the repo.
|
||||
# This pipeline builds the Wpf project, runs unit tests, then saves the MSIX build artifact.
|
||||
name: Daybreak CI Pipeline
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
targetplatform: [x86]
|
||||
|
||||
runs-on: windows-latest
|
||||
|
||||
env:
|
||||
Solution_Path: Daybreak.sln
|
||||
Test_Project_Path: Daybreak.Tests\Daybreak.Tests.csproj
|
||||
Wpf_Project_Path: Daybreak\Daybreak.csproj
|
||||
Actions_Allow_Unsecure_Commands: true
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '9.x'
|
||||
|
||||
- name: Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v2.0.0
|
||||
|
||||
- name: Execute Unit Tests
|
||||
run: dotnet test $env:Test_Project_Path --property:SolutionDir=$env:GITHUB_WORKSPACE -p:ParallelizeTestCollections=false
|
||||
|
||||
- name: Restore the Wpf application to populate the obj folder
|
||||
run: msbuild $env:Solution_Path /t:Restore /p:Configuration=$env:Configuration /p:RuntimeIdentifier=$env:RuntimeIdentifier --property:SolutionDir=$env:GITHUB_WORKSPACE
|
||||
env:
|
||||
Configuration: Debug
|
||||
RuntimeIdentifier: win-${{ matrix.targetplatform }}
|
||||
@@ -0,0 +1,90 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ "master" ]
|
||||
schedule:
|
||||
- cron: '41 12 * * 6'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: windows-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'csharp' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||
|
||||
env:
|
||||
Configuration: Release
|
||||
Solution_Path: Daybreak.sln
|
||||
Test_Project_Path: Daybreak.Tests\Daybreak.Tests.csproj
|
||||
Wpf_Project_Path: Daybreak\Daybreak.csproj
|
||||
Actions_Allow_Unsecure_Commands: true
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
|
||||
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
# queries: security-extended,security-and-quality
|
||||
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '9.x'
|
||||
|
||||
#- name: Autobuild
|
||||
# uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
|
||||
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||
|
||||
# - run: |
|
||||
# echo "Run, Build Application using script"
|
||||
# ./location_of_script_within_repo/buildscript.sh
|
||||
|
||||
- name: Build Daybreak project
|
||||
run: dotnet build Daybreak -c $env:Configuration --property:SolutionDir=$env:GITHUB_WORKSPACE
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
@@ -0,0 +1,53 @@
|
||||
name: Daybreak Version Check
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- "Daybreak/**"
|
||||
- "Daybreak.Installer/**"
|
||||
|
||||
jobs:
|
||||
|
||||
check_version:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
targetplatform: [x86]
|
||||
|
||||
runs-on: windows-latest
|
||||
|
||||
env:
|
||||
Configuration: Release
|
||||
Solution_Path: Daybreak.sln
|
||||
Actions_Allow_Unsecure_Commands: true
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '9.x'
|
||||
|
||||
- name: Get Latest Tag
|
||||
id: getLatestTag
|
||||
uses: WyriHaximus/github-action-get-previous-tag@v1
|
||||
|
||||
- name: Build Daybreak project
|
||||
run: dotnet build Daybreak -c $env:Configuration --property:SolutionDir=$env:GITHUB_WORKSPACE
|
||||
|
||||
- name: Set version variable
|
||||
run: |
|
||||
$version = .\Scripts\GetBuildVersion.ps1
|
||||
echo "::set-env name=Version::$version"
|
||||
|
||||
- name: Check version difference
|
||||
run: |
|
||||
.\Scripts\CompareVersions -currentVersion ${{ env.Version }} -lastVersion ${{ env.LatestReleaseTag }}
|
||||
env:
|
||||
LatestReleaseTag: ${{ steps.getLatestTag.outputs.tag }}
|
||||
+5
-1
@@ -9,6 +9,7 @@
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
*.version
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
@@ -27,6 +28,7 @@ x86/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
build/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Oo]ut/
|
||||
@@ -360,4 +362,6 @@ MigrationBackup/
|
||||
.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
FodyWeavers.xsd
|
||||
|
||||
.idea
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<RootNamespace>Daybreak._7ZipExtractor</RootNamespace>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SharpCompress" Version="0.39.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Extractor is in a different executable because of memory limitations. Daybreak needs to be compiled for x86 and as such has a memory limit of 2GB.
|
||||
* 7Zip algorithm may require more than 2GB memory to unpack large zip files.
|
||||
* As such, Daybreak.7ZipExtractor is x64.
|
||||
*/
|
||||
using SharpCompress.Archives;
|
||||
|
||||
if (args.Length != 2)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
var archivePath = args[0];
|
||||
var destinationDirectory = args[1];
|
||||
|
||||
using var fileStream = new FileStream(archivePath, FileMode.Open);
|
||||
using var archive = ArchiveFactory.Open(fileStream);
|
||||
var progress = 0d;
|
||||
var count = archive.Entries.Count();
|
||||
var reader = archive.ExtractAllEntries();
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
var entry = reader.Entry;
|
||||
if (entry.IsDirectory)
|
||||
{
|
||||
var directoryName = Path.Combine(Path.GetFullPath(destinationDirectory), entry.Key);
|
||||
Directory.CreateDirectory(directoryName);
|
||||
continue;
|
||||
}
|
||||
|
||||
var fileName = Path.Combine(Path.GetFullPath(destinationDirectory), entry.Key);
|
||||
using var entryStream = new FileStream(fileName, FileMode.Create);
|
||||
using (var stream = reader.OpenEntryStream())
|
||||
{
|
||||
stream.CopyTo(entryStream);
|
||||
}
|
||||
|
||||
progress += 1d / count;
|
||||
Console.WriteLine($"{progress} {fileName}");
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -0,0 +1,13 @@
|
||||
using Net.Sdk.Web;
|
||||
|
||||
namespace Daybreak.API.Controllers;
|
||||
|
||||
[GenerateController("api/test")]
|
||||
public sealed class TestController
|
||||
{
|
||||
[GenerateGet("testing")]
|
||||
public IResult GetTest(CancellationToken token)
|
||||
{
|
||||
return Results.Text("Hello from injected ASP-NET Core!", "text/plain");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0-windows</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>Library</OutputType>
|
||||
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
|
||||
<StripSymbols>true</StripSymbols>
|
||||
<InteropExports>true</InteropExports>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
|
||||
<PublishAot>true</PublishAot>
|
||||
<SelfContained>true</SelfContained>
|
||||
|
||||
|
||||
<AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>
|
||||
<UseAppHost>false</UseAppHost>
|
||||
<EnableIISSupport>false</EnableIISSupport>
|
||||
<InvariantGlobalization>true</InvariantGlobalization>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Net.Sdk.Web.Extensions.SourceGenerators" Version="0.9.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Daybreak.Shared\Daybreak.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<DaybreakHostOutputDir>$(MSBuildProjectDirectory)\..\Daybreak\bin\x86\$(Configuration)\$(TargetFramework)\</DaybreakHostOutputDir>
|
||||
<ShouldPublishAot>true</ShouldPublishAot>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="PublishIntoDaybreak" AfterTargets="PostBuild" Condition="'$(ShouldPublishAot)'=='true'">
|
||||
<Message Text="📦 dotnet-publish Daybreak.API → $(DaybreakHostOutputDir)" Importance="High" />
|
||||
|
||||
<Exec Command="dotnet publish "$(MSBuildProjectFullPath)" -c $(Configuration) -r win-x86 --self-contained true -o "$(DaybreakHostOutputDir)"" WorkingDirectory="$(ProjectDir)" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -0,0 +1,85 @@
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Runtime.InteropServices;
|
||||
using Daybreak.API.Extensions;
|
||||
using Daybreak.API.Serialization;
|
||||
using Net.Sdk.Web;
|
||||
|
||||
namespace Daybreak.API;
|
||||
|
||||
public static class EntryPoint
|
||||
{
|
||||
private const int StartPort = 5080;
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "ThreadInit"), STAThread]
|
||||
public static int ThreadInit(IntPtr _, int __)
|
||||
{
|
||||
ConsoleExtensions.AllocateAnsiConsole();
|
||||
var port = FindAvailablePort(StartPort);
|
||||
if (port <= 0)
|
||||
{
|
||||
Console.WriteLine($"No available port found starting from {StartPort}");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Console.WriteLine($"Starting Daybreak API on port {port}");
|
||||
Task.Run(() => StartServer(port));
|
||||
return port;
|
||||
}
|
||||
|
||||
private static async Task StartServer(int port)
|
||||
{
|
||||
try
|
||||
{
|
||||
var builder = WebApplication.CreateBuilder();
|
||||
builder.WebHost.UseUrls($"http://127.0.0.1:{port}");
|
||||
builder.Services.ConfigureHttpJsonOptions(options =>
|
||||
{
|
||||
options.SerializerOptions.TypeInfoResolverChain.Insert(0, new ApiJsonSerializerContext());
|
||||
});
|
||||
builder.Logging.AddConsole();
|
||||
builder.WithRoutes();
|
||||
|
||||
var app = builder.Build();
|
||||
app.UseRoutes();
|
||||
|
||||
await app.RunAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static int FindAvailablePort(int startPort)
|
||||
{
|
||||
var port = startPort;
|
||||
while (!IsPortAvailable(port))
|
||||
{
|
||||
port++;
|
||||
if (port > 65535 || port < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
private static bool IsPortAvailable(int port)
|
||||
{
|
||||
var ipProperties = IPGlobalProperties.GetIPGlobalProperties();
|
||||
var tcpListeners = ipProperties.GetActiveTcpListeners();
|
||||
if (tcpListeners.Any(endpoint => endpoint.Port == port))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var tcpConnections = ipProperties.GetActiveTcpConnections();
|
||||
if (tcpConnections.Any(conn => conn.LocalEndPoint.Port == port))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
namespace Daybreak.API.Extensions;
|
||||
|
||||
public static class ConsoleExtensions
|
||||
{
|
||||
public static void AllocateAnsiConsole()
|
||||
{
|
||||
NativeMethods.AllocConsole();
|
||||
var handle = NativeMethods.GetStdHandle(NativeMethods.STD_OUTPUT_HANDLE);
|
||||
if (!NativeMethods.GetConsoleMode(handle, out var mode))
|
||||
{
|
||||
Console.WriteLine("Failed to get console mode");
|
||||
}
|
||||
|
||||
if (!NativeMethods.SetConsoleMode(handle, mode | NativeMethods.ENABLE_VIRTUAL_TERMINAL_PROCESSING | NativeMethods.ENABLE_PROCESSED_OUTPUT))
|
||||
{
|
||||
Console.WriteLine("Failed to enable virtual terminal processing");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Daybreak.API;
|
||||
|
||||
internal static partial class NativeMethods
|
||||
{
|
||||
public const int STD_OUTPUT_HANDLE = -11;
|
||||
public const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004;
|
||||
public const uint ENABLE_PROCESSED_OUTPUT = 0x0001;
|
||||
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static partial bool AllocConsole();
|
||||
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
public static partial nint GetConsoleWindow();
|
||||
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
public static partial nint GetStdHandle(int nStdHandle);
|
||||
|
||||
[LibraryImport("kernel32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static partial bool GetConsoleMode(nint hConsoleHandle, out uint lpMode);
|
||||
|
||||
[LibraryImport("kernel32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static partial bool SetConsoleMode(nint hConsoleHandle, uint dwMode);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"profiles": {
|
||||
"Daybreak.API": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"applicationUrl": "https://localhost:51249;http://localhost:51250"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Daybreak.API.Serialization;
|
||||
|
||||
[JsonSerializable(typeof(string))]
|
||||
public partial class ApiJsonSerializerContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Platforms>AnyCPU;x86</Platforms>
|
||||
<PublishSingleFile>True</PublishSingleFile>
|
||||
<Self-Contained>True</Self-Contained>
|
||||
<PublishReadyToRun>True</PublishReadyToRun>
|
||||
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,129 @@
|
||||
// See https://aka.ms/new-console-template for more information
|
||||
using System.Diagnostics;
|
||||
using System.IO.Compression;
|
||||
using System.Text;
|
||||
|
||||
static void RenderProgressBar(int currentStep, int totalSteps, int barSize)
|
||||
{
|
||||
Console.CursorLeft = 0; // Reset cursor position to the start of the line
|
||||
Console.Write("["); // Start of the progress bar
|
||||
|
||||
double pctComplete = (double)currentStep / totalSteps;
|
||||
int chars = (int)Math.Round(pctComplete * barSize);
|
||||
|
||||
Console.Write(new string('=', chars)); // The 'completed' part of the bar
|
||||
Console.Write(new string(' ', barSize - chars)); // The 'remaining' part of the bar
|
||||
|
||||
Console.Write("] ");
|
||||
Console.Write($"{pctComplete:P0}"); // Display the percentage completed
|
||||
}
|
||||
|
||||
const string tempFile = "tempfile.zip";
|
||||
const string updatePkg = "update.pkg";
|
||||
const string executableName = "Daybreak.exe";
|
||||
Console.Title = "Daybreak Installer";
|
||||
Console.WriteLine("Starting installation...");
|
||||
while (Process.GetProcesses().Where(p => p.ProcessName == "Daybreak").FirstOrDefault()?.HasExited is false)
|
||||
{
|
||||
Console.WriteLine($"Detected Daybreak process is still running. Waiting 5s and retrying");
|
||||
await Task.Delay(5000);
|
||||
}
|
||||
|
||||
if (File.Exists(updatePkg))
|
||||
{
|
||||
Console.WriteLine("Unpacking files...");
|
||||
|
||||
using var fileStream = new FileStream(updatePkg, FileMode.Open);
|
||||
var sizeBuffer = new byte[4];
|
||||
var copyBuffer = new byte[1024];
|
||||
while (fileStream.Position < fileStream.Length - 1)
|
||||
{
|
||||
/*
|
||||
* For each file downloaded, we write to the package the following:
|
||||
* Size of the name string
|
||||
* UTF-8 encoded name string
|
||||
* Size of the relative path string
|
||||
* UTF-8 encoded relative path string
|
||||
* Size of the binary
|
||||
* Binary data
|
||||
*/
|
||||
|
||||
await fileStream.ReadAsync(sizeBuffer, 0, 4);
|
||||
var fileNameSize = BitConverter.ToInt32(sizeBuffer, 0);
|
||||
var fileNameBuffer = new byte[fileNameSize];
|
||||
await fileStream.ReadAsync(fileNameBuffer, 0, fileNameSize);
|
||||
var fileName = Encoding.UTF8.GetString(fileNameBuffer);
|
||||
|
||||
RenderProgressBar((int)fileStream.Position, (int)fileStream.Length, 40);
|
||||
|
||||
await fileStream.ReadAsync(sizeBuffer, 0, 4);
|
||||
var relativePathSize = BitConverter.ToInt32(sizeBuffer, 0);
|
||||
var relativePathBuffer = new byte[relativePathSize];
|
||||
await fileStream.ReadAsync(relativePathBuffer, 0, relativePathSize);
|
||||
var relativePath = Encoding.UTF8.GetString(relativePathBuffer);
|
||||
|
||||
RenderProgressBar((int)fileStream.Position, (int)fileStream.Length, 40);
|
||||
|
||||
await fileStream.ReadAsync(sizeBuffer, 0, 4);
|
||||
var binarySize = BitConverter.ToInt32(sizeBuffer, 0);
|
||||
var fileInfo = new FileInfo(relativePath);
|
||||
fileInfo.Directory!.Create();
|
||||
using var destinationStream = new FileStream(relativePath, FileMode.Create);
|
||||
while(binarySize > 0)
|
||||
{
|
||||
var toRead = Math.Min(binarySize, copyBuffer.Length);
|
||||
await fileStream.ReadAsync(copyBuffer, 0, toRead);
|
||||
await destinationStream.WriteAsync(copyBuffer, 0, toRead);
|
||||
binarySize -= toRead;
|
||||
|
||||
RenderProgressBar((int)fileStream.Position, (int)fileStream.Length, 40);
|
||||
}
|
||||
}
|
||||
|
||||
fileStream.Close();
|
||||
fileStream.Dispose();
|
||||
File.Delete(updatePkg);
|
||||
}
|
||||
else if (File.Exists(tempFile))
|
||||
{
|
||||
Console.WriteLine("Unpacking files...");
|
||||
try
|
||||
{
|
||||
ZipFile.ExtractToDirectory(tempFile, AppContext.BaseDirectory, true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
Console.WriteLine("Deleting package");
|
||||
try
|
||||
{
|
||||
File.Delete(tempFile);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine($"Failed to delete {tempFile}.\n{e}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine("Unable to find launcher package. Aborting installation");
|
||||
Console.ReadKey();
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLine("Launching application");
|
||||
var process = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = executableName
|
||||
}
|
||||
};
|
||||
|
||||
if (process.Start() is false)
|
||||
{
|
||||
Console.WriteLine("Failed to launch application");
|
||||
Console.ReadKey();
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Daybreak.Shared.Configuration.Options;
|
||||
|
||||
public interface ITradeChatOptions
|
||||
{
|
||||
string HttpsUri { get; set; }
|
||||
|
||||
string WssUri { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class AttributeJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType) => true;
|
||||
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (!objectType.IsAssignableTo(typeof(Models.Guildwars.Attribute)))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.String:
|
||||
var name = reader.ReadAsString();
|
||||
if (name is null ||
|
||||
!Models.Guildwars.Attribute.TryParse(name, out var namedAttribute))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return namedAttribute;
|
||||
case JsonToken.Integer:
|
||||
var id = reader.Value as long?;
|
||||
if (id is not long ||
|
||||
!Models.Guildwars.Attribute.TryParse((int)id.Value, out var parsedAttribute))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return parsedAttribute;
|
||||
|
||||
default:
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
{
|
||||
if (value is not Models.Guildwars.Attribute attribute)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteValue(attribute.Id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media.Effects;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class BooleanToEffectConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is not bool boolean)
|
||||
{
|
||||
return default!;
|
||||
}
|
||||
|
||||
if (parameter is not Effect effect)
|
||||
{
|
||||
return default!;
|
||||
}
|
||||
|
||||
if (!boolean)
|
||||
{
|
||||
return default!;
|
||||
}
|
||||
|
||||
return effect;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Extensions;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
|
||||
public sealed class BooleanToGridLengthConverter : IValueConverter
|
||||
{
|
||||
private static GridLength Collapsed = new(0);
|
||||
|
||||
public GridLength VisibleValue { get; set; }
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return this.GetVisibility(value);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private object GetVisibility(object value)
|
||||
{
|
||||
if (value is not bool)
|
||||
{
|
||||
return this.VisibleValue;
|
||||
}
|
||||
|
||||
var objValue = value.Cast<bool>();
|
||||
if (objValue)
|
||||
{
|
||||
return this.VisibleValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Collapsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Extensions;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
|
||||
public class BooleanToVisibilityConverter : IValueConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Set to true if you want to show control when boolean value is true.
|
||||
/// Set to false if you want to hide/collapse control when value is true.
|
||||
/// </summary>
|
||||
public bool TriggerValue { get; set; } = true;
|
||||
/// <summary>
|
||||
/// Set to true if you just want to hide the control, else set to false if you want to collapse the control.
|
||||
/// </summary>
|
||||
public bool IsHidden { get; set; }
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return this.GetVisibility(value);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private object GetVisibility(object value)
|
||||
{
|
||||
if (value is not bool)
|
||||
{
|
||||
return this.IsHidden ?
|
||||
Visibility.Hidden :
|
||||
Visibility.Collapsed;
|
||||
}
|
||||
|
||||
var objValue = value.Cast<bool>();
|
||||
if (objValue && this.TriggerValue && this.IsHidden || !objValue && !this.TriggerValue && this.IsHidden)
|
||||
{
|
||||
return Visibility.Hidden;
|
||||
}
|
||||
|
||||
if (objValue && this.TriggerValue && !this.IsHidden || !objValue && !this.TriggerValue && !this.IsHidden)
|
||||
{
|
||||
return Visibility.Collapsed;
|
||||
}
|
||||
|
||||
return Visibility.Visible;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class CampaignJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType) => true;
|
||||
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (!objectType.IsAssignableTo(typeof(Campaign)))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.String:
|
||||
var name = reader.ReadAsString();
|
||||
if (name is null ||
|
||||
!Campaign.TryParse(name, out var namedCampaign))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return namedCampaign;
|
||||
case JsonToken.Integer:
|
||||
var id = reader.Value as long?;
|
||||
if (id is not long ||
|
||||
!Campaign.TryParse((int)id.Value, out var parsedCampaign))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return parsedCampaign;
|
||||
|
||||
default:
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
{
|
||||
if (value is not Campaign campaign)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteValue(campaign.Id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class ContinentJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType) => true;
|
||||
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (!objectType.IsAssignableTo(typeof(Continent)))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.String:
|
||||
var name = reader.ReadAsString();
|
||||
if (name is null ||
|
||||
!Continent.TryParse(name, out var namedContinent))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return namedContinent;
|
||||
case JsonToken.Integer:
|
||||
var id = reader.Value as long?;
|
||||
if (id is not long ||
|
||||
!Continent.TryParse((int)id.Value, out var parsedContinent))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return parsedContinent;
|
||||
|
||||
default:
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
{
|
||||
if (value is not Continent continent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteValue(continent.Id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class DateTimeConverter : IValueConverter
|
||||
{
|
||||
public string? Format { get; set; }
|
||||
public bool LongTime { get; set; }
|
||||
public bool LongDate { get; set; }
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is not DateTime dateTime)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if (this.Format is not null)
|
||||
{
|
||||
return dateTime.ToString(this.Format);
|
||||
}
|
||||
|
||||
if (this.LongTime)
|
||||
{
|
||||
return dateTime.ToLongTimeString();
|
||||
}
|
||||
|
||||
if (this.LongDate)
|
||||
{
|
||||
return dateTime.ToLongDateString();
|
||||
}
|
||||
|
||||
return dateTime.ToShortDateString();
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class DoubleMultiplierConverter : IValueConverter
|
||||
{
|
||||
public double Multiplier { get; set; }
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is not double d)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
return d * this.Multiplier;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
|
||||
public sealed class EqualityToVisibilityConverter : IMultiValueConverter
|
||||
{
|
||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (values.Length != 2)
|
||||
{
|
||||
return Visibility.Collapsed;
|
||||
}
|
||||
|
||||
return values[0] == values[1] ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
using Daybreak.Shared;
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using Daybreak.Shared.Services.Events;
|
||||
using ExCSS;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class EventCalendarDayToBrushConverter : IValueConverter
|
||||
{
|
||||
private readonly EventToBrushConverter eventToBrushConverter = new();
|
||||
private readonly IEventService eventService = Global.GlobalServiceProvider.GetRequiredService<IEventService>();
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is not DateTime dayDate)
|
||||
{
|
||||
throw new InvalidOperationException($"Unable to convert from {value.GetType().Name}");
|
||||
}
|
||||
|
||||
dayDate = new DateTime(dayDate.Year, dayDate.Month, dayDate.Day, 19, 0, 0);
|
||||
var activeEvents = this.eventService.GetActiveEvents(dayDate).ToList();
|
||||
if (activeEvents.Count == 0)
|
||||
{
|
||||
return Brushes.Transparent;
|
||||
}
|
||||
|
||||
if (activeEvents.Count == 1 &&
|
||||
activeEvents.FirstOrDefault() is Event ev)
|
||||
{
|
||||
return this.eventToBrushConverter.Convert(ev, typeof(Brush), parameter, culture);
|
||||
}
|
||||
|
||||
var brushes = this.eventService.GetActiveEvents(dayDate).Select(e => this.eventToBrushConverter.Convert(e, typeof(Brush), parameter, culture)).OfType<SolidColorBrush>().ToList();
|
||||
var canvas = new Canvas();
|
||||
double width = 1.0 / brushes.Count; // Assuming a normalized width for each color segment
|
||||
|
||||
for (int i = 0; i < brushes.Count; i++)
|
||||
{
|
||||
var rect = new Rectangle
|
||||
{
|
||||
Width = width,
|
||||
Height = 1,
|
||||
Fill = brushes[i],
|
||||
RenderTransform = new TranslateTransform(i * width, 0)
|
||||
};
|
||||
canvas.Children.Add(rect);
|
||||
}
|
||||
|
||||
return new VisualBrush
|
||||
{
|
||||
Visual = canvas,
|
||||
Stretch = Stretch.None,
|
||||
TileMode = TileMode.None,
|
||||
Viewbox = new Rect(0, 0, 1, 1),
|
||||
ViewboxUnits = BrushMappingMode.RelativeToBoundingBox,
|
||||
Transform = new RotateTransform(45, 0.5, 0.5)
|
||||
};
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using Daybreak.Shared.Models;
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
using Brush = System.Windows.Media.Brush;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class EventToBrushConverter : IValueConverter
|
||||
{
|
||||
private static readonly Dictionary<Event, Brush> EventMapping = new()
|
||||
{
|
||||
{ Event.CanthanNewYear, new SolidColorBrush(ColorPalette.Amber) },
|
||||
{ Event.LuckyTreatsWeek, new SolidColorBrush(ColorPalette.Green) },
|
||||
{ Event.AprilFoolsDay, new SolidColorBrush(ColorPalette.DeepPurple) },
|
||||
{ Event.SweetTreatsWeek, new SolidColorBrush(ColorPalette.Indigo) },
|
||||
{ Event.AnniversaryCelebration, new SolidColorBrush(ColorPalette.Yellow) },
|
||||
{ Event.DragonFestival, new SolidColorBrush(ColorPalette.DeepOrange) },
|
||||
{ Event.WintersdayInJuly, new SolidColorBrush(ColorPalette.LightBlue) },
|
||||
{ Event.WayfarersReverie, new SolidColorBrush(ColorPalette.Magenta) },
|
||||
{ Event.PirateWeek, new SolidColorBrush(ColorPalette.Gold) },
|
||||
{ Event.BreastCancerAwarenessMonth, new SolidColorBrush(ColorPalette.Pink) },
|
||||
{ Event.Halloween, new SolidColorBrush(ColorPalette.Orange) },
|
||||
{ Event.SpecialTreatsWeek, new SolidColorBrush(ColorPalette.Lime) },
|
||||
{ Event.WintersdayJanuary, new SolidColorBrush(ColorPalette.BlueGrey) },
|
||||
{ Event.WintersdayDecember, new SolidColorBrush(ColorPalette.BlueGrey) }
|
||||
};
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is not Event e ||
|
||||
targetType != typeof(Brush))
|
||||
{
|
||||
throw new InvalidOperationException($"Unable to convert from {value.GetType().Name} to {targetType.Name}");
|
||||
}
|
||||
|
||||
return EventMapping[e];
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
|
||||
public class HiddenWhenNull : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return this.GetVerticalAlignment(value);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private object GetVerticalAlignment(object value)
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
return Visibility.Hidden;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Visibility.Visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
|
||||
public sealed class IntToStringConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (targetType == typeof(string) &&
|
||||
value is int i)
|
||||
{
|
||||
return i.ToString();
|
||||
}
|
||||
else if(targetType == typeof(int) &&
|
||||
value is string s)
|
||||
{
|
||||
return int.Parse(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException($"Unable to convert from {value.GetType().Name} to {targetType.Name}");
|
||||
}
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (targetType == typeof(string) &&
|
||||
value is int i)
|
||||
{
|
||||
return i.ToString();
|
||||
}
|
||||
else if (targetType == typeof(int) &&
|
||||
value is string s)
|
||||
{
|
||||
return int.Parse(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException($"Unable to convert from {value.GetType().Name} to {targetType.Name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
|
||||
public class InverseBooleanConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter,
|
||||
System.Globalization.CultureInfo culture)
|
||||
{
|
||||
if (targetType != typeof(bool))
|
||||
{
|
||||
throw new InvalidOperationException("The target must be a boolean");
|
||||
}
|
||||
|
||||
return !(bool)value;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter,
|
||||
System.Globalization.CultureInfo culture)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class ItemBaseJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType) => true;
|
||||
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (!objectType.IsAssignableTo(typeof(ItemBase)))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.String:
|
||||
var name = reader.ReadAsString();
|
||||
if (name is not string ||
|
||||
!ItemBase.TryParse(name, out var namedItem))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return namedItem;
|
||||
case JsonToken.Integer:
|
||||
var id = reader.Value as long?;
|
||||
if (id is not long ||
|
||||
!ItemBase.TryParse((int)id.Value, null, out var parsedItem))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return parsedItem;
|
||||
|
||||
default:
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
{
|
||||
if (value is not ItemBase itemBase)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteValue(itemBase.Id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class ItemBaseToIntConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is int i)
|
||||
{
|
||||
return ItemBase.Parse(i, modifiers: null);
|
||||
}
|
||||
else if(value is ItemBase itemBase)
|
||||
{
|
||||
return itemBase.Id;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Unable to convert value of type {value.GetType().Name}");
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is int i)
|
||||
{
|
||||
return ItemBase.Parse(i, modifiers: null);
|
||||
}
|
||||
else if (value is ItemBase itemBase)
|
||||
{
|
||||
return itemBase.Id;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Unable to convert value of type {value.GetType().Name}");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class ItemBaseToStringConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is string s)
|
||||
{
|
||||
return ItemBase.Parse(s);
|
||||
}
|
||||
else if(value is ItemBase itemBase)
|
||||
{
|
||||
return itemBase.Name ?? string.Empty;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Unable to convert value of type {value.GetType().Name}");
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is string s)
|
||||
{
|
||||
return ItemBase.Parse(s);
|
||||
}
|
||||
else if (value is ItemBase itemBase)
|
||||
{
|
||||
return itemBase.Name ?? string.Empty;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Unable to convert value of type {value.GetType().Name}");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class MapJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType) => true;
|
||||
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (!objectType.IsAssignableTo(typeof(Map)))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.String:
|
||||
var name = reader.ReadAsString();
|
||||
if (name is null ||
|
||||
!Map.TryParse(name, out var namedMap))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return namedMap;
|
||||
case JsonToken.Integer:
|
||||
var id = reader.Value as long?;
|
||||
if (id is not long ||
|
||||
!Map.TryParse((int)id.Value, out var parsedMap))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return parsedMap;
|
||||
|
||||
default:
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
{
|
||||
if (value is not Map map)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteValue(map.Id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
|
||||
public class MenuButtonHighlightConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (targetType == typeof(double) &&
|
||||
value is bool boolean)
|
||||
{
|
||||
return boolean ? 0.4 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (targetType == typeof(bool) &&
|
||||
value is double doubleValue)
|
||||
{
|
||||
return doubleValue == 0.4;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class NpcJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType) => true;
|
||||
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (!objectType.IsAssignableTo(typeof(Npc)))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.String:
|
||||
var name = reader.ReadAsString();
|
||||
if (name is null ||
|
||||
!Npc.TryParse(name, out var namedNpc))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return namedNpc;
|
||||
case JsonToken.Integer:
|
||||
var id = reader.Value as long?;
|
||||
if (id is not long ||
|
||||
!Npc.TryParse((int)id.Value, out var parsedNpc))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return parsedNpc;
|
||||
|
||||
default:
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
{
|
||||
if (value is not Npc npc)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteValue(npc.Ids.FirstOrDefault());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class PriceToStringConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (targetType != typeof(string))
|
||||
{
|
||||
throw new InvalidOperationException($"Unable to convert to {targetType.Name}");
|
||||
}
|
||||
|
||||
var price = value switch
|
||||
{
|
||||
byte byteVal => byteVal,
|
||||
short shortVal => shortVal,
|
||||
ushort ushortVal => ushortVal,
|
||||
int intVal => intVal,
|
||||
uint uintVal => uintVal,
|
||||
long longVal => longVal,
|
||||
ulong ulongVal => ulongVal,
|
||||
decimal decimalVal => (double)decimalVal,
|
||||
float floatVal => (double)floatVal,
|
||||
double doubleVal => (double)doubleVal,
|
||||
_ => throw new InvalidOperationException($"Unable to convert from {value.GetType().Name}")
|
||||
};
|
||||
|
||||
var suffix = 'g';
|
||||
if (price > 1000)
|
||||
{
|
||||
price /= 1000;
|
||||
suffix = 'k';
|
||||
}
|
||||
|
||||
return $"{price}{suffix}";
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class ProfessionJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType) => true;
|
||||
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (!objectType.IsAssignableTo(typeof(Profession)))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.String:
|
||||
var name = reader.ReadAsString();
|
||||
if (name is null ||
|
||||
!Profession.TryParse(name, out var namedProfession))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return namedProfession;
|
||||
case JsonToken.Integer:
|
||||
var id = reader.Value as long?;
|
||||
if (id is not long ||
|
||||
!Profession.TryParse((int)id.Value, out var parsedProfession))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return parsedProfession;
|
||||
|
||||
default:
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
{
|
||||
if (value is not Profession profession)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteValue(profession.Id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class QuestJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType) => true;
|
||||
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (!objectType.IsAssignableTo(typeof(Quest)))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.String:
|
||||
var name = reader.ReadAsString();
|
||||
if (name is null ||
|
||||
!Quest.TryParse(name, out var namedQuest))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return namedQuest;
|
||||
case JsonToken.Integer:
|
||||
var id = reader.Value as long?;
|
||||
if (id is not long ||
|
||||
!Quest.TryParse((int)id.Value, out var parsedQuest))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return parsedQuest;
|
||||
|
||||
default:
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
{
|
||||
if (value is not Quest quest)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteValue(quest.Id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class RegionJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType) => true;
|
||||
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (!objectType.IsAssignableTo(typeof(Region)))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.String:
|
||||
var name = reader.ReadAsString();
|
||||
if (name is null ||
|
||||
!Region.TryParse(name, out var namedRegion))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return namedRegion;
|
||||
case JsonToken.Integer:
|
||||
var id = reader.Value as long?;
|
||||
if (id is not long ||
|
||||
!Region.TryParse((int)id.Value, out var parsedRegion))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return parsedRegion;
|
||||
|
||||
default:
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
{
|
||||
if (value is not Region region)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteValue(region.Id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class SkillJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType) => true;
|
||||
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (!objectType.IsAssignableTo(typeof(Skill)))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.String:
|
||||
var name = reader.ReadAsString();
|
||||
if (name is null ||
|
||||
!Skill.TryParse(name, out var namedSkill))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return namedSkill;
|
||||
case JsonToken.Integer:
|
||||
var id = reader.Value as long?;
|
||||
if (id is not long ||
|
||||
!Skill.TryParse((int)id.Value, out var parsedSkill))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return parsedSkill;
|
||||
|
||||
default:
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
{
|
||||
if (value is not Skill skill)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteValue(skill.Id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
|
||||
public class TileButtonHighlightConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (targetType == typeof(double) &&
|
||||
value is bool boolean)
|
||||
{
|
||||
return boolean ? 1 : 0.4;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (targetType == typeof(bool) &&
|
||||
value is double doubleValue)
|
||||
{
|
||||
return doubleValue == 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
|
||||
public sealed class TimeSinceDateTimeConverter : IValueConverter
|
||||
{
|
||||
private const char PluralAppend = 's';
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return this.GetTimeString(value);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private object GetTimeString(object value)
|
||||
{
|
||||
if (value is not DateTime dateTime)
|
||||
{
|
||||
return default!;
|
||||
}
|
||||
|
||||
var difference = DateTime.Now - dateTime;
|
||||
|
||||
// If less than a minute, return seconds
|
||||
if (difference.TotalSeconds < 60)
|
||||
{
|
||||
var totalSeconds = (int)difference.TotalSeconds;
|
||||
return $"{totalSeconds} second{(difference.TotalSeconds > 1 ? PluralAppend : string.Empty)} ago";
|
||||
}
|
||||
|
||||
// If less than an hour, return minutes
|
||||
if (difference.TotalMinutes < 60)
|
||||
{
|
||||
var totalMinutes = (int)difference.TotalMinutes;
|
||||
return $"{totalMinutes} minute{(difference.TotalMinutes > 1 ? PluralAppend : string.Empty)} ago";
|
||||
}
|
||||
|
||||
// If less than a day, return hours
|
||||
if (difference.TotalHours < 24)
|
||||
{
|
||||
var totalHours = (int)difference.TotalHours;
|
||||
return $"{totalHours} hour{(difference.TotalHours > 1 ? PluralAppend : string.Empty)} ago";
|
||||
}
|
||||
|
||||
// If less than a week, return days
|
||||
if (difference.TotalDays < 7)
|
||||
{
|
||||
var totalDays = (int)difference.TotalDays;
|
||||
return $"{totalDays} day{(difference.TotalDays > 1 ? PluralAppend : string.Empty)} ago";
|
||||
}
|
||||
|
||||
// If less than a month, return weeks
|
||||
var numberOfDaysInCurrentMonth = DateTime.DaysInMonth(DateTime.Now.Year, DateTime.Now.Month);
|
||||
if (difference.TotalDays < numberOfDaysInCurrentMonth)
|
||||
{
|
||||
var numberOfWeeks = (int)difference.TotalDays / 7;
|
||||
return $"{numberOfWeeks} week{(numberOfWeeks > 1 ? PluralAppend : string.Empty)} ago";
|
||||
}
|
||||
|
||||
// If less than a year, return months
|
||||
var daysInCurrentYear = DateTime.IsLeapYear(DateTime.Now.Year) ? 366 : 365;
|
||||
if (difference.TotalDays < daysInCurrentYear)
|
||||
{
|
||||
var days = difference.TotalDays;
|
||||
var year = DateTime.Now.Year;
|
||||
var month = DateTime.Now.Month;
|
||||
var monthCount = 0;
|
||||
while(days > 0)
|
||||
{
|
||||
monthCount++;
|
||||
var numberOfDaysInMonth = DateTime.DaysInMonth(year, month);
|
||||
days -= numberOfDaysInMonth;
|
||||
if (month == 1)
|
||||
{
|
||||
month = 12;
|
||||
year--;
|
||||
}
|
||||
else
|
||||
{
|
||||
month--;
|
||||
}
|
||||
}
|
||||
|
||||
return $"{monthCount} month{(monthCount > 1 ? PluralAppend : string.Empty)} ago";
|
||||
}
|
||||
|
||||
// Return the number of years
|
||||
var remainingDays = difference.TotalDays;
|
||||
var yearCount = 0;
|
||||
var currentYear = DateTime.Now.Year;
|
||||
while(remainingDays > 0)
|
||||
{
|
||||
yearCount++;
|
||||
remainingDays -= DateTime.IsLeapYear(currentYear) ? 366 : 365;
|
||||
currentYear--;
|
||||
}
|
||||
|
||||
return $"{yearCount} year{(yearCount > 1 ? PluralAppend : string.Empty)} ago";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
|
||||
public sealed class TimespanToETAConverter : IValueConverter
|
||||
{
|
||||
private const char PluralAppend = 's';
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return GetETAString(value);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private static string GetETAString(object obj)
|
||||
{
|
||||
if (obj is not TimeSpan timeSpan)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if ((int)timeSpan.TotalDays > 0)
|
||||
{
|
||||
return $"{(int)timeSpan.TotalDays} day{((int)timeSpan.TotalDays > 1 ? PluralAppend : string.Empty)} remaining";
|
||||
}
|
||||
|
||||
return $"{timeSpan.Hours:D2}:{timeSpan.Minutes:D2}:{timeSpan.Seconds:D2} remaining";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class TitleJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType) => true;
|
||||
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (!objectType.IsAssignableTo(typeof(Title)))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.String:
|
||||
var name = reader.ReadAsString();
|
||||
if (name is null ||
|
||||
!Title.TryParse(name, out var namedTitle))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return namedTitle;
|
||||
case JsonToken.Integer:
|
||||
var id = reader.Value as long?;
|
||||
if (id is not long ||
|
||||
!Title.TryParse((int)id.Value, out var parsedTitle))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return parsedTitle;
|
||||
|
||||
default:
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
{
|
||||
if (value is not Title title)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteValue(title.Id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
using Daybreak.Shared.Models.Trade;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class TradeAlertConverter : JsonConverter<ITradeAlert>
|
||||
{
|
||||
public override ITradeAlert? ReadJson(JsonReader reader, Type objectType, ITradeAlert? existingValue, bool hasExistingValue, JsonSerializer serializer)
|
||||
{
|
||||
var jObject = JObject.Load(reader).ToObject<dynamic>();
|
||||
if (jObject is null)
|
||||
{
|
||||
throw new InvalidOperationException($"Unable to deserialize {nameof(ITradeAlert)}");
|
||||
}
|
||||
|
||||
if (jObject[nameof(TradeAlert.MessageCheck)] is null)
|
||||
{
|
||||
return new QuoteAlert
|
||||
{
|
||||
Name = jObject[nameof(QuoteAlert.Name)],
|
||||
Id = jObject[nameof(QuoteAlert.Id)],
|
||||
Enabled = jObject[nameof(QuoteAlert.Enabled)],
|
||||
UpperPriceTarget = jObject[nameof(QuoteAlert.UpperPriceTarget)],
|
||||
LowerPriceTarget = jObject[nameof(QuoteAlert.LowerPriceTarget)],
|
||||
UpperPriceTargetEnabled = jObject[nameof(QuoteAlert.UpperPriceTargetEnabled)],
|
||||
LowerPriceTargetEnabled = jObject[nameof(QuoteAlert.LowerPriceTargetEnabled)],
|
||||
ItemId = jObject[nameof(QuoteAlert.ItemId)]
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
return new TradeAlert
|
||||
{
|
||||
Name = jObject[nameof(TradeAlert.Name)],
|
||||
Id = jObject[nameof(TradeAlert.Id)],
|
||||
Enabled = jObject[nameof(TradeAlert.Enabled)],
|
||||
MessageCheck = jObject[nameof(TradeAlert.MessageCheck)],
|
||||
MessageRegexCheck = jObject[nameof(TradeAlert.MessageRegexCheck)],
|
||||
SenderCheck = jObject[nameof(TradeAlert.SenderCheck)],
|
||||
SenderRegexCheck = jObject[nameof(TradeAlert.SenderRegexCheck)]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, ITradeAlert? value, JsonSerializer serializer)
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
serializer.Serialize(writer, null);
|
||||
return;
|
||||
}
|
||||
|
||||
var jObject = new JObject();
|
||||
jObject[nameof(ITradeAlert.Name)] = value.Name;
|
||||
jObject[nameof(ITradeAlert.Enabled)] = value.Enabled;
|
||||
jObject[nameof(ITradeAlert.Id)] = value.Id;
|
||||
if (value is TradeAlert tradeAlert)
|
||||
{
|
||||
jObject[nameof(TradeAlert.MessageCheck)] = tradeAlert.MessageCheck;
|
||||
jObject[nameof(TradeAlert.MessageRegexCheck)] = tradeAlert.MessageRegexCheck;
|
||||
jObject[nameof(TradeAlert.SenderCheck)] = tradeAlert.SenderCheck;
|
||||
jObject[nameof(TradeAlert.SenderRegexCheck)] = tradeAlert.SenderRegexCheck;
|
||||
}
|
||||
else if (value is QuoteAlert quoteAlert)
|
||||
{
|
||||
jObject[nameof(QuoteAlert.TraderQuoteType)] = quoteAlert.TraderQuoteType.ToString();
|
||||
jObject[nameof(QuoteAlert.ItemId)] = quoteAlert.ItemId;
|
||||
jObject[nameof(QuoteAlert.UpperPriceTarget)] = quoteAlert.UpperPriceTarget;
|
||||
jObject[nameof(QuoteAlert.UpperPriceTargetEnabled)] = quoteAlert.UpperPriceTargetEnabled;
|
||||
jObject[nameof(QuoteAlert.LowerPriceTarget)] = quoteAlert.LowerPriceTarget;
|
||||
jObject[nameof(QuoteAlert.LowerPriceTargetEnabled)] = quoteAlert.LowerPriceTargetEnabled;
|
||||
}
|
||||
|
||||
serializer.Serialize(writer, jObject);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using Daybreak.Shared.Models.Trade;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Daybreak.Shared.Converters;
|
||||
public sealed class TraderQuoteTypeToStringConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (targetType != typeof(string))
|
||||
{
|
||||
throw new InvalidOperationException($"Unable to convert from {nameof(TraderQuoteType)} to {targetType.Name}");
|
||||
}
|
||||
|
||||
return value?.ToString() ?? string.Empty;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is not string s)
|
||||
{
|
||||
throw new InvalidOperationException($"Unable to convert to {targetType.Name}");
|
||||
}
|
||||
|
||||
if (!Enum.TryParse<TraderQuoteType>(s, out var enumValue))
|
||||
{
|
||||
throw new InvalidOperationException($"Invalid string value provided {s}");
|
||||
}
|
||||
|
||||
return enumValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0-windows</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWPF>true</UseWPF>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AvalonEdit" Version="6.3.1.120" />
|
||||
<PackageReference Include="DiffPlex" Version="1.7.2" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.12.1" />
|
||||
<PackageReference Include="ini-parser-netstandard" Version="2.5.3" />
|
||||
<PackageReference Include="LiveChartsCore.SkiaSharpView.WPF" Version="2.0.0-rc2" />
|
||||
<PackageReference Include="MahApps.Metro" Version="2.4.10" />
|
||||
<PackageReference Include="Microsoft.CorrelationVector" Version="1.0.42" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3240.44" />
|
||||
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.135" />
|
||||
<PackageReference Include="NAudio" Version="2.2.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="PeNet" Version="5.1.0" />
|
||||
<PackageReference Include="Plumsy" Version="1.1.0" />
|
||||
<PackageReference Include="securifybv.ShellLink" Version="0.1.0" />
|
||||
<PackageReference Include="Slim" Version="1.9.2" />
|
||||
<PackageReference Include="Squealify" Version="0.8.2.2" />
|
||||
<PackageReference Include="Svg" Version="3.4.7" />
|
||||
<PackageReference Include="System.Formats.Asn1" Version="9.0.5" />
|
||||
<PackageReference Include="System.IO.Compression" Version="4.3.0" />
|
||||
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
|
||||
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
||||
<PackageReference Include="System.Reflection.Metadata" Version="9.0.5" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.5" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.5" />
|
||||
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
|
||||
<PackageReference Include="SystemExtensions.NetCore" Version="1.6.11" />
|
||||
<PackageReference Include="SystemExtensions.NetStandard" Version="1.6.11" />
|
||||
<PackageReference Include="SystemExtensions.NetStandard.DependencyInjection" Version="1.6.9" />
|
||||
<PackageReference Include="WpfExtended" Version="0.7.9" />
|
||||
<PackageReference Include="WpfExtended.SourceGeneration" Version="0.3.0" />
|
||||
<PackageReference Include="WpfScreenHelper" Version="2.1.1" />
|
||||
<PackageReference Include="WriteableBitmapEx" Version="1.6.8" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="RemoveDuplicateAnalyzers" BeforeTargets="CoreCompile">
|
||||
<!-- Work around https://github.com/dotnet/wpf/issues/6792 -->
|
||||
<ItemGroup>
|
||||
<FilteredAnalyzer Include="@(Analyzer->Distinct())" />
|
||||
<Analyzer Remove="@(Analyzer)" />
|
||||
<Analyzer Include="@(FilteredAnalyzer)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Shared.Exceptions;
|
||||
|
||||
public sealed class CredentialsNotFoundException : Exception
|
||||
{
|
||||
public CredentialsNotFoundException()
|
||||
{
|
||||
}
|
||||
|
||||
public CredentialsNotFoundException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public CredentialsNotFoundException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Shared.Exceptions;
|
||||
|
||||
public sealed class ExecutableNotFoundException : Exception
|
||||
{
|
||||
public ExecutableNotFoundException()
|
||||
{
|
||||
}
|
||||
|
||||
public ExecutableNotFoundException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public ExecutableNotFoundException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Shared.Exceptions;
|
||||
|
||||
public sealed class FatalException : Exception
|
||||
{
|
||||
public FatalException()
|
||||
{
|
||||
}
|
||||
|
||||
public FatalException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public FatalException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("Daybreak")]
|
||||
|
||||
namespace Daybreak.Shared;
|
||||
|
||||
public static class Global
|
||||
{
|
||||
//Will get set by Daybreak on application startup
|
||||
public static IServiceProvider GlobalServiceProvider { get; internal set; } = default!;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Daybreak.Shared.Models;
|
||||
public readonly struct ApplicationLauncherContext
|
||||
{
|
||||
public string ExecutablePath { get; init; }
|
||||
public Process Process { get; init; }
|
||||
public uint ProcessId { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Daybreak.Shared.Models;
|
||||
public sealed class BackgroundResponse
|
||||
{
|
||||
public ImageSource? ImageSource { get; set; }
|
||||
public string? CreditText { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
namespace Daybreak.Shared.Models;
|
||||
|
||||
public class BatchedObservableCollection<T> : ObservableCollection<T>
|
||||
{
|
||||
public void RemoveBatch(IEnumerable<T> values)
|
||||
{
|
||||
this.CheckReentrancy();
|
||||
var changed = false;
|
||||
foreach (var value in values)
|
||||
{
|
||||
this.Items.Remove(value);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (!changed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
||||
}
|
||||
|
||||
public void AddBatch(IEnumerable<T> values)
|
||||
{
|
||||
this.CheckReentrancy();
|
||||
var changed = false;
|
||||
foreach (var value in values)
|
||||
{
|
||||
this.Items.Add(value);
|
||||
}
|
||||
|
||||
if (!changed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Daybreak.Shared.Models.Browser;
|
||||
public sealed class BrowserHistory
|
||||
{
|
||||
public List<string> History { get; set; } = [];
|
||||
public int CurrentPosition { get; set; } = -1;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
namespace Daybreak.Shared.Models.Browser;
|
||||
|
||||
public class BrowserPayload
|
||||
{
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum PayloadKeys
|
||||
{
|
||||
None,
|
||||
ContextMenu,
|
||||
XButton1Pressed,
|
||||
XButton2Pressed
|
||||
}
|
||||
|
||||
[JsonProperty(nameof(Key))]
|
||||
public PayloadKeys Key { get; set; }
|
||||
}
|
||||
|
||||
public sealed class BrowserPayload<T> : BrowserPayload
|
||||
{
|
||||
[JsonProperty(nameof(Value))]
|
||||
public T? Value { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Daybreak.Shared.Models.Browser;
|
||||
|
||||
public sealed class DownloadPayload
|
||||
{
|
||||
public string? ResultingFilePath { get; init; }
|
||||
public bool CanDownload { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Daybreak.Shared.Models.Browser;
|
||||
|
||||
public sealed class OnContextMenuPayload
|
||||
{
|
||||
[JsonProperty(nameof(X))]
|
||||
public double X { get; set; }
|
||||
[JsonProperty(nameof(Y))]
|
||||
public double Y { get; set; }
|
||||
[JsonProperty(nameof(Selection))]
|
||||
public string? Selection { get; set; }
|
||||
[JsonProperty(nameof(Url))]
|
||||
public string? Url { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using Daybreak.Shared.Models.Builds;
|
||||
|
||||
namespace Daybreak.Shared.Models;
|
||||
|
||||
public sealed class BuildWithTemplateCode
|
||||
{
|
||||
public IBuildEntry? Build { get; set; }
|
||||
public string? TemplateCode { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.ComponentModel;
|
||||
using Attribute = Daybreak.Shared.Models.Guildwars.Attribute;
|
||||
|
||||
namespace Daybreak.Shared.Models.Builds;
|
||||
|
||||
public sealed class AttributeEntry : INotifyPropertyChanged
|
||||
{
|
||||
private Attribute? attribute;
|
||||
private int points;
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
public Attribute? Attribute
|
||||
{
|
||||
get => this.attribute;
|
||||
set
|
||||
{
|
||||
this.attribute = value;
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Attribute)));
|
||||
}
|
||||
}
|
||||
public int Points
|
||||
{
|
||||
get => this.points;
|
||||
set
|
||||
{
|
||||
this.points = value;
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Points)));
|
||||
}
|
||||
}
|
||||
public override string ToString() => $"{this.Attribute?.Name} - {this.Points}";
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Daybreak.Shared.Models.Builds;
|
||||
public interface IBuildEntry
|
||||
{
|
||||
public DateTimeOffset CreationTime { get; set; }
|
||||
public Dictionary<string, string>? Metadata { get; set; }
|
||||
public string? SourceUrl { get; set; }
|
||||
public string? PreviousName { get; set; }
|
||||
public string? Name { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using Attribute = Daybreak.Shared.Models.Guildwars.Attribute;
|
||||
|
||||
namespace Daybreak.Shared.Models.Builds;
|
||||
public sealed class SingleBuildEntry : BuildEntryBase, IBuildEntry, INotifyPropertyChanged, IEquatable<SingleBuildEntry>
|
||||
{
|
||||
public Profession Primary
|
||||
{
|
||||
get;
|
||||
set
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
field = value;
|
||||
this.UpdateAttributes();
|
||||
this.OnPropertyChanged(nameof(this.Primary));
|
||||
}
|
||||
} = Profession.None;
|
||||
public Profession Secondary
|
||||
{
|
||||
get;
|
||||
set
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
field = value;
|
||||
this.UpdateAttributes();
|
||||
this.OnPropertyChanged(nameof(this.Secondary));
|
||||
}
|
||||
} = Profession.None;
|
||||
public List<AttributeEntry> Attributes
|
||||
{
|
||||
get;
|
||||
set
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
field = value;
|
||||
this.UpdateSkills();
|
||||
this.OnPropertyChanged(nameof(this.Attributes));
|
||||
}
|
||||
} = [];
|
||||
public List<Skill> Skills
|
||||
{
|
||||
get;
|
||||
set
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
field = value;
|
||||
this.OnPropertyChanged(nameof(this.Skills));
|
||||
}
|
||||
} = [Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill];
|
||||
public Skill FirstSkill
|
||||
{
|
||||
get => this.Skills[0];
|
||||
set
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.Skills[0] = value;
|
||||
this.OnPropertyChanged(nameof(this.FirstSkill));
|
||||
}
|
||||
}
|
||||
public Skill SecondSkill
|
||||
{
|
||||
get => this.Skills[1];
|
||||
set
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.Skills[1] = value;
|
||||
this.OnPropertyChanged(nameof(this.SecondSkill));
|
||||
}
|
||||
}
|
||||
public Skill ThirdSkill
|
||||
{
|
||||
get => this.Skills[2];
|
||||
set
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.Skills[2] = value;
|
||||
this.OnPropertyChanged(nameof(this.ThirdSkill));
|
||||
}
|
||||
}
|
||||
public Skill FourthSkill
|
||||
{
|
||||
get => this.Skills[3];
|
||||
set
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.Skills[3] = value;
|
||||
this.OnPropertyChanged(nameof(this.FourthSkill));
|
||||
}
|
||||
}
|
||||
public Skill FifthSkill
|
||||
{
|
||||
get => this.Skills[4];
|
||||
set
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.Skills[4] = value;
|
||||
this.OnPropertyChanged(nameof(this.FifthSkill));
|
||||
}
|
||||
}
|
||||
public Skill SixthSkill
|
||||
{
|
||||
get => this.Skills[5];
|
||||
set
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.Skills[5] = value;
|
||||
this.OnPropertyChanged(nameof(this.SixthSkill));
|
||||
}
|
||||
}
|
||||
public Skill SeventhSkill
|
||||
{
|
||||
get => this.Skills[6];
|
||||
set
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.Skills[6] = value;
|
||||
this.OnPropertyChanged(nameof(this.SeventhSkill));
|
||||
}
|
||||
}
|
||||
public Skill EigthSkill
|
||||
{
|
||||
get => this.Skills[7];
|
||||
set
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.Skills[7] = value;
|
||||
this.OnPropertyChanged(nameof(this.EigthSkill));
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateAttributes()
|
||||
{
|
||||
var attributesToAdd = new List<Attribute>();
|
||||
if (this.Primary.PrimaryAttribute is not null)
|
||||
{
|
||||
attributesToAdd.Add(this.Primary.PrimaryAttribute);
|
||||
}
|
||||
|
||||
attributesToAdd.AddRange(this.Primary.Attributes);
|
||||
attributesToAdd.AddRange(this.Secondary.Attributes);
|
||||
this.Attributes = attributesToAdd.Distinct().Select(attribute =>
|
||||
{
|
||||
if (this.Attributes.FirstOrDefault(attributeEntry => attributeEntry.Attribute == attribute) is AttributeEntry attributeEntry)
|
||||
{
|
||||
return attributeEntry;
|
||||
}
|
||||
|
||||
return new AttributeEntry { Attribute = attribute };
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
private void UpdateSkills()
|
||||
{
|
||||
if (this.FirstSkill.Profession != Profession.None &&
|
||||
this.FirstSkill.Profession != this.Primary &&
|
||||
this.FirstSkill.Profession != this.Secondary)
|
||||
{
|
||||
this.FirstSkill = Skill.NoSkill;
|
||||
}
|
||||
|
||||
if (this.SecondSkill.Profession != Profession.None &&
|
||||
this.SecondSkill.Profession != this.Primary &&
|
||||
this.SecondSkill.Profession != this.Secondary)
|
||||
{
|
||||
this.SecondSkill = Skill.NoSkill;
|
||||
}
|
||||
|
||||
if (this.ThirdSkill.Profession != Profession.None &&
|
||||
this.ThirdSkill.Profession != this.Primary &&
|
||||
this.ThirdSkill.Profession != this.Secondary)
|
||||
{
|
||||
this.ThirdSkill = Skill.NoSkill;
|
||||
}
|
||||
|
||||
if (this.FourthSkill.Profession != Profession.None &&
|
||||
this.FourthSkill.Profession != this.Primary &&
|
||||
this.FourthSkill.Profession != this.Secondary)
|
||||
{
|
||||
this.FourthSkill = Skill.NoSkill;
|
||||
}
|
||||
|
||||
if (this.FifthSkill.Profession != Profession.None &&
|
||||
this.FifthSkill.Profession != this.Primary &&
|
||||
this.FifthSkill.Profession != this.Secondary)
|
||||
{
|
||||
this.FifthSkill = Skill.NoSkill;
|
||||
}
|
||||
|
||||
if (this.SixthSkill.Profession != Profession.None &&
|
||||
this.SixthSkill.Profession != this.Primary &&
|
||||
this.SixthSkill.Profession != this.Secondary)
|
||||
{
|
||||
this.SixthSkill = Skill.NoSkill;
|
||||
}
|
||||
|
||||
if (this.SeventhSkill.Profession != Profession.None &&
|
||||
this.SeventhSkill.Profession != this.Primary &&
|
||||
this.SeventhSkill.Profession != this.Secondary)
|
||||
{
|
||||
this.SeventhSkill = Skill.NoSkill;
|
||||
}
|
||||
|
||||
if (this.EigthSkill.Profession != Profession.None &&
|
||||
this.EigthSkill.Profession != this.Primary &&
|
||||
this.EigthSkill.Profession != this.Secondary)
|
||||
{
|
||||
this.EigthSkill = Skill.NoSkill;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Equals(SingleBuildEntry? other)
|
||||
{
|
||||
return this.Name == other?.Name &&
|
||||
this.PreviousName == other?.PreviousName &&
|
||||
this.SourceUrl == other?.SourceUrl &&
|
||||
this.Primary == other?.Primary &&
|
||||
this.Secondary == other?.Secondary &&
|
||||
this.Skills.SequenceEqual(other.Skills);
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return this.Equals(obj as SingleBuildEntry);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(this.Name, this.PreviousName, this.SourceUrl, this.Primary.Name, this.Secondary.Name, string.Join(';', this.Skills.Select(s => s.Id)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Daybreak.Shared.Models.Builds;
|
||||
public sealed class TeamBuildEntry : BuildEntryBase, IEquatable<TeamBuildEntry>
|
||||
{
|
||||
public List<SingleBuildEntry> Builds
|
||||
{
|
||||
get;
|
||||
set
|
||||
{
|
||||
field = value;
|
||||
this.OnPropertyChanged(nameof(this.Builds));
|
||||
}
|
||||
} = [];
|
||||
|
||||
public bool Equals(TeamBuildEntry? other)
|
||||
{
|
||||
return this.Name == other?.Name &&
|
||||
this.PreviousName == other?.PreviousName &&
|
||||
this.SourceUrl == other?.SourceUrl &&
|
||||
this.Builds.Select((thisBuild, index) =>
|
||||
{
|
||||
var otherBuild = other?.Builds.Skip(index).FirstOrDefault();
|
||||
return thisBuild.Primary == otherBuild?.Primary &&
|
||||
thisBuild.Secondary == otherBuild?.Secondary &&
|
||||
thisBuild.Skills.SequenceEqual(otherBuild.Skills);
|
||||
}).All(result => result);
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return this.Equals(obj as TeamBuildEntry);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(this.Name, this.PreviousName, this.SourceUrl, this.Builds.Select(c => c.GetHashCode()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Daybreak.Shared.Models;
|
||||
public static class ColorPalette
|
||||
{
|
||||
public readonly static Color Red = Color.FromArgb(255, 213, 0, 0);
|
||||
public readonly static Color Pink = Color.FromArgb(255, 197, 17, 98);
|
||||
public readonly static Color Purple = Color.FromArgb(255, 170, 0, 255);
|
||||
public readonly static Color DeepPurple = Color.FromArgb(255, 98, 0, 234);
|
||||
public readonly static Color Indigo = Color.FromArgb(255, 48, 79, 254);
|
||||
public readonly static Color Blue = Color.FromArgb(255, 41, 98, 255);
|
||||
public readonly static Color LightBlue = Color.FromArgb(255, 0, 145, 234);
|
||||
public readonly static Color Cyan = Color.FromArgb(255, 0, 184, 212);
|
||||
public readonly static Color Teal = Color.FromArgb(255, 0, 191, 165);
|
||||
public readonly static Color Yellow = Color.FromArgb(255, 255, 214, 0);
|
||||
public readonly static Color Amber = Color.FromArgb(255, 255, 171, 0);
|
||||
public readonly static Color Orange = Color.FromArgb(255, 255, 109, 0);
|
||||
public readonly static Color DeepOrange = Color.FromArgb(255, 221, 44, 0);
|
||||
public readonly static Color Green = Color.FromArgb(255, 56, 142, 60);
|
||||
public readonly static Color Lime = Color.FromArgb(255, 174, 234, 0);
|
||||
public readonly static Color Magenta = Color.FromArgb(255, 213, 0, 249);
|
||||
public readonly static Color Gold = Color.FromArgb(255, 255, 241, 118);
|
||||
public readonly static Color BlueGrey = Color.FromArgb(255, 96, 125, 139);
|
||||
public readonly static Color Grey = Color.FromArgb(255, 158, 158, 158);
|
||||
|
||||
public readonly static List<Color> Colors =
|
||||
[
|
||||
Pink,
|
||||
Amber,
|
||||
Purple,
|
||||
DeepPurple,
|
||||
Yellow,
|
||||
Indigo,
|
||||
Orange,
|
||||
Blue,
|
||||
DeepOrange,
|
||||
LightBlue,
|
||||
Red,
|
||||
Cyan,
|
||||
Teal,
|
||||
Green,
|
||||
Lime,
|
||||
Magenta,
|
||||
Gold,
|
||||
BlueGrey,
|
||||
Grey
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
namespace Daybreak.Shared.Models;
|
||||
|
||||
public enum ColorScheme
|
||||
{
|
||||
Red,
|
||||
Green,
|
||||
Blue,
|
||||
Purple,
|
||||
Orange,
|
||||
Lime,
|
||||
Emerald,
|
||||
Teal,
|
||||
Cyan,
|
||||
Cobalt,
|
||||
Indigo,
|
||||
Violet,
|
||||
Pink,
|
||||
Magenta,
|
||||
Crimson,
|
||||
Amber,
|
||||
Yellow,
|
||||
Brown,
|
||||
Olive,
|
||||
Steel,
|
||||
Mauve,
|
||||
Taupe,
|
||||
Sienna
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Daybreak.Shared.Models;
|
||||
|
||||
public sealed class ColoredTextElement
|
||||
{
|
||||
public SolidColorBrush Color { get; init; } = default!;
|
||||
public string Text { get; init; } = default!;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using Daybreak.Shared.Models.Builds;
|
||||
|
||||
namespace Daybreak.Shared.Models;
|
||||
public sealed class DownloadedBuild
|
||||
{
|
||||
public string? PreferredName { get; set; }
|
||||
public IBuildEntry? Build { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Shared.Models;
|
||||
|
||||
public sealed class ElevationRequest
|
||||
{
|
||||
public object? DataContext { get; set; }
|
||||
public Type? View { get; set; }
|
||||
public string? MessageToUser { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Extensions;
|
||||
|
||||
namespace Daybreak.Models;
|
||||
public partial class EventViewModel : INotifyPropertyChanged
|
||||
{
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
[GenerateNotifyPropertyChanged]
|
||||
private Event? seasonalEvent;
|
||||
[GenerateNotifyPropertyChanged]
|
||||
private bool active;
|
||||
[GenerateNotifyPropertyChanged]
|
||||
private bool upcoming;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Daybreak.Shared.Models;
|
||||
|
||||
public sealed class ExecutablePath : INotifyPropertyChanged
|
||||
{
|
||||
private string path = string.Empty;
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
public string Path
|
||||
{
|
||||
get => this.path;
|
||||
set
|
||||
{
|
||||
this.path = value;
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Path)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace Daybreak.Shared.Models;
|
||||
|
||||
public enum ExecutionPolicies
|
||||
{
|
||||
AllSigned,
|
||||
Bypass,
|
||||
Default,
|
||||
RemoteSigned,
|
||||
Restricted,
|
||||
Undefined,
|
||||
Unrestricted
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
using Daybreak.Shared.Models.LaunchConfigurations;
|
||||
|
||||
namespace Daybreak.Shared.Models.FocusView;
|
||||
/// <summary>
|
||||
/// XD Name
|
||||
/// </summary>
|
||||
internal sealed class PlayerContextMenuContext
|
||||
{
|
||||
public GuildWarsApplicationLaunchContext? GuildWarsApplicationLaunchContext { get; set; }
|
||||
public PlayerInformation? Player { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
namespace Daybreak.Shared.Models.FocusView;
|
||||
|
||||
public sealed class QuestEntry : QuestLogEntry
|
||||
{
|
||||
public override string Title { get; init; } = string.Empty;
|
||||
public Quest? Quest { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
namespace Daybreak.Shared.Models.FocusView;
|
||||
public sealed class QuestLocationEntry : QuestLogEntry
|
||||
{
|
||||
public override string Title { get; init; } = string.Empty;
|
||||
public Map? Map { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Daybreak.Shared.Models.FocusView;
|
||||
|
||||
public abstract class QuestLogEntry
|
||||
{
|
||||
public abstract string Title { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
namespace Daybreak.Shared.Models.FocusView;
|
||||
public sealed class QuestLogSeparator : QuestLogEntry
|
||||
{
|
||||
public override string Title { get; init; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Daybreak.Shared.Models.Github;
|
||||
|
||||
public sealed class GithubRefTag
|
||||
{
|
||||
[JsonProperty("ref")]
|
||||
public string? Ref;
|
||||
[JsonProperty("node_id")]
|
||||
public string? NodeId;
|
||||
[JsonProperty("url")]
|
||||
public string? Url;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using Daybreak.Shared.Models.Progress;
|
||||
using System.Threading;
|
||||
|
||||
namespace Daybreak.Shared.Models;
|
||||
public sealed class GuildWarsUpdateRequest
|
||||
{
|
||||
public string? ExecutablePath { get; init; }
|
||||
public GuildwarsInstallationStatus? Status { get; init; }
|
||||
public CancellationToken CancellationToken { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Daybreak.Shared.Models;
|
||||
public sealed class GuildWarsUpdateResponse
|
||||
{
|
||||
public bool Result { get; init; }
|
||||
public string? ExecutablePath { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
using Daybreak.Shared.Converters;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
[JsonConverter(typeof(AttributeJsonConverter))]
|
||||
public sealed class Attribute
|
||||
{
|
||||
public static readonly Attribute FastCasting = new() { Name = "Fast Casting", Id = 0, Profession = Profession.Mesmer };
|
||||
public static readonly Attribute IllusionMagic = new() { Name = "Illusion Magic", Id = 1, Profession = Profession.Mesmer };
|
||||
public static readonly Attribute DominationMagic = new() { Name = "Domination Magic", Id = 2, Profession = Profession.Mesmer };
|
||||
public static readonly Attribute InspirationMagic = new() { Name = "Inspiration Magic", Id = 3, Profession = Profession.Mesmer };
|
||||
public static readonly Attribute BloodMagic = new() { Name = "Blood Magic", Id = 4, Profession = Profession.Necromancer };
|
||||
public static readonly Attribute DeathMagic = new() { Name = "Death Magic", Id = 5, Profession = Profession.Necromancer };
|
||||
public static readonly Attribute SoulReaping = new() { Name = "Soul Reaping", Id = 6, Profession = Profession.Necromancer };
|
||||
public static readonly Attribute Curses = new() { Name = "Curses", Id = 7, Profession = Profession.Necromancer };
|
||||
public static readonly Attribute AirMagic = new() { Name = "Air Magic", Id = 8, Profession = Profession.Elementalist };
|
||||
public static readonly Attribute EarthMagic = new() { Name = "Earth Magic", Id = 9, Profession = Profession.Elementalist };
|
||||
public static readonly Attribute FireMagic = new() { Name = "Fire Magic", Id = 10, Profession = Profession.Elementalist };
|
||||
public static readonly Attribute WaterMagic = new() { Name = "Water Magic", Id = 11, Profession = Profession.Elementalist };
|
||||
public static readonly Attribute EnergyStorage = new() { Name = "Energy Storage", Id = 12, Profession = Profession.Elementalist };
|
||||
public static readonly Attribute HealingPrayers = new() { Name = "Healing Prayers", Id = 13, Profession = Profession.Monk };
|
||||
public static readonly Attribute SmitingPrayers = new() { Name = "Smiting Prayers", Id = 14, Profession = Profession.Monk };
|
||||
public static readonly Attribute ProtectionPrayers = new() { Name = "Protection Prayers", Id = 15, Profession = Profession.Monk };
|
||||
public static readonly Attribute DivineFavor = new() { Name = "Divine Favor", Id = 16, Profession = Profession.Monk };
|
||||
public static readonly Attribute Strength = new() { Name = "Strength", Id = 17, Profession = Profession.Warrior };
|
||||
public static readonly Attribute AxeMastery = new() { Name = "Axe Mastery", Id = 18, Profession = Profession.Warrior };
|
||||
public static readonly Attribute HammerMastery = new() { Name = "Hammer Mastery", Id = 19, Profession = Profession.Warrior };
|
||||
public static readonly Attribute Swordsmanship = new() { Name = "Swordsmanship", Id = 20, Profession = Profession.Warrior };
|
||||
public static readonly Attribute Tactics = new() { Name = "Tactics", Id = 21, Profession = Profession.Warrior };
|
||||
public static readonly Attribute BeastMastery = new() { Name = "Beast Mastery", Id = 22, Profession = Profession.Ranger };
|
||||
public static readonly Attribute Expertise = new() { Name = "Expertise", Id = 23, Profession = Profession.Ranger };
|
||||
public static readonly Attribute WildernessSurvival = new() { Name = "Wilderness Survival", Id = 24, Profession = Profession.Ranger };
|
||||
public static readonly Attribute Marksmanship = new() { Name = "Marksmanship", Id = 25, Profession = Profession.Ranger };
|
||||
public static readonly Attribute DaggerMastery = new() { Name = "Dagger Mastery", Id = 29, Profession = Profession.Assassin };
|
||||
public static readonly Attribute DeadlyArts = new() { Name = "Deadly Arts", Id = 30, Profession = Profession.Assassin };
|
||||
public static readonly Attribute ShadowArts = new() { Name = "Shadow Arts", Id = 31, Profession = Profession.Assassin };
|
||||
public static readonly Attribute Communing = new() { Name = "Communing", Id = 32, Profession = Profession.Ritualist };
|
||||
public static readonly Attribute RestorationMagic = new() { Name = "Restoration Magic", Id = 33, Profession = Profession.Ritualist };
|
||||
public static readonly Attribute ChannelingMagic = new() { Name = "Channeling Magic", Id = 34, Profession = Profession.Ritualist };
|
||||
public static readonly Attribute CriticalStrikes = new() { Name = "Critical Strikes", Id = 35, Profession = Profession.Assassin };
|
||||
public static readonly Attribute SpawningPower = new() { Name = "Spawning Power", Id = 36, Profession = Profession.Ritualist };
|
||||
public static readonly Attribute SpearMastery = new() { Name = "Spear Mastery", Id = 37, Profession = Profession.Paragon };
|
||||
public static readonly Attribute Command = new() { Name = "Command", Id = 38, Profession = Profession.Paragon };
|
||||
public static readonly Attribute Motivation = new() { Name = "Motivation", Id = 39, Profession = Profession.Paragon };
|
||||
public static readonly Attribute Leadership = new() { Name = "Leadership", Id = 40, Profession = Profession.Paragon };
|
||||
public static readonly Attribute ScytheMastery = new() { Name = "Scythe Mastery", Id = 41, Profession = Profession.Dervish };
|
||||
public static readonly Attribute WindPrayers = new() { Name = "Wind Prayers", Id = 42, Profession = Profession.Dervish };
|
||||
public static readonly Attribute EarthPrayers = new() { Name = "Earth Prayers", Id = 43, Profession = Profession.Dervish };
|
||||
public static readonly Attribute Mysticism = new() { Name = "Mysticism", Id = 44, Profession = Profession.Dervish };
|
||||
public static readonly IEnumerable<Attribute> Attributes = new List<Attribute>
|
||||
{
|
||||
FastCasting,
|
||||
IllusionMagic,
|
||||
DominationMagic,
|
||||
InspirationMagic,
|
||||
BloodMagic,
|
||||
DeathMagic,
|
||||
SoulReaping,
|
||||
Curses,
|
||||
AirMagic,
|
||||
EarthMagic,
|
||||
FireMagic,
|
||||
WaterMagic,
|
||||
EnergyStorage,
|
||||
HealingPrayers,
|
||||
SmitingPrayers,
|
||||
ProtectionPrayers,
|
||||
DivineFavor,
|
||||
Strength,
|
||||
AxeMastery,
|
||||
HammerMastery,
|
||||
Swordsmanship,
|
||||
Tactics,
|
||||
BeastMastery,
|
||||
Expertise,
|
||||
WildernessSurvival,
|
||||
Marksmanship,
|
||||
DaggerMastery,
|
||||
DeadlyArts,
|
||||
ShadowArts,
|
||||
Communing,
|
||||
RestorationMagic,
|
||||
ChannelingMagic,
|
||||
CriticalStrikes,
|
||||
SpawningPower,
|
||||
SpearMastery,
|
||||
Command,
|
||||
Motivation,
|
||||
Leadership,
|
||||
ScytheMastery,
|
||||
EarthPrayers,
|
||||
WindPrayers,
|
||||
EarthMagic,
|
||||
Mysticism
|
||||
};
|
||||
|
||||
public static bool TryParse(int id, out Attribute attribute)
|
||||
{
|
||||
attribute = Attributes.Where(attr => attr.Id == id).FirstOrDefault()!;
|
||||
if (attribute is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
public static bool TryParse(string name, out Attribute attribute)
|
||||
{
|
||||
attribute = Attributes.Where(attr => attr.Name == name).FirstOrDefault()!;
|
||||
if (attribute is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
public static Attribute Parse(int id)
|
||||
{
|
||||
if (TryParse(id, out var attribute) is false)
|
||||
{
|
||||
throw new InvalidOperationException($"Could not find an attribute with id {id}");
|
||||
}
|
||||
|
||||
return attribute;
|
||||
}
|
||||
public static Attribute Parse(string name)
|
||||
{
|
||||
if (TryParse(name, out var attribute) is false)
|
||||
{
|
||||
throw new InvalidOperationException($"Could not find an attribute with name {name}");
|
||||
}
|
||||
|
||||
return attribute;
|
||||
}
|
||||
|
||||
public int Id { get; private set; }
|
||||
public string? Name { get; private set; }
|
||||
public Profession? Profession { get; private set; }
|
||||
public override string ToString() => this.Name ?? string.Empty;
|
||||
private Attribute()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
using Daybreak.Shared.Models.Builds;
|
||||
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
public sealed class Build
|
||||
{
|
||||
public BuildMetadata? BuildMetadata { get; set; }
|
||||
public Profession Primary { get; set; } = Profession.None;
|
||||
public Profession Secondary { get; set; } = Profession.None;
|
||||
public List<AttributeEntry> Attributes { get; set; } = [];
|
||||
public List<Skill> Skills { get; set; } = [Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill, Skill.NoSkill];
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
using Daybreak.Shared.Models.Builds;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
public abstract class BuildEntryBase : INotifyPropertyChanged, IBuildEntry
|
||||
{
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
public Dictionary<string, string>? Metadata { get; set; }
|
||||
public string? PreviousName { get; set; }
|
||||
public int? ToolboxBuildId
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.Metadata?.TryGetValue(nameof(this.ToolboxBuildId), out var toolBoxBuildString) is true &&
|
||||
int.TryParse(toolBoxBuildString, out var toolboxBuild))
|
||||
{
|
||||
return toolboxBuild;
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.Metadata ??= [];
|
||||
this.Metadata[nameof(this.ToolboxBuildId)] = value.HasValue ? value.Value.ToString() : string.Empty;
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.ToolboxBuildId)));
|
||||
}
|
||||
}
|
||||
public bool IsToolboxBuild
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.Metadata?.TryGetValue(nameof(this.IsToolboxBuild), out var toolBoxBuildString) is true &&
|
||||
bool.TryParse(toolBoxBuildString, out var toolboxBuild))
|
||||
{
|
||||
return toolboxBuild;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.Metadata ??= [];
|
||||
this.Metadata[nameof(this.IsToolboxBuild)] = value.ToString();
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.IsToolboxBuild)));
|
||||
}
|
||||
}
|
||||
public DateTimeOffset CreationTime
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.Metadata?.TryGetValue(nameof(this.CreationTime), out var creationTimeString) is true &&
|
||||
int.TryParse(creationTimeString, out var creationTimeUnix))
|
||||
{
|
||||
return DateTimeOffset.FromUnixTimeSeconds(creationTimeUnix);
|
||||
}
|
||||
|
||||
return DateTimeOffset.MinValue;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.Metadata ??= [];
|
||||
this.Metadata[nameof(this.CreationTime)] = value.ToUniversalTime().ToUnixTimeSeconds().ToString();
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.CreationTime)));
|
||||
}
|
||||
}
|
||||
public string? Name
|
||||
{
|
||||
get;
|
||||
set
|
||||
{
|
||||
field = value;
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Name)));
|
||||
}
|
||||
}
|
||||
public string? SourceUrl
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.Metadata?.TryGetValue(nameof(this.SourceUrl), out var sourceUrl) is true)
|
||||
{
|
||||
return sourceUrl;
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.Metadata ??= [];
|
||||
this.Metadata[nameof(this.SourceUrl)] = value ?? string.Empty;
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.SourceUrl)));
|
||||
}
|
||||
}
|
||||
public List<PartyCompositionMetadataEntry>? PartyComposition
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.Metadata?.TryGetValue(nameof(this.PartyComposition), out var serializedPartyComposition) is true &&
|
||||
!string.IsNullOrWhiteSpace(serializedPartyComposition))
|
||||
{
|
||||
return JsonConvert.DeserializeObject<List<PartyCompositionMetadataEntry>>(serializedPartyComposition);
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.Metadata ??= [];
|
||||
this.Metadata[nameof(PartyCompositionMetadataEntry)] = value is null
|
||||
? string.Empty
|
||||
: JsonConvert.SerializeObject(value, Formatting.None);
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.PartyComposition)));
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnPropertyChanged(string propertyName)
|
||||
{
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
public sealed class BuildMetadata
|
||||
{
|
||||
public List<int>? Base64Decoded { get; set; }
|
||||
public List<string>? BinaryDecoded { get; set; }
|
||||
public int Header { get; set; }
|
||||
public int VersionNumber { get; set; }
|
||||
public int ProfessionIdLength { get; set; }
|
||||
public int PrimaryProfessionId { get; set; }
|
||||
public int SecondaryProfessionId { get; set; }
|
||||
public int AttributeCount { get; set; }
|
||||
public int AttributesLength { get; set; }
|
||||
public int SkillsLength { get; set; }
|
||||
public bool TailPresent { get; set; }
|
||||
public bool NewTemplate { get; set; }
|
||||
public List<int> SkillIds { get; set; } = [];
|
||||
public List<int> AttributesIds { get; set; } = [];
|
||||
public List<int> AttributePoints { get; set; } = [];
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
using Daybreak.Shared.Converters;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
[JsonConverter(typeof(CampaignJsonConverter))]
|
||||
public sealed class Campaign
|
||||
{
|
||||
public static Campaign Core { get; } = new()
|
||||
{
|
||||
Id = 0,
|
||||
Name = "Core",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Guild_Wars_Core",
|
||||
Continents = new List<Continent>
|
||||
{
|
||||
Continent.TheBattleIsles,
|
||||
Continent.TheMists
|
||||
}
|
||||
};
|
||||
|
||||
public static Campaign Prophecies { get; } = new()
|
||||
{
|
||||
Id = 1,
|
||||
Name = "Prophecies",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Guild_Wars_Prophecies",
|
||||
Continents = new List<Continent>
|
||||
{
|
||||
Continent.Tyria
|
||||
}
|
||||
};
|
||||
|
||||
public static Campaign Factions { get; } = new()
|
||||
{
|
||||
Id = 2,
|
||||
Name = "Factions",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Guild_Wars_Factions",
|
||||
Continents = new List<Continent>
|
||||
{
|
||||
Continent.Cantha
|
||||
}
|
||||
};
|
||||
|
||||
public static Campaign Nightfall { get; } = new()
|
||||
{
|
||||
Id = 3,
|
||||
Name = "Nightfall",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Guild_Wars_Nightfall",
|
||||
Continents = new List<Continent>
|
||||
{
|
||||
Continent.Elona,
|
||||
Continent.RealmOfTorment
|
||||
}
|
||||
};
|
||||
|
||||
public static Campaign EyeOfTheNorth { get; } = new()
|
||||
{
|
||||
Id = 4,
|
||||
Name = "Eye of the North",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Guild_Wars_Eye_of_the_North",
|
||||
Continents = new List<Continent>
|
||||
{
|
||||
Continent.Tyria
|
||||
}
|
||||
};
|
||||
|
||||
public static Campaign BonusMissionPack { get; } = new()
|
||||
{
|
||||
Id = 5,
|
||||
Name = "Bonus Mission Pack",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Guild_Wars_Bonus_Mission_Pack",
|
||||
Continents = new List<Continent>
|
||||
{
|
||||
Continent.Tyria,
|
||||
Continent.Elona,
|
||||
Continent.Cantha
|
||||
}
|
||||
};
|
||||
|
||||
public static IReadOnlyList<Campaign> Campaigns { get; } = new List<Campaign>
|
||||
{
|
||||
Core,
|
||||
Prophecies,
|
||||
Factions,
|
||||
Nightfall,
|
||||
EyeOfTheNorth,
|
||||
BonusMissionPack
|
||||
};
|
||||
|
||||
public static bool TryParse(int id, out Campaign campaign)
|
||||
{
|
||||
campaign = Campaigns.Where(campaign => campaign.Id == id).FirstOrDefault()!;
|
||||
if (campaign is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
public static bool TryParse(string name, out Campaign campaign)
|
||||
{
|
||||
campaign = Campaigns.Where(region => region.Name == name).FirstOrDefault()!;
|
||||
if (campaign is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
public static Campaign Parse(int id)
|
||||
{
|
||||
if (TryParse(id, out var campaign) is false)
|
||||
{
|
||||
throw new InvalidOperationException($"Could not find a campaign with id {id}");
|
||||
}
|
||||
|
||||
return campaign;
|
||||
}
|
||||
public static Campaign Parse(string name)
|
||||
{
|
||||
if (TryParse(name, out var region) is false)
|
||||
{
|
||||
throw new InvalidOperationException($"Could not find a campaign with name {name}");
|
||||
}
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
private Campaign()
|
||||
{
|
||||
}
|
||||
|
||||
public int Id { get; init; }
|
||||
public string? Name { get; init; }
|
||||
public string? WikiUrl { get; init; }
|
||||
public IReadOnlyList<Continent>? Continents { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
using Daybreak.Shared.Converters;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
[JsonConverter(typeof(ContinentJsonConverter))]
|
||||
public sealed class Continent
|
||||
{
|
||||
public static Continent Tyria { get; } = new Continent
|
||||
{
|
||||
Id = 0,
|
||||
Name = "Tyria",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Tyria",
|
||||
Regions = new List<Region>
|
||||
{
|
||||
Region.Ascalon,
|
||||
Region.PresearingAscalon,
|
||||
Region.CrystalDesert,
|
||||
Region.Kryta,
|
||||
Region.MaguumaJungle,
|
||||
Region.RingOfFireIslands,
|
||||
Region.ShiverpeakMountains,
|
||||
Region.CharrHomelands,
|
||||
Region.DepthsOfTyria,
|
||||
Region.FarShiverpeaks,
|
||||
Region.TarnishedCoast,
|
||||
Region.TheFlightNorth,
|
||||
Region.TheRiseOfTheWhiteMantle
|
||||
}
|
||||
};
|
||||
|
||||
public static Continent TheMists { get; } = new Continent
|
||||
{
|
||||
Id = 1,
|
||||
Name = "The Mists",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/The_Mists",
|
||||
Regions = new List<Region>
|
||||
{
|
||||
Region.HeroesAscent
|
||||
}
|
||||
};
|
||||
|
||||
public static Continent Cantha { get; } = new Continent
|
||||
{
|
||||
Id = 2,
|
||||
Name = "Cantha",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Cantha",
|
||||
Regions = new List<Region>
|
||||
{
|
||||
Region.ShingJeaIsland,
|
||||
Region.KainengCity,
|
||||
Region.EchovaldForest,
|
||||
Region.TheJadeSea,
|
||||
Region.TheTenguAccords
|
||||
}
|
||||
};
|
||||
|
||||
public static Continent TheBattleIsles { get; } = new Continent
|
||||
{
|
||||
Id = 3,
|
||||
Name = "The Battle Isles",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/The_Battle_Isles",
|
||||
Regions = new List<Region>
|
||||
{
|
||||
Region.TheBattleIsles,
|
||||
}
|
||||
};
|
||||
|
||||
public static Continent Elona { get; } = new Continent
|
||||
{
|
||||
Id = 4,
|
||||
Name = "Elona",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Elona",
|
||||
Regions = new List<Region>
|
||||
{
|
||||
Region.Istan,
|
||||
Region.Kourna,
|
||||
Region.Vabbi,
|
||||
Region.TheDesolation,
|
||||
Region.TheBattleOfJahai
|
||||
}
|
||||
};
|
||||
|
||||
public static Continent RealmOfTorment { get; } = new Continent
|
||||
{
|
||||
Id = 5,
|
||||
Name = "Realm of Torment",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Realm_of_Torment",
|
||||
Regions = new List<Region>
|
||||
{
|
||||
Region.RealmOfTorment
|
||||
}
|
||||
};
|
||||
|
||||
public static IReadOnlyList<Continent> Continents { get; } = new List<Continent>
|
||||
{
|
||||
Tyria,
|
||||
TheMists,
|
||||
Cantha,
|
||||
TheBattleIsles,
|
||||
Elona,
|
||||
RealmOfTorment
|
||||
};
|
||||
|
||||
public static bool TryParse(int id, out Continent continent)
|
||||
{
|
||||
continent = Continents.Where(continent => continent.Id == id).FirstOrDefault()!;
|
||||
if (continent is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
public static bool TryParse(string name, out Continent continent)
|
||||
{
|
||||
continent = Continents.Where(continent => continent.Name == name).FirstOrDefault()!;
|
||||
if (continent is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
public static Continent Parse(int id)
|
||||
{
|
||||
if (TryParse(id, out var continent) is false)
|
||||
{
|
||||
throw new InvalidOperationException($"Could not find a continent with id {id}");
|
||||
}
|
||||
|
||||
return continent;
|
||||
}
|
||||
public static Continent Parse(string name)
|
||||
{
|
||||
if (TryParse(name, out var continent) is false)
|
||||
{
|
||||
throw new InvalidOperationException($"Could not find a continent with name {name}");
|
||||
}
|
||||
|
||||
return continent;
|
||||
}
|
||||
|
||||
private Continent()
|
||||
{
|
||||
}
|
||||
|
||||
public int Id { get; init; }
|
||||
public string? Name { get; init; }
|
||||
public string? WikiUrl { get; init; }
|
||||
public IReadOnlyList<Region>? Regions { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
/// <summary>
|
||||
/// Seasonal holidays and in-game events, as retrieved from https://www.guildwars.com/en/events.
|
||||
/// All events begin and end at 12pm UTC-7
|
||||
/// </summary>
|
||||
public sealed class Event
|
||||
{
|
||||
public static readonly Event WintersdayJanuary = new()
|
||||
{
|
||||
Title = "Wintersday",
|
||||
Description = "See towns glimmering with festive décor, deliver presents to needy little urchins, defeat the scheming Grentches, and spread Wintersday cheer to your fellow Tyrians! The fun culminates with a grand finale that runs every three hours on January 1!",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Wintersday",
|
||||
From = new DateOnly(1, 1, 1),
|
||||
To = new DateOnly(1, 1, 2)
|
||||
};
|
||||
|
||||
public static readonly Event CanthanNewYear = new()
|
||||
{
|
||||
Title = "Canthan New Year",
|
||||
Description = "Join the people of Cantha as they prepare a heavenly feast to honor the Celestial Animal of the coming year! This annual week-long celebration features Canthan cuisine, festive fireworks, special prizes, and the famed Shing Jea Boardwalk!",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Canthan_New_Year",
|
||||
From = new DateOnly(1, 1, 31),
|
||||
To = new DateOnly(1, 2, 7)
|
||||
};
|
||||
|
||||
public static readonly Event LuckyTreatsWeek = new()
|
||||
{
|
||||
Title = "Lucky Treats Week",
|
||||
Description = "Shamrock Ale and Four-Leaf Clovers will be dropping throughout Tyria! Go fast, adventurers, and gather all the green you can before this special week ends!",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Lucky_Treats_Week",
|
||||
From = new DateOnly(1, 3, 14),
|
||||
To = new DateOnly(1, 3, 21)
|
||||
};
|
||||
|
||||
public static readonly Event SweetTreatsWeek = new()
|
||||
{
|
||||
Title = "Sweet Treats Week",
|
||||
Description = "Sweet Treats Week is upon us, which means it’s time to load up on springtime goodies. Chocolate Bunnies and Golden Eggs will be randomly mixed in with regular drops all across Tyria. Get hopping!",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Sweet_Treats_Week",
|
||||
From = new DateOnly(1, 4, 10),
|
||||
To = new DateOnly(1, 4, 17)
|
||||
};
|
||||
|
||||
public static readonly Event AnniversaryCelebration = new()
|
||||
{
|
||||
Title = "Guild Wars Anniversary Celebration",
|
||||
Description = "Guild Wars is another year older and the party just won't stop! Strap on your party hats, unpack your fireworks, and get ready to celebrate!",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Anniversary_Celebration",
|
||||
From = new DateOnly(1, 4, 22),
|
||||
To = new DateOnly(1, 5, 6)
|
||||
};
|
||||
|
||||
public static readonly Event DragonFestival = new()
|
||||
{
|
||||
Title = "Dragon Festival",
|
||||
Description = "The Dragon Festival is almost upon us and Cantha is ready to roll out the red carpet. Time to stock up on bottle rockets, gorge on red bean cakes, and collect enough victory tokens for your pick of festival hats.",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Dragon_Festival",
|
||||
From = new DateOnly(1, 6, 27),
|
||||
To = new DateOnly(1, 7, 4)
|
||||
};
|
||||
|
||||
public static readonly Event WintersdayInJuly = new()
|
||||
{
|
||||
Title = "Wintersday In July",
|
||||
Description = "Just can't wait ‘til Wintersday? Jump into a mini version of Tyria’s famed winter celebration! Stock up on seasonal treats or target your friends in the Snowball Arena during this week-long celebration.",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Wintersday_in_July",
|
||||
From = new DateOnly(1, 7, 24),
|
||||
To = new DateOnly(1, 7, 31)
|
||||
};
|
||||
|
||||
public static readonly Event WayfarersReverie = new()
|
||||
{
|
||||
Title = "Wayfarer's Reverie",
|
||||
Description = "The spirit of adventure beckons to you! It’s time to seek out the festival coordinator on each continent and start a quest to prove your adventuring prowess. Collect enough evidence of your travels and receive a special gift!",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Wayfarer%27s_Reverie",
|
||||
From = new DateOnly(1, 8, 25),
|
||||
To = new DateOnly(1, 9, 1)
|
||||
};
|
||||
|
||||
public static readonly Event PirateWeek = new()
|
||||
{
|
||||
Title = "Pirate Week",
|
||||
Description = "Avast! This seafaring celebration will have NPCs in Lion’s Arch and Kamadan talking like salty sea dogs. Join in the fun or walk the plank. Yarr!",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Pirate_Week",
|
||||
From = new DateOnly(1, 9, 13),
|
||||
To = new DateOnly(1, 9, 20)
|
||||
};
|
||||
|
||||
public static readonly Event BreastCancerAwarenessMonth = new()
|
||||
{
|
||||
Title = "Breast Cancer Awareness Month",
|
||||
Description = "Sadie Salvitas arrives in Lion’s Arch on October 1 and will be selling vials of pink dye throughout the month in support of Breast Cancer Awareness.",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Login_screen_announcements/Archive#Breast_Cancer_Awareness_Month",
|
||||
From = new DateOnly(1, 10, 1),
|
||||
To = new DateOnly(1, 11, 2)
|
||||
};
|
||||
|
||||
public static readonly Event Halloween = new()
|
||||
{
|
||||
Title = "Halloween",
|
||||
Description = "Get ready for two whole weeks of mischief and mayhem in Tyria, courtesy of Mad King Thorn and his Lunatic Court. The madness escalates to the final event on October 31, when the Mad King himself appears every three hours—join if you dare!",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Halloween",
|
||||
From = new DateOnly(1, 10, 18),
|
||||
To = new DateOnly(1, 11, 2)
|
||||
};
|
||||
|
||||
public static readonly Event SpecialTreatsWeek = new()
|
||||
{
|
||||
Title = "Special Treats Week",
|
||||
Description = "It's time for special, seasonal delights such as Slices of Pumpkin Pie and Hard Apple Cider to begin to drop all over Tyria. Gather what you can, but don't stuff yourself; Wintersday is just around the corner!",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Special_Treats_Week",
|
||||
From = new DateOnly(1, 11, 21),
|
||||
To = new DateOnly(1, 11, 28)
|
||||
};
|
||||
|
||||
public static readonly Event WintersdayDecember = new()
|
||||
{
|
||||
Title = "Wintersday",
|
||||
Description = "See towns glimmering with festive décor, deliver presents to needy little urchins, defeat the scheming Grentches, and spread Wintersday cheer to your fellow Tyrians! The fun culminates with a grand finale that runs every three hours on January 1!",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/Wintersday",
|
||||
From = new DateOnly(1, 12, 19),
|
||||
To = new DateOnly(1, 12, 31)
|
||||
};
|
||||
|
||||
public static readonly Event AprilFoolsDay = new()
|
||||
{
|
||||
Title = "April Fools' Day",
|
||||
Description = "*CLASSIFIED INFORMATION*\r\nTGlzdGVuLC Bhbm Qgd W5kZXJz dG FuZC4g VG hhd CBBbm5 paG lsYXRv c iBnb 2xlbSBp cyBvdXQ gd Ghlcm UuIEl0 IGN hb id0IG JlIGJ h cmdh aW5lZ CB3 aX RoL iBJdCBj YW4n d CBiZ SByZWF zb25lZ C B3aX RoLi BJd C Bkb2 Vzbid0I GZlZWwgcGl 0eS wgb3 I gcmVtb3Jz ZSwg b3I gZmV hci4g QW5 kIGl 0IGFi c2 9s dXRl bHk gd2lsbC Bub 3Qgc 3RvcC wgZX Zlc iwg dW50aW w gU2Fy YWggY W5kIE d3Z W4 gYXJ lIGRl YWQu",
|
||||
WikiUrl = "https://wiki.guildwars.com/wiki/April_Fools%27_Day",
|
||||
From = new DateOnly(1, 4, 1),
|
||||
To = new DateOnly(1, 4, 2)
|
||||
};
|
||||
|
||||
public static readonly IEnumerable<Event> Events =
|
||||
[
|
||||
WintersdayJanuary,
|
||||
CanthanNewYear,
|
||||
LuckyTreatsWeek,
|
||||
AprilFoolsDay,
|
||||
SweetTreatsWeek,
|
||||
AnniversaryCelebration,
|
||||
DragonFestival,
|
||||
WintersdayInJuly,
|
||||
WayfarersReverie,
|
||||
PirateWeek,
|
||||
BreastCancerAwarenessMonth,
|
||||
Halloween,
|
||||
SpecialTreatsWeek,
|
||||
WintersdayDecember
|
||||
];
|
||||
|
||||
public string? Title { get; set; }
|
||||
|
||||
public string? Description { get; set; }
|
||||
|
||||
public string? WikiUrl { get; set; }
|
||||
|
||||
public DateOnly From { get; set; }
|
||||
|
||||
public DateOnly To { get; set; }
|
||||
|
||||
private Event()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
public sealed class Hero : IWikiEntity
|
||||
{
|
||||
public static readonly Hero None = new() { Id = 0, Profession = Profession.None };
|
||||
public static readonly Hero Norgu = new() { Id = 1, Name = "Norgu", WikiUrl = "https://wiki.guildwars.com/wiki/Norgu", Profession = Profession.Mesmer };
|
||||
public static readonly Hero Goren = new() { Id = 2, Name = "Goren", WikiUrl = "https://wiki.guildwars.com/wiki/Goren", Profession = Profession.Warrior };
|
||||
public static readonly Hero Tahlkora = new() { Id = 3, Name = "Tahlkora", WikiUrl = "https://wiki.guildwars.com/wiki/Tahlkora", Profession = Profession.Monk };
|
||||
public static readonly Hero MasterOfWhispers = new() { Id = 4, Name = "Master of Whispers", WikiUrl = "https://wiki.guildwars.com/wiki/Master_of_Whispers", Profession = Profession.Necromancer };
|
||||
public static readonly Hero AcolyteJin = new() { Id = 5, Name = "Acolyte Jin", WikiUrl = "https://wiki.guildwars.com/wiki/Acolyte_Jin", Profession = Profession.Ranger };
|
||||
public static readonly Hero Koss = new() { Id = 6, Name = "Koss", WikiUrl = "https://wiki.guildwars.com/wiki/Koss", Profession = Profession.Warrior };
|
||||
public static readonly Hero Dunkoro = new() { Id = 7, Name = "Dunkoro", WikiUrl = "https://wiki.guildwars.com/wiki/Dunkoro", Profession = Profession.Monk };
|
||||
public static readonly Hero AcolyteSousuke = new() { Id = 8, Name = "Acolyte Sousuke", WikiUrl = "https://wiki.guildwars.com/wiki/Acolyte_Sousuke", Profession = Profession.Elementalist };
|
||||
public static readonly Hero Melonni = new() { Id = 9, Name = "Melonni", WikiUrl = "https://wiki.guildwars.com/wiki/Melonni", Profession = Profession.Dervish };
|
||||
public static readonly Hero ZhedShadowhoof = new() { Id = 10, Name = "Zhed Shadowhoof", WikiUrl = "https://wiki.guildwars.com/wiki/Zhed_Shadowhoof", Profession = Profession.Elementalist };
|
||||
public static readonly Hero GeneralMorgahn = new() { Id = 11, Name = "General Morgahn", WikiUrl = "https://wiki.guildwars.com/wiki/General_Morgahn", Profession = Profession.Paragon };
|
||||
public static readonly Hero MagridTheSly = new() { Id = 12, Name = "Magrid the Sly", WikiUrl = "https://wiki.guildwars.com/wiki/Magrid_the_Sly", Profession = Profession.Ranger };
|
||||
public static readonly Hero Zenmai = new() { Id = 13, Name = "Zenmai", WikiUrl = "https://wiki.guildwars.com/wiki/Zenmai", Profession = Profession.Assassin };
|
||||
public static readonly Hero Olias = new() { Id = 14, Name = "Olias", WikiUrl = "https://wiki.guildwars.com/wiki/Olias", Profession = Profession.Necromancer };
|
||||
public static readonly Hero Razah = new() { Id = 15, Name = "Razah", WikiUrl = "https://wiki.guildwars.com/wiki/Razah", Profession = Profession.None };
|
||||
public static readonly Hero MOX = new() { Id = 16, Name = "M.O.X.", WikiUrl = "https://wiki.guildwars.com/wiki/M.O.X.", Profession = Profession.Dervish };
|
||||
public static readonly Hero KeiranThackeray = new() { Id = 17, Name = "Keiran Thackeray", WikiUrl = "https://wiki.guildwars.com/wiki/Keiran_Thackeray", Profession = Profession.Paragon };
|
||||
public static readonly Hero Jora = new() { Id = 18, Name = "Jora", WikiUrl = "https://wiki.guildwars.com/wiki/Jora", Profession = Profession.Warrior };
|
||||
public static readonly Hero PyreFierceshot = new() { Id = 19, Name = "Pyre Fierceshot", WikiUrl = "https://wiki.guildwars.com/wiki/Pyre_Fierceshot", Profession = Profession.Ranger };
|
||||
public static readonly Hero Anton = new() { Id = 20, Name = "Anton", WikiUrl = "https://wiki.guildwars.com/wiki/Anton", Profession = Profession.Assassin };
|
||||
public static readonly Hero Livia = new() { Id = 21, Name = "Livia", WikiUrl = "https://wiki.guildwars.com/wiki/Livia", Profession = Profession.Necromancer };
|
||||
public static readonly Hero Hayda = new() { Id = 22, Name = "Hayda", WikiUrl = "https://wiki.guildwars.com/wiki/Hayda", Profession = Profession.Paragon };
|
||||
public static readonly Hero Kahmu = new() { Id = 23, Name = "Kahmu", WikiUrl = "https://wiki.guildwars.com/wiki/Kahmu", Profession = Profession.Dervish };
|
||||
public static readonly Hero Gwen = new() { Id = 24, Name = "Gwen", WikiUrl = "https://wiki.guildwars.com/wiki/Gwen", Profession = Profession.Mesmer };
|
||||
public static readonly Hero Xandra = new() { Id = 25, Name = "Xandra", WikiUrl = "https://wiki.guildwars.com/wiki/Xandra", Profession = Profession.Ritualist };
|
||||
public static readonly Hero Vekk = new() { Id = 26, Name = "Vekk", WikiUrl = "https://wiki.guildwars.com/wiki/Vekk", Profession = Profession.Elementalist };
|
||||
public static readonly Hero OgdenStonehealer = new() { Id = 27, Name = "Ogden Stonehealer", WikiUrl = "https://wiki.guildwars.com/wiki/Ogden_Stonehealer", Profession = Profession.Monk };
|
||||
public static readonly Hero Merc1 = new() { Id = 28, Name = "Mercenary Hero 1", Profession = Profession.None };
|
||||
public static readonly Hero Merc2 = new() { Id = 29, Name = "Mercenary Hero 2", Profession = Profession.None };
|
||||
public static readonly Hero Merc3 = new() { Id = 30, Name = "Mercenary Hero 3", Profession = Profession.None };
|
||||
public static readonly Hero Merc4 = new() { Id = 31, Name = "Mercenary Hero 4", Profession = Profession.None };
|
||||
public static readonly Hero Merc5 = new() { Id = 32, Name = "Mercenary Hero 5", Profession = Profession.None };
|
||||
public static readonly Hero Merc6 = new() { Id = 33, Name = "Mercenary Hero 6", Profession = Profession.None };
|
||||
public static readonly Hero Merc7 = new() { Id = 34, Name = "Mercenary Hero 7", Profession = Profession.None };
|
||||
public static readonly Hero Merc8 = new() { Id = 35, Name = "Mercenary Hero 8", Profession = Profession.None };
|
||||
public static readonly Hero Miku = new() { Id = 36, Name = "Miku", WikiUrl = "https://wiki.guildwars.com/wiki/Miku", Profession = Profession.Assassin };
|
||||
public static readonly Hero ZeiRi = new() { Id = 37, Name = "Zei Ri", WikiUrl = "https://wiki.guildwars.com/wiki/Zei_Ri", Profession = Profession.Ritualist };
|
||||
|
||||
public static readonly List<Hero> Heroes = [
|
||||
None,
|
||||
Norgu,
|
||||
Goren,
|
||||
Tahlkora,
|
||||
MasterOfWhispers,
|
||||
AcolyteJin,
|
||||
Koss,
|
||||
Dunkoro,
|
||||
AcolyteSousuke,
|
||||
Melonni,
|
||||
ZhedShadowhoof,
|
||||
GeneralMorgahn,
|
||||
MagridTheSly,
|
||||
Zenmai,
|
||||
Olias,
|
||||
Razah,
|
||||
MOX,
|
||||
KeiranThackeray,
|
||||
Jora,
|
||||
PyreFierceshot,
|
||||
Anton,
|
||||
Livia,
|
||||
Hayda,
|
||||
Kahmu,
|
||||
Gwen,
|
||||
Xandra,
|
||||
Vekk,
|
||||
OgdenStonehealer,
|
||||
Merc1,
|
||||
Merc2,
|
||||
Merc3,
|
||||
Merc4,
|
||||
Merc5,
|
||||
Merc6,
|
||||
Merc7,
|
||||
Merc8,
|
||||
Miku,
|
||||
ZeiRi
|
||||
];
|
||||
|
||||
public static bool TryParse(int id, out Hero hero)
|
||||
{
|
||||
hero = Heroes.Where(n => n.Id == id).FirstOrDefault()!;
|
||||
if (hero is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
public static bool TryParse(string name, out Hero hero)
|
||||
{
|
||||
hero = Heroes.Where(n => n.Name == name).FirstOrDefault()!;
|
||||
if (hero is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
public static Hero Parse(int id)
|
||||
{
|
||||
if (TryParse(id, out var hero) is false)
|
||||
{
|
||||
throw new InvalidOperationException($"Could not find a hero with id {id}");
|
||||
}
|
||||
|
||||
return hero;
|
||||
}
|
||||
public static Hero Parse(string name)
|
||||
{
|
||||
if (TryParse(name, out var hero) is false)
|
||||
{
|
||||
throw new InvalidOperationException($"Could not find a hero with name {name}");
|
||||
}
|
||||
|
||||
return hero;
|
||||
}
|
||||
|
||||
private Hero()
|
||||
{
|
||||
}
|
||||
|
||||
public int Id { get; init; }
|
||||
public string? Name { get; init; }
|
||||
public string? WikiUrl { get; init; }
|
||||
public required Profession Profession { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
public interface IIconUrlEntity
|
||||
{
|
||||
public string? IconUrl { get; }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
public interface IItemModHash
|
||||
{
|
||||
public string? ModHash { get; }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
public interface IWikiEntity
|
||||
{
|
||||
public string? WikiUrl { get; }
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
public sealed class Inscription : ItemBase, IWikiEntity, IIconUrlEntity
|
||||
{
|
||||
public static readonly Inscription WeaponInscription = new() { Id = 15542, Name = "Weapon Inscription", WikiUrl = "https://wiki.guildwars.com/wiki/Inscription", IconUrl = "https://wiki.guildwars.com/images/2/22/Inscription_weapons.png" };
|
||||
|
||||
public static readonly Inscription FocusInscription = new() { Id = 19123, Name = "Focus Inscription", WikiUrl = "https://wiki.guildwars.com/wiki/Inscription", IconUrl = "https://wiki.guildwars.com/images/5/59/Inscription_focus_items.png" };
|
||||
|
||||
public static readonly Inscription FocusOrShieldInscription = new() { Id = 15541, Name = "Focus Items or Shields Inscription", WikiUrl = "https://wiki.guildwars.com/wiki/Inscription", IconUrl = "https://wiki.guildwars.com/images/6/61/Inscription_focus_items_or_shields.png" };
|
||||
|
||||
public static IReadOnlyList<Inscription> Inscriptions { get; } =
|
||||
[
|
||||
WeaponInscription,
|
||||
FocusInscription,
|
||||
FocusOrShieldInscription
|
||||
];
|
||||
|
||||
public string? WikiUrl { get; init; }
|
||||
|
||||
public string? IconUrl { get; init; }
|
||||
|
||||
private Inscription()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
public enum InstanceType
|
||||
{
|
||||
Undefined,
|
||||
Outpost,
|
||||
Explorable,
|
||||
Loading
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
using Daybreak.Shared.Converters;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
[JsonConverter(typeof(ItemBaseJsonConverter))]
|
||||
public abstract class ItemBase
|
||||
{
|
||||
public static IReadOnlyCollection<ItemBase> AllItems { get; } = Enumerable.Empty<ItemBase>()
|
||||
.Append(Unknown.Instance)
|
||||
.Concat(Material.All)
|
||||
.Concat(Inscription.Inscriptions)
|
||||
.Concat(Rune.Runes)
|
||||
.Concat(VialOfDye.Vials)
|
||||
.ToList();
|
||||
|
||||
public static bool TryParse<T>(int id, IEnumerable<ItemModifier>? modifiers, out T item)
|
||||
where T : ItemBase
|
||||
{
|
||||
item = default!;
|
||||
if (TryParse(id, modifiers, out var itemBase) is false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (itemBase is not T)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
item = (itemBase as T)!;
|
||||
return true;
|
||||
}
|
||||
public static bool TryParse<T>(string name, out T item)
|
||||
where T : ItemBase
|
||||
{
|
||||
item = default!;
|
||||
if (TryParse(name, out var itemBase) is false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (itemBase is not T)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
item = (itemBase as T)!;
|
||||
return true;
|
||||
}
|
||||
public static T Parse<T>(int id, IEnumerable<ItemModifier>? modifiers)
|
||||
where T : ItemBase
|
||||
{
|
||||
var itemBase = Parse(id, modifiers);
|
||||
if (itemBase is not T)
|
||||
{
|
||||
throw new InvalidOperationException($"Invalid type. Item type is [{itemBase.GetType().Name}] but requested type is [{typeof(T).Name}]");
|
||||
}
|
||||
|
||||
return (itemBase as T)!;
|
||||
}
|
||||
public static T Parse<T>(string name)
|
||||
where T : ItemBase
|
||||
{
|
||||
var itemBase = Parse(name);
|
||||
if (itemBase is not T)
|
||||
{
|
||||
throw new InvalidOperationException($"Invalid type. Item type is [{itemBase.GetType().Name}] but requested type is [{typeof(T).Name}]");
|
||||
}
|
||||
|
||||
return (itemBase as T)!;
|
||||
}
|
||||
|
||||
public static bool TryParse(int id, IEnumerable<ItemModifier>? modifiers, out ItemBase? item)
|
||||
{
|
||||
item = FilterAndFirstOrDefault(i =>
|
||||
{
|
||||
if (i.Id != id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (modifiers is not null &&
|
||||
i.Modifiers is not null)
|
||||
{
|
||||
return i.Modifiers.Count() == modifiers.Count() &&
|
||||
i.Modifiers.All(i1 => modifiers.Any(i2 => i1.Modifier == i2.Modifier));
|
||||
}
|
||||
else if (i.Modifiers is not null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
if (item is not null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
public static ItemBase Parse(int id, IEnumerable<ItemModifier>? modifiers)
|
||||
{
|
||||
if (TryParse(id, modifiers, out var item) is false)
|
||||
{
|
||||
throw new InvalidOperationException($"Could not find a item with id {id}");
|
||||
}
|
||||
|
||||
return item ?? throw new InvalidOperationException($"Could not parse item with id {id}");
|
||||
}
|
||||
|
||||
public static bool TryParse(string name, out ItemBase? item)
|
||||
{
|
||||
item = FilterAndFirstOrDefault(i => i.Name == name);
|
||||
if (item is not null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
public static ItemBase Parse(string name)
|
||||
{
|
||||
if (TryParse(name, out var item) is false)
|
||||
{
|
||||
throw new InvalidOperationException($"Could not find a item with name {name}");
|
||||
}
|
||||
|
||||
return item!;
|
||||
}
|
||||
|
||||
private static ItemBase? FilterAndFirstOrDefault(Func<ItemBase, bool> filter) => AllItems
|
||||
.Where(filter)
|
||||
.FirstOrDefault();
|
||||
|
||||
public int Id { get; init; }
|
||||
|
||||
public string? Name { get; init; }
|
||||
|
||||
public IEnumerable<ItemModifier>? Modifiers { get; init; }
|
||||
|
||||
public sealed class Unknown : ItemBase
|
||||
{
|
||||
public static readonly Unknown Instance = new() { Id = 0, Name = "Unknown" };
|
||||
|
||||
private Unknown()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
public readonly struct ItemModifier
|
||||
{
|
||||
public uint Modifier { get; init; }
|
||||
public uint Identifier => this.Modifier >> 16;
|
||||
public uint Argument1 => (this.Modifier & 0x0000FF00) >> 8;
|
||||
public uint Argument2 => this.Modifier & 0x000000FF;
|
||||
|
||||
public static implicit operator uint(ItemModifier modifier) => modifier.Modifier;
|
||||
public static implicit operator ItemModifier(uint modifier) => new(){ Modifier = modifier };
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Daybreak.Shared.Models.Guildwars;
|
||||
|
||||
public sealed class LoginData
|
||||
{
|
||||
public string Email { get; init; } = string.Empty;
|
||||
public string PlayerName { get; init; } = string.Empty;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user