mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2025-12-16 14:30:31 +00:00
Compare commits
762 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5df9e0af9 | ||
|
|
b7a6cc5158 | ||
|
|
55d49f87ff | ||
|
|
c2abbf0fc0 | ||
|
|
ba11952945 | ||
|
|
a7f2556b48 | ||
|
|
b66dd2c01b | ||
|
|
c6261af03c | ||
|
|
e44d1ac62e | ||
|
|
37afe1959a | ||
|
|
da04f6b100 | ||
|
|
168dc5cb35 | ||
|
|
9f4d5df8d2 | ||
|
|
0c21c223be | ||
|
|
1fc4ac8e07 | ||
|
|
088161e9ba | ||
|
|
246429f7a1 | ||
|
|
2478dd6c10 | ||
|
|
ee234001f1 | ||
|
|
9325959358 | ||
|
|
aed6784f55 | ||
|
|
b5f916dbac | ||
|
|
2555623064 | ||
|
|
83aa57a764 | ||
|
|
44ed1b1547 | ||
|
|
1b91674f9b | ||
|
|
cc363c2f51 | ||
|
|
0982943799 | ||
|
|
c79faf6c0e | ||
|
|
ea110d5da9 | ||
|
|
40dc70e8c7 | ||
|
|
5cc684f4b6 | ||
|
|
3f605d59d4 | ||
|
|
d79af97dfc | ||
|
|
a701e14a62 | ||
|
|
8e30183d7c | ||
|
|
7d21795c2f | ||
|
|
26765f31f7 | ||
|
|
708c523b57 | ||
|
|
d05c6b996c | ||
|
|
f2f83b0a60 | ||
|
|
2c0e14fb55 | ||
|
|
dca2e6f060 | ||
|
|
440e43935a | ||
|
|
1dff9a48a8 | ||
|
|
85e90bb8d5 | ||
|
|
b62b2382fd | ||
|
|
07f64a0107 | ||
|
|
dcdb2cb175 | ||
|
|
33e7ae83dc | ||
|
|
ac0a1da140 | ||
|
|
1ad03ac61c | ||
|
|
b28736cb84 | ||
|
|
602c01e2d9 | ||
|
|
7b65c1aeb7 | ||
|
|
a27973800c | ||
|
|
cb4580c0d9 | ||
|
|
1a74d83eae | ||
|
|
319ee49c67 | ||
|
|
cefa3e1e1e | ||
|
|
061e61b740 | ||
|
|
73d756f211 | ||
|
|
3bb83610b8 | ||
|
|
8e85b87764 | ||
|
|
4d0f5a56ed | ||
|
|
a8359e3e00 | ||
|
|
3812331901 | ||
|
|
1714bd26f9 | ||
|
|
d8ad42f760 | ||
|
|
c477bd2bae | ||
|
|
aa1cd98646 | ||
|
|
5f545a9bbc | ||
|
|
0d3bc2cf47 | ||
|
|
8e65142d4c | ||
|
|
c26a758825 | ||
|
|
a02d8cee86 | ||
|
|
2c4d2981cd | ||
|
|
6c5e0a20f1 | ||
|
|
db920da4b8 | ||
|
|
efdc3eb7bb | ||
|
|
c0da86e4ca | ||
|
|
720a24e9ad | ||
|
|
7dc6096e07 | ||
|
|
7910205674 | ||
|
|
1fbc51d02b | ||
|
|
a3d968c6af | ||
|
|
63c61f8e47 | ||
|
|
1ae59f4229 | ||
|
|
4a95a6928b | ||
|
|
54a092a822 | ||
|
|
9898d47db4 | ||
|
|
b46e55c57b | ||
|
|
cb6f9f3e00 | ||
|
|
d750ba5f99 | ||
|
|
c84db87532 | ||
|
|
3da662ef61 | ||
|
|
2f42c75df7 | ||
|
|
14388487fd | ||
|
|
a155748f88 | ||
|
|
c7fa69a25b | ||
|
|
5194cb103a | ||
|
|
77ec0d1c78 | ||
|
|
d85c9a3c0a | ||
|
|
97a8e6f5c2 | ||
|
|
3d73b42c15 | ||
|
|
4156dfcd4e | ||
|
|
9fb19bffc1 | ||
|
|
fe1cdce59d | ||
|
|
c07caf6be8 | ||
|
|
cab8c60fcb | ||
|
|
023c7da52b | ||
|
|
6b2bcbee6e | ||
|
|
ebac577ede | ||
|
|
0846291779 | ||
|
|
fab9d95096 | ||
|
|
2dc853ebfc | ||
|
|
5867a351a8 | ||
|
|
5605e9a666 | ||
|
|
337b720d31 | ||
|
|
06185d5f7d | ||
|
|
90cfdd140b | ||
|
|
5a41d559a3 | ||
|
|
b6805a94a3 | ||
|
|
6a678cd5a9 | ||
|
|
ecaf61252a | ||
|
|
85c4e4ac37 | ||
|
|
16394182b2 | ||
|
|
a0cc53cbb7 | ||
|
|
f331ee2c24 | ||
|
|
cb0767f28e | ||
|
|
91aaf3be19 | ||
|
|
9540e564fc | ||
|
|
2100d6287c | ||
|
|
8ad8183d4f | ||
|
|
90f2d93768 | ||
|
|
bae8dc330c | ||
|
|
599ca4d2c9 | ||
|
|
ff7a1e7c0e | ||
|
|
216cd51c4a | ||
|
|
568e9935ac | ||
|
|
28e9247c9a | ||
|
|
df3f16d424 | ||
|
|
41d03a15ac | ||
|
|
3f0e67075f | ||
|
|
67329ec668 | ||
|
|
f28d783272 | ||
|
|
2c9d015f38 | ||
|
|
5ad8a93d48 | ||
|
|
ac9c1504e9 | ||
|
|
4cde913453 | ||
|
|
f05d041e6d | ||
|
|
ce4b41ee73 | ||
|
|
0c3c4c08ea | ||
|
|
67d9486495 | ||
|
|
bd00911f85 | ||
|
|
4cb3123ff6 | ||
|
|
4ff1411c38 | ||
|
|
f983a2eab2 | ||
|
|
fd7c86c2da | ||
|
|
d90aa1798b | ||
|
|
afa602f940 | ||
|
|
773698a0d4 | ||
|
|
08907e8953 | ||
|
|
332e9a53d7 | ||
|
|
7a8e2091a6 | ||
|
|
3ed05b8e26 | ||
|
|
d3dbfc5e9e | ||
|
|
30c84efb57 | ||
|
|
3ba8602156 | ||
|
|
9d2aacab58 | ||
|
|
c7b9751e0e | ||
|
|
9cfbc35ac4 | ||
|
|
ba618dc2b6 | ||
|
|
f3c870b8c7 | ||
|
|
46ec3e51b0 | ||
|
|
4ca93c3c45 | ||
|
|
7ab499e2c0 | ||
|
|
102f3de120 | ||
|
|
01fd6f3ad6 | ||
|
|
cca465d30d | ||
|
|
dc7f2acc50 | ||
|
|
79a15ad781 | ||
|
|
4e6905d562 | ||
|
|
03a5853a91 | ||
|
|
f3fae74bde | ||
|
|
8bbff388d2 | ||
|
|
40d5fe75e7 | ||
|
|
cdbabc0a0b | ||
|
|
97ecfc03c8 | ||
|
|
70d35bfeb8 | ||
|
|
a11866c544 | ||
|
|
5aaf5476e0 | ||
|
|
7e78922056 | ||
|
|
e7dad02c63 | ||
|
|
da5fb391a4 | ||
|
|
3b48b79997 | ||
|
|
30e887a85b | ||
|
|
c737c792f6 | ||
|
|
64f4853b13 | ||
|
|
0c890e590c | ||
|
|
b664b85495 | ||
|
|
3894a6a2d1 | ||
|
|
ae8224b734 | ||
|
|
bd5739d7a0 | ||
|
|
3a8a8efbd1 | ||
|
|
4fc1f4c60e | ||
|
|
079bbc8e78 | ||
|
|
70bfbd7d8e | ||
|
|
f0c7222055 | ||
|
|
7b1b3d4d8e | ||
|
|
7d6b4b7a23 | ||
|
|
a4d0b7d1cb | ||
|
|
62e786b9b8 | ||
|
|
38ae309285 | ||
|
|
f87b63d6ee | ||
|
|
3b3f1caf84 | ||
|
|
724be4c1cf | ||
|
|
b4ab287994 | ||
|
|
19d17940c0 | ||
|
|
aa46079ed4 | ||
|
|
5e81e3a6a6 | ||
|
|
e2f2b6aa5d | ||
|
|
a7c67b04ca | ||
|
|
465207034d | ||
|
|
93b9cf4b76 | ||
|
|
dc57860f0d | ||
|
|
f71b0bc945 | ||
|
|
1c9132627b | ||
|
|
b14d5de641 | ||
|
|
530743cf97 | ||
|
|
d1ab859621 | ||
|
|
fe76ada8d0 | ||
|
|
e096f4f081 | ||
|
|
0d8f7b854d | ||
|
|
b9beb6ec16 | ||
|
|
7afcf82c32 | ||
|
|
b27dd345af | ||
|
|
9fdf8c6a75 | ||
|
|
1010f270a0 | ||
|
|
0db051a251 | ||
|
|
890a431e24 | ||
|
|
173e0ea157 | ||
|
|
4c99ce4ab2 | ||
|
|
6f98228c41 | ||
|
|
95d15aa107 | ||
|
|
2f09e74f1a | ||
|
|
f30fcb3941 | ||
|
|
06254a9afc | ||
|
|
fd95c6cac7 | ||
|
|
2196bccda5 | ||
|
|
b0ac2b4147 | ||
|
|
5322321944 | ||
|
|
2f951e0ef6 | ||
|
|
1e6dcc88d2 | ||
|
|
8bbcfc40dc | ||
|
|
811ea46523 | ||
|
|
c37e54cf9b | ||
|
|
4c095e8eb5 | ||
|
|
c580ec7b92 | ||
|
|
0c45d3c5ba | ||
|
|
2bc8a4cefd | ||
|
|
92d28adb07 | ||
|
|
cc2b1dbbaa | ||
|
|
bd98cadab3 | ||
|
|
c417f88e3b | ||
|
|
b26a9af49b | ||
|
|
e4b00b35f2 | ||
|
|
11bab46b8b | ||
|
|
7eb24d7bd6 | ||
|
|
9a26366ff8 | ||
|
|
0058bc6fa5 | ||
|
|
ca3f3e0cab | ||
|
|
cf51ca454d | ||
|
|
35c3c2a2b3 | ||
|
|
12bb61c23d | ||
|
|
2e5a2a1393 | ||
|
|
4259bb088e | ||
|
|
0768765f21 | ||
|
|
dc7ee7fadc | ||
|
|
7665a1c339 | ||
|
|
6015cd5cb7 | ||
|
|
08aa8f2136 | ||
|
|
c27e447f57 | ||
|
|
9f1a3a0304 | ||
|
|
7714478fdc | ||
|
|
91bca33a54 | ||
|
|
c67b967817 | ||
|
|
150ed2c733 | ||
|
|
1c23e4b5b3 | ||
|
|
77c4dee6a8 | ||
|
|
d6fe8eec38 | ||
|
|
c12d83bbf0 | ||
|
|
0e6b75aa5c | ||
|
|
dd1dfdcf34 | ||
|
|
792d8dab34 | ||
|
|
4f23434f81 | ||
|
|
7797c4e0b0 | ||
|
|
6463a2be2d | ||
|
|
972a46ac2e | ||
|
|
db3091b21b | ||
|
|
476733ca19 | ||
|
|
d0c302c1f1 | ||
|
|
164deb1096 | ||
|
|
b39ea679e7 | ||
|
|
062a5f470c | ||
|
|
48fb388da2 | ||
|
|
a23cdc9605 | ||
|
|
1c7eb0f5a1 | ||
|
|
58050c9ec3 | ||
|
|
5908cc40a8 | ||
|
|
bffb5e53bf | ||
|
|
4a0b79f1a1 | ||
|
|
3ddb77e9f8 | ||
|
|
16f7bccb11 | ||
|
|
ecec5cdde2 | ||
|
|
cf4fca9836 | ||
|
|
e5d61b2796 | ||
|
|
fc493ea510 | ||
|
|
7983dc01f1 | ||
|
|
09f914cecd | ||
|
|
9968b0ac36 | ||
|
|
969a5f711c | ||
|
|
ccb4601c85 | ||
|
|
25aabe7553 | ||
|
|
13755d4d06 | ||
|
|
1d6e87d103 | ||
|
|
8673ef8420 | ||
|
|
ab1fb70f4c | ||
|
|
31fe6923ff | ||
|
|
0b07b7c4a7 | ||
|
|
0abe05b7bd | ||
|
|
45ff19f9ae | ||
|
|
d25883ff1b | ||
|
|
d2f43e4e50 | ||
|
|
792167a71c | ||
|
|
f2586d7cb0 | ||
|
|
c37846b4cd | ||
|
|
17c4ec6790 | ||
|
|
7023040882 | ||
|
|
8c38de1b26 | ||
|
|
1917c9da95 | ||
|
|
668bf5009b | ||
|
|
e9ca1e3537 | ||
|
|
ebdb412adf | ||
|
|
e73c72d148 | ||
|
|
d1d843c583 | ||
|
|
464e375529 | ||
|
|
2b12f8a294 | ||
|
|
b305e98519 | ||
|
|
5431e49c2a | ||
|
|
6098cdc31d | ||
|
|
308d7c2c1c | ||
|
|
454f40ffb9 | ||
|
|
dd3b3dec33 | ||
|
|
bc2831c066 | ||
|
|
905d2acdbd | ||
|
|
54c2b6b6d5 | ||
|
|
b6a4ccac7f | ||
|
|
3fce1cc934 | ||
|
|
375a888a37 | ||
|
|
0d62034f32 | ||
|
|
f7d722aaf0 | ||
|
|
56759bc710 | ||
|
|
d27b5c28ef | ||
|
|
a0d1cada54 | ||
|
|
ca7e1da585 | ||
|
|
5f097c4002 | ||
|
|
203dc6daf6 | ||
|
|
e895850f17 | ||
|
|
f776e7947c | ||
|
|
416ec920cb | ||
|
|
b5da72eb40 | ||
|
|
3dde77608e | ||
|
|
a0407553ec | ||
|
|
8d594fe0b6 | ||
|
|
e68e87d388 | ||
|
|
4cabd42c0b | ||
|
|
df33f7d0fc | ||
|
|
d6b5e3981c | ||
|
|
6aa0300c85 | ||
|
|
264ca84513 | ||
|
|
816306872d | ||
|
|
13aced705a | ||
|
|
95d0f879ca | ||
|
|
f37d2297bb | ||
|
|
0d90a53b8e | ||
|
|
f91dfe7efa | ||
|
|
ec757e3ef8 | ||
|
|
3b2ca10b05 | ||
|
|
b438e38268 | ||
|
|
bb405f2824 | ||
|
|
1d640fbec0 | ||
|
|
ecc820333e | ||
|
|
9cc227aa61 | ||
|
|
93420eebc0 | ||
|
|
6014b3bdc6 | ||
|
|
81789c717f | ||
|
|
dfa6330821 | ||
|
|
1d5d9c12a7 | ||
|
|
2cbbbe7359 | ||
|
|
4706cedbf9 | ||
|
|
a11b955a9d | ||
|
|
e1366f6267 | ||
|
|
6bff839821 | ||
|
|
0b37acf16e | ||
|
|
70c39eef0a | ||
|
|
1988b18053 | ||
|
|
67f87396e8 | ||
|
|
3734721c58 | ||
|
|
0f6a3f2ec8 | ||
|
|
ab9ca4b9c3 | ||
|
|
c05cffbd88 | ||
|
|
0e3f3d1143 | ||
|
|
ff02a4a8d4 | ||
|
|
c8c35b5bf7 | ||
|
|
18daa6a8c7 | ||
|
|
c95b58852c | ||
|
|
80ccceb9b0 | ||
|
|
eaa308d3ce | ||
|
|
d05ac7e10d | ||
|
|
a80aef16a0 | ||
|
|
338560fedb | ||
|
|
632830278f | ||
|
|
8b614bd3c4 | ||
|
|
657354c2e8 | ||
|
|
7a0d9f2325 | ||
|
|
ae45c0c7ae | ||
|
|
c3b0e31a0a | ||
|
|
f7207c1326 | ||
|
|
9a9817c6b3 | ||
|
|
1b4ac9da8b | ||
|
|
d98310fc0e | ||
|
|
3240fca63e | ||
|
|
f1631b7f06 | ||
|
|
30e5c5f91b | ||
|
|
257026144d | ||
|
|
9f786dce97 | ||
|
|
c2f582164c | ||
|
|
464ed3b614 | ||
|
|
5bb9494ecc | ||
|
|
0fb583a094 | ||
|
|
358b1a7dbe | ||
|
|
bd91f439c8 | ||
|
|
4181ada887 | ||
|
|
32d116d106 | ||
|
|
30c27f9faf | ||
|
|
b332d576ab | ||
|
|
9def43cef0 | ||
|
|
0820b39a35 | ||
|
|
2a0be85d14 | ||
|
|
efb7262113 | ||
|
|
1a732bbb93 | ||
|
|
b8fe380b61 | ||
|
|
8670cea7a3 | ||
|
|
e2a5ec3616 | ||
|
|
d013366c9a | ||
|
|
e9093cda6d | ||
|
|
0f30a0ef3d | ||
|
|
b1a64e346c | ||
|
|
c524a89c5e | ||
|
|
e73d90e697 | ||
|
|
ee470d9ce9 | ||
|
|
aab5b3aaab | ||
|
|
86281b5fdb | ||
|
|
ddabf7db49 | ||
|
|
1c7523e98e | ||
|
|
120d084b12 | ||
|
|
1e69ec4634 | ||
|
|
31a680ce1c | ||
|
|
3bad19530e | ||
|
|
10986289e6 | ||
|
|
656c1b8d5d | ||
|
|
ef0037aa25 | ||
|
|
af02ccbd6f | ||
|
|
978f3f63bd | ||
|
|
e550cc0f43 | ||
|
|
5894226e93 | ||
|
|
d50fa8eeb7 | ||
|
|
6efd333684 | ||
|
|
05701b60c1 | ||
|
|
f8e7e55a00 | ||
|
|
20663f0226 | ||
|
|
ad175ba2ac | ||
|
|
bdf90a5e51 | ||
|
|
49618534ce | ||
|
|
f2bb2a6bee | ||
|
|
ba4f3aea7b | ||
|
|
b30068103b | ||
|
|
7062928c32 | ||
|
|
7f0764b7b1 | ||
|
|
8b21f4f869 | ||
|
|
8d634b9b1b | ||
|
|
698e567c63 | ||
|
|
6d697c3dda | ||
|
|
746e28c3a2 | ||
|
|
df0f087505 | ||
|
|
0ccec4c8c1 | ||
|
|
e18e1533e3 | ||
|
|
c077381e45 | ||
|
|
a0ecb78086 | ||
|
|
e47bd9faa4 | ||
|
|
e2bf6117dd | ||
|
|
14b0b332c5 | ||
|
|
76f74dabbe | ||
|
|
42dec2de39 | ||
|
|
b965971c79 | ||
|
|
3a7ab02f88 | ||
|
|
b931e935b5 | ||
|
|
521a1b7d34 | ||
|
|
fffcef2d30 | ||
|
|
cf1216a667 | ||
|
|
68ee647ed2 | ||
|
|
2eda952cd0 | ||
|
|
7fac4ac298 | ||
|
|
9016a5109d | ||
|
|
8e055fe587 | ||
|
|
3b2bb0590f | ||
|
|
134d3e2d0d | ||
|
|
b735f8e567 | ||
|
|
3992ea6656 | ||
|
|
03840990be | ||
|
|
27bafb1552 | ||
|
|
9b3ab17902 | ||
|
|
df0ede4ccc | ||
|
|
ecf6846255 | ||
|
|
173e22dde2 | ||
|
|
c5799c561a | ||
|
|
6736ca8fd4 | ||
|
|
8f3cacd32f | ||
|
|
d3cb3a1486 | ||
|
|
ae9dfca3b3 | ||
|
|
edc7c38ba0 | ||
|
|
54e76cf559 | ||
|
|
477cc8ba74 | ||
|
|
573d4c8151 | ||
|
|
5bdaec6980 | ||
|
|
400ff1ff6a | ||
|
|
1841cde776 | ||
|
|
990e696b37 | ||
|
|
d591c67276 | ||
|
|
423cd154a7 | ||
|
|
44dec3ab3f | ||
|
|
7fb7c9146b | ||
|
|
f060ba2094 | ||
|
|
457828260b | ||
|
|
4b080d4d0b | ||
|
|
5d83807357 | ||
|
|
2b794becff | ||
|
|
e69c5a0138 | ||
|
|
90a11c2ffc | ||
|
|
497da6487d | ||
|
|
8ffabf3db3 | ||
|
|
bf42605f88 | ||
|
|
7e12f17c48 | ||
|
|
9360a588ea | ||
|
|
e02e597102 | ||
|
|
a952a2e1e7 | ||
|
|
cb8668ffb8 | ||
|
|
79fb392a9a | ||
|
|
7b490ae26a | ||
|
|
69b05f932f | ||
|
|
e0d614fe2f | ||
|
|
5e81c3fdef | ||
|
|
4707b60ee4 | ||
|
|
158b1a87b3 | ||
|
|
a72f833c67 | ||
|
|
a9d0092bd2 | ||
|
|
154655c35c | ||
|
|
2a2f9c27a4 | ||
|
|
d50b8a7723 | ||
|
|
63421f7ed4 | ||
|
|
8ad24e2f9f | ||
|
|
941539ce23 | ||
|
|
74c4a80e3b | ||
|
|
6e30b31e9e | ||
|
|
b63161c73e | ||
|
|
9c362dced2 | ||
|
|
9a02c79e0a | ||
|
|
0ae4b6ff18 | ||
|
|
7b4166f28d | ||
|
|
bd87673db3 | ||
|
|
4cb3eabd4c | ||
|
|
d3957b5604 | ||
|
|
de072bc5dd | ||
|
|
7bb23efc2f | ||
|
|
88be284117 | ||
|
|
bc983e9f5d | ||
|
|
4c38de75ab | ||
|
|
b58469ce40 | ||
|
|
ab7f12058f | ||
|
|
0dda5a93c9 | ||
|
|
30092cc326 | ||
|
|
721380b153 | ||
|
|
09a0f21506 | ||
|
|
c9f2fdc847 | ||
|
|
e326cc94d0 | ||
|
|
66237dab24 | ||
|
|
53ec07a7f1 | ||
|
|
bbad80ae0e | ||
|
|
e6021a4f11 | ||
|
|
b3f792a2f3 | ||
|
|
7083a397b8 | ||
|
|
f98fd85fe9 | ||
|
|
f9f6e207d4 | ||
|
|
0c4e4e709f | ||
|
|
d7f9ad4916 | ||
|
|
b04f92ca3c | ||
|
|
16a0174cf1 | ||
|
|
c92d78e088 | ||
|
|
1f7b8d2416 | ||
|
|
7ca9b23aa3 | ||
|
|
f0acd8ddfd | ||
|
|
c5009dad31 | ||
|
|
9682d1d5ef | ||
|
|
a4e8fca784 | ||
|
|
8f25040bf5 | ||
|
|
34beec8d6b | ||
|
|
6c0fd638a5 | ||
|
|
0b94213af7 | ||
|
|
f874598fd8 | ||
|
|
a1adcd3a5a | ||
|
|
1596b98e25 | ||
|
|
9b0ad5c545 | ||
|
|
6a47b30987 | ||
|
|
79594a9d00 | ||
|
|
38a9818482 | ||
|
|
a407d538f5 | ||
|
|
44bea85296 | ||
|
|
915d26adfa | ||
|
|
3dd4248587 | ||
|
|
7969e58fbf | ||
|
|
7043ebda23 | ||
|
|
4c0a5b7553 | ||
|
|
533fbe0c2f | ||
|
|
437dfd5f02 | ||
|
|
5f4962ddcc | ||
|
|
7efa609a13 | ||
|
|
0d7049ea7c | ||
|
|
997e7f0420 | ||
|
|
96619b9565 | ||
|
|
4c2a786e54 | ||
|
|
469b1571e1 | ||
|
|
3bc66e0d27 | ||
|
|
9a4fac600a | ||
|
|
546ba8b68f | ||
|
|
ed29c0633f | ||
|
|
35b1135b50 | ||
|
|
90403c98c9 | ||
|
|
71a1c0574a | ||
|
|
ba64a50bb5 | ||
|
|
05131b2b76 | ||
|
|
0894eaee28 | ||
|
|
6f2fd4eccc | ||
|
|
04b534bda1 | ||
|
|
3620796d6d | ||
|
|
a321a38ccd | ||
|
|
ea965dfa85 | ||
|
|
f381106de2 | ||
|
|
b9ab3d6490 | ||
|
|
4cf1d1e08b | ||
|
|
cba6e4df64 | ||
|
|
0dd6f38748 | ||
|
|
970ba437a0 | ||
|
|
e0bbbe3894 | ||
|
|
504791b5b6 | ||
|
|
6a6d0b48b9 | ||
|
|
84ff83bbe2 | ||
|
|
787bcc3546 | ||
|
|
fd811d8cf4 | ||
|
|
3fa743f64b | ||
|
|
ec374c050a | ||
|
|
5a07f8a2a3 | ||
|
|
91b09dc43f | ||
|
|
8d6d355a3b | ||
|
|
da6fd69398 | ||
|
|
0e623cfd15 | ||
|
|
1c01d8f59f | ||
|
|
5723ee7b19 | ||
|
|
1d85292451 | ||
|
|
0d65f5174b | ||
|
|
b7f34f0d5d | ||
|
|
4ffcea72b0 | ||
|
|
9c5fade596 | ||
|
|
331ecc1cc8 | ||
|
|
6428e5abd1 | ||
|
|
b86f83a634 | ||
|
|
ff55e09783 | ||
|
|
d7d24d5e47 | ||
|
|
48a14136a9 | ||
|
|
c9acbb7bf2 | ||
|
|
f98a159799 | ||
|
|
184232995d | ||
|
|
aedede3ba4 | ||
|
|
c874779c0d | ||
|
|
4a2457d571 | ||
|
|
65fdd4196a | ||
|
|
19eefff525 | ||
|
|
626c18ba23 | ||
|
|
d9c8dc1e2d | ||
|
|
25fa5cabbb | ||
|
|
21c9dac593 | ||
|
|
617dccbd9a | ||
|
|
2f2665e2ad | ||
|
|
fcc0d70cd1 | ||
|
|
06b2cf4ff5 | ||
|
|
8642b0775e | ||
|
|
c193858973 | ||
|
|
362e921a27 | ||
|
|
e21fa45718 | ||
|
|
caae270ea8 | ||
|
|
4843d539f0 | ||
|
|
fa8e649288 | ||
|
|
20708ad900 | ||
|
|
5e0b9551da | ||
|
|
e43adf4de7 | ||
|
|
afe16b8eb1 | ||
|
|
e9f9663714 | ||
|
|
d514157903 | ||
|
|
56490f2d86 | ||
|
|
1fd6c8a477 | ||
|
|
e7bdd408be | ||
|
|
f73b4737b6 | ||
|
|
14c905b8ef | ||
|
|
fa7849460c | ||
|
|
4d12c9117f | ||
|
|
e2f08fe35b | ||
|
|
0089a87018 | ||
|
|
6325c454bc | ||
|
|
6b1f64579a | ||
|
|
14cfd61615 | ||
|
|
f2a8768f80 | ||
|
|
556f3fdac0 | ||
|
|
59124fcf68 | ||
|
|
71643446db | ||
|
|
a93ca58e9c | ||
|
|
f12e87c2f4 | ||
|
|
d48c96604b | ||
|
|
0976bbfd2d | ||
|
|
6f66518607 | ||
|
|
e4c20df4a8 | ||
|
|
5135677360 | ||
|
|
f6004f558b | ||
|
|
ddf08c4dc0 | ||
|
|
388eaf614d | ||
|
|
3a0768f9ef | ||
|
|
cb0e04c022 | ||
|
|
55cdac205d | ||
|
|
1bc0d6f16c | ||
|
|
f7377a7043 | ||
|
|
76f1ad45dd | ||
|
|
f21ffde803 | ||
|
|
e9c96f175f | ||
|
|
0f9a4c7c31 | ||
|
|
87451615e8 | ||
|
|
fa19aaae2e | ||
|
|
6b8280fceb | ||
|
|
7a13895429 | ||
|
|
75668ea099 | ||
|
|
d3aa881f55 | ||
|
|
33a1fdf556 | ||
|
|
0c848ec366 | ||
|
|
21d4e46b81 |
@@ -122,9 +122,8 @@ dotnet_code_quality.ca3012.excluded_symbol_names = BotController|CommandControll
|
||||
|
||||
dotnet_code_quality_unused_parameters = all:warning
|
||||
|
||||
dotnet_diagnostic.ca1028.severity = silent
|
||||
dotnet_diagnostic.ca1031.severity = silent
|
||||
dotnet_diagnostic.ca1863.severity = silent
|
||||
dotnet_diagnostic.CA1028.severity = silent
|
||||
dotnet_diagnostic.CA1031.severity = silent
|
||||
|
||||
# Rule - almost everything
|
||||
dotnet_naming_rule.almost_everything_must_be_pascal_case.severity = warning
|
||||
|
||||
6
.gitattributes
vendored
6
.gitattributes
vendored
@@ -1,7 +1,11 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
|
||||
# Unix files that are always LF
|
||||
*.sh text eol=lf
|
||||
|
||||
# Custom for Visual Studio
|
||||
# Windows files that are always CRLF
|
||||
[Dd]esktop.ini text eol=crlf
|
||||
|
||||
# Diff settings
|
||||
*.cs diff=csharp
|
||||
|
||||
4
.github/FUNDING.yml
vendored
4
.github/FUNDING.yml
vendored
@@ -1,4 +1,2 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: JustArchi
|
||||
custom: ["https://paypal.me/JustArchi", "https://pay.revolut.com/justarchi", "https://commerce.coinbase.com/checkout/0c23b844-c51b-45f4-9135-8db7c6fcf98e", "https://steamcommunity.com/tradeoffer/new/?partner=46697991&token=0ix2Ruv_"]
|
||||
custom: ["https://paypal.me/JustArchi", "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=HD2P2P3WGS5Y4", "https://pay.revolut.com/justarchi", "https://steamcommunity.com/tradeoffer/new/?partner=46697991&token=0ix2Ruv_"]
|
||||
|
||||
1
.github/ISSUE_TEMPLATE/Bug-report.yml
vendored
1
.github/ISSUE_TEMPLATE/Bug-report.yml
vendored
@@ -149,6 +149,7 @@ body:
|
||||
|
||||
Ensure that your config has redacted (but NOT removed) potentially-sensitive properties, such as:
|
||||
- IPCPassword (recommended)
|
||||
- LicenseID (mandatory)
|
||||
- SteamOwnerID (optionally)
|
||||
- WebProxy (optionally, if exposing private details)
|
||||
- WebProxyPassword (optionally, if exposing private details)
|
||||
|
||||
4
.github/ISSUE_TEMPLATE/config.yml
vendored
4
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -7,8 +7,8 @@ contact_links:
|
||||
url: https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Localization
|
||||
about: Please use our crowdin platform
|
||||
- name: ❓ Support question or technical issue
|
||||
url: https://github.com/JustArchiNET/ArchiSteamFarm/blob/main/.github/SUPPORT.md
|
||||
about: Please review our support guidelines
|
||||
url: https://github.com/JustArchiNET/ArchiSteamFarm/discussions/categories/support-english
|
||||
about: Please use GitHub discussions or other support channels
|
||||
- name: 🗯️ Negative feedback, complaints and demands
|
||||
url: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
||||
about: We're taking those very seriously
|
||||
|
||||
6
.github/RELEASE_TEMPLATE.md
vendored
6
.github/RELEASE_TEMPLATE.md
vendored
@@ -1,6 +1,6 @@
|
||||
### Notice
|
||||
|
||||
**Pre-releases are experimental versions that often contain unpatched bugs, work-in-progress features and rewritten implementations. If you don't consider yourself advanced user, please download **[latest stable release](https://github.com/JustArchiNET/ArchiSteamFarm/releases/latest)** instead. Pre-release versions are dedicated to users who know how to report bugs, deal with issues and give feedback - no technical support will be given. Check out ASF **[release cycle](https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Release-cycle)** if you'd like to learn more.**
|
||||
**Pre-releases are test versions that often contain unpatched bugs, work-in-progress features and rewritten implementations. If you don't consider yourself advanced user, please download **[latest stable release](https://github.com/JustArchiNET/ArchiSteamFarm/releases/latest)** instead. Pre-release versions are dedicated to users who know how to report bugs, deal with issues and give feedback - no technical support will be given. Check out ASF **[release cycle](https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Release-cycle)** if you'd like to learn more.**
|
||||
|
||||
---
|
||||
|
||||
@@ -14,4 +14,6 @@ This is automated GitHub deployment, human-readable changelog should be availabl
|
||||
|
||||
ASF is available for free, this release was made possible thanks to the people that decided to support the project. If you're grateful for what we're doing, please consider a donation. Developing ASF requires massive amount of time and knowledge, especially when it comes to Steam (and its problems). Even $1 is highly appreciated and shows that you care. Thank you!
|
||||
|
||||
[](https://github.com/sponsors/JustArchi) [](https://commerce.coinbase.com/checkout/0c23b844-c51b-45f4-9135-8db7c6fcf98e) [](https://paypal.me/JustArchi) [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=HD2P2P3WGS5Y4) [](https://pay.revolut.com/justarchi) [](https://steamcommunity.com/tradeoffer/new/?partner=46697991&token=0ix2Ruv_)
|
||||
[](https://github.com/sponsors/JustArchi) [](https://paypal.me/JustArchi) [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=HD2P2P3WGS5Y4) [](https://pay.revolut.com/justarchi) [](https://steamcommunity.com/tradeoffer/new/?partner=46697991&token=0ix2Ruv_)
|
||||
|
||||
[](https://www.blockchain.com/explorer/addresses/btc/3HwcgZbtoF5vSxJkNUvThVSJipKi7r5EqU) [](https://www.blockchain.com/explorer/addresses/eth/0xA1F7Ba62C5a3A8b93Fe6656936192432F328a366) [](https://live.blockcypher.com/ltc/address/MJCeBEZUsNgDhRhqbLFfPiDcf7CSrdvmZ3) [](https://etherscan.io/address/0xCf42D9F53F974CBd7c304eF0243CAe8e029885A8) [](https://etherscan.io/address/0x985FDdD3AD00838A2049B07A33b783104d60f776)
|
||||
|
||||
2
.github/SUPPORT.md
vendored
2
.github/SUPPORT.md
vendored
@@ -2,6 +2,6 @@
|
||||
|
||||
Our **[wiki](https://github.com/JustArchiNET/ArchiSteamFarm/wiki)** is the official online documentation which covers at least a significant majority (if not all) of ASF subjects you could be interested in. We recommend to start with **[setting up](https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Setting-up)**, **[configuration](https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Configuration)** and our **[FAQ](https://github.com/JustArchiNET/ArchiSteamFarm/wiki/FAQ)** which should help you with setting up ASF, configuring it, as well as answering the most common questions that you might have. For more advanced matters, as well as further elaboration, we have other pages available on our **[wiki](https://github.com/JustArchiNET/ArchiSteamFarm/wiki)** that you can visit.
|
||||
|
||||
We also have three independent support channels dedicated to our ASF users, in case you couldn't manage to solve the issue yourself. We answer all support and technical matters in our **[GitHub discussions](https://github.com/JustArchiNET/ArchiSteamFarm/discussions/categories/support)**, **[Steam group](https://steamcommunity.com/groups/archiasf/discussions/1)**, and on our **[Discord server](https://discord.gg/hSQgt8j)**. You're free to use the support channel that matches your preferences, although keep in mind that you have a higher chance solving your issue on the GitHub or Steam, where we're doing our best to answer all questions that couldn't be answered by our community itself (as opposed to Discord server where we're not active 24/7 and therefore not always able to answer).
|
||||
We also have three independent support channels dedicated to our ASF users, in case you couldn't manage to solve the issue yourself. We answer all support and technical matters in our **[GitHub discussions](https://github.com/JustArchiNET/ArchiSteamFarm/discussions/categories/support-english)**, **[Steam group](https://steamcommunity.com/groups/archiasf/discussions/1)**, and on our **[Discord server](https://discord.gg/hSQgt8j)**. You're free to use the support channel that matches your preferences, although keep in mind that you have a higher chance solving your issue on the GitHub or Steam, where we're doing our best to answer all questions that couldn't be answered by our community itself (as opposed to Discord server where we're not active 24/7 and therefore not always able to answer).
|
||||
|
||||
GitHub **issues** (unlike discussions), are being used solely for ASF development, especially in regards to bugs and enhancements. We have a very strict policy regarding that, as GitHub issues is **not** a general support channel, it's dedicated exclusively to ASF development and we're not answering common ASF matters there, as we have appropriate support channels (mentioned above) for that. Common matters include not only general questions or issues that are obviously related to program usage, but also users reporting "bugs" that are clearly considered intended behaviour coming for example (and mainly) from misconfiguration or lack of understanding how the program works. If you're not sure whether your matter relates to ASF development or not, especially if you're not sure if it's a bug or intended behaviour, we recommend to use a support channel instead, where we'll answer you in calm atmosphere and forward your matter as GitHub issue if deemed appropriate. Invalid GitHub issues will be closed immediately and won't be answered.
|
||||
|
||||
0
qodana.yaml → .github/qodana.yaml
vendored
0
qodana.yaml → .github/qodana.yaml
vendored
10
.github/renovate.json5
vendored
10
.github/renovate.json5
vendored
@@ -12,13 +12,5 @@
|
||||
],
|
||||
"git-submodules": {
|
||||
"enabled": true
|
||||
},
|
||||
"packageRules": [
|
||||
{
|
||||
// TODO: <= 3.1 for Mono support, last failed version 6.12, https://steamcommunity.com/groups/archiasf/discussions/1/2997673517556002529
|
||||
"allowedVersions": "<= 3.1",
|
||||
"matchManagers": [ "nuget" ],
|
||||
"matchPackageNames": [ "Microsoft.Extensions.Configuration.Json", "Microsoft.Extensions.Logging.Configuration" ]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
13
.github/workflows/ci.yml
vendored
13
.github/workflows/ci.yml
vendored
@@ -21,13 +21,13 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4.1.1
|
||||
uses: actions/checkout@v4.2.0
|
||||
with:
|
||||
show-progress: false
|
||||
submodules: recursive
|
||||
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v4.0.0
|
||||
uses: actions/setup-dotnet@v4.0.1
|
||||
with:
|
||||
dotnet-version: ${{ env.DOTNET_SDK_VERSION }}
|
||||
|
||||
@@ -39,12 +39,3 @@ jobs:
|
||||
|
||||
- name: Run ${{ matrix.configuration }} ArchiSteamFarm.Tests
|
||||
run: dotnet test ArchiSteamFarm.Tests -c "${{ matrix.configuration }}" -p:ContinuousIntegrationBuild=true -p:UseAppHost=false --nologo
|
||||
|
||||
- name: Upload latest strings for translation on Crowdin
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && matrix.configuration == 'Release' && startsWith(matrix.os, 'ubuntu-') }}
|
||||
uses: crowdin/github-action@v1.19.0
|
||||
with:
|
||||
crowdin_branch_name: main
|
||||
config: '.github/crowdin.yml'
|
||||
project_id: ${{ secrets.ASF_CROWDIN_PROJECT_ID }}
|
||||
token: ${{ secrets.ASF_CROWDIN_API_TOKEN }}
|
||||
|
||||
24
.github/workflows/code-quality.yml
vendored
24
.github/workflows/code-quality.yml
vendored
@@ -1,6 +1,7 @@
|
||||
name: ASF-code-quality
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
- push
|
||||
|
||||
env:
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: true
|
||||
@@ -14,32 +15,25 @@ permissions:
|
||||
|
||||
jobs:
|
||||
main:
|
||||
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
|
||||
environment: qa-qodana
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: actions/checkout@v4.1.1
|
||||
uses: actions/checkout@v4.2.0
|
||||
with:
|
||||
show-progress: false
|
||||
|
||||
- name: Checkout code (for PR)
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: actions/checkout@v4.1.1
|
||||
with:
|
||||
fetch-depth: 100 # History is required for pull request analysis
|
||||
ref: ${{ github.event.pull_request.head.sha }} # To check out the actual pull request commit, not the merge commit
|
||||
show-progress: false
|
||||
|
||||
- name: Run Qodana scan
|
||||
uses: JetBrains/qodana-action@v2023.3.1
|
||||
uses: JetBrains/qodana-action@v2024.2.3
|
||||
with:
|
||||
args: --property=idea.headless.enable.statistics=false
|
||||
args: --config,.github/qodana.yaml,--property=idea.headless.enable.statistics=false
|
||||
pr-mode: false
|
||||
upload-result: true
|
||||
env:
|
||||
QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}
|
||||
|
||||
- name: Report Qodana results to GitHub
|
||||
uses: github/codeql-action/upload-sarif@v3.24.4
|
||||
uses: github/codeql-action/upload-sarif@v3.26.10
|
||||
with:
|
||||
sarif_file: ${{ runner.temp }}/qodana/results/qodana.sarif.json
|
||||
|
||||
28
.github/workflows/crowdin-ci.yml
vendored
Normal file
28
.github/workflows/crowdin-ci.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
name: ASF-crowdin-ci
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
upload:
|
||||
environment: dev-crowdin
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4.2.0
|
||||
with:
|
||||
show-progress: false
|
||||
submodules: recursive
|
||||
|
||||
- name: Upload latest strings for translation on Crowdin
|
||||
uses: crowdin/github-action@v2.2.0
|
||||
with:
|
||||
crowdin_branch_name: main
|
||||
config: '.github/crowdin.yml'
|
||||
project_id: ${{ secrets.ASF_CROWDIN_PROJECT_ID }}
|
||||
token: ${{ secrets.ASF_CROWDIN_API_TOKEN }}
|
||||
12
.github/workflows/docker-ci.yml
vendored
12
.github/workflows/docker-ci.yml
vendored
@@ -19,20 +19,20 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4.1.1
|
||||
uses: actions/checkout@v4.2.0
|
||||
with:
|
||||
show-progress: false
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3.0.0
|
||||
uses: docker/setup-buildx-action@v3.6.1
|
||||
|
||||
- name: Build ${{ matrix.configuration }} Docker image from ${{ matrix.file }}
|
||||
uses: docker/build-push-action@v5.1.0
|
||||
uses: docker/build-push-action@v6.8.0
|
||||
with:
|
||||
build-args: CONFIGURATION=${{ matrix.configuration }}
|
||||
context: .
|
||||
file: ${{ matrix.file }}
|
||||
platforms: ${{ env.PLATFORMS }}
|
||||
build-args: |
|
||||
CONFIGURATION=${{ matrix.configuration }}
|
||||
STEAM_TOKEN_DUMPER_TOKEN=${{ secrets.STEAM_TOKEN_DUMPER_TOKEN }}
|
||||
provenance: true
|
||||
sbom: true
|
||||
|
||||
27
.github/workflows/docker-publish-latest.yml
vendored
27
.github/workflows/docker-publish-latest.yml
vendored
@@ -5,7 +5,6 @@ on:
|
||||
types: [released]
|
||||
|
||||
env:
|
||||
ASF_PRIVATE_SNK: ${{ secrets.ASF_PRIVATE_SNK }}
|
||||
PLATFORMS: linux/amd64,linux/arm,linux/arm64
|
||||
TAG: latest
|
||||
|
||||
@@ -14,40 +13,32 @@ permissions:
|
||||
|
||||
jobs:
|
||||
main:
|
||||
environment: release-docker
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4.1.1
|
||||
uses: actions/checkout@v4.2.0
|
||||
with:
|
||||
show-progress: false
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3.0.0
|
||||
uses: docker/setup-buildx-action@v3.6.1
|
||||
|
||||
- name: Login to ghcr.io
|
||||
uses: docker/login-action@v3.0.0
|
||||
uses: docker/login-action@v3.3.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3.0.0
|
||||
uses: docker/login-action@v3.3.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Prepare private key for signing
|
||||
shell: sh
|
||||
run: |
|
||||
set -eu
|
||||
|
||||
if [ -n "${ASF_PRIVATE_SNK-}" ]; then
|
||||
echo "$ASF_PRIVATE_SNK" | base64 -d > "resources/ArchiSteamFarm.snk"
|
||||
fi
|
||||
|
||||
- name: Prepare environment outputs
|
||||
shell: sh
|
||||
run: |
|
||||
@@ -59,12 +50,16 @@ jobs:
|
||||
echo "DH_REPOSITORY=$(echo ${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }} | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Build and publish Docker image from Dockerfile.Service
|
||||
uses: docker/build-push-action@v5.1.0
|
||||
uses: docker/build-push-action@v6.8.0
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile.Service
|
||||
platforms: ${{ env.PLATFORMS }}
|
||||
build-args: STEAM_TOKEN_DUMPER_TOKEN=${{ secrets.STEAM_TOKEN_DUMPER_TOKEN }}
|
||||
provenance: true
|
||||
sbom: true
|
||||
secrets: |
|
||||
ASF_PRIVATE_SNK=${{ secrets.ASF_PRIVATE_SNK }}
|
||||
STEAM_TOKEN_DUMPER_TOKEN=${{ secrets.STEAM_TOKEN_DUMPER_TOKEN }}
|
||||
labels: |
|
||||
org.opencontainers.image.created=${{ env.DATE_ISO8601 }}
|
||||
org.opencontainers.image.version=${{ env.FIXED_TAG }}
|
||||
|
||||
29
.github/workflows/docker-publish-main.yml
vendored
29
.github/workflows/docker-publish-main.yml
vendored
@@ -6,7 +6,6 @@ on:
|
||||
- main
|
||||
|
||||
env:
|
||||
ASF_PRIVATE_SNK: ${{ secrets.ASF_PRIVATE_SNK }}
|
||||
PLATFORMS: linux/amd64,linux/arm,linux/arm64
|
||||
TAG: main
|
||||
|
||||
@@ -15,40 +14,32 @@ permissions:
|
||||
|
||||
jobs:
|
||||
main:
|
||||
environment: release-docker
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4.1.1
|
||||
uses: actions/checkout@v4.2.0
|
||||
with:
|
||||
show-progress: false
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3.0.0
|
||||
uses: docker/setup-buildx-action@v3.6.1
|
||||
|
||||
- name: Login to ghcr.io
|
||||
uses: docker/login-action@v3.0.0
|
||||
uses: docker/login-action@v3.3.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3.0.0
|
||||
uses: docker/login-action@v3.3.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Prepare private key for signing
|
||||
shell: sh
|
||||
run: |
|
||||
set -eu
|
||||
|
||||
if [ -n "${ASF_PRIVATE_SNK-}" ]; then
|
||||
echo "$ASF_PRIVATE_SNK" | base64 -d > "resources/ArchiSteamFarm.snk"
|
||||
fi
|
||||
|
||||
- name: Prepare environment outputs
|
||||
shell: sh
|
||||
run: |
|
||||
@@ -59,11 +50,15 @@ jobs:
|
||||
echo "DH_REPOSITORY=$(echo ${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }} | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Build and publish Docker image from Dockerfile
|
||||
uses: docker/build-push-action@v5.1.0
|
||||
uses: docker/build-push-action@v6.8.0
|
||||
with:
|
||||
context: .
|
||||
platforms: ${{ env.PLATFORMS }}
|
||||
build-args: STEAM_TOKEN_DUMPER_TOKEN=${{ secrets.STEAM_TOKEN_DUMPER_TOKEN }}
|
||||
provenance: true
|
||||
sbom: true
|
||||
secrets: |
|
||||
ASF_PRIVATE_SNK=${{ secrets.ASF_PRIVATE_SNK }}
|
||||
STEAM_TOKEN_DUMPER_TOKEN=${{ secrets.STEAM_TOKEN_DUMPER_TOKEN }}
|
||||
labels: |
|
||||
org.opencontainers.image.created=${{ env.DATE_ISO8601 }}
|
||||
org.opencontainers.image.version=${{ github.sha }}
|
||||
@@ -77,6 +72,6 @@ jobs:
|
||||
uses: peter-evans/dockerhub-description@v4.0.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
repository: ${{ env.DH_REPOSITORY }}
|
||||
short-description: ${{ github.event.repository.description }}
|
||||
|
||||
27
.github/workflows/docker-publish-released.yml
vendored
27
.github/workflows/docker-publish-released.yml
vendored
@@ -6,7 +6,6 @@ on:
|
||||
- '*'
|
||||
|
||||
env:
|
||||
ASF_PRIVATE_SNK: ${{ secrets.ASF_PRIVATE_SNK }}
|
||||
PLATFORMS: linux/amd64,linux/arm,linux/arm64
|
||||
TAG: released
|
||||
|
||||
@@ -15,40 +14,32 @@ permissions:
|
||||
|
||||
jobs:
|
||||
main:
|
||||
environment: release-docker
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4.1.1
|
||||
uses: actions/checkout@v4.2.0
|
||||
with:
|
||||
show-progress: false
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3.0.0
|
||||
uses: docker/setup-buildx-action@v3.6.1
|
||||
|
||||
- name: Login to ghcr.io
|
||||
uses: docker/login-action@v3.0.0
|
||||
uses: docker/login-action@v3.3.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3.0.0
|
||||
uses: docker/login-action@v3.3.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Prepare private key for signing
|
||||
shell: sh
|
||||
run: |
|
||||
set -eu
|
||||
|
||||
if [ -n "${ASF_PRIVATE_SNK-}" ]; then
|
||||
echo "$ASF_PRIVATE_SNK" | base64 -d > "resources/ArchiSteamFarm.snk"
|
||||
fi
|
||||
|
||||
- name: Prepare environment outputs
|
||||
shell: sh
|
||||
run: |
|
||||
@@ -60,11 +51,15 @@ jobs:
|
||||
echo "DH_REPOSITORY=$(echo ${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }} | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Build and publish Docker image from Dockerfile
|
||||
uses: docker/build-push-action@v5.1.0
|
||||
uses: docker/build-push-action@v6.8.0
|
||||
with:
|
||||
context: .
|
||||
platforms: ${{ env.PLATFORMS }}
|
||||
build-args: STEAM_TOKEN_DUMPER_TOKEN=${{ secrets.STEAM_TOKEN_DUMPER_TOKEN }}
|
||||
provenance: true
|
||||
sbom: true
|
||||
secrets: |
|
||||
ASF_PRIVATE_SNK=${{ secrets.ASF_PRIVATE_SNK }}
|
||||
STEAM_TOKEN_DUMPER_TOKEN=${{ secrets.STEAM_TOKEN_DUMPER_TOKEN }}
|
||||
labels: |
|
||||
org.opencontainers.image.created=${{ env.DATE_ISO8601 }}
|
||||
org.opencontainers.image.version=${{ env.FIXED_TAG }}
|
||||
|
||||
396
.github/workflows/publish.yml
vendored
396
.github/workflows/publish.yml
vendored
@@ -8,7 +8,8 @@ env:
|
||||
DOTNET_NOLOGO: true
|
||||
DOTNET_SDK_VERSION: 8.0
|
||||
NODE_JS_VERSION: 'lts/*'
|
||||
PLUGINS: ArchiSteamFarm.OfficialPlugins.ItemsMatcher ArchiSteamFarm.OfficialPlugins.MobileAuthenticator ArchiSteamFarm.OfficialPlugins.SteamTokenDumper
|
||||
PLUGINS_BUNDLED: ArchiSteamFarm.OfficialPlugins.ItemsMatcher ArchiSteamFarm.OfficialPlugins.MobileAuthenticator ArchiSteamFarm.OfficialPlugins.SteamTokenDumper
|
||||
PLUGINS_INCLUDED: ArchiSteamFarm.OfficialPlugins.Monitoring # Apart from declaring them here, there is certain amount of hardcoding needed below for uploading
|
||||
|
||||
permissions: {}
|
||||
|
||||
@@ -18,13 +19,13 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4.1.1
|
||||
uses: actions/checkout@v4.2.0
|
||||
with:
|
||||
show-progress: false
|
||||
submodules: recursive
|
||||
|
||||
- name: Setup Node.js with npm
|
||||
uses: actions/setup-node@v4.0.2
|
||||
uses: actions/setup-node@v4.0.4
|
||||
with:
|
||||
check-latest: true
|
||||
node-version: ${{ env.NODE_JS_VERSION }}
|
||||
@@ -42,8 +43,9 @@ jobs:
|
||||
run: npm run-script deploy --no-progress --prefix ASF-ui
|
||||
|
||||
- name: Upload ASF-ui
|
||||
uses: actions/upload-artifact@v4.3.1
|
||||
uses: actions/upload-artifact@v4.4.0
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: ASF-ui
|
||||
path: ASF-ui/dist
|
||||
|
||||
@@ -71,16 +73,21 @@ jobs:
|
||||
- os: windows-latest
|
||||
variant: win-x64
|
||||
|
||||
environment: build
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
permissions:
|
||||
attestations: write
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4.1.1
|
||||
uses: actions/checkout@v4.2.0
|
||||
with:
|
||||
show-progress: false
|
||||
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v4.0.0
|
||||
uses: actions/setup-dotnet@v4.0.1
|
||||
with:
|
||||
dotnet-version: ${{ env.DOTNET_SDK_VERSION }}
|
||||
|
||||
@@ -88,7 +95,7 @@ jobs:
|
||||
run: dotnet --info
|
||||
|
||||
- name: Download previously built ASF-ui
|
||||
uses: actions/download-artifact@v4.1.2
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
with:
|
||||
name: ASF-ui
|
||||
path: ASF-ui/dist
|
||||
@@ -125,35 +132,6 @@ jobs:
|
||||
}
|
||||
}
|
||||
|
||||
- name: Prepare for publishing on Unix
|
||||
if: startsWith(matrix.os, 'macos-') || startsWith(matrix.os, 'ubuntu-')
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
dotnet restore
|
||||
dotnet build ArchiSteamFarm -c "$CONFIGURATION" -p:ContinuousIntegrationBuild=true -p:TargetLatestRuntimePatch=false -p:UseAppHost=false --nologo
|
||||
|
||||
- name: Prepare for publishing on Windows
|
||||
if: startsWith(matrix.os, 'windows-')
|
||||
shell: pwsh
|
||||
run: |
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
|
||||
dotnet restore
|
||||
|
||||
if ($LastExitCode -ne 0) {
|
||||
throw "Last command failed."
|
||||
}
|
||||
|
||||
dotnet build ArchiSteamFarm -c "$env:CONFIGURATION" -p:ContinuousIntegrationBuild=true -p:TargetLatestRuntimePatch=false -p:UseAppHost=false --nologo
|
||||
|
||||
if ($LastExitCode -ne 0) {
|
||||
throw "Last command failed."
|
||||
}
|
||||
|
||||
- name: Prepare ArchiSteamFarm.OfficialPlugins.SteamTokenDumper on Unix
|
||||
if: startsWith(matrix.os, 'macos-') || startsWith(matrix.os, 'ubuntu-')
|
||||
env:
|
||||
@@ -181,69 +159,6 @@ jobs:
|
||||
(Get-Content "ArchiSteamFarm.OfficialPlugins.SteamTokenDumper\SharedInfo.cs").Replace('STEAM_TOKEN_DUMPER_TOKEN', "$env:STEAM_TOKEN_DUMPER_TOKEN") | Set-Content "ArchiSteamFarm.OfficialPlugins.SteamTokenDumper\SharedInfo.cs"
|
||||
}
|
||||
|
||||
- name: Publish official plugins on Unix
|
||||
if: startsWith(matrix.os, 'macos-') || startsWith(matrix.os, 'ubuntu-')
|
||||
env:
|
||||
MAX_JOBS: 4
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
publish() {
|
||||
dotnet publish "$1" -c "$CONFIGURATION" -o "out/${1}" -p:ContinuousIntegrationBuild=true -p:TargetLatestRuntimePatch=false -p:UseAppHost=false --no-restore --nologo
|
||||
}
|
||||
|
||||
for plugin in $PLUGINS; do
|
||||
while [ "$(jobs -p | wc -l)" -ge "$MAX_JOBS" ]; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
publish "$plugin" &
|
||||
done
|
||||
|
||||
wait
|
||||
|
||||
- name: Publish official plugins on Windows
|
||||
if: startsWith(matrix.os, 'windows-')
|
||||
env:
|
||||
MAX_JOBS: 4
|
||||
shell: pwsh
|
||||
run: |
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
|
||||
$PublishBlock = {
|
||||
param($plugin)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
|
||||
Set-Location "$env:GITHUB_WORKSPACE"
|
||||
|
||||
dotnet publish "$plugin" -c "$env:CONFIGURATION" -o "out\$plugin" -p:ContinuousIntegrationBuild=true -p:TargetLatestRuntimePatch=false -p:UseAppHost=false --no-restore --nologo
|
||||
|
||||
if ($LastExitCode -ne 0) {
|
||||
throw "Last command failed."
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($plugin in $env:PLUGINS.Split([char[]] $null, [System.StringSplitOptions]::RemoveEmptyEntries)) {
|
||||
# Limit active jobs in parallel to help with memory usage
|
||||
$jobs = $(Get-Job -State Running)
|
||||
|
||||
while (@($jobs).Count -ge $env:MAX_JOBS) {
|
||||
Wait-Job -Job $jobs -Any | Out-Null
|
||||
|
||||
$jobs = $(Get-Job -State Running)
|
||||
}
|
||||
|
||||
Start-Job -Name "$plugin" $PublishBlock -ArgumentList "$plugin"
|
||||
}
|
||||
|
||||
Get-Job | Receive-Job -Wait
|
||||
|
||||
- name: Publish ASF-${{ matrix.variant }} on Unix
|
||||
if: startsWith(matrix.os, 'macos-') || startsWith(matrix.os, 'ubuntu-')
|
||||
env:
|
||||
@@ -260,28 +175,12 @@ jobs:
|
||||
|
||||
dotnet publish ArchiSteamFarm -c "$CONFIGURATION" -o "out/${VARIANT}" "-p:ASFVariant=${VARIANT}" -p:ContinuousIntegrationBuild=true --nologo $variantArgs
|
||||
|
||||
# If we're including official plugins for this framework, copy them to output directory
|
||||
for plugin in $PLUGINS; do
|
||||
if [ -d "out/${plugin}" ]; then
|
||||
mkdir -p "out/${VARIANT}/plugins/${plugin}"
|
||||
cp -pR "out/${plugin}/"* "out/${VARIANT}/plugins/${plugin}"
|
||||
fi
|
||||
done
|
||||
|
||||
# Include .ico file for all platforms, since only Windows script can bundle it inside the exe
|
||||
cp "resources/ASF.ico" "out/${VARIANT}/ArchiSteamFarm.ico"
|
||||
|
||||
# By default use fastest compression
|
||||
seven_zip_args="-mx=1"
|
||||
zip_args="-1"
|
||||
|
||||
# Include extra logic for builds marked for release
|
||||
case "$GITHUB_REF" in
|
||||
"refs/tags/"*)
|
||||
# Tweak compression args for release publishing
|
||||
seven_zip_args="-mx=9 -mfb=258 -mpass=15"
|
||||
zip_args="-9"
|
||||
|
||||
# Update link in Changelog.html accordingly
|
||||
if [ -f "out/${VARIANT}/Changelog.html" ]; then
|
||||
tag="$(echo "$GITHUB_REF" | cut -c 11-)"
|
||||
@@ -292,37 +191,6 @@ jobs:
|
||||
;;
|
||||
esac
|
||||
|
||||
# Create the final zip file
|
||||
case "$(uname -s)" in
|
||||
"Darwin")
|
||||
# We prefer to use zip on macOS as 7z implementation on that OS doesn't handle file permissions (chmod +x)
|
||||
if command -v zip >/dev/null; then
|
||||
(
|
||||
cd "${GITHUB_WORKSPACE}/out/${VARIANT}"
|
||||
zip -q -r $zip_args "../ASF-${VARIANT}.zip" .
|
||||
)
|
||||
elif command -v 7z >/dev/null; then
|
||||
7z a -bd -slp -tzip -mm=Deflate $seven_zip_args "out/ASF-${VARIANT}.zip" "${GITHUB_WORKSPACE}/out/${VARIANT}/*"
|
||||
else
|
||||
echo "ERROR: No supported zip tool!"
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
if command -v 7z >/dev/null; then
|
||||
7z a -bd -slp -tzip -mm=Deflate $seven_zip_args "out/ASF-${VARIANT}.zip" "${GITHUB_WORKSPACE}/out/${VARIANT}/*"
|
||||
elif command -v zip >/dev/null; then
|
||||
(
|
||||
cd "${GITHUB_WORKSPACE}/out/${VARIANT}"
|
||||
zip -q -r $zip_args "../ASF-${VARIANT}.zip" .
|
||||
)
|
||||
else
|
||||
echo "ERROR: No supported zip tool!"
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
- name: Publish ASF-${{ matrix.variant }} on Windows
|
||||
if: startsWith(matrix.os, 'windows-')
|
||||
env:
|
||||
@@ -345,30 +213,13 @@ jobs:
|
||||
throw "Last command failed."
|
||||
}
|
||||
|
||||
# If we're including official plugins for this framework, copy them to output directory
|
||||
foreach ($plugin in $env:PLUGINS.Split([char[]] $null, [System.StringSplitOptions]::RemoveEmptyEntries)) {
|
||||
if (Test-Path "out\$plugin" -PathType Container) {
|
||||
if (!(Test-Path "out\$env:VARIANT\plugins\$plugin" -PathType Container)) {
|
||||
New-Item -ItemType Directory -Path "out\$env:VARIANT\plugins\$plugin" > $null
|
||||
}
|
||||
|
||||
Copy-Item "out\$plugin\*" "out\$env:VARIANT\plugins\$plugin" -Recurse
|
||||
}
|
||||
}
|
||||
|
||||
# Icon is available only in .exe Windows builds, we'll bundle the .ico file for other flavours
|
||||
if (!(Test-Path "out\$env:VARIANT\ArchiSteamFarm.exe" -PathType Leaf)) {
|
||||
Copy-Item 'resources\ASF.ico' "out\$env:VARIANT\ArchiSteamFarm.ico"
|
||||
}
|
||||
|
||||
# By default use fastest compression
|
||||
$compressionArgs = '-mx=1'
|
||||
|
||||
# Include extra logic for builds marked for release
|
||||
if ($env:GITHUB_REF -like 'refs/tags/*') {
|
||||
# Tweak compression args for release publishing
|
||||
$compressionArgs = '-mx=9', '-mfb=258', '-mpass=15'
|
||||
|
||||
# Update link in Changelog.html accordingly
|
||||
if (Test-Path "out\$env:VARIANT\Changelog.html" -PathType Leaf) {
|
||||
$tag = $env:GITHUB_REF.Substring(10)
|
||||
@@ -377,6 +228,111 @@ jobs:
|
||||
}
|
||||
}
|
||||
|
||||
- name: Publish bundled plugins on Unix
|
||||
if: startsWith(matrix.os, 'macos-') || startsWith(matrix.os, 'ubuntu-')
|
||||
env:
|
||||
VARIANT: ${{ matrix.variant }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
if [ "$VARIANT" = 'generic' ]; then
|
||||
variantArgs="-p:TargetLatestRuntimePatch=false -p:UseAppHost=false"
|
||||
else
|
||||
variantArgs="-r $VARIANT"
|
||||
fi
|
||||
|
||||
for plugin in $PLUGINS_BUNDLED; do
|
||||
dotnet publish "$plugin" -c "$CONFIGURATION" -o "out/${VARIANT}/plugins/${plugin}" "-p:ASFVariant=${VARIANT}" -p:ContinuousIntegrationBuild=true --nologo $variantArgs
|
||||
done
|
||||
|
||||
- name: Publish bundled plugins on Windows
|
||||
if: startsWith(matrix.os, 'windows-')
|
||||
env:
|
||||
VARIANT: ${{ matrix.variant }}
|
||||
shell: pwsh
|
||||
run: |
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
|
||||
if ($env:VARIANT -like 'generic*') {
|
||||
$variantArgs = '-p:TargetLatestRuntimePatch=false', '-p:UseAppHost=false'
|
||||
} else {
|
||||
$variantArgs = '-r', "$env:VARIANT"
|
||||
}
|
||||
|
||||
foreach ($plugin in $env:PLUGINS_BUNDLED.Split([char[]] $null, [System.StringSplitOptions]::RemoveEmptyEntries)) {
|
||||
dotnet publish "$plugin" -c "$env:CONFIGURATION" -o "out\$env:VARIANT\plugins\$plugin" "-p:ASFVariant=$env:VARIANT" -p:ContinuousIntegrationBuild=true --nologo $variantArgs
|
||||
|
||||
if ($LastExitCode -ne 0) {
|
||||
throw "Last command failed."
|
||||
}
|
||||
}
|
||||
|
||||
- name: Zip ASF-${{ matrix.variant }} on Unix
|
||||
if: startsWith(matrix.os, 'macos-') || startsWith(matrix.os, 'ubuntu-')
|
||||
env:
|
||||
VARIANT: ${{ matrix.variant }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
# By default use fastest compression
|
||||
seven_zip_args="-mx=1"
|
||||
zip_args="-1"
|
||||
|
||||
# Tweak compression args for release publishing
|
||||
case "$GITHUB_REF" in
|
||||
"refs/tags/"*)
|
||||
seven_zip_args="-mx=9 -mfb=258 -mpass=15"
|
||||
zip_args="-9"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Create the final zip file
|
||||
case "$(uname -s)" in
|
||||
"Darwin")
|
||||
# We prefer to use zip on macOS as 7z implementation on that OS doesn't handle file permissions (chmod +x)
|
||||
if command -v zip >/dev/null; then
|
||||
(
|
||||
cd "${GITHUB_WORKSPACE}/out/${VARIANT}"
|
||||
zip -q -r $zip_args "../ASF-${VARIANT}.zip" .
|
||||
)
|
||||
else
|
||||
7z a -bd -slp -tzip -mm=Deflate $seven_zip_args "out/ASF-${VARIANT}.zip" "${GITHUB_WORKSPACE}/out/${VARIANT}/*"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
if command -v 7z >/dev/null; then
|
||||
7z a -bd -slp -tzip -mm=Deflate $seven_zip_args "out/ASF-${VARIANT}.zip" "${GITHUB_WORKSPACE}/out/${VARIANT}/*"
|
||||
else
|
||||
(
|
||||
cd "${GITHUB_WORKSPACE}/out/${VARIANT}"
|
||||
zip -q -r $zip_args "../ASF-${VARIANT}.zip" .
|
||||
)
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
- name: Zip ASF-${{ matrix.variant }} on Windows
|
||||
if: startsWith(matrix.os, 'windows-')
|
||||
env:
|
||||
VARIANT: ${{ matrix.variant }}
|
||||
shell: pwsh
|
||||
run: |
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
|
||||
# By default use fastest compression
|
||||
$compressionArgs = '-mx=1'
|
||||
|
||||
# Tweak compression args for release publishing
|
||||
if ($env:GITHUB_REF -like 'refs/tags/*') {
|
||||
$compressionArgs = '-mx=9', '-mfb=258', '-mpass=15'
|
||||
}
|
||||
|
||||
# Create the final zip file
|
||||
7z a -bd -slp -tzip -mm=Deflate $compressionArgs "out\ASF-$env:VARIANT.zip" "$env:GITHUB_WORKSPACE\out\$env:VARIANT\*"
|
||||
|
||||
@@ -404,74 +360,138 @@ jobs:
|
||||
}
|
||||
}
|
||||
|
||||
- name: Upload ASF-${{ matrix.variant }}
|
||||
uses: actions/upload-artifact@v4.3.1
|
||||
- name: Generate artifact attestation for ASF-${{ matrix.variant }}.zip
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
uses: actions/attest-build-provenance@v1.4.3
|
||||
with:
|
||||
subject-path: out/ASF-${{ matrix.variant }}.zip
|
||||
|
||||
- name: Upload ASF-${{ matrix.variant }}
|
||||
uses: actions/upload-artifact@v4.4.0
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: ${{ matrix.os }}_ASF-${{ matrix.variant }}
|
||||
path: out/ASF-${{ matrix.variant }}.zip
|
||||
|
||||
- name: Publish included plugins on Unix
|
||||
if: ${{ matrix.os == 'ubuntu-latest' && matrix.variant == 'generic' }}
|
||||
env:
|
||||
VARIANT: ${{ matrix.variant }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
# By default use fastest compression
|
||||
seven_zip_args="-mx=1"
|
||||
zip_args="-1"
|
||||
|
||||
# Tweak compression args for release publishing
|
||||
case "$GITHUB_REF" in
|
||||
"refs/tags/"*)
|
||||
seven_zip_args="-mx=9 -mfb=258 -mpass=15"
|
||||
zip_args="-9"
|
||||
;;
|
||||
esac
|
||||
|
||||
for plugin in $PLUGINS_INCLUDED; do
|
||||
dotnet publish "$plugin" -c "$CONFIGURATION" -o "out/${plugin}" "-p:ASFVariant=${VARIANT}" -p:ContinuousIntegrationBuild=true -p:TargetLatestRuntimePatch=false -p:UseAppHost=false --nologo
|
||||
|
||||
# Create the final zip file
|
||||
if command -v 7z >/dev/null; then
|
||||
7z a -bd -slp -tzip -mm=Deflate $seven_zip_args "out/${plugin}.zip" "${GITHUB_WORKSPACE}/out/${plugin}/*"
|
||||
else
|
||||
(
|
||||
cd "${GITHUB_WORKSPACE}/out/${plugin}"
|
||||
zip -q -r $zip_args "../${plugin}.zip" .
|
||||
)
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Generate artifact attestation for ArchiSteamFarm.OfficialPlugins.Monitoring
|
||||
if: ${{ github.event_name == 'push' && matrix.os == 'ubuntu-latest' && matrix.variant == 'generic' }}
|
||||
uses: actions/attest-build-provenance@v1.4.3
|
||||
with:
|
||||
subject-path: out/ArchiSteamFarm.OfficialPlugins.Monitoring.zip
|
||||
|
||||
- name: Upload ArchiSteamFarm.OfficialPlugins.Monitoring
|
||||
if: ${{ matrix.os == 'ubuntu-latest' && matrix.variant == 'generic' }}
|
||||
uses: actions/upload-artifact@v4.4.0
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: ArchiSteamFarm.OfficialPlugins.Monitoring
|
||||
path: out/ArchiSteamFarm.OfficialPlugins.Monitoring.zip
|
||||
|
||||
release:
|
||||
if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }}
|
||||
needs: publish-asf
|
||||
environment: release-github
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
attestations: write
|
||||
contents: write
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4.1.1
|
||||
uses: actions/checkout@v4.2.0
|
||||
with:
|
||||
show-progress: false
|
||||
|
||||
- name: Download ASF-generic artifact from ubuntu-latest
|
||||
uses: actions/download-artifact@v4.1.2
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
with:
|
||||
name: ubuntu-latest_ASF-generic
|
||||
path: out
|
||||
|
||||
- name: Download ASF-linux-arm artifact from ubuntu-latest
|
||||
uses: actions/download-artifact@v4.1.2
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
with:
|
||||
name: ubuntu-latest_ASF-linux-arm
|
||||
path: out
|
||||
|
||||
- name: Download ASF-linux-arm64 artifact from ubuntu-latest
|
||||
uses: actions/download-artifact@v4.1.2
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
with:
|
||||
name: ubuntu-latest_ASF-linux-arm64
|
||||
path: out
|
||||
|
||||
- name: Download ASF-linux-x64 artifact from ubuntu-latest
|
||||
uses: actions/download-artifact@v4.1.2
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
with:
|
||||
name: ubuntu-latest_ASF-linux-x64
|
||||
path: out
|
||||
|
||||
- name: Download ASF-osx-arm64 artifact from macos-latest
|
||||
uses: actions/download-artifact@v4.1.2
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
with:
|
||||
name: macos-latest_ASF-osx-arm64
|
||||
path: out
|
||||
|
||||
- name: Download ASF-osx-x64 artifact from macos-latest
|
||||
uses: actions/download-artifact@v4.1.2
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
with:
|
||||
name: macos-latest_ASF-osx-x64
|
||||
path: out
|
||||
|
||||
- name: Download ASF-win-arm64 artifact from windows-latest
|
||||
uses: actions/download-artifact@v4.1.2
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
with:
|
||||
name: windows-latest_ASF-win-arm64
|
||||
path: out
|
||||
|
||||
- name: Download ASF-win-x64 artifact from windows-latest
|
||||
uses: actions/download-artifact@v4.1.2
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
with:
|
||||
name: windows-latest_ASF-win-x64
|
||||
path: out
|
||||
|
||||
- name: Download ArchiSteamFarm.OfficialPlugins.Monitoring artifact
|
||||
uses: actions/download-artifact@v4.1.8
|
||||
with:
|
||||
name: ArchiSteamFarm.OfficialPlugins.Monitoring
|
||||
path: out
|
||||
|
||||
- name: Import GPG key for signing
|
||||
uses: crazy-max/ghaction-import-gpg@v6.1.0
|
||||
with:
|
||||
@@ -479,34 +499,46 @@ jobs:
|
||||
|
||||
- name: Generate SHA-512 checksums and signature
|
||||
shell: sh
|
||||
working-directory: out
|
||||
run: |
|
||||
set -eu
|
||||
|
||||
(
|
||||
cd "out"
|
||||
sha512sum *.zip > SHA512SUMS
|
||||
gpg -a -b -o SHA512SUMS.sign SHA512SUMS
|
||||
|
||||
sha512sum *.zip > SHA512SUMS
|
||||
gpg -a -b -o SHA512SUMS.sign SHA512SUMS
|
||||
)
|
||||
- name: Generate artifact attestation for SHA512SUMS
|
||||
uses: actions/attest-build-provenance@v1.4.3
|
||||
with:
|
||||
subject-path: out/SHA512SUMS
|
||||
|
||||
- name: Upload SHA512SUMS
|
||||
uses: actions/upload-artifact@v4.3.1
|
||||
uses: actions/upload-artifact@v4.4.0
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: SHA512SUMS
|
||||
path: out/SHA512SUMS
|
||||
|
||||
- name: Upload SHA512SUMS.sign
|
||||
uses: actions/upload-artifact@v4.3.1
|
||||
- name: Generate artifact attestation for SHA512SUMS.sign
|
||||
uses: actions/attest-build-provenance@v1.4.3
|
||||
with:
|
||||
subject-path: out/SHA512SUMS.sign
|
||||
|
||||
- name: Upload SHA512SUMS.sign
|
||||
uses: actions/upload-artifact@v4.4.0
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: SHA512SUMS.sign
|
||||
path: out/SHA512SUMS.sign
|
||||
|
||||
- name: Create ArchiSteamFarm GitHub release
|
||||
uses: ncipollo/release-action@v1.14.0
|
||||
with:
|
||||
allowUpdates: true
|
||||
artifactErrorsFailBuild: true
|
||||
artifacts: "out/*"
|
||||
bodyFile: .github/RELEASE_TEMPLATE.md
|
||||
makeLatest: false
|
||||
name: ArchiSteamFarm V${{ github.ref_name }}
|
||||
prerelease: true
|
||||
token: ${{ secrets.ARCHIBOT_GITHUB_TOKEN }}
|
||||
updateOnlyUnreleased: true
|
||||
|
||||
34
.github/workflows/translations.yml
vendored
34
.github/workflows/translations.yml
vendored
@@ -3,17 +3,19 @@ name: ASF-translations
|
||||
on:
|
||||
schedule:
|
||||
- cron: '55 1 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
update:
|
||||
environment: dev-crowdin
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4.1.1
|
||||
uses: actions/checkout@v4.2.0
|
||||
with:
|
||||
show-progress: false
|
||||
submodules: recursive
|
||||
@@ -21,16 +23,15 @@ jobs:
|
||||
|
||||
- name: Reset wiki to follow origin
|
||||
shell: sh
|
||||
working-directory: wiki
|
||||
run: |
|
||||
set -eu
|
||||
|
||||
cd wiki
|
||||
|
||||
git fetch --depth=1 origin master
|
||||
git reset --hard origin/master
|
||||
|
||||
- name: Download latest translations from Crowdin
|
||||
uses: crowdin/github-action@v1.19.0
|
||||
uses: crowdin/github-action@v2.2.0
|
||||
with:
|
||||
upload_sources: false
|
||||
download_translations: true
|
||||
@@ -49,28 +50,21 @@ jobs:
|
||||
git_user_signingkey: true
|
||||
git_commit_gpgsign: true
|
||||
|
||||
- name: Commit the changes to wiki
|
||||
- name: Commit and push the changes to wiki
|
||||
shell: sh
|
||||
working-directory: wiki
|
||||
run: |
|
||||
set -eu
|
||||
|
||||
cd wiki
|
||||
|
||||
git add -A "locale"
|
||||
|
||||
if ! git diff --cached --quiet; then
|
||||
git commit -m "Automatic translations update"
|
||||
|
||||
git push origin HEAD:master
|
||||
fi
|
||||
|
||||
- name: Push changes to wiki
|
||||
uses: ad-m/github-push-action@v0.8.0
|
||||
with:
|
||||
github_token: ${{ secrets.ARCHIBOT_GITHUB_TOKEN }}
|
||||
branch: master
|
||||
directory: wiki
|
||||
repository: ${{ github.repository }}.wiki
|
||||
|
||||
- name: Commit the changes to ASF
|
||||
- name: Commit and push the changes to ASF
|
||||
shell: sh
|
||||
run: |
|
||||
set -eu
|
||||
@@ -79,10 +73,6 @@ jobs:
|
||||
|
||||
if ! git diff --cached --quiet; then
|
||||
git commit -m "Automatic translations update"
|
||||
fi
|
||||
|
||||
- name: Push changes to ASF
|
||||
uses: ad-m/github-push-action@v0.8.0
|
||||
with:
|
||||
github_token: ${{ secrets.ARCHIBOT_GITHUB_TOKEN }}
|
||||
branch: ${{ github.ref }}
|
||||
git push
|
||||
fi
|
||||
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -543,3 +543,12 @@ $RECYCLE.BIN/
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
|
||||
# _ ____ _____
|
||||
# / \ / ___| | ___|
|
||||
# / _ \ \___ \ | |_
|
||||
# / ___ \ ___) || _|
|
||||
# /_/ \_\|____/ |_|
|
||||
|
||||
# Files that could be ignored by above rules, that we want to ship
|
||||
!ArchiSteamFarm/overlay/**
|
||||
|
||||
2
ASF-ui
2
ASF-ui
Submodule ASF-ui updated: cd1173a0d6...fa46e12afa
@@ -4,7 +4,6 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ConfigureAwaitChecker.Analyzer" PrivateAssets="all" />
|
||||
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
|
||||
<PackageReference Include="SteamKit2" IncludeAssets="compile" />
|
||||
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
@@ -32,6 +34,7 @@ using ArchiSteamFarm.Core;
|
||||
using ArchiSteamFarm.Plugins.Interfaces;
|
||||
using ArchiSteamFarm.Steam;
|
||||
using ArchiSteamFarm.Steam.Data;
|
||||
using ArchiSteamFarm.Steam.Exchange;
|
||||
using SteamKit2;
|
||||
|
||||
namespace ArchiSteamFarm.CustomPlugins.ExamplePlugin;
|
||||
@@ -43,7 +46,7 @@ namespace ArchiSteamFarm.CustomPlugins.ExamplePlugin;
|
||||
// If you do not want to handle a particular action (e.g. OnBotMessage that is offered in IBotMessage), it's the best idea to not inherit it at all
|
||||
// This will keep your code compact, efficient and less dependent. You can always add additional interfaces when you'll need them, this example project will inherit quite a bit of them to show you potential usage
|
||||
[SuppressMessage("ReSharper", "MemberCanBeFileLocal")]
|
||||
internal sealed class ExamplePlugin : IASF, IBot, IBotCommand2, IBotConnection, IBotFriendRequest, IBotMessage, IBotModules, IBotTradeOffer {
|
||||
internal sealed class ExamplePlugin : IASF, IBot, IBotCommand2, IBotConnection, IBotFriendRequest, IBotMessage, IBotModules, IBotTradeOffer2 {
|
||||
// This is used for identification purposes, typically you want to use a friendly name of your plugin here, such as the name of your main class
|
||||
// Please note that this property can have direct dependencies only on structures that were initialized by the constructor, as it's possible to be called before OnLoaded() takes place
|
||||
[JsonInclude]
|
||||
@@ -171,14 +174,14 @@ internal sealed class ExamplePlugin : IASF, IBot, IBotCommand2, IBotConnection,
|
||||
// If this message doesn't come from one of our bots, we can reply to the user in some pre-defined way
|
||||
bot.ArchiLogger.LogGenericTrace("Hey boss, we got some unknown message here!");
|
||||
|
||||
return Task.FromResult((string?) "I didn't get that, did you mean to use a command?");
|
||||
return Task.FromResult<string?>("I didn't get that, did you mean to use a command?");
|
||||
}
|
||||
|
||||
// This method is called when bot receives a trade offer that ASF isn't willing to accept (ignored and rejected trades)
|
||||
// It allows you not only to analyze such trades, but generate a response whether ASF should accept it (true), or proceed like usual (false)
|
||||
// Thanks to that, you can implement custom rules for all trades that aren't handled by ASF, for example cross-set trading on your own custom rules
|
||||
// You'd implement your own logic here, as an example we'll allow all trades to be accepted if the bot's name starts from "TrashBot"
|
||||
public Task<bool> OnBotTradeOffer(Bot bot, TradeOffer tradeOffer) => Task.FromResult(bot.BotName.StartsWith("TrashBot", StringComparison.OrdinalIgnoreCase));
|
||||
public Task<bool> OnBotTradeOffer(Bot bot, TradeOffer tradeOffer, ParseTradeResult.EResult asfResult) => Task.FromResult(bot.BotName.StartsWith("TrashBot", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
// This is the earliest method that will be called, right after loading the plugin, long before any bot initialization takes place
|
||||
// It's a good place to initialize all potential (non-bot-specific) structures that you will need across lifetime of your plugin, such as global timers, concurrent dictionaries and alike
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ConfigureAwaitChecker.Analyzer" PrivateAssets="all" />
|
||||
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
|
||||
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AngleSharp.XPath" IncludeAssets="compile" />
|
||||
<PackageReference Include="ConfigureAwaitChecker.Analyzer" PrivateAssets="all" />
|
||||
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
|
||||
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
@@ -20,7 +22,6 @@
|
||||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
@@ -51,7 +52,7 @@ public sealed class SignInWithSteamController : ArchiController {
|
||||
Bot? bot = Bot.GetBot(botName);
|
||||
|
||||
if (bot == null) {
|
||||
return BadRequest(new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.BotNotFound, botName)));
|
||||
return BadRequest(new GenericResponse(false, Strings.FormatBotNotFound(botName)));
|
||||
}
|
||||
|
||||
if (!bot.IsConnectedAndLoggedOn) {
|
||||
@@ -62,7 +63,7 @@ public sealed class SignInWithSteamController : ArchiController {
|
||||
using HtmlDocumentResponse? challengeResponse = await bot.ArchiWebHandler.UrlGetToHtmlDocumentWithSession(request.RedirectURL).ConfigureAwait(false);
|
||||
|
||||
if (challengeResponse?.Content == null) {
|
||||
return StatusCode((int) HttpStatusCode.ServiceUnavailable, new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)));
|
||||
return StatusCode((int) HttpStatusCode.ServiceUnavailable, new GenericResponse(false, Strings.FormatErrorRequestFailedTooManyTimes(WebBrowser.MaxTries)));
|
||||
}
|
||||
|
||||
IAttr? paramsNode = challengeResponse.Content.SelectSingleNode<IAttr>("//input[@name='openidparams']/@value");
|
||||
@@ -70,7 +71,7 @@ public sealed class SignInWithSteamController : ArchiController {
|
||||
if (paramsNode == null) {
|
||||
ASF.ArchiLogger.LogNullError(paramsNode);
|
||||
|
||||
return StatusCode((int) HttpStatusCode.InternalServerError, new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorObjectIsNull, nameof(paramsNode))));
|
||||
return StatusCode((int) HttpStatusCode.InternalServerError, new GenericResponse(false, Strings.FormatErrorObjectIsNull(nameof(paramsNode))));
|
||||
}
|
||||
|
||||
string paramsValue = paramsNode.Value;
|
||||
@@ -78,7 +79,7 @@ public sealed class SignInWithSteamController : ArchiController {
|
||||
if (string.IsNullOrEmpty(paramsValue)) {
|
||||
ASF.ArchiLogger.LogNullError(paramsValue);
|
||||
|
||||
return StatusCode((int) HttpStatusCode.InternalServerError, new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorObjectIsNull, nameof(paramsValue))));
|
||||
return StatusCode((int) HttpStatusCode.InternalServerError, new GenericResponse(false, Strings.FormatErrorObjectIsNull(nameof(paramsValue))));
|
||||
}
|
||||
|
||||
IAttr? nonceNode = challengeResponse.Content.SelectSingleNode<IAttr>("//input[@name='nonce']/@value");
|
||||
@@ -86,7 +87,7 @@ public sealed class SignInWithSteamController : ArchiController {
|
||||
if (nonceNode == null) {
|
||||
ASF.ArchiLogger.LogNullError(nonceNode);
|
||||
|
||||
return StatusCode((int) HttpStatusCode.InternalServerError, new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorObjectIsNull, nameof(nonceNode))));
|
||||
return StatusCode((int) HttpStatusCode.InternalServerError, new GenericResponse(false, Strings.FormatErrorObjectIsNull(nameof(nonceNode))));
|
||||
}
|
||||
|
||||
string nonceValue = nonceNode.Value;
|
||||
@@ -94,7 +95,7 @@ public sealed class SignInWithSteamController : ArchiController {
|
||||
if (string.IsNullOrEmpty(nonceValue)) {
|
||||
ASF.ArchiLogger.LogNullError(nonceValue);
|
||||
|
||||
return StatusCode((int) HttpStatusCode.InternalServerError, new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorObjectIsNull, nameof(nonceValue))));
|
||||
return StatusCode((int) HttpStatusCode.InternalServerError, new GenericResponse(false, Strings.FormatErrorObjectIsNull(nameof(nonceValue))));
|
||||
}
|
||||
|
||||
Uri loginRequest = new(ArchiWebHandler.SteamCommunityURL, "/openid/login");
|
||||
@@ -114,6 +115,6 @@ public sealed class SignInWithSteamController : ArchiController {
|
||||
// Accept OpenID request presented and follow redirection back to the data we initially expected
|
||||
BasicResponse? loginResponse = await bot.ArchiWebHandler.WebBrowser.UrlPost(loginRequest, data: data, requestOptions: WebBrowser.ERequestOptions.ReturnRedirections).ConfigureAwait(false);
|
||||
|
||||
return loginResponse != null ? Ok(new GenericResponse<SignInWithSteamResponse>(new SignInWithSteamResponse(loginResponse.FinalUri))) : StatusCode((int) HttpStatusCode.ServiceUnavailable, new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)));
|
||||
return loginResponse != null ? Ok(new GenericResponse<SignInWithSteamResponse>(new SignInWithSteamResponse(loginResponse.FinalUri))) : StatusCode((int) HttpStatusCode.ServiceUnavailable, new GenericResponse(false, Strings.FormatErrorRequestFailedTooManyTimes(WebBrowser.MaxTries)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ConfigureAwaitChecker.Analyzer" PrivateAssets="all" />
|
||||
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.ResxSourceGenerator" PrivateAssets="all" />
|
||||
<PackageReference Include="SteamKit2" IncludeAssets="compile" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" IncludeAssets="compile" />
|
||||
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
|
||||
@@ -17,17 +17,6 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Localization\Strings.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Strings.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Localization\Strings.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Strings.resx</DependentUpon>
|
||||
<DesignTime>True</DesignTime>
|
||||
</Compile>
|
||||
<EmbeddedResource Update="Localization\Strings.resx" EmitFormatMethods="true" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
@@ -41,7 +43,7 @@ using SteamKit2;
|
||||
namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher;
|
||||
|
||||
internal static class Backend {
|
||||
internal static async Task<ObjectResponse<GenericResponse<BackgroundTaskResponse>>?> AnnounceDiffForListing(WebBrowser webBrowser, ulong steamID, IReadOnlyCollection<AssetForListing> inventory, string inventoryChecksum, IReadOnlyCollection<Asset.EType> acceptedMatchableTypes, uint totalInventoryCount, bool matchEverything, string tradeToken, IReadOnlyCollection<AssetForListing> inventoryRemoved, string? previousInventoryChecksum, string? nickname = null, string? avatarHash = null) {
|
||||
internal static async Task<ObjectResponse<GenericResponse<BackgroundTaskResponse>>?> AnnounceDiffForListing(WebBrowser webBrowser, ulong steamID, IReadOnlyCollection<AssetForListing> inventory, string inventoryChecksum, IReadOnlyCollection<EAssetType> acceptedMatchableTypes, uint totalInventoryCount, bool matchEverything, string tradeToken, IReadOnlyCollection<AssetForListing> inventoryRemoved, string? previousInventoryChecksum, string? nickname = null, string? avatarHash = null) {
|
||||
ArgumentNullException.ThrowIfNull(webBrowser);
|
||||
|
||||
if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount) {
|
||||
@@ -72,7 +74,7 @@ internal static class Backend {
|
||||
return await webBrowser.UrlPostToJsonObject<GenericResponse<BackgroundTaskResponse>, AnnouncementDiffRequest>(request, data: data, requestOptions: WebBrowser.ERequestOptions.ReturnRedirections | WebBrowser.ERequestOptions.ReturnClientErrors | WebBrowser.ERequestOptions.AllowInvalidBodyOnErrors | WebBrowser.ERequestOptions.CompressRequest).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal static async Task<ObjectResponse<GenericResponse<BackgroundTaskResponse>>?> AnnounceForListing(WebBrowser webBrowser, ulong steamID, IReadOnlyCollection<AssetForListing> inventory, string inventoryChecksum, IReadOnlyCollection<Asset.EType> acceptedMatchableTypes, uint totalInventoryCount, bool matchEverything, string tradeToken, string? nickname = null, string? avatarHash = null) {
|
||||
internal static async Task<ObjectResponse<GenericResponse<BackgroundTaskResponse>>?> AnnounceForListing(WebBrowser webBrowser, ulong steamID, IReadOnlyCollection<AssetForListing> inventory, string inventoryChecksum, IReadOnlyCollection<EAssetType> acceptedMatchableTypes, uint totalInventoryCount, bool matchEverything, string tradeToken, string? nickname = null, string? avatarHash = null) {
|
||||
ArgumentNullException.ThrowIfNull(webBrowser);
|
||||
|
||||
if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount) {
|
||||
@@ -129,7 +131,7 @@ internal static class Backend {
|
||||
return response?.StatusCode;
|
||||
}
|
||||
|
||||
internal static async Task<(HttpStatusCode StatusCode, ImmutableHashSet<ListedUser> Users)?> GetListedUsersForMatching(Guid licenseID, Bot bot, WebBrowser webBrowser, IReadOnlyCollection<Asset> inventory, IReadOnlyCollection<Asset.EType> acceptedMatchableTypes) {
|
||||
internal static async Task<(HttpStatusCode StatusCode, ImmutableHashSet<ListedUser> Users)?> GetListedUsersForMatching(Guid licenseID, Bot bot, WebBrowser webBrowser, IReadOnlyCollection<Asset> inventory, IReadOnlyCollection<EAssetType> acceptedMatchableTypes) {
|
||||
ArgumentOutOfRangeException.ThrowIfEqual(licenseID, Guid.Empty);
|
||||
ArgumentNullException.ThrowIfNull(bot);
|
||||
ArgumentNullException.ThrowIfNull(webBrowser);
|
||||
@@ -156,10 +158,10 @@ internal static class Backend {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (response.StatusCode, response.Content?.Result ?? ImmutableHashSet<ListedUser>.Empty);
|
||||
return (response.StatusCode, response.Content?.Result ?? []);
|
||||
}
|
||||
|
||||
internal static async Task<ObjectResponse<GenericResponse<ImmutableHashSet<SetPart>>>?> GetSetParts(WebBrowser webBrowser, ulong steamID, IReadOnlyCollection<Asset.EType> matchableTypes, IReadOnlyCollection<uint> realAppIDs, CancellationToken cancellationToken = default) {
|
||||
internal static async Task<ObjectResponse<GenericResponse<ImmutableHashSet<SetPart>>>?> GetSetParts(WebBrowser webBrowser, ulong steamID, IReadOnlyCollection<EAssetType> matchableTypes, IReadOnlyCollection<uint> realAppIDs, CancellationToken cancellationToken = default) {
|
||||
ArgumentNullException.ThrowIfNull(webBrowser);
|
||||
|
||||
if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount) {
|
||||
@@ -201,7 +203,7 @@ internal static class Backend {
|
||||
|
||||
ArgumentOutOfRangeException.ThrowIfEqual(requestID, Guid.Empty);
|
||||
|
||||
if (SharedInfo.BuildInfo.IsCustomBuild) {
|
||||
if (BuildInfo.IsCustomBuild) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
@@ -20,7 +22,6 @@
|
||||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
@@ -133,7 +134,7 @@ internal sealed class BotCache : SerializableFile {
|
||||
string json = await File.ReadAllTextAsync(filePath).ConfigureAwait(false);
|
||||
|
||||
if (string.IsNullOrEmpty(json)) {
|
||||
ASF.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(json)));
|
||||
ASF.ArchiLogger.LogGenericError(Strings.FormatErrorIsEmpty(nameof(json)));
|
||||
|
||||
return new BotCache(filePath);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
@@ -22,7 +24,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.Core;
|
||||
@@ -85,15 +86,15 @@ internal static class Commands {
|
||||
}
|
||||
|
||||
if (bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.MatchEverything)) {
|
||||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(BotConfig.ETradingPreferences.MatchEverything)));
|
||||
return bot.Commands.FormatBotResponse(Strings.FormatWarningFailedWithError(nameof(BotConfig.ETradingPreferences.MatchEverything)));
|
||||
}
|
||||
|
||||
if ((ASF.GlobalConfig?.LicenseID == null) || (ASF.GlobalConfig.LicenseID == Guid.Empty)) {
|
||||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(ASF.GlobalConfig.LicenseID)));
|
||||
return bot.Commands.FormatBotResponse(Strings.FormatWarningFailedWithError(nameof(ASF.GlobalConfig.LicenseID)));
|
||||
}
|
||||
|
||||
if (!ItemsMatcherPlugin.RemoteCommunications.TryGetValue(bot, out RemoteCommunication? remoteCommunication)) {
|
||||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(remoteCommunication)));
|
||||
return bot.Commands.FormatBotResponse(Strings.FormatWarningFailedWithError(nameof(remoteCommunication)));
|
||||
}
|
||||
|
||||
remoteCommunication.TriggerMatchActivelyEarlier();
|
||||
@@ -115,12 +116,12 @@ internal static class Commands {
|
||||
HashSet<Bot>? bots = Bot.GetBots(botNames);
|
||||
|
||||
if ((bots == null) || (bots.Count == 0)) {
|
||||
return access >= EAccess.Owner ? Steam.Interaction.Commands.FormatStaticResponse(string.Format(CultureInfo.CurrentCulture, Strings.BotNotFound, botNames)) : null;
|
||||
return access >= EAccess.Owner ? Steam.Interaction.Commands.FormatStaticResponse(Strings.FormatBotNotFound(botNames)) : null;
|
||||
}
|
||||
|
||||
IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => ResponseMatch(Steam.Interaction.Commands.GetProxyAccess(bot, access, steamID), bot)))).ConfigureAwait(false);
|
||||
|
||||
List<string> responses = [..results.Where(static result => !string.IsNullOrEmpty(result))];
|
||||
List<string> responses = [..results.Where(static result => !string.IsNullOrEmpty(result))!];
|
||||
|
||||
return responses.Count > 0 ? string.Join(Environment.NewLine, responses) : null;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
@@ -38,7 +40,7 @@ internal sealed class AnnouncementDiffRequest : AnnouncementRequest {
|
||||
[JsonRequired]
|
||||
private string PreviousInventoryChecksum { get; init; }
|
||||
|
||||
internal AnnouncementDiffRequest(Guid guid, ulong steamID, IReadOnlyCollection<AssetForListing> inventory, string inventoryChecksum, IReadOnlyCollection<Asset.EType> matchableTypes, uint totalInventoryCount, bool matchEverything, byte maxTradeHoldDuration, string tradeToken, IReadOnlyCollection<AssetForListing> inventoryRemoved, string previousInventoryChecksum, string? nickname = null, string? avatarHash = null) : base(guid, steamID, inventory, inventoryChecksum, matchableTypes, totalInventoryCount, matchEverything, maxTradeHoldDuration, tradeToken, nickname, avatarHash) {
|
||||
internal AnnouncementDiffRequest(Guid guid, ulong steamID, IReadOnlyCollection<AssetForListing> inventory, string inventoryChecksum, IReadOnlyCollection<EAssetType> matchableTypes, uint totalInventoryCount, bool matchEverything, byte maxTradeHoldDuration, string tradeToken, IReadOnlyCollection<AssetForListing> inventoryRemoved, string previousInventoryChecksum, string? nickname = null, string? avatarHash = null) : base(guid, steamID, inventory, inventoryChecksum, matchableTypes, totalInventoryCount, matchEverything, maxTradeHoldDuration, tradeToken, nickname, avatarHash) {
|
||||
ArgumentOutOfRangeException.ThrowIfEqual(guid, Guid.Empty);
|
||||
|
||||
if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount) {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
@@ -48,7 +50,7 @@ internal class AnnouncementRequest {
|
||||
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
private ImmutableHashSet<Asset.EType> MatchableTypes { get; init; }
|
||||
private ImmutableHashSet<EAssetType> MatchableTypes { get; init; }
|
||||
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
@@ -73,7 +75,7 @@ internal class AnnouncementRequest {
|
||||
[JsonRequired]
|
||||
private string TradeToken { get; init; }
|
||||
|
||||
internal AnnouncementRequest(Guid guid, ulong steamID, IReadOnlyCollection<AssetForListing> inventory, string inventoryChecksum, IReadOnlyCollection<Asset.EType> matchableTypes, uint totalInventoryCount, bool matchEverything, byte maxTradeHoldDuration, string tradeToken, string? nickname = null, string? avatarHash = null) {
|
||||
internal AnnouncementRequest(Guid guid, ulong steamID, IReadOnlyCollection<AssetForListing> inventory, string inventoryChecksum, IReadOnlyCollection<EAssetType> matchableTypes, uint totalInventoryCount, bool matchEverything, byte maxTradeHoldDuration, string tradeToken, string? nickname = null, string? avatarHash = null) {
|
||||
ArgumentOutOfRangeException.ThrowIfEqual(guid, Guid.Empty);
|
||||
|
||||
if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount) {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
@@ -39,7 +41,7 @@ internal class AssetForMatching {
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("r")]
|
||||
[JsonRequired]
|
||||
internal Asset.ERarity Rarity { get; private init; }
|
||||
internal EAssetRarity Rarity { get; private init; }
|
||||
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("e")]
|
||||
@@ -54,7 +56,7 @@ internal class AssetForMatching {
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("p")]
|
||||
[JsonRequired]
|
||||
internal Asset.EType Type { get; private init; }
|
||||
internal EAssetType Type { get; private init; }
|
||||
|
||||
[JsonConstructor]
|
||||
protected AssetForMatching() { }
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
@@ -40,5 +42,5 @@ internal class AssetInInventory : AssetForMatching {
|
||||
AssetID = asset.AssetID;
|
||||
}
|
||||
|
||||
internal Asset ToAsset() => new(Asset.SteamAppID, Asset.SteamCommunityContextID, ClassID, Amount, tradable: Tradable, assetID: AssetID, realAppID: RealAppID, type: Type, rarity: Rarity);
|
||||
internal Asset ToAsset() => new(Asset.SteamAppID, Asset.SteamCommunityContextID, ClassID, Amount, new InventoryDescription(Asset.SteamAppID, ClassID, tradable: Tradable, realAppID: RealAppID, type: Type, rarity: Rarity), AssetID);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
@@ -40,13 +42,13 @@ internal sealed class InventoriesRequest {
|
||||
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
internal ImmutableHashSet<Asset.EType> MatchableTypes { get; private init; }
|
||||
internal ImmutableHashSet<EAssetType> MatchableTypes { get; private init; }
|
||||
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
internal ulong SteamID { get; private init; }
|
||||
|
||||
internal InventoriesRequest(Guid guid, ulong steamID, IReadOnlyCollection<Asset> inventory, IReadOnlyCollection<Asset.EType> matchableTypes) {
|
||||
internal InventoriesRequest(Guid guid, ulong steamID, IReadOnlyCollection<Asset> inventory, IReadOnlyCollection<EAssetType> matchableTypes) {
|
||||
ArgumentOutOfRangeException.ThrowIfEqual(guid, Guid.Empty);
|
||||
|
||||
if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount) {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
@@ -31,11 +33,11 @@ namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Data;
|
||||
internal sealed class ListedUser {
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
internal ImmutableHashSet<AssetInInventory> Assets { get; private init; } = ImmutableHashSet<AssetInInventory>.Empty;
|
||||
internal ImmutableHashSet<AssetInInventory> Assets { get; private init; } = [];
|
||||
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
internal ImmutableHashSet<Asset.EType> MatchableTypes { get; private init; } = ImmutableHashSet<Asset.EType>.Empty;
|
||||
internal ImmutableHashSet<EAssetType> MatchableTypes { get; private init; } = [];
|
||||
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
@@ -36,7 +38,7 @@ internal sealed class SetPart {
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("r")]
|
||||
[JsonRequired]
|
||||
internal Asset.ERarity Rarity { get; private init; }
|
||||
internal EAssetRarity Rarity { get; private init; }
|
||||
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("e")]
|
||||
@@ -46,7 +48,7 @@ internal sealed class SetPart {
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("p")]
|
||||
[JsonRequired]
|
||||
internal Asset.EType Type { get; private init; }
|
||||
internal EAssetType Type { get; private init; }
|
||||
|
||||
[JsonConstructor]
|
||||
private SetPart() { }
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
@@ -35,7 +37,7 @@ internal sealed class SetPartsRequest {
|
||||
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
internal ImmutableHashSet<Asset.EType> MatchableTypes { get; private init; }
|
||||
internal ImmutableHashSet<EAssetType> MatchableTypes { get; private init; }
|
||||
|
||||
[JsonInclude]
|
||||
[JsonRequired]
|
||||
@@ -45,7 +47,7 @@ internal sealed class SetPartsRequest {
|
||||
[JsonRequired]
|
||||
internal ulong SteamID { get; private init; }
|
||||
|
||||
internal SetPartsRequest(Guid guid, ulong steamID, IReadOnlyCollection<Asset.EType> matchableTypes, IReadOnlyCollection<uint> realAppIDs) {
|
||||
internal SetPartsRequest(Guid guid, ulong steamID, IReadOnlyCollection<EAssetType> matchableTypes, IReadOnlyCollection<uint> realAppIDs) {
|
||||
ArgumentOutOfRangeException.ThrowIfEqual(guid, Guid.Empty);
|
||||
|
||||
if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount) {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Localization {
|
||||
using System;
|
||||
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Strings {
|
||||
|
||||
private static System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Strings() {
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.Equals(null, resourceMan)) {
|
||||
System.Resources.ResourceManager temp = new System.Resources.ResourceManager("ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Localization.Strings", typeof(Strings).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal static string ActivelyMatchingItemsRound {
|
||||
get {
|
||||
return ResourceManager.GetString("ActivelyMatchingItemsRound", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string ListingAnnouncing {
|
||||
get {
|
||||
return ResourceManager.GetString("ListingAnnouncing", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string MatchingFound {
|
||||
get {
|
||||
return ResourceManager.GetString("MatchingFound", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string TradeOfferFailed {
|
||||
get {
|
||||
return ResourceManager.GetString("TradeOfferFailed", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string ActivelyMatchingSomeConfirmationsFailed {
|
||||
get {
|
||||
return ResourceManager.GetString("ActivelyMatchingSomeConfirmationsFailed", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
</root>
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingSomeConfirmationsFailed" xml:space="preserve">
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string"/>
|
||||
<xsd:attribute name="type" type="xsd:string"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string"/>
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
|
||||
<xsd:attribute ref="xml:space"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
</root>
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,19 +53,29 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
<value>{0} sets ont été matché pendant ce round.</value>
|
||||
<comment>{0} will be replaced by number of sets traded</comment>
|
||||
</data>
|
||||
<data name="ListingAnnouncing" xml:space="preserve">
|
||||
<value>Annonce de {0} ({1}) avec l'inventaire réalisé à partir de {2} au total sur la liste...</value>
|
||||
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname, {2} will be replaced with number of items in the inventory</comment>
|
||||
</data>
|
||||
<data name="MatchingFound" xml:space="preserve">
|
||||
<value>Correspondance totale de {0} éléments avec le bot {1} ({2}), envoi de l'offre d'échange...</value>
|
||||
<comment>{0} will be replaced by number of items matched, {1} will be replaced by steam ID (number), {2} will be replaced by user's nickname</comment>
|
||||
</data>
|
||||
<data name="TradeOfferFailed" xml:space="preserve">
|
||||
<value>Impossible d'envoyer une offre d'échange au bot {0} ({1}), en cours ...</value>
|
||||
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname'</comment>
|
||||
</data>
|
||||
<data name="ActivelyMatchingSomeConfirmationsFailed" xml:space="preserve">
|
||||
<value>Certaines confirmations ont échoué, environ {0} sur les transactions {1} ont été envoyées avec succès.</value>
|
||||
<comment>{0} will be replaced by amount of the trade offers that succeeded (number), {1} will be replaced by amount of the trade offers that were supposed to be sent in total (number)</comment>
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
</root>
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
</root>
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,17 +53,31 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
<value>Potivim un total de {0} in această rundă.</value>
|
||||
<comment>{0} will be replaced by number of sets traded</comment>
|
||||
</data>
|
||||
<data name="ListingAnnouncing" xml:space="preserve">
|
||||
<value>Anunțând {0} ({1}) cu inventarul făcut din {2} articole în total pe listă...</value>
|
||||
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname, {2} will be replaced with number of items in the inventory</comment>
|
||||
</data>
|
||||
<data name="MatchingFound" xml:space="preserve">
|
||||
<value>Se potrivește cu un total de {0} elemente cu botul {1} ({2}), se trimite oferta de schimb...</value>
|
||||
<comment>{0} will be replaced by number of items matched, {1} will be replaced by steam ID (number), {2} will be replaced by user's nickname</comment>
|
||||
</data>
|
||||
<data name="TradeOfferFailed" xml:space="preserve">
|
||||
<value>Nu s-a putut trimite o cerere de schimb bot-ului {0} ({1}), trecem peste...</value>
|
||||
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname'</comment>
|
||||
</data>
|
||||
<data name="ActivelyMatchingSomeConfirmationsFailed" xml:space="preserve">
|
||||
<value>Unele confirmări au eșuat, aproximativ {0} din {1} de schimburi au fost trimise cu succes.</value>
|
||||
<comment>{0} will be replaced by amount of the trade offers that succeeded (number), {1} will be replaced by amount of the trade offers that were supposed to be sent in total (number)</comment>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
</root>
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
</root>
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
|
||||
|
||||
191
ArchiSteamFarm.OfficialPlugins.ItemsMatcher/MatchingUtilities.cs
Normal file
191
ArchiSteamFarm.OfficialPlugins.ItemsMatcher/MatchingUtilities.cs
Normal file
@@ -0,0 +1,191 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
// |
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// |
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// |
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ArchiSteamFarm.Steam.Data;
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher;
|
||||
|
||||
internal static class MatchingUtilities {
|
||||
internal static (Dictionary<(uint RealAppID, EAssetType Type, EAssetRarity Rarity), Dictionary<ulong, uint>> FullState, Dictionary<(uint RealAppID, EAssetType Type, EAssetRarity Rarity), Dictionary<ulong, uint>> TradableState) GetDividedInventoryState(IReadOnlyCollection<Asset> inventory) {
|
||||
if ((inventory == null) || (inventory.Count == 0)) {
|
||||
throw new ArgumentNullException(nameof(inventory));
|
||||
}
|
||||
|
||||
Dictionary<(uint RealAppID, EAssetType Type, EAssetRarity Rarity), Dictionary<ulong, uint>> fullState = new();
|
||||
Dictionary<(uint RealAppID, EAssetType Type, EAssetRarity Rarity), Dictionary<ulong, uint>> tradableState = new();
|
||||
|
||||
foreach (Asset item in inventory) {
|
||||
(uint RealAppID, EAssetType Type, EAssetRarity Rarity) key = (item.RealAppID, item.Type, item.Rarity);
|
||||
|
||||
if (fullState.TryGetValue(key, out Dictionary<ulong, uint>? fullSet)) {
|
||||
fullSet[item.ClassID] = fullSet.GetValueOrDefault(item.ClassID) + item.Amount;
|
||||
} else {
|
||||
fullState[key] = new Dictionary<ulong, uint> { { item.ClassID, item.Amount } };
|
||||
}
|
||||
|
||||
if (!item.Tradable) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tradableState.TryGetValue(key, out Dictionary<ulong, uint>? tradableSet)) {
|
||||
tradableSet[item.ClassID] = tradableSet.GetValueOrDefault(item.ClassID) + item.Amount;
|
||||
} else {
|
||||
tradableState[key] = new Dictionary<ulong, uint> { { item.ClassID, item.Amount } };
|
||||
}
|
||||
}
|
||||
|
||||
return (fullState, tradableState);
|
||||
}
|
||||
|
||||
internal static Dictionary<(uint RealAppID, EAssetType Type, EAssetRarity Rarity), Dictionary<ulong, uint>> GetTradableInventoryState(IReadOnlyCollection<Asset> inventory) {
|
||||
if ((inventory == null) || (inventory.Count == 0)) {
|
||||
throw new ArgumentNullException(nameof(inventory));
|
||||
}
|
||||
|
||||
Dictionary<(uint RealAppID, EAssetType Type, EAssetRarity Rarity), Dictionary<ulong, uint>> tradableState = new();
|
||||
|
||||
foreach (Asset item in inventory.Where(static item => item.Tradable)) {
|
||||
(uint RealAppID, EAssetType Type, EAssetRarity Rarity) key = (item.RealAppID, item.Type, item.Rarity);
|
||||
|
||||
if (tradableState.TryGetValue(key, out Dictionary<ulong, uint>? tradableSet)) {
|
||||
tradableSet[item.ClassID] = tradableSet.GetValueOrDefault(item.ClassID) + item.Amount;
|
||||
} else {
|
||||
tradableState[key] = new Dictionary<ulong, uint> { { item.ClassID, item.Amount } };
|
||||
}
|
||||
}
|
||||
|
||||
return tradableState;
|
||||
}
|
||||
|
||||
internal static HashSet<Asset> GetTradableItemsFromInventory(IReadOnlyCollection<Asset> inventory, IReadOnlyDictionary<ulong, uint> classIDs, bool randomize = false) {
|
||||
if ((inventory == null) || (inventory.Count == 0)) {
|
||||
throw new ArgumentNullException(nameof(inventory));
|
||||
}
|
||||
|
||||
if ((classIDs == null) || (classIDs.Count == 0)) {
|
||||
throw new ArgumentNullException(nameof(classIDs));
|
||||
}
|
||||
|
||||
// We need a copy of classIDs passed since we're going to manipulate them
|
||||
Dictionary<ulong, uint> classIDsState = classIDs.ToDictionary();
|
||||
|
||||
HashSet<Asset> result = [];
|
||||
|
||||
IEnumerable<Asset> items = inventory.Where(static item => item.Tradable);
|
||||
|
||||
// Randomization helps to decrease "items no longer available" in regards to sending offers to other users
|
||||
if (randomize) {
|
||||
#pragma warning disable CA5394 // This call isn't used in a security-sensitive manner
|
||||
items = items.Where(item => classIDsState.ContainsKey(item.ClassID)).OrderBy(static _ => Random.Shared.Next());
|
||||
#pragma warning restore CA5394 // This call isn't used in a security-sensitive manner
|
||||
}
|
||||
|
||||
foreach (Asset item in items) {
|
||||
if (!classIDsState.TryGetValue(item.ClassID, out uint amount)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (amount >= item.Amount) {
|
||||
result.Add(item);
|
||||
|
||||
if (amount > item.Amount) {
|
||||
classIDsState[item.ClassID] = amount - item.Amount;
|
||||
} else {
|
||||
classIDsState.Remove(item.ClassID);
|
||||
|
||||
if (classIDsState.Count == 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Asset itemToAdd = item.DeepClone();
|
||||
|
||||
itemToAdd.Amount = amount;
|
||||
|
||||
result.Add(itemToAdd);
|
||||
|
||||
classIDsState.Remove(itemToAdd.ClassID);
|
||||
|
||||
if (classIDsState.Count == 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we got here it means we still have classIDs to match
|
||||
throw new InvalidOperationException(nameof(classIDs));
|
||||
}
|
||||
|
||||
internal static bool IsEmptyForMatching(IReadOnlyDictionary<(uint RealAppID, EAssetType Type, EAssetRarity Rarity), Dictionary<ulong, uint>> fullState, IReadOnlyDictionary<(uint RealAppID, EAssetType Type, EAssetRarity Rarity), Dictionary<ulong, uint>> tradableState) {
|
||||
ArgumentNullException.ThrowIfNull(fullState);
|
||||
ArgumentNullException.ThrowIfNull(tradableState);
|
||||
|
||||
foreach (((uint RealAppID, EAssetType Type, EAssetRarity Rarity) set, IReadOnlyDictionary<ulong, uint> state) in tradableState) {
|
||||
if (!fullState.TryGetValue(set, out Dictionary<ulong, uint>? fullSet) || (fullSet.Count == 0)) {
|
||||
throw new InvalidOperationException(nameof(fullSet));
|
||||
}
|
||||
|
||||
if (!IsEmptyForMatching(fullSet, state)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// We didn't find any matchable combinations, so this inventory is empty
|
||||
return true;
|
||||
}
|
||||
|
||||
internal static bool IsEmptyForMatching(IReadOnlyDictionary<ulong, uint> fullSet, IReadOnlyDictionary<ulong, uint> tradableSet) {
|
||||
ArgumentNullException.ThrowIfNull(fullSet);
|
||||
ArgumentNullException.ThrowIfNull(tradableSet);
|
||||
|
||||
foreach ((ulong classID, uint amount) in tradableSet) {
|
||||
switch (amount) {
|
||||
case 0:
|
||||
// No tradable items, this should never happen, dictionary should not have this key to begin with
|
||||
throw new InvalidOperationException(nameof(amount));
|
||||
case 1:
|
||||
// Single tradable item, can be matchable or not depending on the rest of the inventory
|
||||
if (!fullSet.TryGetValue(classID, out uint fullAmount) || (fullAmount == 0)) {
|
||||
throw new InvalidOperationException(nameof(fullAmount));
|
||||
}
|
||||
|
||||
if (fullAmount > 1) {
|
||||
// If we have a single tradable item but more than 1 in total, this is matchable
|
||||
return false;
|
||||
}
|
||||
|
||||
// A single exclusive tradable item is not matchable, continue
|
||||
continue;
|
||||
default:
|
||||
// Any other combination of tradable items is always matchable
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// We didn't find any matchable combinations, so this inventory is empty
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
@@ -27,7 +29,6 @@ using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -61,11 +62,11 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
private const byte MinimumSteamGuardEnabledDays = 15; // As imposed by Steam limits
|
||||
private const byte MinPersonaStateTTL = 5; // Minimum amount of minutes we must wait before requesting persona state update
|
||||
|
||||
private static readonly FrozenSet<Asset.EType> AcceptedMatchableTypes = new HashSet<Asset.EType>(4) {
|
||||
Asset.EType.Emoticon,
|
||||
Asset.EType.FoilTradingCard,
|
||||
Asset.EType.ProfileBackground,
|
||||
Asset.EType.TradingCard
|
||||
private static readonly FrozenSet<EAssetType> AcceptedMatchableTypes = new HashSet<EAssetType>(4) {
|
||||
EAssetType.Emoticon,
|
||||
EAssetType.FoilTradingCard,
|
||||
EAssetType.ProfileBackground,
|
||||
EAssetType.TradingCard
|
||||
}.ToFrozenSet();
|
||||
|
||||
private readonly Bot Bot;
|
||||
@@ -110,7 +111,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
TimeSpan.FromHours(6)
|
||||
);
|
||||
} else {
|
||||
bot.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningNoLicense, nameof(BotConfig.ETradingPreferences.MatchActively)));
|
||||
bot.ArchiLogger.LogGenericError(Strings.FormatWarningNoLicense(nameof(BotConfig.ETradingPreferences.MatchActively)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -214,7 +215,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
// This is actually network failure, so we'll stop sending heartbeats but not record it as valid check
|
||||
ShouldSendHeartBeats = false;
|
||||
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(IsEligibleForListing)}: {eligible?.ToString() ?? "null"}"));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatWarningFailedWithError($"{nameof(IsEligibleForListing)}: {eligible?.ToString() ?? "null"}"));
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -224,12 +225,12 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
LastAnnouncement = DateTime.UtcNow;
|
||||
ShouldSendAnnouncementEarlier = ShouldSendHeartBeats = false;
|
||||
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(IsEligibleForListing)}: {eligible.Value}"));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatWarningFailedWithError($"{nameof(IsEligibleForListing)}: {eligible.Value}"));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
HashSet<Asset.EType> acceptedMatchableTypes = Bot.BotConfig.MatchableTypes.Where(AcceptedMatchableTypes.Contains).ToHashSet();
|
||||
HashSet<EAssetType> acceptedMatchableTypes = Bot.BotConfig.MatchableTypes.Where(AcceptedMatchableTypes.Contains).ToHashSet();
|
||||
|
||||
if (acceptedMatchableTypes.Count == 0) {
|
||||
throw new InvalidOperationException(nameof(acceptedMatchableTypes));
|
||||
@@ -241,7 +242,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
// This is actually a network failure, so we'll stop sending heartbeats but not record it as valid check
|
||||
ShouldSendHeartBeats = false;
|
||||
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(tradeToken)));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatWarningFailedWithError(nameof(tradeToken)));
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -250,8 +251,8 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
List<Asset> inventory;
|
||||
|
||||
try {
|
||||
inventory = await Bot.ArchiWebHandler.GetInventoryAsync().ToListAsync().ConfigureAwait(false);
|
||||
} catch (HttpRequestException e) {
|
||||
inventory = await Bot.ArchiHandler.GetMyInventoryAsync().ToListAsync().ConfigureAwait(false);
|
||||
} catch (TimeoutException e) {
|
||||
// This is actually a network failure, so we'll stop sending heartbeats but not record it as valid check
|
||||
ShouldSendHeartBeats = false;
|
||||
|
||||
@@ -282,10 +283,10 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
|
||||
List<AssetForListing> assetsForListing = [];
|
||||
|
||||
Dictionary<(uint RealAppID, Asset.EType Type, Asset.ERarity Rarity), bool> tradableSets = new();
|
||||
Dictionary<(uint RealAppID, EAssetType Type, EAssetRarity Rarity), bool> tradableSets = new();
|
||||
|
||||
foreach (Asset item in inventory) {
|
||||
if (item is { AssetID: > 0, Amount: > 0, ClassID: > 0, RealAppID: > 0, Type: > Asset.EType.Unknown, Rarity: > Asset.ERarity.Unknown, IsSteamPointsShopItem: false } && acceptedMatchableTypes.Contains(item.Type)) {
|
||||
if (item is { AssetID: > 0, Amount: > 0, ClassID: > 0, RealAppID: > 0, Type: > EAssetType.Unknown, Rarity: > EAssetRarity.Unknown, IsSteamPointsShopItem: false } && acceptedMatchableTypes.Contains(item.Type)) {
|
||||
// Only tradable assets matter for MatchEverything bots
|
||||
if (!matchEverything || item.Tradable) {
|
||||
assetsForListing.Add(new AssetForListing(item, index, previousAssetID));
|
||||
@@ -293,7 +294,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
|
||||
// But even for Fair bots, we should track and skip sets where we don't have any item to trade with
|
||||
if (!matchEverything) {
|
||||
(uint RealAppID, Asset.EType Type, Asset.ERarity Rarity) key = (item.RealAppID, item.Type, item.Rarity);
|
||||
(uint RealAppID, EAssetType Type, EAssetRarity Rarity) key = (item.RealAppID, item.Type, item.Rarity);
|
||||
|
||||
if (tradableSets.TryGetValue(key, out bool tradable)) {
|
||||
if (!tradable && item.Tradable) {
|
||||
@@ -375,15 +376,15 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
if (!matchEverything) {
|
||||
// We should deduplicate our sets before sending them to the server, for doing that we'll use ASFB set parts data
|
||||
HashSet<uint> realAppIDs = [];
|
||||
Dictionary<(uint RealAppID, Asset.EType Type, Asset.ERarity Rarity), Dictionary<ulong, uint>> state = new();
|
||||
Dictionary<(uint RealAppID, EAssetType Type, EAssetRarity Rarity), Dictionary<ulong, uint>> state = new();
|
||||
|
||||
foreach (AssetForListing asset in assetsForListing) {
|
||||
realAppIDs.Add(asset.RealAppID);
|
||||
|
||||
(uint RealAppID, Asset.EType Type, Asset.ERarity Rarity) key = (asset.RealAppID, asset.Type, asset.Rarity);
|
||||
(uint RealAppID, EAssetType Type, EAssetRarity Rarity) key = (asset.RealAppID, asset.Type, asset.Rarity);
|
||||
|
||||
if (state.TryGetValue(key, out Dictionary<ulong, uint>? set)) {
|
||||
set[asset.ClassID] = set.TryGetValue(asset.ClassID, out uint amount) ? amount + asset.Amount : asset.Amount;
|
||||
set[asset.ClassID] = set.GetValueOrDefault(asset.ClassID) + asset.Amount;
|
||||
} else {
|
||||
state[key] = new Dictionary<ulong, uint> { { asset.ClassID, asset.Amount } };
|
||||
}
|
||||
@@ -394,17 +395,17 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
if (setPartsResponse == null) {
|
||||
// This is actually a network failure, so we'll stop sending heartbeats but not record it as valid check
|
||||
ShouldSendHeartBeats = false;
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.ErrorObjectIsNull, nameof(setPartsResponse)));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatErrorObjectIsNull(nameof(setPartsResponse)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (setPartsResponse.StatusCode.IsRedirectionCode()) {
|
||||
ShouldSendHeartBeats = false;
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, setPartsResponse.StatusCode));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatWarningFailedWithError(setPartsResponse.StatusCode));
|
||||
|
||||
if (setPartsResponse.FinalUri.Host != ArchiWebHandler.SteamCommunityURL.Host) {
|
||||
ASF.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownValuePleaseReport, nameof(setPartsResponse.FinalUri), setPartsResponse.FinalUri));
|
||||
ASF.ArchiLogger.LogGenericError(Strings.FormatWarningUnknownValuePleaseReport(nameof(setPartsResponse.FinalUri), setPartsResponse.FinalUri));
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -418,7 +419,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
if (!setPartsResponse.StatusCode.IsSuccessCode()) {
|
||||
// ArchiNet told us that we've sent a bad request, so the process should restart from the beginning at later time
|
||||
ShouldSendHeartBeats = false;
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, setPartsResponse.StatusCode));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatWarningFailedWithError(setPartsResponse.StatusCode));
|
||||
|
||||
switch (setPartsResponse.StatusCode) {
|
||||
case HttpStatusCode.Forbidden:
|
||||
@@ -441,16 +442,16 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
|
||||
if (setPartsResponse.Content?.Result == null) {
|
||||
// This should never happen if we got the correct response
|
||||
Bot.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownValuePleaseReport, nameof(setPartsResponse), setPartsResponse.Content?.Result));
|
||||
Bot.ArchiLogger.LogGenericError(Strings.FormatWarningUnknownValuePleaseReport(nameof(setPartsResponse), setPartsResponse.Content?.Result));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Dictionary<(uint RealAppID, Asset.EType Type, Asset.ERarity Rarity), HashSet<ulong>> databaseSets = setPartsResponse.Content.Result.GroupBy(static setPart => (setPart.RealAppID, setPart.Type, setPart.Rarity)).ToDictionary(static group => group.Key, static group => group.Select(static setPart => setPart.ClassID).ToHashSet());
|
||||
Dictionary<(uint RealAppID, EAssetType Type, EAssetRarity Rarity), HashSet<ulong>> databaseSets = setPartsResponse.Content.Result.GroupBy(static setPart => (setPart.RealAppID, setPart.Type, setPart.Rarity)).ToDictionary(static group => group.Key, static group => group.Select(static setPart => setPart.ClassID).ToHashSet());
|
||||
|
||||
Dictionary<ulong, uint> setCopy = [];
|
||||
|
||||
foreach (((uint RealAppID, Asset.EType Type, Asset.ERarity Rarity) key, Dictionary<ulong, uint> set) in state) {
|
||||
foreach (((uint RealAppID, EAssetType Type, EAssetRarity Rarity) key, Dictionary<ulong, uint> set) in state) {
|
||||
if (!databaseSets.TryGetValue(key, out HashSet<ulong>? databaseSet)) {
|
||||
// We have no clue about this set, we can't do any optimization
|
||||
continue;
|
||||
@@ -488,7 +489,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
HashSet<AssetForListing> assetsForListingFiltered = [];
|
||||
|
||||
foreach (AssetForListing asset in assetsForListing.Where(asset => state.TryGetValue((asset.RealAppID, asset.Type, asset.Rarity), out Dictionary<ulong, uint>? setState) && setState.TryGetValue(asset.ClassID, out uint targetAmount) && (targetAmount > 0)).OrderByDescending(static asset => asset.Tradable).ThenByDescending(static asset => asset.Index)) {
|
||||
(uint RealAppID, Asset.EType Type, Asset.ERarity Rarity) key = (asset.RealAppID, asset.Type, asset.Rarity);
|
||||
(uint RealAppID, EAssetType Type, EAssetRarity Rarity) key = (asset.RealAppID, asset.Type, asset.Rarity);
|
||||
|
||||
if (!state.TryGetValue(key, out Dictionary<ulong, uint>? setState) || !setState.TryGetValue(asset.ClassID, out uint targetAmount) || (targetAmount == 0)) {
|
||||
// We're not interested in this combination
|
||||
@@ -530,7 +531,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
// There is a possibility that our inventory has changed even if our announced assets did not, record that
|
||||
BotCache.LastInventoryChecksumBeforeDeduplication = inventoryChecksumBeforeDeduplication;
|
||||
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(assetsForListing)} > {MaxItemsCount}"));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatWarningFailedWithError($"{nameof(assetsForListing)} > {MaxItemsCount}"));
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -561,7 +562,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
|
||||
HashSet<AssetForListing> inventoryAddedChanged = assetsForListing.Where(asset => !previousInventoryState.Remove(asset.AssetID, out AssetForListing? previousAsset) || (asset.BackendHashCode != previousAsset.BackendHashCode)).ToHashSet();
|
||||
|
||||
Bot.ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Localization.Strings.ListingAnnouncing, Bot.SteamID, nickname ?? Bot.SteamID.ToString(CultureInfo.InvariantCulture), assetsForListing.Count));
|
||||
Bot.ArchiLogger.LogGenericInfo(Localization.Strings.FormatListingAnnouncing(Bot.SteamID, nickname ?? Bot.SteamID.ToString(CultureInfo.InvariantCulture), assetsForListing.Count));
|
||||
|
||||
ObjectResponse<GenericResponse<BackgroundTaskResponse>>? diffResponse = null;
|
||||
Guid diffRequestID = Guid.Empty;
|
||||
@@ -576,17 +577,17 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
if (diffResponse == null) {
|
||||
// This is actually a network failure, so we'll stop sending heartbeats but not record it as valid check
|
||||
ShouldSendHeartBeats = false;
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.ErrorObjectIsNull, nameof(diffResponse)));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatErrorObjectIsNull(nameof(diffResponse)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (diffResponse.StatusCode.IsRedirectionCode()) {
|
||||
ShouldSendHeartBeats = false;
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, diffResponse.StatusCode));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatWarningFailedWithError(diffResponse.StatusCode));
|
||||
|
||||
if (diffResponse.FinalUri.Host != ArchiWebHandler.SteamCommunityURL.Host) {
|
||||
ASF.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownValuePleaseReport, nameof(diffResponse.FinalUri), diffResponse.FinalUri));
|
||||
ASF.ArchiLogger.LogGenericError(Strings.FormatWarningUnknownValuePleaseReport(nameof(diffResponse.FinalUri), diffResponse.FinalUri));
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -600,7 +601,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
if (!diffResponse.StatusCode.IsSuccessCode()) {
|
||||
// ArchiNet told us that we've sent a bad request, so the process should restart from the beginning at later time
|
||||
ShouldSendHeartBeats = false;
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, diffResponse.StatusCode));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatWarningFailedWithError(diffResponse.StatusCode));
|
||||
|
||||
switch (diffResponse.StatusCode) {
|
||||
case HttpStatusCode.Conflict:
|
||||
@@ -629,7 +630,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
// Great, do we need to wait?
|
||||
if (diffResponse.Content?.Result == null) {
|
||||
// This should never happen if we got the correct response
|
||||
Bot.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownValuePleaseReport, nameof(diffResponse), diffResponse.Content?.Result));
|
||||
Bot.ArchiLogger.LogGenericError(Strings.FormatWarningUnknownValuePleaseReport(nameof(diffResponse), diffResponse.Content?.Result));
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -644,7 +645,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
|
||||
if (diffResponse == null) {
|
||||
// We've waited long enough, something is definitely wrong with us or the backend
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(diffResponse)));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatWarningFailedWithError(nameof(diffResponse)));
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -666,7 +667,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
}
|
||||
}
|
||||
|
||||
Bot.ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Localization.Strings.ListingAnnouncing, Bot.SteamID, nickname ?? Bot.SteamID.ToString(CultureInfo.InvariantCulture), assetsForListing.Count));
|
||||
Bot.ArchiLogger.LogGenericInfo(Localization.Strings.FormatListingAnnouncing(Bot.SteamID, nickname ?? Bot.SteamID.ToString(CultureInfo.InvariantCulture), assetsForListing.Count));
|
||||
|
||||
ObjectResponse<GenericResponse<BackgroundTaskResponse>>? announceResponse = null;
|
||||
Guid announceRequestID = Guid.Empty;
|
||||
@@ -681,17 +682,17 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
if (announceResponse == null) {
|
||||
// This is actually a network failure, so we'll stop sending heartbeats but not record it as valid check
|
||||
ShouldSendHeartBeats = false;
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.ErrorObjectIsNull, nameof(announceResponse)));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatErrorObjectIsNull(nameof(announceResponse)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (announceResponse.StatusCode.IsRedirectionCode()) {
|
||||
ShouldSendHeartBeats = false;
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, announceResponse.StatusCode));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatWarningFailedWithError(announceResponse.StatusCode));
|
||||
|
||||
if (announceResponse.FinalUri.Host != ArchiWebHandler.SteamCommunityURL.Host) {
|
||||
ASF.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownValuePleaseReport, nameof(announceResponse.FinalUri), announceResponse.FinalUri));
|
||||
ASF.ArchiLogger.LogGenericError(Strings.FormatWarningUnknownValuePleaseReport(nameof(announceResponse.FinalUri), announceResponse.FinalUri));
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -705,7 +706,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
if (!announceResponse.StatusCode.IsSuccessCode()) {
|
||||
// ArchiNet told us that we've sent a bad request, so the process should restart from the beginning at later time
|
||||
ShouldSendHeartBeats = false;
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, announceResponse.StatusCode));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatWarningFailedWithError(announceResponse.StatusCode));
|
||||
|
||||
switch (announceResponse.StatusCode) {
|
||||
case HttpStatusCode.Conflict:
|
||||
@@ -734,7 +735,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
// Great, do we need to wait?
|
||||
if (announceResponse.Content?.Result == null) {
|
||||
// This should never happen if we got the correct response
|
||||
Bot.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownValuePleaseReport, nameof(announceResponse), announceResponse.Content?.Result));
|
||||
Bot.ArchiLogger.LogGenericError(Strings.FormatWarningUnknownValuePleaseReport(nameof(announceResponse), announceResponse.Content?.Result));
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -749,7 +750,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
|
||||
if (announceResponse == null) {
|
||||
// We've waited long enough, something is definitely wrong with us or the backend
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(announceResponse)));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatWarningFailedWithError(nameof(announceResponse)));
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -800,7 +801,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
bool? hasPublicInventory = await Bot.HasPublicInventory().ConfigureAwait(false);
|
||||
|
||||
if (hasPublicInventory != true) {
|
||||
Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(Bot.HasPublicInventory)}: {hasPublicInventory?.ToString() ?? "null"}"));
|
||||
Bot.ArchiLogger.LogGenericTrace(Strings.FormatWarningFailedWithError($"{nameof(Bot.HasPublicInventory)}: {hasPublicInventory?.ToString() ?? "null"}"));
|
||||
|
||||
return hasPublicInventory;
|
||||
}
|
||||
@@ -811,28 +812,28 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
private async Task<bool?> IsEligibleForMatching() {
|
||||
// Bot can't be limited
|
||||
if (Bot.IsAccountLimited) {
|
||||
Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(Bot.IsAccountLimited)}: {Bot.IsAccountLimited}"));
|
||||
Bot.ArchiLogger.LogGenericTrace(Strings.FormatWarningFailedWithError($"{nameof(Bot.IsAccountLimited)}: {Bot.IsAccountLimited}"));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Bot can't be on lockdown
|
||||
if (Bot.IsAccountLocked) {
|
||||
Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(Bot.IsAccountLocked)}: {Bot.IsAccountLocked}"));
|
||||
Bot.ArchiLogger.LogGenericTrace(Strings.FormatWarningFailedWithError($"{nameof(Bot.IsAccountLocked)}: {Bot.IsAccountLocked}"));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Bot must have ASF 2FA
|
||||
if (!Bot.HasMobileAuthenticator) {
|
||||
Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(Bot.HasMobileAuthenticator)}: {Bot.HasMobileAuthenticator}"));
|
||||
Bot.ArchiLogger.LogGenericTrace(Strings.FormatWarningFailedWithError($"{nameof(Bot.HasMobileAuthenticator)}: {Bot.HasMobileAuthenticator}"));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Bot must have at least one accepted matchable type set
|
||||
if ((Bot.BotConfig.MatchableTypes.Count == 0) || Bot.BotConfig.MatchableTypes.All(static type => !AcceptedMatchableTypes.Contains(type))) {
|
||||
Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(Bot.BotConfig.MatchableTypes)}: {string.Join(", ", Bot.BotConfig.MatchableTypes)}"));
|
||||
Bot.ArchiLogger.LogGenericTrace(Strings.FormatWarningFailedWithError($"{nameof(Bot.BotConfig.MatchableTypes)}: {string.Join(", ", Bot.BotConfig.MatchableTypes)}"));
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -841,21 +842,21 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
CCredentials_GetSteamGuardDetails_Response? steamGuardStatus = await Bot.ArchiHandler.GetSteamGuardStatus().ConfigureAwait(false);
|
||||
|
||||
if (steamGuardStatus == null) {
|
||||
Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(steamGuardStatus)}: null"));
|
||||
Bot.ArchiLogger.LogGenericTrace(Strings.FormatWarningFailedWithError($"{nameof(steamGuardStatus)}: null"));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Bot must have SteamGuard active for at least 15 days
|
||||
if (!steamGuardStatus.is_steamguard_enabled || ((steamGuardStatus.timestamp_steamguard_enabled > 0) && ((DateTimeOffset.UtcNow - DateTimeOffset.FromUnixTimeSeconds(steamGuardStatus.timestamp_steamguard_enabled)).TotalDays < MinimumSteamGuardEnabledDays))) {
|
||||
Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(steamGuardStatus.is_steamguard_enabled)}/{nameof(steamGuardStatus.timestamp_steamguard_enabled)}: {steamGuardStatus.is_steamguard_enabled}/{steamGuardStatus.timestamp_steamguard_enabled}"));
|
||||
Bot.ArchiLogger.LogGenericTrace(Strings.FormatWarningFailedWithError($"{nameof(steamGuardStatus.is_steamguard_enabled)}/{nameof(steamGuardStatus.timestamp_steamguard_enabled)}: {steamGuardStatus.is_steamguard_enabled}/{steamGuardStatus.timestamp_steamguard_enabled}"));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Bot must have 2FA enabled for matching to work
|
||||
if (!steamGuardStatus.is_twofactor_enabled) {
|
||||
Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(steamGuardStatus.is_twofactor_enabled)}: false"));
|
||||
Bot.ArchiLogger.LogGenericTrace(Strings.FormatWarningFailedWithError($"{nameof(steamGuardStatus.is_twofactor_enabled)}: false"));
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -863,14 +864,14 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
CCredentials_LastCredentialChangeTime_Response? credentialChangeTimeDetails = await Bot.ArchiHandler.GetCredentialChangeTimeDetails().ConfigureAwait(false);
|
||||
|
||||
if (credentialChangeTimeDetails == null) {
|
||||
Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(credentialChangeTimeDetails)}: null"));
|
||||
Bot.ArchiLogger.LogGenericTrace(Strings.FormatWarningFailedWithError($"{nameof(credentialChangeTimeDetails)}: null"));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Bot didn't change password in last 5 days
|
||||
if ((credentialChangeTimeDetails.timestamp_last_password_reset > 0) && ((DateTimeOffset.UtcNow - DateTimeOffset.FromUnixTimeSeconds(credentialChangeTimeDetails.timestamp_last_password_reset)).TotalDays < MinimumPasswordResetCooldownDays)) {
|
||||
Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(credentialChangeTimeDetails.timestamp_last_password_reset)}: {credentialChangeTimeDetails.timestamp_last_password_reset}"));
|
||||
Bot.ArchiLogger.LogGenericTrace(Strings.FormatWarningFailedWithError($"{nameof(credentialChangeTimeDetails.timestamp_last_password_reset)}: {credentialChangeTimeDetails.timestamp_last_password_reset}"));
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -896,12 +897,12 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
bool? eligible = await IsEligibleForMatching().ConfigureAwait(false);
|
||||
|
||||
if (eligible != true) {
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(IsEligibleForMatching)}: {eligible?.ToString() ?? "null"}"));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatWarningFailedWithError($"{nameof(IsEligibleForMatching)}: {eligible?.ToString() ?? "null"}"));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
HashSet<Asset.EType> acceptedMatchableTypes = Bot.BotConfig.MatchableTypes.Where(AcceptedMatchableTypes.Contains).ToHashSet();
|
||||
HashSet<EAssetType> acceptedMatchableTypes = Bot.BotConfig.MatchableTypes.Where(AcceptedMatchableTypes.Contains).ToHashSet();
|
||||
|
||||
if (acceptedMatchableTypes.Count == 0) {
|
||||
Bot.ArchiLogger.LogNullError(acceptedMatchableTypes);
|
||||
@@ -923,13 +924,13 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
HttpStatusCode? licenseStatus = await Backend.GetLicenseStatus(ASF.GlobalConfig.LicenseID.Value, WebBrowser).ConfigureAwait(false);
|
||||
|
||||
if (licenseStatus == null) {
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(licenseStatus)));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatWarningFailedWithError(nameof(licenseStatus)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!licenseStatus.Value.IsSuccessCode()) {
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, licenseStatus.Value));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatWarningFailedWithError(licenseStatus.Value));
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -937,31 +938,31 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
HashSet<Asset> assetsForMatching;
|
||||
|
||||
try {
|
||||
assetsForMatching = await Bot.ArchiWebHandler.GetInventoryAsync().Where(item => item is { AssetID: > 0, Amount: > 0, ClassID: > 0, RealAppID: > 0, Type: > Asset.EType.Unknown, Rarity: > Asset.ERarity.Unknown, IsSteamPointsShopItem: false } && acceptedMatchableTypes.Contains(item.Type) && !Bot.BotDatabase.MatchActivelyBlacklistAppIDs.Contains(item.RealAppID)).ToHashSetAsync().ConfigureAwait(false);
|
||||
} catch (HttpRequestException e) {
|
||||
assetsForMatching = await Bot.ArchiHandler.GetMyInventoryAsync().Where(item => item is { AssetID: > 0, Amount: > 0, ClassID: > 0, RealAppID: > 0, Type: > EAssetType.Unknown, Rarity: > EAssetRarity.Unknown, IsSteamPointsShopItem: false } && acceptedMatchableTypes.Contains(item.Type) && !Bot.BotDatabase.MatchActivelyBlacklistAppIDs.Contains(item.RealAppID)).ToHashSetAsync().ConfigureAwait(false);
|
||||
} catch (TimeoutException e) {
|
||||
Bot.ArchiLogger.LogGenericWarningException(e);
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(assetsForMatching)));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatWarningFailedWithError(nameof(assetsForMatching)));
|
||||
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
Bot.ArchiLogger.LogGenericException(e);
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(assetsForMatching)));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatWarningFailedWithError(nameof(assetsForMatching)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (assetsForMatching.Count == 0) {
|
||||
Bot.ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(assetsForMatching)));
|
||||
Bot.ArchiLogger.LogGenericInfo(Strings.FormatErrorIsEmpty(nameof(assetsForMatching)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove from our inventory items that can't be possibly matched due to no dupes to offer available
|
||||
HashSet<(uint RealAppID, Asset.EType Type, Asset.ERarity Rarity)> setsToKeep = Trading.GetInventorySets(assetsForMatching).Where(static set => set.Value.Any(static amount => amount > 1)).Select(static set => set.Key).ToHashSet();
|
||||
HashSet<(uint RealAppID, EAssetType Type, EAssetRarity Rarity)> setsToKeep = Trading.GetInventorySets(assetsForMatching).Where(static set => set.Value.Any(static amount => amount > 1)).Select(static set => set.Key).ToHashSet();
|
||||
|
||||
if (assetsForMatching.RemoveWhere(item => !setsToKeep.Contains((item.RealAppID, item.Type, item.Rarity))) > 0) {
|
||||
if (assetsForMatching.Count == 0) {
|
||||
Bot.ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(assetsForMatching)));
|
||||
Bot.ArchiLogger.LogGenericInfo(Strings.FormatErrorIsEmpty(nameof(assetsForMatching)));
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -969,15 +970,15 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
|
||||
// We should deduplicate our sets before sending them to the server, for doing that we'll use ASFB set parts data
|
||||
HashSet<uint> realAppIDs = [];
|
||||
Dictionary<(uint RealAppID, Asset.EType Type, Asset.ERarity Rarity), Dictionary<ulong, uint>> setsState = new();
|
||||
Dictionary<(uint RealAppID, EAssetType Type, EAssetRarity Rarity), Dictionary<ulong, uint>> setsState = new();
|
||||
|
||||
foreach (Asset asset in assetsForMatching) {
|
||||
realAppIDs.Add(asset.RealAppID);
|
||||
|
||||
(uint RealAppID, Asset.EType Type, Asset.ERarity Rarity) key = (asset.RealAppID, asset.Type, asset.Rarity);
|
||||
(uint RealAppID, EAssetType Type, EAssetRarity Rarity) key = (asset.RealAppID, asset.Type, asset.Rarity);
|
||||
|
||||
if (setsState.TryGetValue(key, out Dictionary<ulong, uint>? set)) {
|
||||
set[asset.ClassID] = set.TryGetValue(asset.ClassID, out uint amount) ? amount + asset.Amount : asset.Amount;
|
||||
set[asset.ClassID] = set.GetValueOrDefault(asset.ClassID) + asset.Amount;
|
||||
} else {
|
||||
setsState[key] = new Dictionary<ulong, uint> { { asset.ClassID, asset.Amount } };
|
||||
}
|
||||
@@ -998,16 +999,16 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
|
||||
if (setPartsResponse == null) {
|
||||
// This is actually a network failure
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.ErrorObjectIsNull, nameof(setPartsResponse)));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatErrorObjectIsNull(nameof(setPartsResponse)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (setPartsResponse.StatusCode.IsRedirectionCode()) {
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, setPartsResponse.StatusCode));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatWarningFailedWithError(setPartsResponse.StatusCode));
|
||||
|
||||
if (setPartsResponse.FinalUri.Host != ArchiWebHandler.SteamCommunityURL.Host) {
|
||||
ASF.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownValuePleaseReport, nameof(setPartsResponse.FinalUri), setPartsResponse.FinalUri));
|
||||
ASF.ArchiLogger.LogGenericError(Strings.FormatWarningUnknownValuePleaseReport(nameof(setPartsResponse.FinalUri), setPartsResponse.FinalUri));
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1019,23 +1020,23 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
}
|
||||
|
||||
if (!setPartsResponse.StatusCode.IsSuccessCode()) {
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, setPartsResponse.StatusCode));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatWarningFailedWithError(setPartsResponse.StatusCode));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (setPartsResponse.Content?.Result == null) {
|
||||
// This should never happen if we got the correct response
|
||||
Bot.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownValuePleaseReport, nameof(setPartsResponse), setPartsResponse.Content?.Result));
|
||||
Bot.ArchiLogger.LogGenericError(Strings.FormatWarningUnknownValuePleaseReport(nameof(setPartsResponse), setPartsResponse.Content?.Result));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Dictionary<(uint RealAppID, Asset.EType Type, Asset.ERarity Rarity), HashSet<ulong>> databaseSets = setPartsResponse.Content.Result.GroupBy(static setPart => (setPart.RealAppID, setPart.Type, setPart.Rarity)).ToDictionary(static group => group.Key, static group => group.Select(static setPart => setPart.ClassID).ToHashSet());
|
||||
Dictionary<(uint RealAppID, EAssetType Type, EAssetRarity Rarity), HashSet<ulong>> databaseSets = setPartsResponse.Content.Result.GroupBy(static setPart => (setPart.RealAppID, setPart.Type, setPart.Rarity)).ToDictionary(static group => group.Key, static group => group.Select(static setPart => setPart.ClassID).ToHashSet());
|
||||
|
||||
Dictionary<ulong, uint> setCopy = [];
|
||||
|
||||
foreach (((uint RealAppID, Asset.EType Type, Asset.ERarity Rarity) key, Dictionary<ulong, uint> set) in setsState) {
|
||||
foreach (((uint RealAppID, EAssetType Type, EAssetRarity Rarity) key, Dictionary<ulong, uint> set) in setsState) {
|
||||
uint minimumAmount = uint.MaxValue;
|
||||
uint maximumAmount = uint.MinValue;
|
||||
|
||||
@@ -1094,7 +1095,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
HashSet<Asset> assetsForMatchingFiltered = [];
|
||||
|
||||
foreach (Asset asset in assetsForMatching.Where(asset => setsState.TryGetValue((asset.RealAppID, asset.Type, asset.Rarity), out Dictionary<ulong, uint>? setState) && setState.TryGetValue(asset.ClassID, out uint targetAmount) && (targetAmount > 0)).OrderByDescending(static asset => asset.Tradable)) {
|
||||
(uint RealAppID, Asset.EType Type, Asset.ERarity Rarity) key = (asset.RealAppID, asset.Type, asset.Rarity);
|
||||
(uint RealAppID, EAssetType Type, EAssetRarity Rarity) key = (asset.RealAppID, asset.Type, asset.Rarity);
|
||||
|
||||
if (!setsState.TryGetValue(key, out Dictionary<ulong, uint>? setState) || !setState.TryGetValue(asset.ClassID, out uint targetAmount) || (targetAmount == 0)) {
|
||||
// We're not interested in this combination
|
||||
@@ -1117,13 +1118,13 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
assetsForMatching = assetsForMatchingFiltered;
|
||||
|
||||
if (assetsForMatching.Count == 0) {
|
||||
Bot.ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(assetsForMatching)));
|
||||
Bot.ArchiLogger.LogGenericInfo(Strings.FormatErrorIsEmpty(nameof(assetsForMatching)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (assetsForMatching.Count > MaxItemsCount) {
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(assetsForMatching)} > {MaxItemsCount}"));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatWarningFailedWithError($"{nameof(assetsForMatching)} > {MaxItemsCount}"));
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1131,26 +1132,24 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
(HttpStatusCode StatusCode, ImmutableHashSet<ListedUser> Users)? response = await Backend.GetListedUsersForMatching(ASF.GlobalConfig.LicenseID.Value, Bot, WebBrowser, assetsForMatching, acceptedMatchableTypes).ConfigureAwait(false);
|
||||
|
||||
if (response == null) {
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(response)));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatWarningFailedWithError(nameof(response)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!response.Value.StatusCode.IsSuccessCode()) {
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, response.Value.StatusCode));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatWarningFailedWithError(response.Value.StatusCode));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.Value.Users.IsEmpty) {
|
||||
Bot.ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(response.Value.Users)));
|
||||
Bot.ArchiLogger.LogGenericInfo(Strings.FormatErrorIsEmpty(nameof(response.Value.Users)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#pragma warning disable CA2000 // False positive, we're actually wrapping it in the using clause below exactly for that purpose
|
||||
using (await Bot.Actions.GetTradingLock().ConfigureAwait(false)) {
|
||||
#pragma warning restore CA2000 // False positive, we're actually wrapping it in the using clause below exactly for that purpose
|
||||
tradesSent = await MatchActively(response.Value.Users, assetsForMatching, acceptedMatchableTypes).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
@@ -1165,7 +1164,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> MatchActively(IReadOnlyCollection<ListedUser> listedUsers, IReadOnlyCollection<Asset> ourAssets, IReadOnlyCollection<Asset.EType> acceptedMatchableTypes) {
|
||||
private async Task<bool> MatchActively(ImmutableHashSet<ListedUser> listedUsers, HashSet<Asset> ourAssets, HashSet<EAssetType> acceptedMatchableTypes) {
|
||||
if ((listedUsers == null) || (listedUsers.Count == 0)) {
|
||||
throw new ArgumentNullException(nameof(listedUsers));
|
||||
}
|
||||
@@ -1178,11 +1177,11 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
throw new ArgumentNullException(nameof(acceptedMatchableTypes));
|
||||
}
|
||||
|
||||
(Dictionary<(uint RealAppID, Asset.EType Type, Asset.ERarity Rarity), Dictionary<ulong, uint>> ourFullState, Dictionary<(uint RealAppID, Asset.EType Type, Asset.ERarity Rarity), Dictionary<ulong, uint>> ourTradableState) = Trading.GetDividedInventoryState(ourAssets);
|
||||
(Dictionary<(uint RealAppID, EAssetType Type, EAssetRarity Rarity), Dictionary<ulong, uint>> ourFullState, Dictionary<(uint RealAppID, EAssetType Type, EAssetRarity Rarity), Dictionary<ulong, uint>> ourTradableState) = MatchingUtilities.GetDividedInventoryState(ourAssets);
|
||||
|
||||
if (Trading.IsEmptyForMatching(ourFullState, ourTradableState)) {
|
||||
if (MatchingUtilities.IsEmptyForMatching(ourFullState, ourTradableState)) {
|
||||
// User doesn't have any more dupes in the inventory
|
||||
Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, $"{nameof(ourFullState)} || {nameof(ourTradableState)}"));
|
||||
Bot.ArchiLogger.LogGenericTrace(Strings.FormatErrorIsEmpty($"{nameof(ourFullState)} || {nameof(ourTradableState)}"));
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1248,9 +1247,17 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
byte failuresInRow = 0;
|
||||
uint matchedSets = 0;
|
||||
|
||||
foreach (ListedUser listedUser in listedUsers.Where(listedUser => (listedUser.SteamID != Bot.SteamID) && acceptedMatchableTypes.Any(listedUser.MatchableTypes.Contains) && !Bot.IsBlacklistedFromTrades(listedUser.SteamID)).OrderByDescending(listedUser => !deprioritizedSteamIDs.Contains(listedUser.SteamID)).ThenByDescending(static listedUser => listedUser.TotalGamesCount > 1).ThenByDescending(static listedUser => listedUser.MatchEverything).ThenBy(static listedUser => listedUser.TotalInventoryCount)) {
|
||||
HashSet<(uint RealAppID, EAssetType Type, EAssetRarity Rarity)> skippedSetsThisUser = [];
|
||||
HashSet<(uint RealAppID, EAssetType Type, EAssetRarity Rarity)> skippedSetsThisTrade = [];
|
||||
|
||||
Dictionary<ulong, uint> classIDsToGive = new();
|
||||
Dictionary<ulong, uint> classIDsToReceive = new();
|
||||
Dictionary<ulong, uint> fairClassIDsToGive = new();
|
||||
Dictionary<ulong, uint> fairClassIDsToReceive = new();
|
||||
|
||||
foreach (ListedUser listedUser in listedUsers.Where(listedUser => (listedUser.SteamID != Bot.SteamID) && acceptedMatchableTypes.Overlaps(listedUser.MatchableTypes) && !Bot.IsBlacklistedFromTrades(listedUser.SteamID)).OrderByDescending(listedUser => !deprioritizedSteamIDs.Contains(listedUser.SteamID)).ThenByDescending(static listedUser => listedUser.TotalGamesCount > 1).ThenByDescending(static listedUser => listedUser.MatchEverything).ThenBy(static listedUser => listedUser.TotalInventoryCount)) {
|
||||
if (failuresInRow >= WebBrowser.MaxTries) {
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(failuresInRow)} >= {WebBrowser.MaxTries}"));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatWarningFailedWithError($"{nameof(failuresInRow)} >= {WebBrowser.MaxTries}"));
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -1261,7 +1268,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
break;
|
||||
}
|
||||
|
||||
HashSet<(uint RealAppID, Asset.EType Type, Asset.ERarity Rarity)> wantedSets = ourTradableState.Keys.Where(set => listedUser.MatchableTypes.Contains(set.Type)).ToHashSet();
|
||||
HashSet<(uint RealAppID, EAssetType Type, EAssetRarity Rarity)> wantedSets = ourTradableState.Keys.Where(set => listedUser.MatchableTypes.Contains(set.Type)).ToHashSet();
|
||||
|
||||
if (wantedSets.Count == 0) {
|
||||
continue;
|
||||
@@ -1273,7 +1280,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
|
||||
switch (tradeHoldDuration) {
|
||||
case null:
|
||||
Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(tradeHoldDuration)));
|
||||
Bot.ArchiLogger.LogGenericTrace(Strings.FormatErrorIsEmpty(nameof(tradeHoldDuration)));
|
||||
|
||||
continue;
|
||||
case > 0 when (tradeHoldDuration.Value > maxTradeHoldDuration) || (tradeHoldDuration.Value > listedUser.MaxTradeHoldDuration):
|
||||
@@ -1282,26 +1289,27 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
continue;
|
||||
}
|
||||
|
||||
HashSet<Asset> theirInventory = listedUser.Assets.Where(item => (!listedUser.MatchEverything || item.Tradable) && wantedSets.Contains((item.RealAppID, item.Type, item.Rarity)) && ((tradeHoldDuration.Value == 0) || !(item.Type is Asset.EType.FoilTradingCard or Asset.EType.TradingCard && CardsFarmer.SalesBlacklist.Contains(item.RealAppID)))).Select(static asset => asset.ToAsset()).ToHashSet();
|
||||
HashSet<Asset> theirInventory = listedUser.Assets.Where(item => (!listedUser.MatchEverything || item.Tradable) && wantedSets.Contains((item.RealAppID, item.Type, item.Rarity)) && ((tradeHoldDuration.Value == 0) || !(item.Type is EAssetType.FoilTradingCard or EAssetType.TradingCard && CardsFarmer.SalesBlacklist.Contains(item.RealAppID)))).Select(static asset => asset.ToAsset()).ToHashSet();
|
||||
|
||||
if (theirInventory.Count == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
HashSet<(uint RealAppID, Asset.EType Type, Asset.ERarity Rarity)> skippedSetsThisUser = [];
|
||||
skippedSetsThisUser.Clear();
|
||||
|
||||
Dictionary<(uint RealAppID, Asset.EType Type, Asset.ERarity Rarity), Dictionary<ulong, uint>> theirTradableState = Trading.GetTradableInventoryState(theirInventory);
|
||||
Dictionary<(uint RealAppID, EAssetType Type, EAssetRarity Rarity), Dictionary<ulong, uint>> theirTradableState = MatchingUtilities.GetTradableInventoryState(theirInventory);
|
||||
|
||||
for (byte i = 0; i < Trading.MaxTradesPerAccount; i++) {
|
||||
byte itemsInTrade = 0;
|
||||
HashSet<(uint RealAppID, Asset.EType Type, Asset.ERarity Rarity)> skippedSetsThisTrade = [];
|
||||
|
||||
Dictionary<ulong, uint> classIDsToGive = new();
|
||||
Dictionary<ulong, uint> classIDsToReceive = new();
|
||||
Dictionary<ulong, uint> fairClassIDsToGive = new();
|
||||
Dictionary<ulong, uint> fairClassIDsToReceive = new();
|
||||
skippedSetsThisTrade.Clear();
|
||||
|
||||
foreach (((uint RealAppID, Asset.EType Type, Asset.ERarity Rarity) set, Dictionary<ulong, uint> ourFullItems) in ourFullState.Where(set => !skippedSetsThisUser.Contains(set.Key) && listedUser.MatchableTypes.Contains(set.Key.Type) && set.Value.Values.Any(static count => count > 1))) {
|
||||
classIDsToGive.Clear();
|
||||
classIDsToReceive.Clear();
|
||||
fairClassIDsToGive.Clear();
|
||||
fairClassIDsToReceive.Clear();
|
||||
|
||||
foreach (((uint RealAppID, EAssetType Type, EAssetRarity Rarity) set, Dictionary<ulong, uint> ourFullItems) in ourFullState.Where(set => !skippedSetsThisUser.Contains(set.Key) && listedUser.MatchableTypes.Contains(set.Key.Type) && set.Value.Values.Any(static count => count > 1))) {
|
||||
if (!ourTradableState.TryGetValue(set, out Dictionary<ulong, uint>? ourTradableItems) || (ourTradableItems.Count == 0)) {
|
||||
// We may have no more tradable items from this set
|
||||
continue;
|
||||
@@ -1312,14 +1320,14 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Trading.IsEmptyForMatching(ourFullItems, ourTradableItems)) {
|
||||
if (MatchingUtilities.IsEmptyForMatching(ourFullItems, ourTradableItems)) {
|
||||
// We may have no more matchable items from this set
|
||||
continue;
|
||||
}
|
||||
|
||||
// Those 2 collections are on user-basis since we can't be sure that the trade passes through (and therefore we need to keep original state in case of a failure)
|
||||
Dictionary<ulong, uint> ourFullSet = new(ourFullItems);
|
||||
Dictionary<ulong, uint> ourTradableSet = new(ourTradableItems);
|
||||
Dictionary<ulong, uint> ourFullSet = ourFullItems.ToDictionary();
|
||||
Dictionary<ulong, uint> ourTradableSet = ourTradableItems.ToDictionary();
|
||||
|
||||
bool match;
|
||||
|
||||
@@ -1331,26 +1339,27 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ((ulong theirItem, uint theirTradableAmount) in theirTradableItems.OrderBy(item => ourFullSet.TryGetValue(item.Key, out uint ourAmountOfTheirItem) ? ourAmountOfTheirItem : 0)) {
|
||||
foreach ((ulong theirItem, uint theirTradableAmount) in theirTradableItems.OrderBy(item => ourFullSet.GetValueOrDefault(item.Key))) {
|
||||
if (ourFullSet.TryGetValue(theirItem, out uint ourAmountOfTheirItem) && (ourFullAmount <= ourAmountOfTheirItem + 1)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!listedUser.MatchEverything) {
|
||||
// We have a potential match, let's check fairness for them
|
||||
fairClassIDsToGive.TryGetValue(ourItem, out uint fairGivenAmount);
|
||||
fairClassIDsToReceive.TryGetValue(theirItem, out uint fairReceivedAmount);
|
||||
uint fairGivenAmount = fairClassIDsToGive.GetValueOrDefault(ourItem);
|
||||
uint fairReceivedAmount = fairClassIDsToReceive.GetValueOrDefault(theirItem);
|
||||
|
||||
fairClassIDsToGive[ourItem] = ++fairGivenAmount;
|
||||
fairClassIDsToReceive[theirItem] = ++fairReceivedAmount;
|
||||
|
||||
// Filter their inventory for the sets we're trading or have traded with this user
|
||||
HashSet<Asset> fairFiltered = theirInventory.Where(item => ((item.RealAppID == set.RealAppID) && (item.Type == set.Type) && (item.Rarity == set.Rarity)) || skippedSetsThisTrade.Contains((item.RealAppID, item.Type, item.Rarity))).Select(static item => item.CreateShallowCopy()).ToHashSet();
|
||||
HashSet<Asset> fairFiltered = theirInventory.Where(item => ((item.RealAppID == set.RealAppID) && (item.Type == set.Type) && (item.Rarity == set.Rarity)) || skippedSetsThisTrade.Contains((item.RealAppID, item.Type, item.Rarity))).ToHashSet();
|
||||
|
||||
// Copy list to HashSet<Steam.Asset>
|
||||
HashSet<Asset> fairItemsToGive = Trading.GetTradableItemsFromInventory(ourInventory.Values.Where(item => ((item.RealAppID == set.RealAppID) && (item.Type == set.Type) && (item.Rarity == set.Rarity)) || skippedSetsThisTrade.Contains((item.RealAppID, item.Type, item.Rarity))).Select(static item => item.CreateShallowCopy()).ToHashSet(), fairClassIDsToGive.ToDictionary(static classID => classID.Key, static classID => classID.Value));
|
||||
HashSet<Asset> fairItemsToReceive = Trading.GetTradableItemsFromInventory(fairFiltered.Select(static item => item.CreateShallowCopy()).ToHashSet(), fairClassIDsToReceive.ToDictionary(static classID => classID.Key, static classID => classID.Value));
|
||||
// Get tradable items from our and their inventory
|
||||
HashSet<Asset> fairItemsToGive = MatchingUtilities.GetTradableItemsFromInventory(ourInventory.Values.Where(item => ((item.RealAppID == set.RealAppID) && (item.Type == set.Type) && (item.Rarity == set.Rarity)) || skippedSetsThisTrade.Contains((item.RealAppID, item.Type, item.Rarity))).ToHashSet(), fairClassIDsToGive);
|
||||
HashSet<Asset> fairItemsToReceive = MatchingUtilities.GetTradableItemsFromInventory(fairFiltered, fairClassIDsToReceive);
|
||||
|
||||
// Actual check
|
||||
// Actual check, since we do this against remote user, we flip places for items
|
||||
if (!Trading.IsTradeNeutralOrBetter(fairFiltered, fairItemsToReceive, fairItemsToGive)) {
|
||||
// Revert the changes
|
||||
if (fairGivenAmount > 1) {
|
||||
@@ -1373,11 +1382,11 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
skippedSetsThisTrade.Add(set);
|
||||
|
||||
// Update our state based on given items
|
||||
classIDsToGive[ourItem] = classIDsToGive.TryGetValue(ourItem, out uint ourGivenAmount) ? ourGivenAmount + 1 : 1;
|
||||
classIDsToGive[ourItem] = classIDsToGive.GetValueOrDefault(ourItem) + 1;
|
||||
ourFullSet[ourItem] = ourFullAmount - 1; // We don't need to remove anything here because we can guarantee that ourItem.Value is at least 2
|
||||
|
||||
// Update our state based on received items
|
||||
classIDsToReceive[theirItem] = classIDsToReceive.TryGetValue(theirItem, out uint ourReceivedAmount) ? ourReceivedAmount + 1 : 1;
|
||||
classIDsToReceive[theirItem] = classIDsToReceive.GetValueOrDefault(theirItem) + 1;
|
||||
ourFullSet[theirItem] = ourAmountOfTheirItem + 1;
|
||||
|
||||
if (ourTradableAmount > 1) {
|
||||
@@ -1412,25 +1421,25 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
}
|
||||
|
||||
if (skippedSetsThisTrade.Count == 0) {
|
||||
Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(skippedSetsThisTrade)));
|
||||
Bot.ArchiLogger.LogGenericTrace(Strings.FormatErrorIsEmpty(nameof(skippedSetsThisTrade)));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Remove the items from inventories
|
||||
HashSet<Asset> itemsToGive = Trading.GetTradableItemsFromInventory(ourInventory.Values, classIDsToGive);
|
||||
HashSet<Asset> itemsToReceive = Trading.GetTradableItemsFromInventory(theirInventory, classIDsToReceive, true);
|
||||
HashSet<Asset> itemsToGive = MatchingUtilities.GetTradableItemsFromInventory(ourInventory.Values, classIDsToGive);
|
||||
HashSet<Asset> itemsToReceive = MatchingUtilities.GetTradableItemsFromInventory(theirInventory, classIDsToReceive, true);
|
||||
|
||||
if ((itemsToGive.Count != itemsToReceive.Count) || !Trading.IsFairExchange(itemsToGive, itemsToReceive)) {
|
||||
// Failsafe
|
||||
throw new InvalidOperationException($"{nameof(itemsToGive)} && {nameof(itemsToReceive)}");
|
||||
}
|
||||
|
||||
Bot.ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Localization.Strings.MatchingFound, itemsToReceive.Count, listedUser.SteamID, listedUser.Nickname));
|
||||
Bot.ArchiLogger.LogGenericInfo(Localization.Strings.FormatMatchingFound(itemsToReceive.Count, listedUser.SteamID, listedUser.Nickname));
|
||||
|
||||
Bot.ArchiLogger.LogGenericTrace($"{Bot.SteamID} <- {string.Join(", ", itemsToReceive.Select(static item => $"{item.RealAppID}/{item.Type}/{item.Rarity}/{item.ClassID} #{item.Amount}"))} | {string.Join(", ", itemsToGive.Select(static item => $"{item.RealAppID}/{item.Type}/{item.Rarity}/{item.ClassID} #{item.Amount}"))} -> {listedUser.SteamID}");
|
||||
|
||||
(bool success, HashSet<ulong>? tradeOfferIDs, HashSet<ulong>? mobileTradeOfferIDs) = await Bot.ArchiWebHandler.SendTradeOffer(listedUser.SteamID, itemsToGive, itemsToReceive, listedUser.TradeToken, true).ConfigureAwait(false);
|
||||
(bool success, HashSet<ulong>? tradeOfferIDs, HashSet<ulong>? mobileTradeOfferIDs) = await Bot.ArchiWebHandler.SendTradeOffer(listedUser.SteamID, itemsToGive, itemsToReceive, listedUser.TradeToken, nameof(MatchActively), true).ConfigureAwait(false);
|
||||
|
||||
if (tradeOfferIDs?.Count > 0) {
|
||||
matchActivelyTradeOfferIDs.UnionWith(tradeOfferIDs);
|
||||
@@ -1445,7 +1454,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
(bool twoFactorSuccess, IReadOnlyCollection<Confirmation>? handledConfirmations, _) = await Bot.Actions.HandleTwoFactorAuthenticationConfirmations(true, Confirmation.EConfirmationType.Trade, pendingMobileTradeOfferIDs, true).ConfigureAwait(false);
|
||||
|
||||
if (!twoFactorSuccess) {
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Localization.Strings.ActivelyMatchingSomeConfirmationsFailed, handledConfirmations?.Count ?? 0, pendingMobileTradeOfferIDs.Count));
|
||||
Bot.ArchiLogger.LogGenericWarning(Localization.Strings.FormatActivelyMatchingSomeConfirmationsFailed(handledConfirmations?.Count ?? 0, pendingMobileTradeOfferIDs.Count));
|
||||
}
|
||||
|
||||
pendingMobileTradeOfferIDs.Clear();
|
||||
@@ -1456,7 +1465,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
// The user likely no longer has the items we need, this is fine, we can continue the matching with other ones
|
||||
failuresInRow++;
|
||||
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Localization.Strings.TradeOfferFailed, listedUser.SteamID, listedUser.Nickname));
|
||||
Bot.ArchiLogger.LogGenericWarning(Localization.Strings.FormatTradeOfferFailed(listedUser.SteamID, listedUser.Nickname));
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -1503,10 +1512,14 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
// However, since this is only an assumption, we must mark newly acquired items as untradable so we're sure that they're not considered for trading, only for matching
|
||||
foreach (Asset itemToReceive in itemsToReceive) {
|
||||
if (ourInventory.TryGetValue(itemToReceive.AssetID, out Asset? item)) {
|
||||
item.Tradable = false;
|
||||
item.Description ??= new InventoryDescription(itemToReceive.AppID, itemToReceive.ClassID, itemToReceive.InstanceID, realAppID: itemToReceive.RealAppID, type: itemToReceive.Type, rarity: itemToReceive.Rarity);
|
||||
|
||||
item.Description.Body.tradable = false;
|
||||
item.Amount += itemToReceive.Amount;
|
||||
} else {
|
||||
itemToReceive.Tradable = false;
|
||||
itemToReceive.Description ??= new InventoryDescription(itemToReceive.AppID, itemToReceive.ClassID, itemToReceive.InstanceID, realAppID: itemToReceive.RealAppID, type: itemToReceive.Type, rarity: itemToReceive.Rarity);
|
||||
|
||||
itemToReceive.Description.Body.tradable = false;
|
||||
ourInventory[itemToReceive.AssetID] = itemToReceive;
|
||||
}
|
||||
|
||||
@@ -1515,11 +1528,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
throw new InvalidOperationException(nameof(fullAmounts));
|
||||
}
|
||||
|
||||
if (!fullAmounts.TryGetValue(itemToReceive.ClassID, out uint fullAmount)) {
|
||||
fullAmount = 0;
|
||||
}
|
||||
|
||||
fullAmounts[itemToReceive.ClassID] = itemToReceive.Amount + fullAmount;
|
||||
fullAmounts[itemToReceive.ClassID] = fullAmounts.GetValueOrDefault(itemToReceive.ClassID) + itemToReceive.Amount;
|
||||
}
|
||||
|
||||
skippedSetsThisUser.UnionWith(skippedSetsThisTrade);
|
||||
@@ -1531,7 +1540,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
|
||||
matchedSets += (uint) skippedSetsThisUser.Count;
|
||||
|
||||
if (Trading.IsEmptyForMatching(ourFullState, ourTradableState)) {
|
||||
if (MatchingUtilities.IsEmptyForMatching(ourFullState, ourTradableState)) {
|
||||
// User doesn't have any more dupes in the inventory
|
||||
break;
|
||||
}
|
||||
@@ -1541,11 +1550,11 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
(bool twoFactorSuccess, IReadOnlyCollection<Confirmation>? handledConfirmations, _) = Bot.IsConnectedAndLoggedOn ? await Bot.Actions.HandleTwoFactorAuthenticationConfirmations(true, Confirmation.EConfirmationType.Trade, pendingMobileTradeOfferIDs, true).ConfigureAwait(false) : (false, null, null);
|
||||
|
||||
if (!twoFactorSuccess) {
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Localization.Strings.ActivelyMatchingSomeConfirmationsFailed, handledConfirmations?.Count ?? 0, pendingMobileTradeOfferIDs.Count));
|
||||
Bot.ArchiLogger.LogGenericWarning(Localization.Strings.FormatActivelyMatchingSomeConfirmationsFailed(handledConfirmations?.Count ?? 0, pendingMobileTradeOfferIDs.Count));
|
||||
}
|
||||
}
|
||||
|
||||
Bot.ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Localization.Strings.ActivelyMatchingItemsRound, matchedSets));
|
||||
Bot.ArchiLogger.LogGenericInfo(Localization.Strings.FormatActivelyMatchingItemsRound(matchedSets));
|
||||
|
||||
return matchedSets > 0;
|
||||
}
|
||||
@@ -1601,10 +1610,10 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
if (response.StatusCode.IsRedirectionCode()) {
|
||||
ShouldSendHeartBeats = false;
|
||||
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, response.StatusCode));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatWarningFailedWithError(response.StatusCode));
|
||||
|
||||
if (response.FinalUri.Host != ArchiWebHandler.SteamCommunityURL.Host) {
|
||||
ASF.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownValuePleaseReport, nameof(response.FinalUri), response.FinalUri));
|
||||
ASF.ArchiLogger.LogGenericError(Strings.FormatWarningUnknownValuePleaseReport(nameof(response.FinalUri), response.FinalUri));
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1620,7 +1629,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
if (!response.StatusCode.IsSuccessCode()) {
|
||||
ShouldSendHeartBeats = false;
|
||||
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, response.StatusCode));
|
||||
Bot.ArchiLogger.LogGenericWarning(Strings.FormatWarningFailedWithError(response.StatusCode));
|
||||
|
||||
switch (response.StatusCode) {
|
||||
case HttpStatusCode.Conflict:
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ConfigureAwaitChecker.Analyzer" PrivateAssets="all" />
|
||||
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.ResxSourceGenerator" PrivateAssets="all" />
|
||||
<PackageReference Include="SteamKit2" IncludeAssets="compile" />
|
||||
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
|
||||
</ItemGroup>
|
||||
@@ -15,17 +15,6 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Localization\Strings.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Strings.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Localization\Strings.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Strings.resx</DependentUpon>
|
||||
<DesignTime>True</DesignTime>
|
||||
</Compile>
|
||||
<EmbeddedResource Update="Localization\Strings.resx" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// |
|
||||
// Copyright 2015-2024 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
@@ -22,7 +24,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
@@ -36,8 +37,6 @@ using SteamKit2.Internal;
|
||||
namespace ArchiSteamFarm.OfficialPlugins.MobileAuthenticator;
|
||||
|
||||
internal static class Commands {
|
||||
private const byte MaxFinalizationAttempts = 900 / Steam.Security.MobileAuthenticator.CodeInterval;
|
||||
|
||||
internal static async Task<string?> OnBotCommand(Bot bot, EAccess access, string message, string[] args, ulong steamID = 0) {
|
||||
ArgumentNullException.ThrowIfNull(bot);
|
||||
|
||||
@@ -100,7 +99,7 @@ internal static class Commands {
|
||||
}
|
||||
|
||||
if (bot.HasMobileAuthenticator) {
|
||||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(bot.HasMobileAuthenticator)));
|
||||
return bot.Commands.FormatBotResponse(Strings.FormatWarningFailedWithError(nameof(bot.HasMobileAuthenticator)));
|
||||
}
|
||||
|
||||
if (!bot.IsConnectedAndLoggedOn) {
|
||||
@@ -121,17 +120,17 @@ internal static class Commands {
|
||||
} catch (Exception e) {
|
||||
bot.ArchiLogger.LogGenericException(e);
|
||||
|
||||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, e.Message));
|
||||
return bot.Commands.FormatBotResponse(Strings.FormatWarningFailedWithError(e.Message));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(json)) {
|
||||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(json)));
|
||||
return bot.Commands.FormatBotResponse(Strings.FormatErrorIsEmpty(nameof(json)));
|
||||
}
|
||||
|
||||
Steam.Security.MobileAuthenticator? mobileAuthenticator = json.ToJsonObject<Steam.Security.MobileAuthenticator>();
|
||||
|
||||
if (mobileAuthenticator == null) {
|
||||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(json)));
|
||||
return bot.Commands.FormatBotResponse(Strings.FormatErrorIsEmpty(nameof(json)));
|
||||
}
|
||||
|
||||
mobileAuthenticator.Init(bot);
|
||||
@@ -144,47 +143,26 @@ internal static class Commands {
|
||||
|
||||
ulong steamTime = await mobileAuthenticator.GetSteamTime().ConfigureAwait(false);
|
||||
|
||||
bool successFinalizing = false;
|
||||
string? code = mobileAuthenticator.GenerateTokenForTime(steamTime);
|
||||
|
||||
for (byte i = 0; i < MaxFinalizationAttempts; i++) {
|
||||
if (i > 0) {
|
||||
steamTime += Steam.Security.MobileAuthenticator.CodeInterval;
|
||||
}
|
||||
|
||||
string? code = mobileAuthenticator.GenerateTokenForTime(steamTime);
|
||||
|
||||
if (string.IsNullOrEmpty(code)) {
|
||||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(mobileAuthenticator.GenerateTokenForTime)));
|
||||
}
|
||||
|
||||
CTwoFactor_FinalizeAddAuthenticator_Response? response = await mobileAuthenticatorHandler.FinalizeAuthenticator(bot.SteamID, activationCode, code, steamTime).ConfigureAwait(false);
|
||||
|
||||
if (response == null) {
|
||||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(mobileAuthenticatorHandler.FinalizeAuthenticator)));
|
||||
}
|
||||
|
||||
if (response.want_more) {
|
||||
// OK, whatever
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!response.success) {
|
||||
EResult result = (EResult) response.status;
|
||||
|
||||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, result));
|
||||
}
|
||||
|
||||
successFinalizing = true;
|
||||
|
||||
break;
|
||||
if (string.IsNullOrEmpty(code)) {
|
||||
return bot.Commands.FormatBotResponse(Strings.FormatWarningFailedWithError(nameof(mobileAuthenticator.GenerateTokenForTime)));
|
||||
}
|
||||
|
||||
if (!successFinalizing) {
|
||||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.ErrorRequestFailedTooManyTimes, MaxFinalizationAttempts));
|
||||
CTwoFactor_FinalizeAddAuthenticator_Response? response = await mobileAuthenticatorHandler.FinalizeAuthenticator(bot.SteamID, activationCode, code, steamTime).ConfigureAwait(false);
|
||||
|
||||
if (response == null) {
|
||||
return bot.Commands.FormatBotResponse(Strings.FormatWarningFailedWithError(nameof(mobileAuthenticatorHandler.FinalizeAuthenticator)));
|
||||
}
|
||||
|
||||
if (!response.success) {
|
||||
EResult result = (EResult) response.status;
|
||||
|
||||
return bot.Commands.FormatBotResponse(Strings.FormatWarningFailedWithError(result));
|
||||
}
|
||||
|
||||
if (!bot.TryImportAuthenticator(mobileAuthenticator)) {
|
||||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(bot.TryImportAuthenticator)));
|
||||
return bot.Commands.FormatBotResponse(Strings.FormatWarningFailedWithError(nameof(bot.TryImportAuthenticator)));
|
||||
}
|
||||
|
||||
string maFileFinishedPath = $"{maFilePath}.NEW";
|
||||
@@ -194,7 +172,7 @@ internal static class Commands {
|
||||
} catch (Exception e) {
|
||||
bot.ArchiLogger.LogGenericException(e);
|
||||
|
||||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, e.Message));
|
||||
return bot.Commands.FormatBotResponse(Strings.FormatWarningFailedWithError(e.Message));
|
||||
}
|
||||
|
||||
return bot.Commands.FormatBotResponse(Strings.Done);
|
||||
@@ -215,12 +193,12 @@ internal static class Commands {
|
||||
HashSet<Bot>? bots = Bot.GetBots(botNames);
|
||||
|
||||
if ((bots == null) || (bots.Count == 0)) {
|
||||
return access >= EAccess.Owner ? Steam.Interaction.Commands.FormatStaticResponse(string.Format(CultureInfo.CurrentCulture, Strings.BotNotFound, botNames)) : null;
|
||||
return access >= EAccess.Owner ? Steam.Interaction.Commands.FormatStaticResponse(Strings.FormatBotNotFound(botNames)) : null;
|
||||
}
|
||||
|
||||
IList<string?> results = await Utilities.InParallel(bots.Select(bot => ResponseTwoFactorFinalize(Steam.Interaction.Commands.GetProxyAccess(bot, access, steamID), bot, activationCode))).ConfigureAwait(false);
|
||||
|
||||
List<string> responses = [..results.Where(static result => !string.IsNullOrEmpty(result))];
|
||||
List<string> responses = [..results.Where(static result => !string.IsNullOrEmpty(result))!];
|
||||
|
||||
return responses.Count > 0 ? string.Join(Environment.NewLine, responses) : null;
|
||||
}
|
||||
@@ -237,7 +215,7 @@ internal static class Commands {
|
||||
}
|
||||
|
||||
if (bot.HasMobileAuthenticator) {
|
||||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(bot.HasMobileAuthenticator)));
|
||||
return bot.Commands.FormatBotResponse(Strings.FormatWarningFailedWithError(nameof(bot.HasMobileAuthenticator)));
|
||||
}
|
||||
|
||||
string maFilePath = bot.GetFilePath(Bot.EFileType.MobileAuthenticator);
|
||||
@@ -254,17 +232,17 @@ internal static class Commands {
|
||||
} catch (Exception e) {
|
||||
bot.ArchiLogger.LogGenericException(e);
|
||||
|
||||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, e.Message));
|
||||
return bot.Commands.FormatBotResponse(Strings.FormatWarningFailedWithError(e.Message));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(json)) {
|
||||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(json)));
|
||||
return bot.Commands.FormatBotResponse(Strings.FormatErrorIsEmpty(nameof(json)));
|
||||
}
|
||||
|
||||
Steam.Security.MobileAuthenticator? mobileAuthenticator = json.ToJsonObject<Steam.Security.MobileAuthenticator>();
|
||||
|
||||
if (mobileAuthenticator == null) {
|
||||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(json)));
|
||||
return bot.Commands.FormatBotResponse(Strings.FormatErrorIsEmpty(nameof(json)));
|
||||
}
|
||||
|
||||
mobileAuthenticator.Init(bot);
|
||||
@@ -272,13 +250,17 @@ internal static class Commands {
|
||||
if (!string.IsNullOrEmpty(activationCode)) {
|
||||
string? generatedCode = await mobileAuthenticator.GenerateToken().ConfigureAwait(false);
|
||||
|
||||
if (generatedCode != activationCode) {
|
||||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{generatedCode} != {activationCode}"));
|
||||
if (string.IsNullOrEmpty(generatedCode)) {
|
||||
return bot.Commands.FormatBotResponse(Strings.FormatWarningFailedWithError(nameof(generatedCode)));
|
||||
}
|
||||
|
||||
if (!generatedCode.Equals(activationCode, StringComparison.OrdinalIgnoreCase)) {
|
||||
return bot.Commands.FormatBotResponse(Strings.FormatWarningFailedWithError($"{generatedCode} != {activationCode}"));
|
||||
}
|
||||
}
|
||||
|
||||
if (!bot.TryImportAuthenticator(mobileAuthenticator)) {
|
||||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(bot.TryImportAuthenticator)));
|
||||
return bot.Commands.FormatBotResponse(Strings.FormatWarningFailedWithError(nameof(bot.TryImportAuthenticator)));
|
||||
}
|
||||
|
||||
string maFileFinishedPath = $"{maFilePath}.NEW";
|
||||
@@ -288,7 +270,7 @@ internal static class Commands {
|
||||
} catch (Exception e) {
|
||||
bot.ArchiLogger.LogGenericException(e);
|
||||
|
||||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, e.Message));
|
||||
return bot.Commands.FormatBotResponse(Strings.FormatWarningFailedWithError(e.Message));
|
||||
}
|
||||
|
||||
return bot.Commands.FormatBotResponse(Strings.Done);
|
||||
@@ -308,12 +290,12 @@ internal static class Commands {
|
||||
HashSet<Bot>? bots = Bot.GetBots(botNames);
|
||||
|
||||
if ((bots == null) || (bots.Count == 0)) {
|
||||
return access >= EAccess.Owner ? Steam.Interaction.Commands.FormatStaticResponse(string.Format(CultureInfo.CurrentCulture, Strings.BotNotFound, botNames)) : null;
|
||||
return access >= EAccess.Owner ? Steam.Interaction.Commands.FormatStaticResponse(Strings.FormatBotNotFound(botNames)) : null;
|
||||
}
|
||||
|
||||
IList<string?> results = await Utilities.InParallel(bots.Select(bot => ResponseTwoFactorFinalized(Steam.Interaction.Commands.GetProxyAccess(bot, access, steamID), bot, activationCode))).ConfigureAwait(false);
|
||||
|
||||
List<string> responses = [..results.Where(static result => !string.IsNullOrEmpty(result))];
|
||||
List<string> responses = [..results.Where(static result => !string.IsNullOrEmpty(result))!];
|
||||
|
||||
return responses.Count > 0 ? string.Join(Environment.NewLine, responses) : null;
|
||||
}
|
||||
@@ -330,7 +312,7 @@ internal static class Commands {
|
||||
}
|
||||
|
||||
if (bot.HasMobileAuthenticator) {
|
||||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(bot.HasMobileAuthenticator)));
|
||||
return bot.Commands.FormatBotResponse(Strings.FormatWarningFailedWithError(nameof(bot.HasMobileAuthenticator)));
|
||||
}
|
||||
|
||||
if (!bot.IsConnectedAndLoggedOn) {
|
||||
@@ -354,7 +336,7 @@ internal static class Commands {
|
||||
EResult result = (EResult) response.status;
|
||||
|
||||
if (result != EResult.OK) {
|
||||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, result));
|
||||
return bot.Commands.FormatBotResponse(Strings.FormatWarningFailedWithError(result));
|
||||
}
|
||||
|
||||
MaFileData maFileData = new(response, bot.SteamID, deviceID);
|
||||
@@ -367,7 +349,7 @@ internal static class Commands {
|
||||
} catch (Exception e) {
|
||||
bot.ArchiLogger.LogGenericException(e);
|
||||
|
||||
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, e.Message));
|
||||
return bot.Commands.FormatBotResponse(Strings.FormatWarningFailedWithError(e.Message));
|
||||
}
|
||||
|
||||
return bot.Commands.FormatBotResponse(Strings.Done);
|
||||
@@ -387,12 +369,12 @@ internal static class Commands {
|
||||
HashSet<Bot>? bots = Bot.GetBots(botNames);
|
||||
|
||||
if ((bots == null) || (bots.Count == 0)) {
|
||||
return access >= EAccess.Owner ? Steam.Interaction.Commands.FormatStaticResponse(string.Format(CultureInfo.CurrentCulture, Strings.BotNotFound, botNames)) : null;
|
||||
return access >= EAccess.Owner ? Steam.Interaction.Commands.FormatStaticResponse(Strings.FormatBotNotFound(botNames)) : null;
|
||||
}
|
||||
|
||||
IList<string?> results = await Utilities.InParallel(bots.Select(bot => ResponseTwoFactorInit(Steam.Interaction.Commands.GetProxyAccess(bot, access, steamID), bot))).ConfigureAwait(false);
|
||||
|
||||
List<string> responses = [..results.Where(static result => !string.IsNullOrEmpty(result))];
|
||||
List<string> responses = [..results.Where(static result => !string.IsNullOrEmpty(result))!];
|
||||
|
||||
return responses.Count > 0 ? string.Join(Environment.NewLine, responses) : null;
|
||||
}
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.MobileAuthenticator.Localization {
|
||||
using System;
|
||||
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Strings {
|
||||
|
||||
private static System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Strings() {
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.Equals(null, resourceMan)) {
|
||||
System.Resources.ResourceManager temp = new System.Resources.ResourceManager("ArchiSteamFarm.OfficialPlugins.MobileAuthenticator.Localization.Strings", typeof(Strings).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,13 +53,11 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
</root>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user