Compare commits

..

297 Commits

Author SHA1 Message Date
Łukasz Domeradzki
607b380ddd Bump 2024-11-17 20:15:42 +01:00
Łukasz Domeradzki
1ec9118af2 Merge branch 'main' of https://github.com/JustArchiNET/ArchiSteamFarm 2024-11-15 23:54:42 +01:00
renovate[bot]
c911ad45bf chore(deps): update dependency microsoft.identitymodel.jsonwebtokens to 8.2.1 2024-11-15 19:50:58 +00:00
renovate[bot]
0dee3e311a chore(deps): update asf-ui digest to 1f0b191 2024-11-15 08:05:11 +00:00
ArchiBot
17ef5e3aee Automatic translations update 2024-11-15 02:22:07 +00:00
renovate[bot]
1505e2dbd4 chore(deps): update github/codeql-action action to v3.27.4 2024-11-14 16:57:46 +00:00
Łukasz Domeradzki
1ea5913f3d Misc 2024-11-14 12:02:18 +01:00
renovate[bot]
7f548a1982 chore(deps): update asf-ui digest to e83c58e 2024-11-14 05:07:08 +00:00
ArchiBot
d1b7133db3 Automatic translations update 2024-11-14 02:19:56 +00:00
renovate[bot]
c5bee672d1 chore(deps): update dependency opentelemetry.extensions.hosting to 1.10.0 2024-11-13 03:04:04 +00:00
renovate[bot]
50b054890a chore(deps): update asf-ui digest to 33319ed 2024-11-13 01:34:12 +00:00
renovate[bot]
ef9d269660 chore(deps): update github/codeql-action action to v3.27.3 2024-11-12 23:30:37 +00:00
renovate[bot]
f01b0d6641 chore(deps): update swashbuckle-aspnetcore monorepo to v7 (#3338)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-13 00:30:07 +01:00
renovate[bot]
f9519141b1 chore(deps): update dotnet monorepo to v9 (#3337)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-13 00:29:18 +01:00
Łukasz Domeradzki
1b626caa53 .NET ⑨ (strongest version) (#3244)
* Initial .NET 9 bump

* Resolve selected .NET 9 analyzer warnings

* Fill TODO

* Fix build errors

* Misc

* Use new methods

* .NET 9 changes

* Dockerfiles no longer preview

* Misc

* Trimming works again

* Trimming works in docker too

* Test fix

* Update Directory.Build.props
2024-11-13 00:28:52 +01:00
renovate[bot]
4167b6be54 chore(deps): update dependency microsoft.codeanalysis.resxsourcegenerator to 3.11.0-beta1.24508.2 2024-11-12 20:39:22 +00:00
renovate[bot]
8305ba92c3 chore(deps): update dependency mstest to 3.6.3 2024-11-12 17:30:32 +00:00
renovate[bot]
8efe6d7f70 chore(deps): update github/codeql-action action to v3.27.2 2024-11-12 14:46:50 +00:00
renovate[bot]
8cd9587ab7 chore(deps): update asf-ui digest to 406694f 2024-11-12 04:44:09 +00:00
ArchiBot
ed0da062df Automatic translations update 2024-11-12 02:18:36 +00:00
ArchiBot
83daa09c80 Automatic translations update 2024-11-11 02:20:07 +00:00
renovate[bot]
5599bf179b chore(deps): update wiki digest to 5d6bb1d 2024-11-10 18:15:44 +00:00
Łukasz Domeradzki
44cf96ce70 Bump 2024-11-10 15:42:19 +01:00
Łukasz Domeradzki
540408a3d0 Fix kestrel deadlock in update procedure when using update command 2024-11-10 15:36:41 +01:00
ArchiBot
9058898f3b Automatic translations update 2024-11-10 02:20:43 +00:00
ArchiBot
4643529e7f Automatic translations update 2024-11-09 02:17:54 +00:00
renovate[bot]
b0f9268996 chore(deps): update github/codeql-action action to v3.27.1 2024-11-08 18:34:33 +00:00
ArchiBot
b863a7e523 Automatic translations update 2024-11-08 02:19:25 +00:00
renovate[bot]
4a77c987ed chore(deps): update dependency steamkit2 to 3.0.0 2024-11-07 13:32:41 +00:00
ArchiBot
7d7c4ba3a5 Automatic translations update 2024-11-07 02:19:45 +00:00
renovate[bot]
f2e8fd0ec4 chore(deps): update wiki digest to 50688c7 2024-11-06 19:33:17 +00:00
Łukasz Domeradzki
a8f1cef5b8 Remove obsolete functionalities, bump 2024-11-06 18:47:39 +01:00
Łukasz Domeradzki
7c481de811 Closes #3327 2024-11-06 17:40:05 +01:00
ArchiBot
b66d883c1c Automatic translations update 2024-11-06 02:18:56 +00:00
renovate[bot]
48a742add5 chore(deps): update actions/attest-build-provenance action to v1.4.4 2024-11-05 21:02:39 +00:00
renovate[bot]
adddc1b5ba chore(deps): update asf-ui digest to 3cc6e93 2024-11-03 05:10:14 +00:00
ArchiBot
d63ef5e58c Automatic translations update 2024-11-03 02:22:03 +00:00
renovate[bot]
765651d94d chore(deps): update dependency microsoft.identitymodel.jsonwebtokens to 8.2.0 2024-11-02 22:07:14 +00:00
renovate[bot]
8c9462d387 chore(deps): update asf-ui digest to aed20b6 2024-11-02 07:27:55 +00:00
renovate[bot]
04bfe96e16 chore(deps): update asf-ui digest to bc7d0a9 2024-11-01 00:35:11 +00:00
renovate[bot]
2f8ef39ead chore(deps): update dependency mstest to 3.6.2 2024-10-31 16:15:08 +00:00
Łukasz Domeradzki
35cdfbf169 Misc 2024-10-31 11:58:18 +01:00
ArchiBot
fd69303a0e Automatic translations update 2024-10-31 02:20:54 +00:00
renovate[bot]
271311eeaf chore(deps): update asf-ui digest to a047b72 2024-10-30 04:28:28 +00:00
ArchiBot
00b2b24e54 Automatic translations update 2024-10-29 02:21:03 +00:00
renovate[bot]
c8e6b9efa5 chore(deps): update asf-ui digest to 7ffa683 2024-10-28 23:00:38 +00:00
renovate[bot]
b22f2f6420 chore(deps): update asf-ui digest to 3a33033 2024-10-28 16:16:27 +00:00
renovate[bot]
fa5c65f927 chore(deps): update crowdin/github-action action to v2.3.0 2024-10-28 14:34:25 +00:00
renovate[bot]
98f29b485b chore(deps): update jetbrains/qodana-action action to v2024.2.6 2024-10-28 11:29:07 +00:00
ArchiBot
712a38c70f Automatic translations update 2024-10-28 02:21:46 +00:00
Łukasz Domeradzki
c4dc037b3b Bump 2024-10-27 19:08:23 +01:00
Łukasz Domeradzki
6dddaa5992 Fix kestrel deadlock in update procedure
This time for good
2024-10-27 18:48:26 +01:00
renovate[bot]
8879ed71c5 chore(deps): update asf-ui digest to 7c5eb33 2024-10-27 03:40:36 +00:00
renovate[bot]
b4c4f73e5e chore(deps): update crazy-max/ghaction-import-gpg action to v6.2.0 2024-10-26 22:39:09 +00:00
renovate[bot]
17e64803c6 chore(deps): update dependency markdig.signed to 0.38.0 2024-10-25 22:22:01 +00:00
renovate[bot]
9c3b354fa2 chore(deps): update asf-ui digest to a45b124 2024-10-25 18:22:10 +00:00
renovate[bot]
040caa1f40 chore(deps): update dependency jetbrains.annotations to 2024.3.0 2024-10-25 03:01:44 +00:00
renovate[bot]
4cd8a7cb46 chore(deps): update actions/setup-node action to v4.1.0 2024-10-25 02:10:00 +00:00
renovate[bot]
782b54ac33 chore(deps): update actions/setup-dotnet action to v4.1.0 2024-10-24 21:50:51 +00:00
renovate[bot]
6437575763 chore(deps): update jetbrains/qodana-action action to v2024.2.5 2024-10-24 19:22:31 +00:00
renovate[bot]
df8856454a chore(deps): update asf-ui digest to 515711c 2024-10-24 16:55:33 +00:00
renovate[bot]
132f47d86f chore(deps): update asf-ui digest to 1cdd235 2024-10-24 05:14:34 +00:00
renovate[bot]
07f8dc543f chore(deps): update asf-ui digest to 7b3c90f 2024-10-23 23:17:51 +00:00
renovate[bot]
9a2fd8c91d chore(deps): update actions/checkout action to v4.2.2 2024-10-23 16:33:07 +00:00
renovate[bot]
6867f69909 chore(deps): update asf-ui digest to 61541c9 2024-10-23 10:29:16 +00:00
renovate[bot]
2c80f35388 chore(deps): update github/codeql-action action to v3.27.0 2024-10-22 21:42:13 +00:00
renovate[bot]
4e855011bc chore(deps): update asf-ui digest to 238c527 2024-10-22 18:46:50 +00:00
ArchiBot
a46dd753ba Automatic translations update 2024-10-22 02:20:44 +00:00
Łukasz Domeradzki
d7f3a0bf7e Bump 2024-10-21 13:08:52 +02:00
Łukasz Domeradzki
411c49addd Add proper support for server list provider cache 2024-10-21 12:56:17 +02:00
Łukasz Domeradzki
6bc29e8c3f Squashed commit of the following:
commit 7501fd264b7248633c6853a6f232dfbf894b944a
Author: Łukasz Domeradzki <JustArchi@JustArchi.net>
Date:   Mon Oct 21 12:18:54 2024 +0200

    Remove CI artifact

commit d6ad6e78e386d08b2b7aeb53992b4b987b08d729
Author: Łukasz Domeradzki <JustArchi@JustArchi.net>
Date:   Mon Oct 21 10:23:04 2024 +0200

    Bump experiments

commit d5553a52f3bc656c5dd1c280b9189bc48e4d417e
Merge: 6e34cdc2 4b3224a7
Author: Łukasz Domeradzki <JustArchi@JustArchi.net>
Date:   Mon Oct 21 10:19:16 2024 +0200

    Merge branch 'main' into unified-experiments

commit 6e34cdc26c0804852c2b0cbadedcafbe45afb787
Author: Łukasz Domeradzki <JustArchi@JustArchi.net>
Date:   Thu Oct 17 17:28:08 2024 +0200

    Update experiments

commit 70b1c6e367c697ee669b16bf4d18b17aef4c2bb0
Merge: c22eb587 def6b675
Author: Łukasz Domeradzki <JustArchi@JustArchi.net>
Date:   Thu Oct 17 17:18:34 2024 +0200

    Merge branch 'main' into unified-experiments

commit c22eb5872ebcd1a284e354b645d4dc634412513b
Author: Łukasz Domeradzki <JustArchi@JustArchi.net>
Date:   Mon Oct 14 20:07:23 2024 +0200

    Make it work

commit 9907d375040ca5a0750b70df541597be29abc21f
Merge: de4b33c2 d166e198
Author: Łukasz Domeradzki <JustArchi@JustArchi.net>
Date:   Mon Oct 14 19:31:06 2024 +0200

    Merge branch 'main' into unified-experiments

commit de4b33c2c458d516b1945dd7ea24db321f15f7f9
Author: Łukasz Domeradzki <JustArchi@JustArchi.net>
Date:   Sun Oct 13 20:22:32 2024 +0200

    Fix docker build again

commit 60f3be0bd89375d19333f017389c0ba223ea721a
Author: Łukasz Domeradzki <JustArchi@JustArchi.net>
Date:   Sun Oct 13 20:18:27 2024 +0200

    Fix docker build

commit 07502180c4eb32549533917efca661e13ccf1a2f
Author: Łukasz Domeradzki <JustArchi@JustArchi.net>
Date:   Sun Oct 13 20:15:18 2024 +0200

    Commit missing part

commit 75fd1b867511419fa11d224042f5bc761571ac8d
Author: Łukasz Domeradzki <JustArchi@JustArchi.net>
Date:   Sun Oct 13 20:12:12 2024 +0200

    Craft some experiments
2024-10-21 12:19:23 +02:00
ArchiBot
4b3224a748 Automatic translations update 2024-10-21 02:21:09 +00:00
renovate[bot]
1b95433cb6 chore(deps): update asf-ui digest to 7aba78d 2024-10-20 21:59:26 +00:00
Łukasz Domeradzki
64db3f4c09 Misc
https://docs.docker.com/reference/build-checks/redundant-target-platform/
2024-10-20 23:59:02 +02:00
renovate[bot]
22509fed14 chore(deps): update asf-ui digest to 2485e01 2024-10-20 04:25:22 +00:00
ArchiBot
819b5f3dbf Automatic translations update 2024-10-20 02:22:33 +00:00
renovate[bot]
2c1975d203 chore(deps): update asf-ui digest to 2e68b90 2024-10-19 04:59:45 +00:00
ArchiBot
46d6aa44d1 Automatic translations update 2024-10-19 02:19:31 +00:00
renovate[bot]
17130b7215 chore(deps): update wiki digest to bc10b9e 2024-10-18 23:23:50 +00:00
renovate[bot]
3b0d0e033f chore(deps): update asf-ui digest to 499e1c4 2024-10-18 02:27:53 +00:00
renovate[bot]
def6b6751b chore(deps): update asf-ui digest to c289dc1 2024-10-17 09:56:10 +00:00
ArchiBot
90756bde27 Automatic translations update 2024-10-17 02:20:15 +00:00
renovate[bot]
a28c431dcd chore(deps): update swashbuckle-aspnetcore monorepo to 6.9.0 2024-10-15 13:32:00 +00:00
renovate[bot]
50fc619d92 chore(deps): update github/codeql-action action to v3.26.13 2024-10-15 00:19:55 +00:00
renovate[bot]
2475c040b9 chore(deps): update asf-ui digest to 867bd21 2024-10-14 21:12:28 +00:00
ArchiBot
d166e198de Automatic translations update 2024-10-14 12:36:26 +00:00
Łukasz Domeradzki
5a9750a4b6 Workaround stale cache of CM servers 2024-10-14 13:42:29 +02:00
ArchiBot
fc64511268 Automatic translations update 2024-10-14 02:21:05 +00:00
Łukasz Domeradzki
f2b8897ed1 Misc 2024-10-13 18:36:50 +02:00
Łukasz Domeradzki
dae03afc2d Bump 2024-10-13 18:27:20 +02:00
renovate[bot]
5d383dcae6 chore(deps): update dependency steamkit2 to 3.0.0-beta.4 2024-10-13 09:54:17 +00:00
ArchiBot
3e4c7ac9f8 Automatic translations update 2024-10-13 02:21:36 +00:00
Łukasz Domeradzki
f48caa08e9 Misc 2024-10-12 21:05:00 +02:00
Łukasz Domeradzki
f32fafdf15 Resolve eternal TODO with ASF API update routine 2024-10-12 21:03:11 +02:00
Łukasz Domeradzki
f427b89617 Bump 2024-10-12 18:55:44 +02:00
Łukasz Domeradzki
b0e36948c5 Misc
Don't force reconnect if we're somehow already connected during Start()
2024-10-12 16:11:10 +02:00
Łukasz Domeradzki
b0254aea2d Implement extra bullet-proofing and synchronization over connect/disconnect logic
Address @ezhevita findings in regards to race conditions:

- NRE in this lambda function: 1a9f2a23c4/ArchiSteamFarm/Steam/Bot.cs (L1962)
- NRE in the ArchiSteamFarm.Steam.Bot.StopHandlingCallbacks (probably race condition?)

In general, both are caused by race conditions which can happen if user attempts to start/stop bot while critical section of handling callbacks loop is going. The code is overly complex unfortunately, so debugging it/guarantee of safety is problematic.

This commit therefore attempts to fix the underlying issue by synchronizing the code that starts/stops the underlying callbacks handling loop. While the loop itself is already thread-safe, the code that starts/stops it was not before. Now Start() as well as Stop() can not occur concurrently. On top of that, the only other place which has potential to stop the loop - final disconnect, is also guarded with additional condition that it can fire only if we're NOT set to KeepRunning at the time of calling, which should fix the situation where late disconnected callback could potentially stop already triggered new loop.

As usual in such complex situations, time will tell if this fixes all the issues we have.
2024-10-12 16:06:11 +02:00
renovate[bot]
a84b9ca395 chore(deps): update asf-ui digest to 3c6cb34 2024-10-11 15:38:43 +00:00
ArchiBot
1a9f2a23c4 Automatic translations update 2024-10-11 02:19:45 +00:00
renovate[bot]
e6cb7ceb7b chore(deps): update asf-ui digest to 0e3c497 2024-10-10 19:21:22 +00:00
renovate[bot]
ec28ae562b chore(deps): update asf-ui digest to 30aa298 2024-10-10 00:20:42 +00:00
renovate[bot]
74b832ea4e chore(deps): update actions/upload-artifact action to v4.4.3 2024-10-09 18:16:55 +00:00
renovate[bot]
32c107ae53 chore(deps): update dependency microsoft.identitymodel.jsonwebtokens to 8.1.2 2024-10-09 06:24:49 +00:00
renovate[bot]
87d28aea81 chore(deps): update actions/upload-artifact action to v4.4.2 2024-10-09 03:37:16 +00:00
ArchiBot
79b81ac5d1 Automatic translations update 2024-10-09 02:24:33 +00:00
renovate[bot]
57489bc9cb chore(deps): update asf-ui digest to 1d4a3f6 2024-10-08 21:43:48 +00:00
renovate[bot]
e45b09b675 chore(deps): update dependency microsoft.codeanalysis.resxsourcegenerator to 3.11.0-beta1.24454.1 2024-10-08 15:31:53 +00:00
renovate[bot]
c3d579a835 chore(deps): update asf-ui digest to 178501e 2024-10-08 03:58:21 +00:00
ArchiBot
9d2f4fd795 Automatic translations update 2024-10-08 02:21:10 +00:00
renovate[bot]
a173c84ffb chore(deps): update github/codeql-action action to v3.26.12 2024-10-07 22:00:26 +00:00
renovate[bot]
94ed85914a chore(deps): update actions/checkout action to v4.2.1 2024-10-07 19:05:34 +00:00
renovate[bot]
90c2986277 chore(deps): update actions/upload-artifact action to v4.4.1 2024-10-07 16:08:28 +00:00
ArchiBot
3cff63193d Automatic translations update 2024-10-07 02:21:23 +00:00
renovate[bot]
53066b1f14 chore(deps): update wiki digest to 9bef679 2024-10-06 16:49:08 +00:00
Łukasz Domeradzki
c7524af07a Misc 2024-10-06 15:58:38 +02:00
Łukasz Domeradzki
500a148632 Bump 2024-10-06 15:24:57 +02:00
Łukasz Domeradzki
33c9aeda21 Closes #3304 2024-10-06 15:14:48 +02:00
ArchiBot
9b40ab3b52 Automatic translations update 2024-10-06 02:21:58 +00:00
Łukasz Domeradzki
5a115f1822 Bump 2024-10-05 13:50:42 +02:00
Sebastian Göls
de9900ad14 Revert JSON serialization to how it was with Newtonsoft (#3302) 2024-10-05 13:49:48 +02:00
renovate[bot]
731fbca87c chore(deps): update dependency microsoft.identitymodel.jsonwebtokens to 8.1.1 2024-10-05 03:44:52 +00:00
ArchiBot
8ed27013a4 Automatic translations update 2024-10-05 02:19:08 +00:00
renovate[bot]
9590afa752 chore(deps): update docker/setup-buildx-action action to v3.7.1 2024-10-04 16:27:37 +00:00
Łukasz Domeradzki
f534997e0e Close log endpoints upon graceful shutdown request
Previously we've kept websocket connection open for as long as caller requested it. During graceful shutdown, ASP.NET normally waits for all pending requests to finish, while no longer accepting new ones - this is a very good approach. In our case however, since we didn't do anything with that event before, the graceful shutdown was timing out after 30 seconds before eventually forcefully killing any still-ongoing requests, websocket connection in our case.

Hook into application lifetime in order to be notified when the graceful shutdown happens. This way we can create linked cancellation token for request abort and graceful shutdown and close the websocket connection when any of those two happens.
2024-10-04 17:58:56 +02:00
Łukasz Domeradzki
d609a68dc4 Bump 2024-10-04 14:34:58 +02:00
Łukasz Domeradzki
92456aa838 Avoid terminating the process if not mandatory 2024-10-04 14:32:42 +02:00
Łukasz Domeradzki
d074f47659 Ignore unobserved HttpIOException 2024-10-04 14:27:02 +02:00
renovate[bot]
4cc16897cf chore(deps): update github/codeql-action action to v3.26.11 2024-10-04 04:29:31 +00:00
ArchiBot
8cabec1aff Automatic translations update 2024-10-04 02:20:05 +00:00
renovate[bot]
e7650ab10e chore(deps): update dependency mstest to 3.6.1 2024-10-03 21:23:55 +00:00
renovate[bot]
97ecba07bb chore(deps): update asf-ui digest to 6a1e814 2024-10-03 18:44:34 +00:00
renovate[bot]
061413303a chore(deps): update docker/setup-buildx-action action to v3.7.0 2024-10-03 09:41:06 +00:00
ArchiBot
6bb3d4b48a Automatic translations update 2024-10-03 02:20:14 +00:00
renovate[bot]
90a27b2a4d chore(deps): update asf-ui digest to 615cc1a 2024-10-02 19:24:54 +00:00
renovate[bot]
61aa656611 chore(deps): update wiki digest to 36a8184 2024-10-02 07:23:08 +00:00
renovate[bot]
c6ae45f6ab chore(deps): update asf-ui digest to ef73b2a 2024-10-02 03:33:55 +00:00
ArchiBot
d72eb0b06d Automatic translations update 2024-10-02 02:20:03 +00:00
renovate[bot]
5c728127f1 chore(deps): update wiki digest to 545a92c 2024-10-01 10:09:58 +00:00
ArchiBot
a64472188c Automatic translations update 2024-10-01 02:23:36 +00:00
renovate[bot]
39f7f0a1c6 chore(deps): update docker/build-push-action action to v6.9.0 2024-09-30 21:30:10 +00:00
Łukasz Domeradzki
1e3461918e Misc 2024-09-30 22:49:03 +02:00
Łukasz Domeradzki
ae0704e2bb Remove obsolete alias 2024-09-30 22:46:48 +02:00
Łukasz Domeradzki
42e07c2445 Merge branch 'main' of https://github.com/JustArchiNET/ArchiSteamFarm 2024-09-30 22:45:57 +02:00
Łukasz Domeradzki
641cf5a350 Rewrite points balance from AWH to AH 2024-09-30 22:45:02 +02:00
renovate[bot]
f984a9122e chore(deps): update wiki digest to 66d2709 (#3295)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-30 22:25:50 +02:00
Łukasz Domeradzki
889795a326 Bump 2024-09-30 22:24:40 +02:00
Łukasz Domeradzki
d5df9e0af9 Bump 2024-09-30 22:24:04 +02:00
Łukasz Domeradzki
b7a6cc5158 Activate multiple definitions in parallel 2024-09-30 22:15:38 +02:00
Łukasz Domeradzki
55d49f87ff Closes #3299 2024-09-30 22:02:09 +02:00
Łukasz Domeradzki
c2abbf0fc0 Misc optimization 2024-09-30 19:19:26 +02:00
Łukasz Domeradzki
ba11952945 Handle exceptions in ArchiCacheable
While our code does not throw them, this is public helper and we don't need to enforce from other callers exceptions-less flow. We can use it for a failure.
2024-09-30 19:16:52 +02:00
renovate[bot]
a7f2556b48 chore(deps): update github/codeql-action action to v3.26.10 2024-09-30 13:49:28 +00:00
renovate[bot]
b66dd2c01b chore(deps): update swashbuckle-aspnetcore monorepo to 6.8.1 2024-09-30 10:22:56 +00:00
ArchiBot
c6261af03c Automatic translations update 2024-09-30 02:21:42 +00:00
ArchiBot
e44d1ac62e Automatic translations update 2024-09-29 02:21:59 +00:00
renovate[bot]
37afe1959a chore(deps): update asf-ui digest to fa46e12 2024-09-28 10:46:57 +00:00
ArchiBot
da04f6b100 Automatic translations update 2024-09-28 02:19:20 +00:00
renovate[bot]
168dc5cb35 chore(deps): update asf-ui digest to faa5f79 2024-09-27 22:19:00 +00:00
Łukasz Domeradzki
9f4d5df8d2 Bump 2024-09-28 00:18:33 +02:00
Łukasz Domeradzki
0c21c223be Closes #3294 2024-09-28 00:03:15 +02:00
Łukasz Domeradzki
1fc4ac8e07 Update GlobalConfig.cs 2024-09-27 23:31:01 +02:00
Łukasz Domeradzki
088161e9ba Experimental update channel rebrand 2024-09-27 23:23:55 +02:00
renovate[bot]
246429f7a1 chore(deps): update docker/build-push-action action to v6.8.0 2024-09-27 12:36:42 +00:00
ArchiBot
2478dd6c10 Automatic translations update 2024-09-27 02:20:15 +00:00
ArchiBot
ee234001f1 Automatic translations update 2024-09-26 02:19:53 +00:00
renovate[bot]
9325959358 chore(deps): update asf-ui digest to 9f5672d 2024-09-25 22:49:39 +00:00
renovate[bot]
aed6784f55 chore(deps): update actions/checkout action to v4.2.0 2024-09-25 19:41:36 +00:00
Łukasz Domeradzki
b5f916dbac Add support for desktop.ini on Windows 2024-09-25 11:59:41 +02:00
renovate[bot]
2555623064 chore(deps): update github/codeql-action action to v3.26.9 2024-09-24 18:08:58 +00:00
renovate[bot]
83aa57a764 chore(deps): update dependency microsoft.identitymodel.jsonwebtokens to 8.1.0 2024-09-24 16:36:14 +00:00
ArchiBot
44ed1b1547 Automatic translations update 2024-09-24 02:20:24 +00:00
renovate[bot]
1b91674f9b chore(deps): update dependency nlog.web.aspnetcore to 5.3.14 2024-09-23 22:05:05 +00:00
renovate[bot]
cc363c2f51 chore(deps): update asf-ui digest to 975f624 2024-09-23 17:01:59 +00:00
renovate[bot]
0982943799 chore(deps): update crowdin/github-action action to v2.2.0 2024-09-23 14:24:50 +00:00
renovate[bot]
c79faf6c0e chore(deps): update swashbuckle-aspnetcore monorepo to 6.8.0 2024-09-23 11:11:54 +00:00
ArchiBot
ea110d5da9 Automatic translations update 2024-09-23 02:19:31 +00:00
Łukasz Domeradzki
40dc70e8c7 Misc 2024-09-22 20:42:44 +02:00
Łukasz Domeradzki
5cc684f4b6 .NET 9 improvements 2024-09-22 20:11:50 +02:00
Łukasz Domeradzki
3f605d59d4 Misc 2024-09-22 19:49:22 +02:00
renovate[bot]
d79af97dfc chore(deps): update asf-ui digest to c79c3a1 2024-09-21 03:25:56 +00:00
Łukasz Domeradzki
a701e14a62 Bump 2024-09-20 21:50:46 +02:00
renovate[bot]
8e30183d7c chore(deps): update dependency steamkit2 to 3.0.0-beta.3 2024-09-20 10:54:53 +00:00
renovate[bot]
7d21795c2f chore(deps): update asf-ui digest to 54a84d6 2024-09-20 06:07:16 +00:00
renovate[bot]
26765f31f7 chore(deps): update jetbrains/qodana-action action to v2024.2.3 2024-09-20 02:00:58 +00:00
renovate[bot]
708c523b57 chore(deps): update github/codeql-action action to v3.26.8 2024-09-19 21:58:05 +00:00
renovate[bot]
d05c6b996c chore(deps): update actions/setup-node action to v4.0.4 2024-09-19 18:22:17 +00:00
renovate[bot]
f2f83b0a60 chore(deps): update asf-ui digest to 338bd57 2024-09-19 17:13:20 +00:00
Łukasz Domeradzki
2c0e14fb55 Force github plugins re-update due to compatibility reasons 2024-09-19 16:43:26 +02:00
Łukasz Domeradzki
dca2e6f060 Bump 2024-09-19 14:09:10 +02:00
Łukasz Domeradzki
440e43935a Misc 2024-09-19 14:08:45 +02:00
Łukasz Domeradzki
1dff9a48a8 Closes #3291
As presented in the issue, we might end up in situation when parallel-processing and accepting two neutral+ trade offers will result in unwanted inventory state, because while they're both neutral+ and therefore OK to accept standalone, the combination of them both causes active badge progress degradation.

Considering the requirements we have, e.g. still processing trades in parallel, being performant, low on resources and with limited Steam servers overhead, the solution that I came up with in regards to this issue is quite simple:

- After we determine the trade to be neutral+, but before we tell the parse trade routine to accept it, we check if shared with other parallel processes set of handled sets contains any sets that we're currently processing.
- If no, we update that set to include everything we're dealing with, and tell the caller to accept this trade.
- If yes, we tell the caller to retry this trade after (other) accepted trades are confirmed and handled as usual.

This solves some issues and creates some optimistic assumptions:
- First of all, it solves the original issue, since if trade A and B both touch set S, then only one of them will be accepted. It's not deterministic which one (the one that gets to the check first), and not important anyway.
- We do not "lock" the sets before we determine that trade is neutral+, because otherwise unrelated users could spam us with non-neutral+ trades in order to lock the bot in infinite retry. This way they can't, as if the trade is determined to not be neutral+ then it never checks for concurrent processing.
- We are optimistic about resources usage. This routine could be made much more complicated to be more synchronous in order to avoid unnecessary calls to inventory and matching, however, that'd slow down the whole process only because the next call MAYBE will be determined as unneeded. Due to that, ASF is optimistic that trades will (usually) be unrelated, and can be processed in parallel, and if the conflict happens then simply we end up in a situation where we did some extra work for no reason, which is better than waiting with the work till all previous trades are processed.
- As soon as the conditions are met, the conflicting trades are retried to check if the conditions allow to accept them. If yes, they'll be accepted almost immediately after previous ones, if not, they'll be rejected as non-neutral+ anymore.

This way the additional code does not hurt the performance, parallel processing or anything else in usually expected optimistic scenarios, while adding some additional overhead in pessimistic ones, which is justified considering we don't want to degrade the badge progress.
2024-09-19 13:53:11 +02:00
renovate[bot]
85e90bb8d5 chore(deps): update asf-ui digest to 122393d 2024-09-19 00:13:45 +00:00
renovate[bot]
b62b2382fd chore(deps): update crowdin/github-action action to v2.1.3 2024-09-18 13:51:51 +00:00
renovate[bot]
07f64a0107 chore(deps): update asf-ui digest to 7ae118c 2024-09-18 11:33:46 +00:00
ArchiBot
dcdb2cb175 Automatic translations update 2024-09-18 08:49:16 +00:00
Łukasz Domeradzki
33e7ae83dc Fix wiki push 2024-09-18 10:48:24 +02:00
renovate[bot]
ac0a1da140 chore(deps): update jetbrains/qodana-action action to v2024.2.2 2024-09-17 16:55:13 +00:00
ArchiBot
1ad03ac61c Automatic translations update 2024-09-17 02:06:16 +00:00
renovate[bot]
b28736cb84 chore(deps): update asf-ui digest to 39127c2 2024-09-16 21:53:31 +00:00
Łukasz Domeradzki
602c01e2d9 Misc localization improvement 2024-09-16 20:51:32 +02:00
Łukasz Domeradzki
7b65c1aeb7 Add support for telling plugins if runtime is trimmed 2024-09-16 17:58:35 +02:00
Łukasz Domeradzki
a27973800c Provide extra info when failing to initialize plugins with TypeLoadException 2024-09-16 16:45:52 +02:00
Łukasz Domeradzki
cb4580c0d9 Remove github-push-action 2024-09-16 16:18:01 +02:00
renovate[bot]
1a74d83eae chore(deps): update github/codeql-action action to v3.26.7 2024-09-13 15:16:25 +00:00
Łukasz Domeradzki
319ee49c67 Bump 2024-09-13 14:47:07 +02:00
Łukasz Domeradzki
cefa3e1e1e Fix reconnection with connection being lost
After changes regarding to callbacks handling, we accidentally broke the reconnection logic. In particular, forced connection implicitly did disconnect with disconnect callback, but disconnect callback killed our callbacks handling loop for future connection since it was instructed to not reconnect... Pretty convulated logic.

Let's attempt to fix and simplify it. There is no forced connection concept anymore, but rather a new reconnect function which either, triggers reconnection through usual disconnection logic, or connects in edge case if we attempted to reconnect with already disconnnected client.

This way the status transition is more predictable, as we Connect() only in 3 cases:
- Initial start, including !start command, when we actually spawn the callbacks handling loop
- Upon disconnection, if we're configured to reconnect
- Reconnection, in case we're already disconnected and can't use above

And we use reconnect when:
- Failure in heartbeats to detect disconnections sooner
- Failure in refreshing access tokens, since if we lose our refresh token then the only way to get a new one is to reconnect

And finally disconnect is triggered when:
- Stopping the bot, especially !stop
- Bulletproofing against trying to connect when !KeepRunning and likewise
- Usual Steam maintenance and other network issues (which usually trigger reconnection)

The codebase is too huge to analyze every possible edge case, but with this logic I can no longer reproduce the previous issue
2024-09-13 14:41:11 +02:00
Łukasz Domeradzki
061e61b740 Closes #3289 2024-09-13 13:42:20 +02:00
Łukasz Domeradzki
73d756f211 Bump 2024-09-13 12:50:21 +02:00
Łukasz Domeradzki
3bb83610b8 Misc refactor after #3287 2024-09-13 10:04:56 +02:00
dm1tz
8e85b87764 Add loot& and transfer& commands (#3287)
* Add `loot&` and `transfer&` commands

* Remove trailing comment
2024-09-13 09:20:35 +02:00
renovate[bot]
4d0f5a56ed chore(deps): update dependency nlog.web.aspnetcore to 5.3.13 2024-09-12 22:51:20 +00:00
ArchiBot
a8359e3e00 Automatic translations update 2024-09-12 02:17:57 +00:00
renovate[bot]
3812331901 chore(deps): update dependency mstest to 3.6.0 2024-09-11 10:21:01 +00:00
ArchiBot
1714bd26f9 Automatic translations update 2024-09-11 02:18:09 +00:00
renovate[bot]
d8ad42f760 chore(deps): update dependency microsoft.codeanalysis.resxsourcegenerator to 3.11.0-beta1.24415.1 2024-09-10 20:03:11 +00:00
renovate[bot]
c477bd2bae chore(deps): update wiki digest to c7cb49b 2024-09-10 11:38:24 +00:00
ArchiBot
aa1cd98646 Automatic translations update 2024-09-10 02:18:00 +00:00
ArchiBot
5f545a9bbc Automatic translations update 2024-09-09 02:18:15 +00:00
ArchiBot
0d3bc2cf47 Automatic translations update 2024-09-07 02:16:32 +00:00
renovate[bot]
8e65142d4c chore(deps): update asf-ui digest to e6ac58d 2024-09-06 14:15:24 +00:00
renovate[bot]
c26a758825 chore(deps): update crowdin/github-action action to v2.1.2 2024-09-06 07:28:01 +00:00
ArchiBot
a02d8cee86 Automatic translations update 2024-09-06 02:17:32 +00:00
renovate[bot]
2c4d2981cd chore(deps): update actions/attest-build-provenance action to v1.4.3 2024-09-05 18:44:30 +00:00
ArchiBot
6c5e0a20f1 Automatic translations update 2024-09-05 02:17:28 +00:00
renovate[bot]
db920da4b8 chore(deps): update wiki digest to 70757b8 2024-09-04 22:58:17 +00:00
Łukasz Domeradzki
efdc3eb7bb Misc 2024-09-04 22:24:31 +02:00
renovate[bot]
c0da86e4ca chore(deps): update asf-ui digest to 65b5c0c (#3281)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-04 14:46:51 +02:00
ArchiBot
720a24e9ad Automatic translations update 2024-09-04 02:17:13 +00:00
renovate[bot]
7dc6096e07 chore(deps): update asf-ui digest to 2997f0d 2024-09-03 22:00:17 +00:00
renovate[bot]
7910205674 chore(deps): update asf-ui digest to 8d4b148 2024-09-03 17:03:59 +00:00
Łukasz Domeradzki
1fbc51d02b Update ArchiSteamFarm.sln.DotSettings 2024-09-03 17:46:17 +02:00
renovate[bot]
a3d968c6af chore(deps): update asf-ui digest to 486401d (#3279)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-02 08:57:43 +02:00
Łukasz Domeradzki
63c61f8e47 Misc 2024-09-01 23:56:25 +02:00
Łukasz Domeradzki
1ae59f4229 Bump 2024-09-01 14:07:27 +02:00
Łukasz Domeradzki
4a95a6928b Bump 2024-09-01 14:05:18 +02:00
Łukasz Domeradzki
54a092a822 Take into account extended_onlyallowrunincountries when deciding upon region locks 2024-09-01 14:05:08 +02:00
renovate[bot]
9898d47db4 chore(deps): update asf-ui digest to ef232d5 (#3277)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-01 13:43:21 +02:00
renovate[bot]
b46e55c57b chore(deps): update asf-ui digest to f16eae1 2024-08-30 22:07:03 +00:00
renovate[bot]
cb6f9f3e00 chore(deps): update actions/upload-artifact action to v4.4.0 2024-08-30 19:47:10 +00:00
renovate[bot]
d750ba5f99 chore(deps): update github/codeql-action action to v3.26.6 2024-08-29 14:23:00 +00:00
ArchiBot
c84db87532 Automatic translations update 2024-08-27 02:15:43 +00:00
renovate[bot]
3da662ef61 chore(deps): update swashbuckle-aspnetcore monorepo to v6.7.3 2024-08-26 09:26:01 +00:00
Łukasz Domeradzki
2f42c75df7 Update Directory.Build.props 2024-08-26 11:25:11 +02:00
Łukasz Domeradzki
14388487fd Fix build 2024-08-26 10:07:31 +02:00
Łukasz Domeradzki
a155748f88 Misc 2024-08-26 10:04:54 +02:00
renovate[bot]
c7fa69a25b chore(deps): update dependency steamkit2 to v3.0.0-beta.2 2024-08-26 08:00:56 +00:00
renovate[bot]
5194cb103a chore(deps): update swashbuckle-aspnetcore monorepo to v6.7.2 2024-08-24 14:13:46 +00:00
renovate[bot]
77ec0d1c78 chore(deps): update github/codeql-action action to v3.26.5 2024-08-24 02:34:08 +00:00
renovate[bot]
d85c9a3c0a chore(deps): update asf-ui digest to 1641151 2024-08-23 18:03:25 +00:00
renovate[bot]
97a8e6f5c2 chore(deps): update actions/attest-build-provenance action to v1.4.2 2024-08-22 23:37:30 +00:00
renovate[bot]
3d73b42c15 chore(deps): update asf-ui digest to 2b37add 2024-08-22 20:06:49 +00:00
renovate[bot]
4156dfcd4e chore(deps): update dependency microsoft.identitymodel.jsonwebtokens to v8.0.2 2024-08-22 06:39:35 +00:00
renovate[bot]
9fb19bffc1 chore(deps): update github/codeql-action action to v3.26.4 2024-08-21 20:32:34 +00:00
ArchiBot
fe1cdce59d Automatic translations update 2024-08-21 02:13:51 +00:00
ArchiBot
c07caf6be8 Automatic translations update 2024-08-20 02:13:43 +00:00
renovate[bot]
cab8c60fcb chore(deps): update github/codeql-action action to v3.26.3 2024-08-19 19:59:22 +00:00
renovate[bot]
023c7da52b chore(deps): update wiki digest to e7c71c7 2024-08-19 12:37:17 +00:00
Łukasz Domeradzki
6b2bcbee6e Drop VS public signing workaround
They had enough of time to fix their stupidity
2024-08-19 14:36:19 +02:00
ArchiBot
ebac577ede Automatic translations update 2024-08-19 02:15:10 +00:00
renovate[bot]
0846291779 chore(deps): update swashbuckle-aspnetcore monorepo to v6.7.1 2024-08-18 07:55:58 +00:00
Łukasz Domeradzki
fab9d95096 Allow nullable T for concurrent list
Even if we don't use it, no reason to not support it, since it is in underlying collection
2024-08-18 03:21:03 +02:00
Łukasz Domeradzki
2dc853ebfc Misc 2024-08-18 03:17:30 +02:00
Łukasz Domeradzki
5867a351a8 Misc 2024-08-18 03:14:11 +02:00
Łukasz Domeradzki
5605e9a666 Misc 2024-08-18 01:59:25 +02:00
Łukasz Domeradzki
337b720d31 Misc deduplication 2024-08-18 01:53:13 +02:00
Łukasz Domeradzki
06185d5f7d Misc 2024-08-17 22:19:17 +02:00
Łukasz Domeradzki
90cfdd140b Bump 2024-08-17 21:45:40 +02:00
Łukasz Domeradzki
5a41d559a3 Misc
No point in making this available for all IEnumerables, only ICollections are affected
2024-08-16 03:35:09 +02:00
Łukasz Domeradzki
b6805a94a3 Add workaround for LINQ race condition with concurrent collections
This is some next-level race condition, so for those interested:
- Concurrent collections are thread-safe in a way that each operation is atomic
- Naturally if you call two atomic operations in a row, the result is no longer atomic, since there could be some changes between the first and the last
- Certain LINQ operations such as OrderBy(), Reverse(), ToArray(), among more, use internal buffer for operation with certain optimization that checks if input is ICollection, if yes, it calls Count and CopyTo(), for OrderBy in this example
- In result, such LINQ call is not guaranteed to be thread-safe, since it assumes those two calls to be atomic, while they're not in reality.

This issue is quite hard to spot in real applications, since it's not that easy to trigger it (you need to call the operation on ICollection and then have another thread modifying it while enumerating). This is probably why we've never had any real problem until I've discovered this madness with @Aareksio in entirely different project.

As a workaround, we'll explicitly convert some ICollection inputs to IEnumerable, in particular around OrderBy(), so the optimization is skipped and the result is not corrupted.

I've added unit tests which ensure this workaround works properly, and you can easily reproduce the problem by removing AsLinqThreadSafeEnumerable() in them.

See https://github.com/dotnet/runtime/discussions/50687 for more insight

I have no clue who thought that ignoring this issue is a good idea, at the very least concurrent collections should have opt-out mechanism from those optimizations, there is no reason for them to not do that.
2024-08-16 03:25:58 +02:00
renovate[bot]
6a678cd5a9 chore(deps): update github/codeql-action action to v3.26.2 2024-08-14 16:30:56 +00:00
renovate[bot]
ecaf61252a chore(deps): update asf-ui digest to 6900304 2024-08-14 08:46:01 +00:00
ArchiBot
85c4e4ac37 Automatic translations update 2024-08-14 02:14:19 +00:00
renovate[bot]
16394182b2 chore(deps): update github/codeql-action action to v3.26.1 2024-08-13 23:09:58 +00:00
renovate[bot]
a0cc53cbb7 chore(deps): update docker/build-push-action action to v6.7.0 2024-08-13 19:17:41 +00:00
renovate[bot]
f331ee2c24 chore(deps): update dependency mstest to v3.5.2 2024-08-13 17:39:50 +00:00
renovate[bot]
cb0767f28e chore(deps): update dependency microsoft.codeanalysis.resxsourcegenerator to v3.11.0-beta1.24324.1 2024-08-13 13:40:40 +00:00
renovate[bot]
91aaf3be19 chore(deps): update dependency nlog.web.aspnetcore to v5.3.12 2024-08-13 04:29:59 +00:00
ArchiBot
9540e564fc Automatic translations update 2024-08-13 02:15:24 +00:00
renovate[bot]
2100d6287c chore(deps): update asf-ui digest to 184c664 2024-08-12 01:06:04 +00:00
ArchiBot
8ad8183d4f Automatic translations update 2024-08-11 02:16:59 +00:00
Łukasz Domeradzki
90f2d93768 Optimize mobile authenticator, add unit tests 2024-08-11 02:21:00 +02:00
renovate[bot]
bae8dc330c chore(deps): update asf-ui digest to 1136a49 2024-08-10 04:23:27 +00:00
ArchiBot
599ca4d2c9 Automatic translations update 2024-08-10 02:13:43 +00:00
Łukasz Domeradzki
ff7a1e7c0e Misc optimization 2024-08-09 23:03:56 +02:00
renovate[bot]
216cd51c4a chore(deps): update actions/attest-build-provenance action to v1.4.1 2024-08-09 17:47:24 +00:00
Łukasz Domeradzki
568e9935ac Bump 2024-08-08 14:19:46 +02:00
renovate[bot]
28e9247c9a chore(deps): update docker/build-push-action action to v6.6.1 2024-08-07 21:16:33 +00:00
renovate[bot]
df3f16d424 chore(deps): update jetbrains/qodana-action action to v2024.1.9 2024-08-07 15:40:18 +00:00
renovate[bot]
41d03a15ac chore(deps): update docker/build-push-action action to v6.6.0 2024-08-07 12:26:35 +00:00
renovate[bot]
3f0e67075f chore(deps): update asf-ui digest to eb4cb97 2024-08-07 03:57:07 +00:00
ArchiBot
67329ec668 Automatic translations update 2024-08-07 02:14:49 +00:00
Łukasz Domeradzki
f28d783272 Misc 2024-08-07 03:15:22 +02:00
Łukasz Domeradzki
2c9d015f38 Fix @xPaw breaking changes
How could you!
2024-08-07 03:02:04 +02:00
renovate[bot]
5ad8a93d48 chore(deps): update dependency steamkit2 to v3.0.0-beta.1 2024-08-06 22:11:53 +00:00
renovate[bot]
ac9c1504e9 chore(deps): update github/codeql-action action to v3.26.0 2024-08-06 18:12:59 +00:00
renovate[bot]
4cde913453 chore(deps): update actions/upload-artifact action to v4.3.6 2024-08-06 15:22:49 +00:00
Łukasz Domeradzki
f05d041e6d Bump 2024-08-06 12:31:56 +02:00
140 changed files with 3941 additions and 1179 deletions

View File

@@ -122,8 +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.CA1028.severity = silent
dotnet_diagnostic.CA1031.severity = silent
# Rule - almost everything
dotnet_naming_rule.almost_everything_must_be_pascal_case.severity = warning
@@ -225,6 +225,10 @@ dotnet_style_qualification_for_property = false:warning
dotnet_style_readonly_field = true:warning
dotnet_style_require_accessibility_modifiers = always:warning
[ArchiSteamFarm/**.cs]
# ASF project includes plugin system, therefore CA1515 typically doesn't make sense there
dotnet_diagnostic.CA1515.severity = silent
###############################
# JetBrains, IntelliJ/Rider #
###############################

6
.gitattributes vendored
View File

@@ -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

View File

@@ -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.**
---

View File

@@ -5,7 +5,7 @@ on: [push, pull_request]
env:
DOTNET_CLI_TELEMETRY_OPTOUT: true
DOTNET_NOLOGO: true
DOTNET_SDK_VERSION: 8.0
DOTNET_SDK_VERSION: 9.0
permissions: {}
@@ -21,13 +21,13 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4.2.2
with:
show-progress: false
submodules: recursive
- name: Setup .NET Core
uses: actions/setup-dotnet@v4.0.1
uses: actions/setup-dotnet@v4.1.0
with:
dotnet-version: ${{ env.DOTNET_SDK_VERSION }}

View File

@@ -20,12 +20,12 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4.2.2
with:
show-progress: false
- name: Run Qodana scan
uses: JetBrains/qodana-action@v2024.1.8
uses: JetBrains/qodana-action@v2024.2.6
with:
args: --config,.github/qodana.yaml,--property=idea.headless.enable.statistics=false
pr-mode: false
@@ -34,6 +34,6 @@ jobs:
QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}
- name: Report Qodana results to GitHub
uses: github/codeql-action/upload-sarif@v3.25.15
uses: github/codeql-action/upload-sarif@v3.27.4
with:
sarif_file: ${{ runner.temp }}/qodana/results/qodana.sarif.json

View File

@@ -14,13 +14,13 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4.2.2
with:
show-progress: false
submodules: recursive
- name: Upload latest strings for translation on Crowdin
uses: crowdin/github-action@v2.1.1
uses: crowdin/github-action@v2.3.0
with:
crowdin_branch_name: main
config: '.github/crowdin.yml'

View File

@@ -19,16 +19,16 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4.2.2
with:
show-progress: false
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.6.1
uses: docker/setup-buildx-action@v3.7.1
- name: Build ${{ matrix.configuration }} Docker image from ${{ matrix.file }}
uses: docker/build-push-action@v6.5.0
uses: docker/build-push-action@v6.9.0
with:
build-args: CONFIGURATION=${{ matrix.configuration }}
context: .

View File

@@ -18,13 +18,13 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4.2.2
with:
show-progress: false
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.6.1
uses: docker/setup-buildx-action@v3.7.1
- name: Login to ghcr.io
uses: docker/login-action@v3.3.0
@@ -50,7 +50,7 @@ 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@v6.5.0
uses: docker/build-push-action@v6.9.0
with:
context: .
file: Dockerfile.Service

View File

@@ -19,13 +19,13 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4.2.2
with:
show-progress: false
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.6.1
uses: docker/setup-buildx-action@v3.7.1
- name: Login to ghcr.io
uses: docker/login-action@v3.3.0
@@ -50,7 +50,7 @@ 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@v6.5.0
uses: docker/build-push-action@v6.9.0
with:
context: .
platforms: ${{ env.PLATFORMS }}

View File

@@ -19,13 +19,13 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4.2.2
with:
show-progress: false
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.6.1
uses: docker/setup-buildx-action@v3.7.1
- name: Login to ghcr.io
uses: docker/login-action@v3.3.0
@@ -51,7 +51,7 @@ 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@v6.5.0
uses: docker/build-push-action@v6.9.0
with:
context: .
platforms: ${{ env.PLATFORMS }}

View File

@@ -6,7 +6,7 @@ env:
CONFIGURATION: Release
DOTNET_CLI_TELEMETRY_OPTOUT: true
DOTNET_NOLOGO: true
DOTNET_SDK_VERSION: 8.0
DOTNET_SDK_VERSION: 9.0
NODE_JS_VERSION: 'lts/*'
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
@@ -19,13 +19,13 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4.2.2
with:
show-progress: false
submodules: recursive
- name: Setup Node.js with npm
uses: actions/setup-node@v4.0.3
uses: actions/setup-node@v4.1.0
with:
check-latest: true
node-version: ${{ env.NODE_JS_VERSION }}
@@ -43,7 +43,7 @@ jobs:
run: npm run-script deploy --no-progress --prefix ASF-ui
- name: Upload ASF-ui
uses: actions/upload-artifact@v4.3.5
uses: actions/upload-artifact@v4.4.3
with:
if-no-files-found: error
name: ASF-ui
@@ -82,12 +82,12 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4.2.2
with:
show-progress: false
- name: Setup .NET Core
uses: actions/setup-dotnet@v4.0.1
uses: actions/setup-dotnet@v4.1.0
with:
dotnet-version: ${{ env.DOTNET_SDK_VERSION }}
@@ -362,12 +362,12 @@ jobs:
- name: Generate artifact attestation for ASF-${{ matrix.variant }}.zip
if: ${{ github.event_name == 'push' }}
uses: actions/attest-build-provenance@v1.4.0
uses: actions/attest-build-provenance@v1.4.4
with:
subject-path: out/ASF-${{ matrix.variant }}.zip
- name: Upload ASF-${{ matrix.variant }}
uses: actions/upload-artifact@v4.3.5
uses: actions/upload-artifact@v4.4.3
with:
if-no-files-found: error
name: ${{ matrix.os }}_ASF-${{ matrix.variant }}
@@ -409,13 +409,13 @@ jobs:
- 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.0
uses: actions/attest-build-provenance@v1.4.4
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.3.5
uses: actions/upload-artifact@v4.4.3
with:
if-no-files-found: error
name: ArchiSteamFarm.OfficialPlugins.Monitoring
@@ -434,7 +434,7 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4.2.2
with:
show-progress: false
@@ -493,7 +493,7 @@ jobs:
path: out
- name: Import GPG key for signing
uses: crazy-max/ghaction-import-gpg@v6.1.0
uses: crazy-max/ghaction-import-gpg@v6.2.0
with:
gpg_private_key: ${{ secrets.ARCHIBOT_GPG_PRIVATE_KEY }}
@@ -507,24 +507,24 @@ jobs:
gpg -a -b -o SHA512SUMS.sign SHA512SUMS
- name: Generate artifact attestation for SHA512SUMS
uses: actions/attest-build-provenance@v1.4.0
uses: actions/attest-build-provenance@v1.4.4
with:
subject-path: out/SHA512SUMS
- name: Upload SHA512SUMS
uses: actions/upload-artifact@v4.3.5
uses: actions/upload-artifact@v4.4.3
with:
if-no-files-found: error
name: SHA512SUMS
path: out/SHA512SUMS
- name: Generate artifact attestation for SHA512SUMS.sign
uses: actions/attest-build-provenance@v1.4.0
uses: actions/attest-build-provenance@v1.4.4
with:
subject-path: out/SHA512SUMS.sign
- name: Upload SHA512SUMS.sign
uses: actions/upload-artifact@v4.3.5
uses: actions/upload-artifact@v4.4.3
with:
if-no-files-found: error
name: SHA512SUMS.sign

View File

@@ -15,7 +15,7 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4.2.2
with:
show-progress: false
submodules: recursive
@@ -31,7 +31,7 @@ jobs:
git reset --hard origin/master
- name: Download latest translations from Crowdin
uses: crowdin/github-action@v2.1.1
uses: crowdin/github-action@v2.3.0
with:
upload_sources: false
download_translations: true
@@ -43,14 +43,14 @@ jobs:
token: ${{ secrets.ASF_CROWDIN_API_TOKEN }}
- name: Import GPG key for signing
uses: crazy-max/ghaction-import-gpg@v6.1.0
uses: crazy-max/ghaction-import-gpg@v6.2.0
with:
gpg_private_key: ${{ secrets.ARCHIBOT_GPG_PRIVATE_KEY }}
git_config_global: true
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: |
@@ -60,17 +60,11 @@ jobs:
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
View File

@@ -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

Submodule ASF-ui updated: bd3816f67e...1f0b1914a4

View File

@@ -174,7 +174,7 @@ 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)

View File

@@ -203,7 +203,7 @@ internal static class Backend {
ArgumentOutOfRangeException.ThrowIfEqual(requestID, Guid.Empty);
if (SharedInfo.BuildInfo.IsCustomBuild) {
if (BuildInfo.IsCustomBuild) {
return null;
}

View File

@@ -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>

View File

@@ -64,6 +64,10 @@
<value>در این دور جمعاً {0} ست مطابقت داده شد.</value>
<comment>{0} will be replaced by number of sets traded</comment>
</data>
<data name="ListingAnnouncing" xml:space="preserve">
<value>اینونتوری {0}({1}) دارای {2} آیتم است...</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>در مجموع {0} مورد با ربات {1} ({2}) مطابقت داده شد، درحال ارسال ترید...</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>

View File

@@ -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>

View File

@@ -1255,7 +1255,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
Dictionary<ulong, uint> fairClassIDsToGive = new();
Dictionary<ulong, uint> fairClassIDsToReceive = new();
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)) {
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(Strings.FormatWarningFailedWithError($"{nameof(failuresInRow)} >= {WebBrowser.MaxTries}"));

View File

@@ -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>

View File

@@ -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>

View File

@@ -32,14 +32,14 @@ namespace ArchiSteamFarm.OfficialPlugins.MobileAuthenticator;
internal sealed class MobileAuthenticatorHandler : ClientMsgHandler {
private readonly ArchiLogger ArchiLogger;
private readonly SteamUnifiedMessages.UnifiedService<ITwoFactor> UnifiedTwoFactorService;
private readonly TwoFactor UnifiedTwoFactorService;
internal MobileAuthenticatorHandler(ArchiLogger archiLogger, SteamUnifiedMessages steamUnifiedMessages) {
ArgumentNullException.ThrowIfNull(archiLogger);
ArgumentNullException.ThrowIfNull(steamUnifiedMessages);
ArchiLogger = archiLogger;
UnifiedTwoFactorService = steamUnifiedMessages.CreateService<ITwoFactor>();
UnifiedTwoFactorService = steamUnifiedMessages.CreateService<TwoFactor>();
}
public override void HandleMsg(IPacketMsg packetMsg) => ArgumentNullException.ThrowIfNull(packetMsg);
@@ -66,23 +66,17 @@ internal sealed class MobileAuthenticatorHandler : ClientMsgHandler {
steamid = steamID
};
SteamUnifiedMessages.ServiceMethodResponse response;
SteamUnifiedMessages.ServiceMethodResponse<CTwoFactor_AddAuthenticator_Response> response;
try {
response = await UnifiedTwoFactorService.SendMessage(x => x.AddAuthenticator(request)).ToLongRunningTask().ConfigureAwait(false);
response = await UnifiedTwoFactorService.AddAuthenticator(request).ToLongRunningTask().ConfigureAwait(false);
} catch (Exception e) {
ArchiLogger.LogGenericWarningException(e);
return null;
}
if (response.Result != EResult.OK) {
return null;
}
CTwoFactor_AddAuthenticator_Response body = response.GetDeserializedResponse<CTwoFactor_AddAuthenticator_Response>();
return body;
return response.Result == EResult.OK ? response.Body : null;
}
internal async Task<CTwoFactor_FinalizeAddAuthenticator_Response?> FinalizeAuthenticator(ulong steamID, string activationCode, string authenticatorCode, ulong authenticatorTime) {
@@ -109,22 +103,16 @@ internal sealed class MobileAuthenticatorHandler : ClientMsgHandler {
steamid = steamID
};
SteamUnifiedMessages.ServiceMethodResponse response;
SteamUnifiedMessages.ServiceMethodResponse<CTwoFactor_FinalizeAddAuthenticator_Response> response;
try {
response = await UnifiedTwoFactorService.SendMessage(x => x.FinalizeAddAuthenticator(request)).ToLongRunningTask().ConfigureAwait(false);
response = await UnifiedTwoFactorService.FinalizeAddAuthenticator(request).ToLongRunningTask().ConfigureAwait(false);
} catch (Exception e) {
ArchiLogger.LogGenericWarningException(e);
return null;
}
if (response.Result != EResult.OK) {
return null;
}
CTwoFactor_FinalizeAddAuthenticator_Response body = response.GetDeserializedResponse<CTwoFactor_FinalizeAddAuthenticator_Response>();
return body;
return response.Result == EResult.OK ? response.Body : null;
}
}

View File

@@ -58,7 +58,7 @@ internal sealed class MonitoringPlugin : OfficialPlugin, IDisposable, IOfficialG
private static readonly Measurement<byte> BuildInfo = new(
1,
new KeyValuePair<string, object?>(TagNames.Version, SharedInfo.Version.ToString()),
new KeyValuePair<string, object?>(TagNames.Variant, SharedInfo.BuildInfo.Variant)
new KeyValuePair<string, object?>(TagNames.Variant, Core.BuildInfo.Variant)
);
private static readonly Measurement<byte> RuntimeInfo = new(

View File

@@ -68,10 +68,7 @@
<value>{0} зараз адключаны ў адпаведнасці з вашай канфігурацыяй. Калі вы хочаце дапамагчы SteamDB у адпраўцы даных, калі ласка, зазірніце ў нашу вікі.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>{0} быў паспяхова ініцыялізаваны, загадзя дзякуй за дапамогу. Першая адпраўка адбудзецца прыкладна праз {1}.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">
<value>Не атрымалася загрузіць {0}, будзе ініцыялізаваны новы асобнік...</value>
<comment>{0} will be replaced by the name of the file (e.g. "GlobalCache")</comment>

View File

@@ -68,10 +68,7 @@
<value>{0} в момента е деактивирана според вашата настройка. Ако искате да помогнете на SteamDB при подаването на данни, моля разгледайте нашата уикипедия.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>{0} е инициализиранa успешно, благодаря Ви предварително за вашата помощ. Първото подаване на данни ще се случи приблизително след {1}.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">
<value>{0} не беше успешно заредена, вместо това ще бъде стартирана нова инстанция...</value>
<comment>{0} will be replaced by the name of the file (e.g. "GlobalCache")</comment>

View File

@@ -0,0 +1,92 @@
<?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>

View File

@@ -69,7 +69,7 @@
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>{0} byl úspěšně inicializován, předem vám děkujeme za vaši pomoc. První příspěvek se od teď stane přibližně za {1}.</value>
<value>{0} byl úspěšně inicializován, předem děkujeme za vaši pomoc. První zpráva bude vygenerována zhruba za {1}.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">

View File

@@ -69,7 +69,7 @@
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>{0} wurde erfolgreich initialisiert. Wir danken Ihnen im Voraus für Ihre Hilfe. Die erste Übermittlung wird in etwa {1} ab jetzt erfolgen.</value>
<value>{0} wurde erfolgreich initialisiert. Wir danken Ihnen im Voraus für Ihre Hilfe. Die erste Übermittlung wird in etwa {1} erfolgen.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">

View File

@@ -68,10 +68,7 @@
<value>{0} είναι απενεργοποιημένο σύμφωνα με τις ρυθμίσεις σας. Αν θέλετε να βοηθήσετε το SteamDB στην υποβολή δεδομένων, παρακαλώ ελέγξτε το wiki μας.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>{0} έχει αρχικοποιηθεί με επιτυχία, σας ευχαριστώ εκ των προτέρων για τη βοήθειά σας. Η πρώτη υποβολή θα γίνει σε περίπου {1} από τώρα.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">
<value>{0} δεν μπόρεσε να φορτωθεί, μια νέα παρουσία θα αρχικοποιηθεί...</value>
<comment>{0} will be replaced by the name of the file (e.g. "GlobalCache")</comment>

View File

@@ -69,7 +69,7 @@
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>{0} ha sido iniciado con éxito, gracias de antemano por tu ayuda. El primer envío tendrá lugar en aproximadamente {1} a partir de ahora.</value>
<value>{0} ha sido iniciado correctamente, gracias de antemano por tu ayuda. El primer envío será en aproximadamente {1}.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">

View File

@@ -60,33 +60,115 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<data name="PluginDisabledMissingBuildToken" xml:space="preserve">
<value>{0} به دلیل وجود نداشتن بیلد توکن غیرفعال شد</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginDisabledInConfig" xml:space="preserve">
<value>{0} در حال حاضر با توجه به پیکربندی شما غیر فعال است. اگر می خواهید به SteamDB در ثبت کردن داده کمک کنید، لطفاً ویکی را چک کنید.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>{0} با موفقیت لود شد، تشکر از شما بابت کمک. اولین ثبت تقریباً در {1} ی دیگر انجام خواهد شد.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">
<value>قادر به لود کردن {0} نبودیم، یک نشست دیگر لود خواهد شد...</value>
<comment>{0} will be replaced by the name of the file (e.g. "GlobalCache")</comment>
</data>
<data name="BotNoAppsToRefresh" xml:space="preserve">
<value>هیچ برنامه ای که نیاز به رفرش کردن داشته باشد در این ربات وجود ندارد.</value>
</data>
<data name="BotRetrievingTotalAppAccessTokens" xml:space="preserve">
<value>تعداد کلی app access token های دریافت شده: {0}...</value>
<comment>{0} will be replaced by the number (total count) of app access tokens being retrieved</comment>
</data>
<data name="BotRetrievingAppAccessTokens" xml:space="preserve">
<value>در حال دریافت تعداد {0} از app access tokens...</value>
<comment>{0} will be replaced by the number (count this batch) of app access tokens being retrieved</comment>
</data>
<data name="BotFinishedRetrievingAppAccessTokens" xml:space="preserve">
<value>دریافت تعداد {0} از app access tokens به اتمام رسید.</value>
<comment>{0} will be replaced by the number (count this batch) of app access tokens retrieved</comment>
</data>
<data name="BotFinishedRetrievingTotalAppAccessTokens" xml:space="preserve">
<value>دریافت تعداد {0} از app access tokens به اتمام رسید.</value>
<comment>{0} will be replaced by the number (total count) of app access tokens retrieved</comment>
</data>
<data name="BotRetrievingTotalDepots" xml:space="preserve">
<value>در حال دریافت depot برای تعداد {0} برنامه...</value>
<comment>{0} will be replaced by the number (total count) of apps being retrieved</comment>
</data>
<data name="BotRetrievingAppInfos" xml:space="preserve">
<value>درحال دریافت اطلاعات {0} برنامه...</value>
<comment>{0} will be replaced by the number (count this batch) of app infos being retrieved</comment>
</data>
<data name="BotFinishedRetrievingAppInfos" xml:space="preserve">
<value>دریافت اطلاعات {0} برنامه با موفقیت انجام شد.</value>
<comment>{0} will be replaced by the number (count this batch) of app infos retrieved</comment>
</data>
<data name="BotFinishedRetrievingDepotKeys" xml:space="preserve">
<value>تعداد {0} از {1} کلید های depot با موفقیت دریافت شد.</value>
<comment>{0} will be replaced by the number (count this batch) of depot keys that were successfully retrieved, {1} will be replaced by the number (count this batch) of depot keys that were supposed to be retrieved</comment>
</data>
<data name="BotFinishedRetrievingTotalDepots" xml:space="preserve">
<value>دریافت تمامی کلید های depot برای تعداد {0} برنامه انجام شد.</value>
<comment>{0} will be replaced by the number (total count) of apps retrieved</comment>
</data>
<data name="SubmissionNoNewData" xml:space="preserve">
<value>داده ی جدیدی برای ثبت کردن وجود ندارد، همه چی به روز است.</value>
</data>
<data name="SubmissionNoContributorSet" xml:space="preserve">
<value>ثبت کردن داده با شکست مواجه شد زیرا هیچ SteamID معتبری اضافه نشده است. تنظیمات {0} را درست کنید.</value>
<comment>{0} will be replaced by the name of the config property (e.g. "SteamOwnerID") that the user is expected to set</comment>
</data>
<data name="SubmissionInProgress" xml:space="preserve">
<value>در حال ثبت کردن تعداد برنامه/پکیج/depot های ثبت شده: {0}/{1}/{2}...</value>
<comment>{0} will be replaced by the number of app access tokens being submitted, {1} will be replaced by the number of package access tokens being submitted, {2} will be replaced by the number of depot keys being submitted</comment>
</data>
<data name="SubmissionFailedTooManyRequests" xml:space="preserve">
<value>درخواست ثبت کردن به دلیل فرستادن درخواست های بیش از حد با شکست مواجه شد، تقریباً {0} ی دیگر دوباره امتحان می کنیم.</value>
<comment>{0} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="SubmissionSuccessful" xml:space="preserve">
<value>داده با موفقیت فرستاده و ثبت شد. سرور به طور کلی تعداد برنامه/پکیج/depot های: {0} ({1} وریفای شده)/{2} ({3} وریفای شده)/{4} ({5} وریفای شده) را ثبت کرده است.</value>
<comment>{0} will be replaced by the number of new app access tokens that the server has registered, {1} will be replaced by the number of verified app access tokens that the server has registered, {2} will be replaced by the number of new package access tokens that the server has registered, {3} will be replaced by the number of verified package access tokens that the server has registered, {4} will be replaced by the number of new depot keys that the server has registered, {5} will be replaced by the number of verified depot keys that the server has registered</comment>
</data>
<data name="SubmissionSuccessfulNewApps" xml:space="preserve">
<value>برنامه های جدید: {0}</value>
<comment>{0} will be replaced by list of the apps (IDs, numbers), separated by a comma</comment>
</data>
<data name="SubmissionSuccessfulVerifiedApps" xml:space="preserve">
<value>برنامه های وریفای شده: {0}</value>
<comment>{0} will be replaced by list of the apps (IDs, numbers), separated by a comma</comment>
</data>
<data name="SubmissionSuccessfulNewPackages" xml:space="preserve">
<value>پکیج های جدید: {0}</value>
<comment>{0} will be replaced by list of the packages (IDs, numbers), separated by a comma</comment>
</data>
<data name="SubmissionSuccessfulVerifiedPackages" xml:space="preserve">
<value>پکیج های وریفای شده: {0}</value>
<comment>{0} will be replaced by list of the packages (IDs, numbers), separated by a comma</comment>
</data>
<data name="SubmissionSuccessfulNewDepots" xml:space="preserve">
<value>Depot های جدید: {0}</value>
<comment>{0} will be replaced by list of the depots (IDs, numbers), separated by a comma</comment>
</data>
<data name="SubmissionSuccessfulVerifiedDepots" xml:space="preserve">
<value>Depot های وریفای شده: {0}</value>
<comment>{0} will be replaced by list of the depots (IDs, numbers), separated by a comma</comment>
</data>
<data name="PluginSecretListInitialized" xml:space="preserve">
<value>{0} لود شد، این افزونه هیچ کدام از این ها را برطرف نمی کند: {1}.</value>
<comment>{0} will be replaced by the name of the config property (e.g. "SecretPackageIDs"), {1} will be replaced by list of the objects (IDs, numbers), separated by a comma</comment>
</data>
<data name="LoadingGlobalCache" xml:space="preserve">
<value>در حال لود کردن کش سراسری STD...</value>
</data>
<data name="ValidatingGlobalCacheIntegrity" xml:space="preserve">
<value>در حال بازبینی کش سراسری STD...</value>
</data>
<data name="GlobalCacheIntegrityValidationFailed" xml:space="preserve">
<value>بازبینی کش سراسری STD با مشکل مواجه شد. این نشان دهنده ی یک وضعیت فایل/حافظه ی خراب را نشان می دهد، یک مورد تازه لود خواهد شد.</value>
</data>
</root>

View File

@@ -68,10 +68,7 @@
<value>{0} on tällä hetkellä poistettu käytöstä asetuksistasi. Jos haluat auttaa SteamDB:tä tietojen lähettämisessä, ole hyvä ja tutustu wikimme.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>{0} on alustettu onnistuneesti, kiitos etukäteen avustasi. Ensimmäinen lähetys tapahtuu noin {1} jälkeen.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">
<value>{0} ei voitu ladata. Uusi instanssi alustetaan...</value>
<comment>{0} will be replaced by the name of the file (e.g. "GlobalCache")</comment>

View File

@@ -69,7 +69,7 @@
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>{0} a été initialisé avec succès, merci d'avance pour votre aide. La première soumission se fera dans environ {1} à partir de maintenant.</value>
<value>{0} a bien été initialisé, merci d'avance pour votre aide. La première soumission se fera dans approximativement {1} à partir de maintenant.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">

View File

@@ -0,0 +1,92 @@
<?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>

View File

@@ -68,10 +68,7 @@
<value>A {0} jelenleg ki van kapcsolva a konfigurációid alapján. Ha szeretnéd segíteni a SteamDB-t adatok beküldésével, kérlek nézd meg a wikit.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>A(z) {0} inicializálása sikeresen megtörtént, segítségét előre is köszönjük. Az első beküldés körülbelül {1} múlva fog megtörténni.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">
<value>A(z) {0} nem tölthető be, új példány lesz inicializálva...</value>
<comment>{0} will be replaced by the name of the file (e.g. "GlobalCache")</comment>

View File

@@ -68,10 +68,7 @@
<value>{0} è attualmente disabilitato in base alla tua configurazione. Se desideri aiutare SteamDB nell'invio dei dati, controlla la nostra wiki.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>{0} è stato inizializzato con successo, grazie in anticipo per il tuo aiuto. Il primo invio avverrà in circa {1} da ora.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">
<value>{0} non può essere caricato, una nuova richiesta verrà iniziata...</value>
<comment>{0} will be replaced by the name of the file (e.g. "GlobalCache")</comment>

View File

@@ -65,10 +65,7 @@
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>{0} buvo sėkmingai įrašytas, dėkojame už jūsų pagalbą. Pirma pateiktis įvyks už maždaug {1} nuo dabar.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">
<value>{0} nepavyko užkrauti, bus įrašyta nauja instancija...</value>
<comment>{0} will be replaced by the name of the file (e.g. "GlobalCache")</comment>

View File

@@ -69,7 +69,7 @@
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>{0} ir veiksmīgi inicializēts, paldies jau iepriekš par palīdzību. Pirmā iesniegšana notiks aptuveni pēc {1} no šī brīža.</value>
<value>{0} ir veiksmīgi inicializēts, paldies par palīdzību. Pirmā iesniegšana notiks pēc {1}.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">

View File

@@ -68,10 +68,7 @@
<value>{0} is momenteel uitgeschakeld volgens uw configuratie. Als je SteamDB wilt helpen bij het indienen van gegevens, bekijk dan onze wiki.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>{0} is succesvol geïnitialiseerd. Alvast bedankt voor uw hulp. De eerste inzending vindt vanaf nu plaats in ongeveer {1}.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">
<value>{0} kon niet worden geladen, een nieuwe instantie zal worden geïnitialiseerd...</value>
<comment>{0} will be replaced by the name of the file (e.g. "GlobalCache")</comment>

View File

@@ -69,7 +69,7 @@
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>{0} został pomyślnie zainicjowany, dziękujemy z góry za pomoc. Pierwsze zgłoszenie nastąpi za około {1} od teraz.</value>
<value>{0} został pomyślnie zainicjowany, dziękujemy z góry za pomoc. Pierwsze zgłoszenie nastąpi za około {1}.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">

View File

@@ -69,7 +69,7 @@
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>O {0} foi inicializado com sucesso, agradecemos a sua ajuda. O primeiro envio ocorrerá em aproximadamente {1}.</value>
<value>{0} foi inicializado com sucesso, obrigado desde já pela sua ajuda. O primeiro envio ocorrerá em aproximadamente {1}.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">

View File

@@ -68,10 +68,7 @@
<value>{0} está atualmente desativado de acordo com a sua configuração. Se quiser ajudar o SteamDB na submissão de dados, por favor confira o nosso wiki.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>{0} foi inicializado com sucesso, obrigado antecipadamente pela sua ajuda. A primeira submissão ocorrerá aproximadamente daqui a {1} a partir de agora.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">
<value>{0} não pôde ser carregado, uma instância nova será inicializada...</value>
<comment>{0} will be replaced by the name of the file (e.g. "GlobalCache")</comment>

View File

@@ -69,7 +69,7 @@
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>{0} HAS BEEN INITIALIZD SUCCESFULLY, THANK U IN ADVANCE 4 UR HALP. TEH FURST SUBMISHUN WILL HAPPEN IN APPROXIMATELY {1} FRUM NAO.</value>
<value>{0} HAS BEEN INITIALIZD SUCCESFULLY, THANK U IN ADVANCE 4 UR HALP. TEH FURST SUBMISHUN WILL HAPPEN IN APPROXIMATELY {1}.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">

View File

@@ -69,7 +69,7 @@
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>{0} has been initialized successfully, thank you in advance for your help. The first submission will happen in approximately {1} from now.</value>
<value>{0} has been initialized successfully, thank you in advance for your help. The first submission will happen in approximately {1}.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">

View File

@@ -68,10 +68,7 @@
<value>{0} este momentan dezactivat în funcție de configurația ta. Dacă doriți să ajutați SteamDB în transmiterea de date, vă rugăm să consultați wiki-ul.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>{0} a fost inițializat cu succes, mulțumim anticipat pentru ajutor. Prima depunere se va întâmpla în aproximativ {1} de acum.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">
<value>{0} nu a putut fi încărcat, o nouă instanță va fi inițializată...</value>
<comment>{0} will be replaced by the name of the file (e.g. "GlobalCache")</comment>

View File

@@ -69,7 +69,7 @@
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>{0} был успешно инициализирован. Заранее благодарим за вашу помощь. Первый сбор будет примерно через {1}.</value>
<value>Инициализация {0} прошла успешно, заранее спасибо за помощь. Первая отправка произойдет через {1}.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">

View File

@@ -68,10 +68,7 @@
<value>{0} bol na základe vašej konfigurácie vypnutý. Ak máte záujem pomôcť so zberom údajov pre SteamDB, navštívte našu wiki.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>{0} bol úspešne spustený. Týmto vám ďakujeme za vašu pomoc. Prvý zápis sa udej od teraz za {1}.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">
<value>{0} sa nedokázal načítať, bude načítaný nanovo...</value>
<comment>{0} will be replaced by the name of the file (e.g. "GlobalCache")</comment>

View File

@@ -68,10 +68,7 @@
<value>{0} yapılandırmanıza göre şu anda devre dışı. SteamDB'ye veri gönderimi için yardımcı olmak isterseniz viki sayfamızı ziyaret edin.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>{0} başarılı bir şekilde kuruldu, yardımınız için şimdiden teşekkürler. İlk gönderim {1} içinde gerçekleşecektir.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">
<value>{0} yüklenemedi, yeni bir örnek başlatılacak...</value>
<comment>{0} will be replaced by the name of the file (e.g. "GlobalCache")</comment>

View File

@@ -68,10 +68,7 @@
<value>{0} наразі вимкнено відповідно до вашої конфігурації. Якщо ви хочете допомогти SteamDB у надсиланні даних, перегляньте нашу вікі.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin")</comment>
</data>
<data name="PluginInitializedAndEnabled" xml:space="preserve">
<value>{0} успішно ініціалізовано, наперед дякуємо за допомогу. Перше подання відбудеться приблизно через {1}.</value>
<comment>{0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes")</comment>
</data>
<data name="FileCouldNotBeLoadedFreshInit" xml:space="preserve">
<value>{0} не вдалося завантажити, буде ініціалізований новий екземпляр...</value>
<comment>{0} will be replaced by the name of the file (e.g. "GlobalCache")</comment>

View File

@@ -196,7 +196,7 @@ internal sealed class SteamTokenDumperPlugin : OfficialPlugin, IASF, IBot, IBotC
break;
}
return Task.FromResult((string?) null);
return Task.FromResult<string?>(null);
}
public async Task OnBotDestroy(Bot bot) {
@@ -255,7 +255,7 @@ internal sealed class SteamTokenDumperPlugin : OfficialPlugin, IASF, IBot, IBotC
return Task.CompletedTask;
}
public Task<IReadOnlyCollection<ClientMsgHandler>?> OnBotSteamHandlersInit(Bot bot) => Task.FromResult((IReadOnlyCollection<ClientMsgHandler>?) null);
public Task<IReadOnlyCollection<ClientMsgHandler>?> OnBotSteamHandlersInit(Bot bot) => Task.FromResult<IReadOnlyCollection<ClientMsgHandler>?>(null);
public override Task OnLoaded() {
Utilities.WarnAboutIncompleteTranslation(Strings.ResourceManager);

View File

@@ -0,0 +1,65 @@
// ----------------------------------------------------------------------------------------------
// _ _ _ ____ _ _____
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// ----------------------------------------------------------------------------------------------
// |
// 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.ComponentModel;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using static ArchiSteamFarm.Helpers.ArchiCryptoHelper;
namespace ArchiSteamFarm.Tests;
#pragma warning disable CA1812 // False positive, the class is used during MSTest
[TestClass]
internal sealed class ArchiCryptoHelper {
private const string TestPassword = "a2o41PuPdZNDLw9AT6dZt5pLVC23MN9O7NfKI4a0MWJgWWIAVGt3naYiIA0BhPel";
[DataRow(ECryptoMethod.PlainText)]
[DataRow(ECryptoMethod.AES)]
[DataTestMethod]
internal async Task CanEncryptDecrypt(ECryptoMethod cryptoMethod) {
if (!Enum.IsDefined(cryptoMethod)) {
throw new InvalidEnumArgumentException(nameof(cryptoMethod), (int) cryptoMethod, typeof(ECryptoMethod));
}
string? encrypted = Encrypt(cryptoMethod, TestPassword);
Assert.IsNotNull(encrypted);
string? decrypted = await Decrypt(cryptoMethod, encrypted).ConfigureAwait(false);
Assert.IsNotNull(decrypted);
Assert.AreEqual(TestPassword, decrypted);
}
[TestMethod]
internal async Task CanEncryptDecryptProtectedDataForCurrentUser() {
if (!OperatingSystem.IsWindows()) {
// Not supported on other platforms than Windows
return;
}
await CanEncryptDecrypt(ECryptoMethod.ProtectedDataForCurrentUser).ConfigureAwait(false);
}
}
#pragma warning restore CA1812 // False positive, the class is used during MSTest

View File

@@ -25,7 +25,14 @@ using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Nodes;
using ArchiSteamFarm.Core;
using ArchiSteamFarm.Helpers.Json;
using ArchiSteamFarm.Steam.Data;
using ArchiSteamFarm.Steam.Storage;
using ArchiSteamFarm.Storage;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using static ArchiSteamFarm.Steam.Bot;
@@ -34,6 +41,38 @@ namespace ArchiSteamFarm.Tests;
#pragma warning disable CA1812 // False positive, the class is used during MSTest
[TestClass]
internal sealed class Bot {
internal static Steam.Bot GenerateBot(string botName = "Test") {
ArgumentException.ThrowIfNullOrEmpty(botName);
ConstructorInfo? constructor = typeof(Steam.Bot).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, [typeof(string), typeof(BotConfig), typeof(BotDatabase)]);
if (constructor == null) {
throw new InvalidOperationException(nameof(constructor));
}
JsonElement emptyObject = new JsonObject().ToJsonElement();
BotConfig? botConfig = emptyObject.ToJsonObject<BotConfig>();
if (botConfig == null) {
throw new InvalidOperationException(nameof(botConfig));
}
BotDatabase? botDatabase = emptyObject.ToJsonObject<BotDatabase>();
if (botDatabase == null) {
throw new InvalidOperationException(nameof(botDatabase));
}
ASF.GlobalDatabase ??= emptyObject.ToJsonObject<GlobalDatabase>();
if (constructor.Invoke([botName, botConfig, botDatabase]) is not Steam.Bot result) {
throw new InvalidOperationException(nameof(result));
}
return result;
}
[TestMethod]
internal void MaxItemsBarelyEnoughForOneSet() {
const uint relevantAppID = 42;

View File

@@ -0,0 +1,93 @@
// ----------------------------------------------------------------------------------------------
// _ _ _ ____ _ _____
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// ----------------------------------------------------------------------------------------------
// |
// 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.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using ArchiSteamFarm.Collections;
using ArchiSteamFarm.Core;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace ArchiSteamFarm.Tests;
#pragma warning disable CA1812 // False positive, the class is used during MSTest
[TestClass]
internal sealed class ConcurrentTests {
[TestMethod]
internal void ConcurrentDictionarySupportsWritingDuringLinq() {
ConcurrentDictionary<ushort, bool> collection = [];
for (byte i = 0; i < 10; i++) {
collection.TryAdd(i, true);
}
Utilities.InBackground(
() => {
for (ushort i = 10; i < ushort.MaxValue; i++) {
collection.TryAdd(i, true);
}
}, true
);
foreach (KeyValuePair<ushort, bool> _ in collection.AsLinqThreadSafeEnumerable().OrderBy(static entry => entry.Key)) { }
}
[TestMethod]
internal void ConcurrentHashSetSupportsWritingDuringLinq() {
ConcurrentHashSet<ushort> collection = [];
for (byte i = 0; i < 10; i++) {
collection.Add(i);
}
Utilities.InBackground(
() => {
for (ushort i = 10; i < ushort.MaxValue; i++) {
collection.Add(i);
}
}, true
);
foreach (ushort _ in collection.AsLinqThreadSafeEnumerable().OrderBy(static entry => entry)) { }
}
[TestMethod]
internal void ConcurrentListSupportsWritingDuringLinq() {
ConcurrentList<ushort> collection = [];
for (byte i = 0; i < 10; i++) {
collection.Add(i);
}
Utilities.InBackground(
() => {
for (ushort i = 10; i < ushort.MaxValue; i++) {
collection.Add(i);
}
}, true
);
foreach (ushort _ in collection.AsLinqThreadSafeEnumerable().OrderBy(static entry => entry)) { }
}
}
#pragma warning restore CA1812 // False positive, the class is used during MSTest

View File

@@ -0,0 +1,97 @@
// ----------------------------------------------------------------------------------------------
// _ _ _ ____ _ _____
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// ----------------------------------------------------------------------------------------------
// |
// 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.Reflection;
using System.Text.Json.Nodes;
using ArchiSteamFarm.Helpers.Json;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace ArchiSteamFarm.Tests;
#pragma warning disable CA1812 // False positive, the class is used during MSTest
[TestClass]
internal sealed class MobileAuthenticator {
[DataRow("qrg+wW8/u/TDt2i/+FQuPhuVrmY=", (ulong) 1337, "QFo72j9TnG+uRXe9EIJs4zyBPo0=")]
[DataRow("qrg+wW8/u/TDt2i/+FQuPhuVrmY=", (ulong) 1337, "mYbCKs8ZvsVN2odCMxpvidrIu1c=", "conf")]
[DataRow("qrg+wW8/u/TDt2i/+FQuPhuVrmY=", (ulong) 1723332288, "hiEx+JBqJqFJnSSL+dEthPHOmsc=")]
[DataRow("qrg+wW8/u/TDt2i/+FQuPhuVrmY=", (ulong) 1723332288, "hpZUxyNgwBvtKPROvedjuvVPQiE=", "conf")]
[DataTestMethod]
internal void GenerateConfirmationHash(string identitySecret, ulong time, string expectedCode, string? tag = null) {
ArgumentException.ThrowIfNullOrEmpty(identitySecret);
ArgumentOutOfRangeException.ThrowIfZero(time);
ArgumentException.ThrowIfNullOrEmpty(expectedCode);
MethodInfo? method = typeof(Steam.Security.MobileAuthenticator).GetMethod(nameof(GenerateConfirmationHash), BindingFlags.Instance | BindingFlags.NonPublic, [typeof(ulong), typeof(string)]);
if (method == null) {
throw new InvalidOperationException(nameof(method));
}
using Steam.Security.MobileAuthenticator authenticator = GenerateMobileAuthenticator(identitySecret, identitySecret);
string? result = method.Invoke(authenticator, [time, tag]) as string;
Assert.IsNotNull(result);
Assert.AreEqual(expectedCode, result);
}
[DataRow("KDHC3rsY8+CmiswnXJcE5e5dRfd=", (ulong) 1337, "47J4D")]
[DataRow("KDHC3rsY8+CmiswnXJcE5e5dRfd=", (ulong) 1723332288, "JQ3HQ")]
[DataTestMethod]
internal void GenerateTokenForTime(string sharedSecret, ulong time, string expectedCode) {
ArgumentException.ThrowIfNullOrEmpty(sharedSecret);
ArgumentOutOfRangeException.ThrowIfZero(time);
ArgumentException.ThrowIfNullOrEmpty(expectedCode);
using Steam.Security.MobileAuthenticator authenticator = GenerateMobileAuthenticator(sharedSecret, sharedSecret);
string? result = authenticator.GenerateTokenForTime(time);
Assert.IsNotNull(result);
Assert.AreEqual(expectedCode, result);
}
private static Steam.Security.MobileAuthenticator GenerateMobileAuthenticator(string identitySecret, string sharedSecret) {
ArgumentException.ThrowIfNullOrEmpty(identitySecret);
ArgumentException.ThrowIfNullOrEmpty(sharedSecret);
JsonObject jsonObject = new() {
["identity_secret"] = identitySecret,
["shared_secret"] = sharedSecret
};
Steam.Security.MobileAuthenticator? result = jsonObject.ToJsonElement().ToJsonObject<Steam.Security.MobileAuthenticator>();
if (result == null) {
throw new InvalidOperationException(nameof(result));
}
Steam.Bot bot = Bot.GenerateBot();
result.Init(bot);
return result;
}
}
#pragma warning restore CA1812 // False positive, the class is used during MSTest

View File

@@ -166,6 +166,9 @@
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=CA5384/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=CA5385/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=CA5397/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=CanReplaceCastWithLambdaReturnType/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=CanReplaceCastWithTypeArgument/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=CanReplaceCastWithVariableType/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=CanSimplifyStringEscapeSequence/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ClassCanBeSealed_002EGlobal/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ClassCanBeSealed_002ELocal/@EntryIndexedValue">SUGGESTION</s:String>
@@ -185,7 +188,7 @@
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertToExpressionBodyWhenPossible/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertToLambdaExpressionWhenPossible/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=DuplicateResource/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=DuplicateResource/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceDoWhileStatementBraces/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceFixedStatementBraces/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceForeachStatementBraces/@EntryIndexedValue">WARNING</s:String>
@@ -252,10 +255,11 @@
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=PatternAlwaysMatches/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=PatternAlwaysOfType/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=PlaceAssignmentExpressionIntoBlock/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=PrimaryConstructorParameterCaptureDisallowed/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=PropertyNotResolved/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RawStringCanBeSimplified/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantArrayCreationExpression/@EntryIndexedValue"></s:String>
<s:Boolean x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantArrayCreationExpression/@EntryIndexRemoved">True</s:Boolean>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantArrayCreationExpression/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantAttributeParentheses/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantBlankLines/@EntryIndexedValue">SUGGESTION</s:String>
@@ -524,19 +528,19 @@
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/XmlFormatter/WRAP_LINES/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CSharpFileLayoutPatterns/Pattern/@EntryValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;&#xD;
&lt;Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"&gt;&#xD;
&lt;TypePattern DisplayName=&quot;Non-reorderable types&quot; Priority=&quot;99999999&quot;&gt;
&lt;TypePattern DisplayName="Non-reorderable types" Priority="99999999"&gt;
&lt;TypePattern.Match&gt;
&lt;Or&gt;
&lt;And&gt;
&lt;Kind Is=&quot;Interface&quot; /&gt;
&lt;Kind Is="Interface" /&gt;
&lt;Or&gt;
&lt;HasAttribute Name=&quot;System.Runtime.InteropServices.InterfaceTypeAttribute&quot; /&gt;
&lt;HasAttribute Name=&quot;System.Runtime.InteropServices.ComImport&quot; /&gt;
&lt;HasAttribute Name="System.Runtime.InteropServices.InterfaceTypeAttribute" /&gt;
&lt;HasAttribute Name="System.Runtime.InteropServices.ComImport" /&gt;
&lt;/Or&gt;
&lt;/And&gt;
&lt;Kind Is=&quot;Struct&quot; /&gt;
&lt;HasAttribute Name=&quot;System.Runtime.InteropServices.StructLayoutAttribute&quot; /&gt;
&lt;HasAttribute Name=&quot;JetBrains.Annotations.NoReorderAttribute&quot; /&gt;
&lt;Kind Is="Struct" /&gt;
&lt;HasAttribute Name="System.Runtime.InteropServices.StructLayoutAttribute" /&gt;
&lt;HasAttribute Name="JetBrains.Annotations.NoReorderAttribute" /&gt;
&lt;/Or&gt;
&lt;/TypePattern.Match&gt;
&lt;/TypePattern&gt;
@@ -847,6 +851,7 @@ limitations under the License.</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpRenamePlacementToArrangementMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002EMemberReordering_002EMigrations_002ECSharpFileLayoutPatternRemoveIsAttributeUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAlwaysTreatStructAsNotReorderableMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>

View File

@@ -23,16 +23,19 @@
using System;
using System.Runtime.CompilerServices;
#if ASF_SIGNED_BUILD
using ArchiSteamFarm;
#endif
[assembly: CLSCompliant(false)]
#if ASF_SIGNED_BUILD
[assembly: InternalsVisibleTo("ArchiSteamFarm.Tests, PublicKey=002400000480000014020000060200000024000052534131001000000100010099f0e5961ec7497fd7de1cba2b8c5eff3b18c1faf3d7a8d56e063359c7f928b54b14eae24d23d9d3c1a5db7ceca82edb6956d43e8ea2a0b7223e6e6836c0b809de43fde69bf33fba73cf669e71449284d477333d4b6e54fb69f7b6c4b4811b8fe26e88975e593cffc0e321490a50500865c01e50ab87c8a943b2a788af47dc20f2b860062b7b6df25477e471a744485a286b435cea2df3953cbb66febd8db73f3ccb4588886373141d200f749ba40bb11926b668cc15f328412dd0b0b835909229985336eb4a34f47925558dc6dc3910ea09c1aad5c744833f26ad9de727559d393526a7a29b3383de87802a034ead8ecc2d37340a5fa9b406774446256337d77e3c9e8486b5e732097e238312deaf5b4efcc04df8ecb986d90ee12b4a8a9a00319cc25cb91fd3e36a3cc39e501f83d14eb1e1a6fa6a1365483d99f4cefad1ea5dec204dad958e2a9a93add19781a8aa7bac71747b11d156711eafd1e873e19836eb573fa5cde284739df09b658ed40c56c7b5a7596840774a7065864e6c2af7b5a8bf7a2d238de83d77891d98ef5a4a58248c655a1c7c97c99e01d9928dc60c629eeb523356dc3686e3f9a1a30ffcd0268cd03718292f21d839fce741f4c1163001ab5b654c37d862998962a05e8028e061c611384772777ef6a49b00ebb4f228308e61b2afe408b33db2d82c4f385e26d7438ec0a183c64eeca4138cbc3dc2")]
[assembly: InternalsVisibleTo("ArchiSteamFarm.CustomPlugins.SignInWithSteam, PublicKey=002400000480000014020000060200000024000052534131001000000100010099f0e5961ec7497fd7de1cba2b8c5eff3b18c1faf3d7a8d56e063359c7f928b54b14eae24d23d9d3c1a5db7ceca82edb6956d43e8ea2a0b7223e6e6836c0b809de43fde69bf33fba73cf669e71449284d477333d4b6e54fb69f7b6c4b4811b8fe26e88975e593cffc0e321490a50500865c01e50ab87c8a943b2a788af47dc20f2b860062b7b6df25477e471a744485a286b435cea2df3953cbb66febd8db73f3ccb4588886373141d200f749ba40bb11926b668cc15f328412dd0b0b835909229985336eb4a34f47925558dc6dc3910ea09c1aad5c744833f26ad9de727559d393526a7a29b3383de87802a034ead8ecc2d37340a5fa9b406774446256337d77e3c9e8486b5e732097e238312deaf5b4efcc04df8ecb986d90ee12b4a8a9a00319cc25cb91fd3e36a3cc39e501f83d14eb1e1a6fa6a1365483d99f4cefad1ea5dec204dad958e2a9a93add19781a8aa7bac71747b11d156711eafd1e873e19836eb573fa5cde284739df09b658ed40c56c7b5a7596840774a7065864e6c2af7b5a8bf7a2d238de83d77891d98ef5a4a58248c655a1c7c97c99e01d9928dc60c629eeb523356dc3686e3f9a1a30ffcd0268cd03718292f21d839fce741f4c1163001ab5b654c37d862998962a05e8028e061c611384772777ef6a49b00ebb4f228308e61b2afe408b33db2d82c4f385e26d7438ec0a183c64eeca4138cbc3dc2")]
[assembly: InternalsVisibleTo("ArchiSteamFarm.OfficialPlugins.ItemsMatcher, PublicKey=002400000480000014020000060200000024000052534131001000000100010099f0e5961ec7497fd7de1cba2b8c5eff3b18c1faf3d7a8d56e063359c7f928b54b14eae24d23d9d3c1a5db7ceca82edb6956d43e8ea2a0b7223e6e6836c0b809de43fde69bf33fba73cf669e71449284d477333d4b6e54fb69f7b6c4b4811b8fe26e88975e593cffc0e321490a50500865c01e50ab87c8a943b2a788af47dc20f2b860062b7b6df25477e471a744485a286b435cea2df3953cbb66febd8db73f3ccb4588886373141d200f749ba40bb11926b668cc15f328412dd0b0b835909229985336eb4a34f47925558dc6dc3910ea09c1aad5c744833f26ad9de727559d393526a7a29b3383de87802a034ead8ecc2d37340a5fa9b406774446256337d77e3c9e8486b5e732097e238312deaf5b4efcc04df8ecb986d90ee12b4a8a9a00319cc25cb91fd3e36a3cc39e501f83d14eb1e1a6fa6a1365483d99f4cefad1ea5dec204dad958e2a9a93add19781a8aa7bac71747b11d156711eafd1e873e19836eb573fa5cde284739df09b658ed40c56c7b5a7596840774a7065864e6c2af7b5a8bf7a2d238de83d77891d98ef5a4a58248c655a1c7c97c99e01d9928dc60c629eeb523356dc3686e3f9a1a30ffcd0268cd03718292f21d839fce741f4c1163001ab5b654c37d862998962a05e8028e061c611384772777ef6a49b00ebb4f228308e61b2afe408b33db2d82c4f385e26d7438ec0a183c64eeca4138cbc3dc2")]
[assembly: InternalsVisibleTo("ArchiSteamFarm.OfficialPlugins.MobileAuthenticator, PublicKey=002400000480000014020000060200000024000052534131001000000100010099f0e5961ec7497fd7de1cba2b8c5eff3b18c1faf3d7a8d56e063359c7f928b54b14eae24d23d9d3c1a5db7ceca82edb6956d43e8ea2a0b7223e6e6836c0b809de43fde69bf33fba73cf669e71449284d477333d4b6e54fb69f7b6c4b4811b8fe26e88975e593cffc0e321490a50500865c01e50ab87c8a943b2a788af47dc20f2b860062b7b6df25477e471a744485a286b435cea2df3953cbb66febd8db73f3ccb4588886373141d200f749ba40bb11926b668cc15f328412dd0b0b835909229985336eb4a34f47925558dc6dc3910ea09c1aad5c744833f26ad9de727559d393526a7a29b3383de87802a034ead8ecc2d37340a5fa9b406774446256337d77e3c9e8486b5e732097e238312deaf5b4efcc04df8ecb986d90ee12b4a8a9a00319cc25cb91fd3e36a3cc39e501f83d14eb1e1a6fa6a1365483d99f4cefad1ea5dec204dad958e2a9a93add19781a8aa7bac71747b11d156711eafd1e873e19836eb573fa5cde284739df09b658ed40c56c7b5a7596840774a7065864e6c2af7b5a8bf7a2d238de83d77891d98ef5a4a58248c655a1c7c97c99e01d9928dc60c629eeb523356dc3686e3f9a1a30ffcd0268cd03718292f21d839fce741f4c1163001ab5b654c37d862998962a05e8028e061c611384772777ef6a49b00ebb4f228308e61b2afe408b33db2d82c4f385e26d7438ec0a183c64eeca4138cbc3dc2")]
[assembly: InternalsVisibleTo("ArchiSteamFarm.OfficialPlugins.Monitoring, PublicKey=002400000480000014020000060200000024000052534131001000000100010099f0e5961ec7497fd7de1cba2b8c5eff3b18c1faf3d7a8d56e063359c7f928b54b14eae24d23d9d3c1a5db7ceca82edb6956d43e8ea2a0b7223e6e6836c0b809de43fde69bf33fba73cf669e71449284d477333d4b6e54fb69f7b6c4b4811b8fe26e88975e593cffc0e321490a50500865c01e50ab87c8a943b2a788af47dc20f2b860062b7b6df25477e471a744485a286b435cea2df3953cbb66febd8db73f3ccb4588886373141d200f749ba40bb11926b668cc15f328412dd0b0b835909229985336eb4a34f47925558dc6dc3910ea09c1aad5c744833f26ad9de727559d393526a7a29b3383de87802a034ead8ecc2d37340a5fa9b406774446256337d77e3c9e8486b5e732097e238312deaf5b4efcc04df8ecb986d90ee12b4a8a9a00319cc25cb91fd3e36a3cc39e501f83d14eb1e1a6fa6a1365483d99f4cefad1ea5dec204dad958e2a9a93add19781a8aa7bac71747b11d156711eafd1e873e19836eb573fa5cde284739df09b658ed40c56c7b5a7596840774a7065864e6c2af7b5a8bf7a2d238de83d77891d98ef5a4a58248c655a1c7c97c99e01d9928dc60c629eeb523356dc3686e3f9a1a30ffcd0268cd03718292f21d839fce741f4c1163001ab5b654c37d862998962a05e8028e061c611384772777ef6a49b00ebb4f228308e61b2afe408b33db2d82c4f385e26d7438ec0a183c64eeca4138cbc3dc2")]
[assembly: InternalsVisibleTo("ArchiSteamFarm.OfficialPlugins.SteamTokenDumper, PublicKey=002400000480000014020000060200000024000052534131001000000100010099f0e5961ec7497fd7de1cba2b8c5eff3b18c1faf3d7a8d56e063359c7f928b54b14eae24d23d9d3c1a5db7ceca82edb6956d43e8ea2a0b7223e6e6836c0b809de43fde69bf33fba73cf669e71449284d477333d4b6e54fb69f7b6c4b4811b8fe26e88975e593cffc0e321490a50500865c01e50ab87c8a943b2a788af47dc20f2b860062b7b6df25477e471a744485a286b435cea2df3953cbb66febd8db73f3ccb4588886373141d200f749ba40bb11926b668cc15f328412dd0b0b835909229985336eb4a34f47925558dc6dc3910ea09c1aad5c744833f26ad9de727559d393526a7a29b3383de87802a034ead8ecc2d37340a5fa9b406774446256337d77e3c9e8486b5e732097e238312deaf5b4efcc04df8ecb986d90ee12b4a8a9a00319cc25cb91fd3e36a3cc39e501f83d14eb1e1a6fa6a1365483d99f4cefad1ea5dec204dad958e2a9a93add19781a8aa7bac71747b11d156711eafd1e873e19836eb573fa5cde284739df09b658ed40c56c7b5a7596840774a7065864e6c2af7b5a8bf7a2d238de83d77891d98ef5a4a58248c655a1c7c97c99e01d9928dc60c629eeb523356dc3686e3f9a1a30ffcd0268cd03718292f21d839fce741f4c1163001ab5b654c37d862998962a05e8028e061c611384772777ef6a49b00ebb4f228308e61b2afe408b33db2d82c4f385e26d7438ec0a183c64eeca4138cbc3dc2")]
[assembly: InternalsVisibleTo($"ArchiSteamFarm.Tests, PublicKey={SharedInfo.PublicKey}")]
[assembly: InternalsVisibleTo($"ArchiSteamFarm.CustomPlugins.SignInWithSteam, PublicKey={SharedInfo.PublicKey}")]
[assembly: InternalsVisibleTo($"ArchiSteamFarm.OfficialPlugins.ItemsMatcher, PublicKey={SharedInfo.PublicKey}")]
[assembly: InternalsVisibleTo($"ArchiSteamFarm.OfficialPlugins.MobileAuthenticator, PublicKey={SharedInfo.PublicKey}")]
[assembly: InternalsVisibleTo($"ArchiSteamFarm.OfficialPlugins.Monitoring, PublicKey={SharedInfo.PublicKey}")]
[assembly: InternalsVisibleTo($"ArchiSteamFarm.OfficialPlugins.SteamTokenDumper, PublicKey={SharedInfo.PublicKey}")]
#else
[assembly: InternalsVisibleTo("ArchiSteamFarm.Tests")]
[assembly: InternalsVisibleTo("ArchiSteamFarm.CustomPlugins.SignInWithSteam")]

View File

@@ -30,11 +30,10 @@ using Nito.AsyncEx;
namespace ArchiSteamFarm.Collections;
public sealed class ConcurrentList<T> : IList<T>, IReadOnlyList<T> where T : notnull {
public sealed class ConcurrentList<T> : IList<T>, IReadOnlyList<T> {
[PublicAPI]
public event EventHandler? OnModified;
[PublicAPI]
public int Count {
get {
using (Lock.ReaderLock()) {
@@ -48,18 +47,17 @@ public sealed class ConcurrentList<T> : IList<T>, IReadOnlyList<T> where T : not
private readonly List<T> BackingCollection;
private readonly AsyncReaderWriterLock Lock = new();
int ICollection<T>.Count => Count;
int IReadOnlyCollection<T>.Count => Count;
public T this[int index] {
get {
ArgumentOutOfRangeException.ThrowIfNegative(index);
using (Lock.ReaderLock()) {
return BackingCollection[index];
}
}
set {
ArgumentNullException.ThrowIfNull(value);
ArgumentOutOfRangeException.ThrowIfNegative(index);
using (Lock.WriterLock()) {
BackingCollection[index] = value;
@@ -79,8 +77,6 @@ public sealed class ConcurrentList<T> : IList<T>, IReadOnlyList<T> where T : not
}
public void Add(T item) {
ArgumentNullException.ThrowIfNull(item);
using (Lock.WriterLock()) {
BackingCollection.Add(item);
}
@@ -97,8 +93,6 @@ public sealed class ConcurrentList<T> : IList<T>, IReadOnlyList<T> where T : not
}
public bool Contains(T item) {
ArgumentNullException.ThrowIfNull(item);
using (Lock.ReaderLock()) {
return BackingCollection.Contains(item);
}
@@ -117,8 +111,6 @@ public sealed class ConcurrentList<T> : IList<T>, IReadOnlyList<T> where T : not
public IEnumerator<T> GetEnumerator() => new ConcurrentEnumerator<T>(BackingCollection, Lock.ReaderLock());
public int IndexOf(T item) {
ArgumentNullException.ThrowIfNull(item);
using (Lock.ReaderLock()) {
return BackingCollection.IndexOf(item);
}
@@ -126,7 +118,6 @@ public sealed class ConcurrentList<T> : IList<T>, IReadOnlyList<T> where T : not
public void Insert(int index, T item) {
ArgumentOutOfRangeException.ThrowIfNegative(index);
ArgumentNullException.ThrowIfNull(item);
using (Lock.WriterLock()) {
BackingCollection.Insert(index, item);
@@ -136,8 +127,6 @@ public sealed class ConcurrentList<T> : IList<T>, IReadOnlyList<T> where T : not
}
public bool Remove(T item) {
ArgumentNullException.ThrowIfNull(item);
using (Lock.WriterLock()) {
if (!BackingCollection.Remove(item)) {
return false;

View File

@@ -35,7 +35,6 @@ public sealed class ObservableConcurrentDictionary<TKey, TValue> : IDictionary<T
[PublicAPI]
public event EventHandler? OnModified;
[PublicAPI]
public int Count => BackingDictionary.Count;
[PublicAPI]
@@ -43,23 +42,23 @@ public sealed class ObservableConcurrentDictionary<TKey, TValue> : IDictionary<T
public bool IsReadOnly => false;
[PublicAPI]
public ICollection<TKey> Keys => BackingDictionary.Keys;
public ICollection<TValue> Values => BackingDictionary.Values;
private readonly ConcurrentDictionary<TKey, TValue> BackingDictionary;
int ICollection<KeyValuePair<TKey, TValue>>.Count => BackingDictionary.Count;
int IReadOnlyCollection<KeyValuePair<TKey, TValue>>.Count => BackingDictionary.Count;
IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys => BackingDictionary.Keys;
ICollection<TKey> IDictionary<TKey, TValue>.Keys => BackingDictionary.Keys;
IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values => BackingDictionary.Values;
ICollection<TValue> IDictionary<TKey, TValue>.Values => BackingDictionary.Values;
IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys => Keys;
IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values => Values;
public TValue this[TKey key] {
get => BackingDictionary[key];
get {
ArgumentNullException.ThrowIfNull(key);
return BackingDictionary[key];
}
set {
ArgumentNullException.ThrowIfNull(value);
ArgumentNullException.ThrowIfNull(key);
if (BackingDictionary.TryGetValue(key, out TValue? savedValue) && EqualityComparer<TValue>.Default.Equals(savedValue, value)) {
return;
@@ -107,7 +106,7 @@ public sealed class ObservableConcurrentDictionary<TKey, TValue> : IDictionary<T
}
public void Clear() {
if (BackingDictionary.IsEmpty) {
if (IsEmpty) {
return;
}
@@ -117,6 +116,12 @@ public sealed class ObservableConcurrentDictionary<TKey, TValue> : IDictionary<T
public bool Contains(KeyValuePair<TKey, TValue> item) => ((ICollection<KeyValuePair<TKey, TValue>>) BackingDictionary).Contains(item);
public bool ContainsKey(TKey key) {
ArgumentNullException.ThrowIfNull(key);
return BackingDictionary.ContainsKey(key);
}
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) {
ArgumentNullException.ThrowIfNull(array);
ArgumentOutOfRangeException.ThrowIfNegative(arrayIndex);
@@ -151,33 +156,15 @@ public sealed class ObservableConcurrentDictionary<TKey, TValue> : IDictionary<T
return true;
}
bool IDictionary<TKey, TValue>.ContainsKey(TKey key) {
public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) {
ArgumentNullException.ThrowIfNull(key);
return BackingDictionary.ContainsKey(key);
}
bool IReadOnlyDictionary<TKey, TValue>.ContainsKey(TKey key) {
ArgumentNullException.ThrowIfNull(key);
return BackingDictionary.ContainsKey(key);
return BackingDictionary.TryGetValue(key, out value);
}
[MustDisposeResource]
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
bool IReadOnlyDictionary<TKey, TValue>.TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) {
ArgumentNullException.ThrowIfNull(key);
return BackingDictionary.TryGetValue(key, out value);
}
bool IDictionary<TKey, TValue>.TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) {
ArgumentNullException.ThrowIfNull(key);
return BackingDictionary.TryGetValue(key, out value);
}
[PublicAPI]
public bool TryAdd(TKey key, TValue value) {
ArgumentNullException.ThrowIfNull(key);
@@ -190,11 +177,4 @@ public sealed class ObservableConcurrentDictionary<TKey, TValue> : IDictionary<T
return true;
}
[PublicAPI]
public bool TryGetValue(TKey key, out TValue? value) {
ArgumentNullException.ThrowIfNull(key);
return BackingDictionary.TryGetValue(key, out value);
}
}

View File

@@ -36,6 +36,7 @@ using System.Threading;
using System.Threading.Tasks;
using ArchiSteamFarm.Helpers;
using ArchiSteamFarm.IPC;
using ArchiSteamFarm.IPC.Controllers.Api;
using ArchiSteamFarm.Localization;
using ArchiSteamFarm.NLog;
using ArchiSteamFarm.Plugins;
@@ -48,7 +49,6 @@ using ArchiSteamFarm.Web.GitHub.Data;
using ArchiSteamFarm.Web.Responses;
using JetBrains.Annotations;
using SteamKit2;
using SteamKit2.Discovery;
namespace ArchiSteamFarm.Core;
@@ -675,23 +675,6 @@ public static class ASF {
throw new InvalidOperationException(nameof(WebBrowser));
}
// Ensure that we ask for a list of servers if we don't have any saved servers available
IEnumerable<ServerRecord> servers = await GlobalDatabase.ServerListProvider.FetchServerListAsync().ConfigureAwait(false);
if (!servers.Any()) {
ArchiLogger.LogGenericInfo(Strings.FormatInitializing(nameof(SteamDirectory)));
SteamConfiguration steamConfiguration = SteamConfiguration.Create(static builder => builder.WithProtocolTypes(GlobalConfig.SteamProtocols).WithCellID(GlobalDatabase.CellID).WithServerListProvider(GlobalDatabase.ServerListProvider).WithHttpClientFactory(static () => WebBrowser.GenerateDisposableHttpClient()));
try {
await SteamDirectory.LoadAsync(steamConfiguration).ConfigureAwait(false);
ArchiLogger.LogGenericInfo(Strings.Success);
} catch (Exception e) {
ArchiLogger.LogGenericWarningException(e);
ArchiLogger.LogGenericWarning(Strings.BotSteamDirectoryInitializationFailed);
}
}
HashSet<string> botNames;
try {
@@ -772,7 +755,7 @@ public static class ASF {
channel ??= GlobalConfig.UpdateChannel;
if (!SharedInfo.BuildInfo.CanUpdate || (channel == GlobalConfig.EUpdateChannel.None)) {
if (!BuildInfo.CanUpdate || (channel == GlobalConfig.EUpdateChannel.None)) {
return (false, null);
}
@@ -824,7 +807,7 @@ public static class ASF {
return (false, newVersion);
}
targetFile = $"{SharedInfo.ASF}-{SharedInfo.BuildInfo.Variant}.zip";
targetFile = $"{SharedInfo.ASF}-{BuildInfo.Variant}.zip";
ReleaseAsset? binaryAsset = releaseResponse.Assets.FirstOrDefault(asset => !string.IsNullOrEmpty(asset.Name) && asset.Name.Equals(targetFile, StringComparison.OrdinalIgnoreCase));
if (binaryAsset == null) {
@@ -838,7 +821,7 @@ public static class ASF {
// Keep short timeout allowed for this call, as we don't want to hold the flow for too long
using CancellationTokenSource archiNetCancellation = new(TimeSpan.FromSeconds(15));
string? remoteChecksum = await ArchiNet.FetchBuildChecksum(newVersion, SharedInfo.BuildInfo.Variant, archiNetCancellation.Token).ConfigureAwait(false);
string? remoteChecksum = await ArchiNet.FetchBuildChecksum(newVersion, BuildInfo.Variant, archiNetCancellation.Token).ConfigureAwait(false);
switch (remoteChecksum) {
case null:
@@ -894,11 +877,14 @@ public static class ASF {
if (kestrelWasRunning) {
// We disable ArchiKestrel here as the update process moves the core files and might result in IPC crash
// TODO: It might fail if the update was triggered from the API, this should be something to improve in the future, by changing the structure into request -> return response -> finish update
ASFController.PendingVersionUpdate = newVersion;
try {
await ArchiKestrel.Stop().ConfigureAwait(false);
} catch (Exception e) {
ArchiLogger.LogGenericWarningException(e);
} finally {
ASFController.PendingVersionUpdate = null;
}
}

View File

@@ -0,0 +1,68 @@
// ----------------------------------------------------------------------------------------------
// _ _ _ ____ _ _____
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// ----------------------------------------------------------------------------------------------
// |
// 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.
namespace ArchiSteamFarm.Core;
internal static class BuildInfo {
#if ASF_VARIANT_DOCKER
internal static bool CanUpdate => false;
internal static string Variant => "docker";
#elif ASF_VARIANT_GENERIC
internal static bool CanUpdate => true;
internal static string Variant => "generic";
#elif ASF_VARIANT_LINUX_ARM
internal static bool CanUpdate => true;
internal static string Variant => "linux-arm";
#elif ASF_VARIANT_LINUX_ARM64
internal static bool CanUpdate => true;
internal static string Variant => "linux-arm64";
#elif ASF_VARIANT_LINUX_X64
internal static bool CanUpdate => true;
internal static string Variant => "linux-x64";
#elif ASF_VARIANT_OSX_ARM64
internal static bool CanUpdate => true;
internal static string Variant => "osx-arm64";
#elif ASF_VARIANT_OSX_X64
internal static bool CanUpdate => true;
internal static string Variant => "osx-x64";
#elif ASF_VARIANT_WIN_ARM64
internal static bool CanUpdate => true;
internal static string Variant => "win-arm64";
#elif ASF_VARIANT_WIN_X64
internal static bool CanUpdate => true;
internal static string Variant => "win-x64";
#else
internal static bool CanUpdate => false;
internal static string Variant => SourceVariant;
#endif
#if ASF_RUNTIME_TRIMMED
internal static bool IsRuntimeTrimmed => true;
#else
internal static bool IsRuntimeTrimmed => false;
#endif
private const string SourceVariant = "source";
internal static bool IsCustomBuild => Variant == SourceVariant;
}

View File

@@ -185,32 +185,32 @@ internal static class OS {
internal static bool VerifyEnvironment() {
// We're not going to analyze source builds, as we don't know what changes the author has made, assume they have a point
if (SharedInfo.BuildInfo.IsCustomBuild) {
if (BuildInfo.IsCustomBuild) {
return true;
}
if (SharedInfo.BuildInfo.Variant == "generic") {
if (BuildInfo.Variant == "generic") {
// Generic is supported everywhere
return true;
}
if ((SharedInfo.BuildInfo.Variant == "docker") || SharedInfo.BuildInfo.Variant.StartsWith("linux-", StringComparison.Ordinal)) {
if ((BuildInfo.Variant == "docker") || BuildInfo.Variant.StartsWith("linux-", StringComparison.Ordinal)) {
// OS-specific Linux and Docker builds are supported only on Linux
return OperatingSystem.IsLinux();
}
if (SharedInfo.BuildInfo.Variant.StartsWith("osx-", StringComparison.Ordinal)) {
if (BuildInfo.Variant.StartsWith("osx-", StringComparison.Ordinal)) {
// OS-specific macOS build is supported only on macOS
return OperatingSystem.IsMacOS();
}
if (SharedInfo.BuildInfo.Variant.StartsWith("win-", StringComparison.Ordinal)) {
if (BuildInfo.Variant.StartsWith("win-", StringComparison.Ordinal)) {
// OS-specific Windows build is supported only on Windows
return OperatingSystem.IsWindows();
}
// Unknown combination, we intend to cover all of the available ones above, so this results in an error
ASF.ArchiLogger.LogGenericError(Strings.FormatWarningUnknownValuePleaseReport(nameof(SharedInfo.BuildInfo.Variant), SharedInfo.BuildInfo.Variant));
ASF.ArchiLogger.LogGenericError(Strings.FormatWarningUnknownValuePleaseReport(nameof(BuildInfo.Variant), BuildInfo.Variant));
return false;
}

View File

@@ -55,6 +55,14 @@ public static class Utilities {
private static readonly FrozenSet<char> DirectorySeparators = new HashSet<char>(2) { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }.ToFrozenSet();
[PublicAPI]
public static IEnumerable<T> AsLinqThreadSafeEnumerable<T>(this ICollection<T> collection) {
ArgumentNullException.ThrowIfNull(collection);
// See: https://github.com/dotnet/runtime/discussions/50687
return collection.Select(static entry => entry);
}
[PublicAPI]
public static string GenerateChecksumFor(byte[] source) {
ArgumentNullException.ThrowIfNull(source);

View File

@@ -87,6 +87,10 @@ public sealed class ArchiCacheable<T> : IDisposable {
} catch (OperationCanceledException e) {
ASF.ArchiLogger.LogGenericDebuggingException(e);
return GetFailedValueFor(cacheFallback);
} catch (Exception e) {
ASF.ArchiLogger.LogGenericException(e);
return GetFailedValueFor(cacheFallback);
} finally {
InitSemaphore.Release();

View File

@@ -22,6 +22,7 @@
// limitations under the License.
using System;
using System.Buffers;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
@@ -241,11 +242,31 @@ public static class ArchiCryptoHelper {
try {
byte[] key = SHA256.HashData(EncryptionKey);
byte[] textData = Encoding.UTF8.GetBytes(text);
byte[] encryptedData = Encoding.UTF8.GetBytes(text);
encryptedData = CryptoHelper.SymmetricEncrypt(encryptedData, key);
Span<byte> iv = stackalloc byte[16];
RandomNumberGenerator.Fill(iv);
return Convert.ToBase64String(encryptedData);
using Aes aes = Aes.Create();
aes.BlockSize = 128;
aes.KeySize = 256;
aes.Key = key;
byte[] encryptedIv = aes.EncryptEcb(iv, PaddingMode.None);
byte[] encryptedText = aes.EncryptCbc(textData, iv);
int encryptedCount = encryptedIv.Length + encryptedText.Length;
byte[] result = ArrayPool<byte>.Shared.Rent(encryptedCount);
try {
Array.Copy(encryptedIv, result, encryptedIv.Length);
Array.Copy(encryptedText, 0, result, encryptedIv.Length, encryptedText.Length);
return Convert.ToBase64String(result, 0, encryptedCount);
} finally {
ArrayPool<byte>.Shared.Return(result);
}
} catch (Exception e) {
ASF.ArchiLogger.LogGenericException(e);

View File

@@ -26,6 +26,7 @@ using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization.Metadata;
using System.Threading;
@@ -112,6 +113,7 @@ public static class JsonUtilities {
private static JsonSerializerOptions CreateDefaultJsonSerializerOptions(bool writeIndented = false) =>
new() {
AllowTrailingCommas = true,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
PropertyNamingPolicy = null,
ReadCommentHandling = JsonCommentHandling.Skip,
TypeInfoResolver = new DefaultJsonTypeInfoResolver { Modifiers = { ApplyCustomModifiers } },

View File

@@ -26,6 +26,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using ArchiSteamFarm.Core;
using ArchiSteamFarm.IPC.Requests;
@@ -34,11 +35,22 @@ using ArchiSteamFarm.Localization;
using ArchiSteamFarm.Steam.Interaction;
using ArchiSteamFarm.Storage;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Hosting;
namespace ArchiSteamFarm.IPC.Controllers.Api;
[Route("Api/ASF")]
public sealed class ASFController : ArchiController {
internal static Version? PendingVersionUpdate { get; set; }
private readonly IHostApplicationLifetime ApplicationLifetime;
public ASFController(IHostApplicationLifetime applicationLifetime) {
ArgumentNullException.ThrowIfNull(applicationLifetime);
ApplicationLifetime = applicationLifetime;
}
/// <summary>
/// Encrypts data with ASF encryption mechanisms using provided details.
/// </summary>
@@ -70,7 +82,7 @@ public sealed class ASFController : ArchiController {
uint memoryUsage = (uint) GC.GetTotalMemory(false) / 1024;
ASFResponse result = new(SharedInfo.BuildInfo.Variant, SharedInfo.BuildInfo.CanUpdate, ASF.GlobalConfig, memoryUsage, OS.ProcessStartTime, SharedInfo.Version);
ASFResponse result = new(BuildInfo.Variant, BuildInfo.CanUpdate, ASF.GlobalConfig, memoryUsage, OS.ProcessStartTime, SharedInfo.Version);
return Ok(new GenericResponse<ASFResponse>(result));
}
@@ -185,12 +197,35 @@ public sealed class ASFController : ArchiController {
return BadRequest(new GenericResponse(false, Strings.FormatErrorIsInvalid(nameof(request.Channel))));
}
(bool success, string? message, Version? version) = await Actions.Update(request.Channel, request.Forced).ConfigureAwait(false);
// Update process can result in kestrel shutdown request, just before patching the files
// In this case, we have very little opportunity to do anything, especially we will not have access to the return value of the action
// That's because update action will synchronously stop the kestrel, and wait for it before proceeding with an update, and that'll wait for us finishing the request, never happening
// Therefore, we'll allow this action to proceed while listening for application shutdown request, if it happens, we'll do our best by getting alternative signal that update is proceeding
TaskCompletionSource<bool> applicationStopping = new();
if (string.IsNullOrEmpty(message)) {
message = success ? Strings.Success : Strings.WarningFailed;
CancellationTokenRegistration applicationStoppingRegistration = ApplicationLifetime.ApplicationStopping.Register(() => applicationStopping.SetResult(true));
await using (applicationStoppingRegistration.ConfigureAwait(false)) {
Task<(bool Success, string? Message, Version? Version)> updateTask = Actions.Update(request.Channel, request.Forced);
bool success;
string? message = null;
Version? version;
if (await Task.WhenAny(updateTask, applicationStopping.Task).ConfigureAwait(false) == updateTask) {
(success, message, version) = await updateTask.ConfigureAwait(false);
} else {
// It's almost guaranteed that this is the result of update process requesting kestrel shutdown
// However, we're still going to check PendingVersionUpdate, which should be set by the update process as alternative way to inform us about pending update
version = PendingVersionUpdate;
success = version != null;
}
if (string.IsNullOrEmpty(message)) {
message = success ? Strings.Success : Strings.WarningFailed;
}
return Ok(new GenericResponse<string>(success, message, version?.ToString()));
}
return Ok(new GenericResponse<string>(success, message, version?.ToString()));
}
}

View File

@@ -318,6 +318,34 @@ public sealed class BotController : ArchiController {
return Ok(new GenericResponse(results.All(static result => result.Success), string.Join(Environment.NewLine, results.Select(static result => result.Message))));
}
/// <summary>
/// Redeems points on given bots.
/// </summary>
[Consumes("application/json")]
[HttpPost("{botNames:required}/RedeemPoints/{definitionID:required}")]
[ProducesResponseType<GenericResponse<IReadOnlyDictionary<string, EResult>>>((int) HttpStatusCode.OK)]
[ProducesResponseType<GenericResponse>((int) HttpStatusCode.BadRequest)]
public async Task<ActionResult<GenericResponse>> RedeemPointsPost(string botNames, uint definitionID, [FromQuery] bool forced = false) {
ArgumentException.ThrowIfNullOrEmpty(botNames);
ArgumentOutOfRangeException.ThrowIfZero(definitionID);
HashSet<Bot>? bots = Bot.GetBots(botNames);
if ((bots == null) || (bots.Count == 0)) {
return BadRequest(new GenericResponse(false, Strings.FormatBotNotFound(botNames)));
}
IList<EResult> results = await Utilities.InParallel(bots.Select(bot => bot.Actions.RedeemPoints(definitionID, forced))).ConfigureAwait(false);
Dictionary<string, EResult> result = new(bots.Count, Bot.BotsComparer);
foreach (Bot bot in bots) {
result[bot.BotName] = results[result.Count];
}
return Ok(new GenericResponse<IReadOnlyDictionary<string, EResult>>(result));
}
/// <summary>
/// Redeems cd-keys on given bot.
/// </summary>

View File

@@ -23,6 +23,7 @@
using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using ArchiSteamFarm.Core;
using ArchiSteamFarm.IPC.Requests;
@@ -31,11 +32,20 @@ using ArchiSteamFarm.Localization;
using ArchiSteamFarm.Steam;
using ArchiSteamFarm.Storage;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Hosting;
namespace ArchiSteamFarm.IPC.Controllers.Api;
[Route("Api/Command")]
public sealed class CommandController : ArchiController {
private readonly IHostApplicationLifetime ApplicationLifetime;
public CommandController(IHostApplicationLifetime applicationLifetime) {
ArgumentNullException.ThrowIfNull(applicationLifetime);
ApplicationLifetime = applicationLifetime;
}
/// <summary>
/// Executes a command.
/// </summary>
@@ -72,8 +82,28 @@ public sealed class CommandController : ArchiController {
command = command[commandPrefix.Length..];
}
string? response = await targetBot.Commands.Response(EAccess.Owner, command).ConfigureAwait(false);
// Update process can result in kestrel shutdown request, just before patching the files
// In this case, we have very little opportunity to do anything, especially we will not have access to the return value of the command
// That's because update command will synchronously stop the kestrel, and wait for it before proceeding with an update, and that'll wait for us finishing the request, never happening
// Therefore, we'll allow this command to proceed while listening for application shutdown request, if it happens, we'll do our best by getting alternative signal that update is proceeding
TaskCompletionSource<bool> applicationStopping = new();
return Ok(new GenericResponse<string>(response));
CancellationTokenRegistration applicationStoppingRegistration = ApplicationLifetime.ApplicationStopping.Register(() => applicationStopping.SetResult(true));
await using (applicationStoppingRegistration.ConfigureAwait(false)) {
Task<string?> commandTask = targetBot.Commands.Response(EAccess.Owner, command);
string? response;
if (await Task.WhenAny(commandTask, applicationStopping.Task).ConfigureAwait(false) == commandTask) {
response = await commandTask.ConfigureAwait(false);
} else {
// It's almost guaranteed that this is the result of update process requesting kestrel shutdown
// However, we're still going to check PendingVersionUpdate, which should be set by the update process as alternative way to inform us about pending update
response = ASFController.PendingVersionUpdate != null ? Strings.PatchingFiles : Strings.Exiting;
}
return Ok(new GenericResponse<string>(response));
}
}
}

View File

@@ -38,6 +38,7 @@ using ArchiSteamFarm.NLog;
using ArchiSteamFarm.NLog.Targets;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Hosting;
namespace ArchiSteamFarm.IPC.Controllers.Api;
@@ -45,6 +46,14 @@ namespace ArchiSteamFarm.IPC.Controllers.Api;
public sealed class NLogController : ArchiController {
private static readonly ConcurrentDictionary<WebSocket, (SemaphoreSlim Semaphore, CancellationToken CancellationToken)> ActiveLogWebSockets = new();
private readonly IHostApplicationLifetime ApplicationLifetime;
public NLogController(IHostApplicationLifetime applicationLifetime) {
ArgumentNullException.ThrowIfNull(applicationLifetime);
ApplicationLifetime = applicationLifetime;
}
/// <summary>
/// Fetches ASF log file, this works on assumption that the log file is in fact generated, as user could disable it through custom configuration.
/// </summary>
@@ -91,7 +100,7 @@ public sealed class NLogController : ArchiController {
[HttpGet]
[ProducesResponseType<IEnumerable<GenericResponse<string>>>((int) HttpStatusCode.OK)]
[ProducesResponseType<GenericResponse>((int) HttpStatusCode.BadRequest)]
public async Task<ActionResult> Get(CancellationToken cancellationToken) {
public async Task<ActionResult> Get() {
if (HttpContext == null) {
throw new InvalidOperationException(nameof(HttpContext));
}
@@ -107,7 +116,9 @@ public sealed class NLogController : ArchiController {
SemaphoreSlim sendSemaphore = new(1, 1);
if (!ActiveLogWebSockets.TryAdd(webSocket, (sendSemaphore, cancellationToken))) {
using CancellationTokenSource cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(HttpContext.RequestAborted, ApplicationLifetime.ApplicationStopping);
if (!ActiveLogWebSockets.TryAdd(webSocket, (sendSemaphore, cancellationTokenSource.Token))) {
sendSemaphore.Dispose();
return new EmptyResult();
@@ -116,20 +127,22 @@ public sealed class NLogController : ArchiController {
try {
// Push initial history if available
if (ArchiKestrel.HistoryTarget != null) {
// ReSharper disable once AccessToDisposedClosure - we're waiting for completion with Task.WhenAll(), we're not going to exit using block
await Task.WhenAll(ArchiKestrel.HistoryTarget.ArchivedMessages.Select(archivedMessage => PostLoggedMessageUpdate(webSocket, archivedMessage, sendSemaphore, cancellationToken))).ConfigureAwait(false);
// ReSharper disable AccessToDisposedClosure - we're waiting for completion with Task.WhenAll(), we're not going to exit using block
await Task.WhenAll(ArchiKestrel.HistoryTarget.ArchivedMessages.Select(archivedMessage => PostLoggedMessageUpdate(webSocket, archivedMessage, sendSemaphore, cancellationTokenSource.Token))).ConfigureAwait(false);
// ReSharper restore AccessToDisposedClosure - we're waiting for completion with Task.WhenAll(), we're not going to exit using block
}
while (webSocket.State == WebSocketState.Open) {
WebSocketReceiveResult result = await webSocket.ReceiveAsync(Array.Empty<byte>(), cancellationToken).ConfigureAwait(false);
while ((webSocket.State == WebSocketState.Open) && !cancellationTokenSource.IsCancellationRequested) {
WebSocketReceiveResult result = await webSocket.ReceiveAsync(Array.Empty<byte>(), cancellationTokenSource.Token).ConfigureAwait(false);
if (result.MessageType != WebSocketMessageType.Close) {
await webSocket.CloseAsync(WebSocketCloseStatus.InvalidMessageType, "You're not supposed to be sending any message but Close!", cancellationToken).ConfigureAwait(false);
await webSocket.CloseAsync(WebSocketCloseStatus.InvalidMessageType, "You're not supposed to be sending any message but Close!", cancellationTokenSource.Token).ConfigureAwait(false);
break;
}
await webSocket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "", cancellationToken).ConfigureAwait(false);
await webSocket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "", cancellationTokenSource.Token).ConfigureAwait(false);
break;
}

View File

@@ -457,7 +457,6 @@ StackTrace:
<value>Падключэнне...</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>Спыненне...</value>
</data>

View File

@@ -481,9 +481,6 @@
<data name="BotHeartBeatFailed" xml:space="preserve">
<value>Неуспешно прекъсване на връзката на клиента. Премахва се този бот!</value>
</data>
<data name="BotSteamDirectoryInitializationFailed" xml:space="preserve">
<value>Неуспешно стартиране на SteamDirectory: свързването с мрежата на Steam може да отнеме много повече време от обичайното!</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>Спиране…</value>
</data>

View File

@@ -338,7 +338,6 @@
<value>Povezivanje...</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>Zaustavljanje...</value>
</data>

View File

@@ -0,0 +1,398 @@
<?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>
<data name="AcceptingTrade" xml:space="preserve">
<value>Acceptant intercanvi: {0}</value>
<comment>{0} will be replaced by trade number</comment>
</data>
<data name="AutoUpdateCheckInfo" xml:space="preserve">
<value>ASF cercarà automàticament noves versions cada {0}.</value>
<comment>{0} will be replaced by translated TimeSpan string (such as "24 hours")</comment>
</data>
<data name="Content" xml:space="preserve">
<value>Contingut:
{0}</value>
<comment>{0} will be replaced by content string. Please note that this string should include newline for formatting.</comment>
</data>
<data name="ErrorIsInvalid" xml:space="preserve">
<value>{0} és invàlid!</value>
<comment>{0} will be replaced by object's name</comment>
</data>
<data name="ErrorRequestFailedTooManyTimes" xml:space="preserve">
<value>La petició ha fallat després de {0} intents!</value>
<comment>{0} will be replaced by maximum number of tries</comment>
</data>
<data name="ErrorUpdateCheckFailed" xml:space="preserve">
<value>No s'ha pogut comprovar l'última versió!</value>
</data>
<data name="Exiting" xml:space="preserve">
<value>Sortint...</value>
</data>
<data name="WarningFailed" xml:space="preserve">
<value>Ha fallat!</value>
</data>
<data name="GlobalConfigChanged" xml:space="preserve">
<value>El fitxer de configuració global s'ha modificat!</value>
</data>
<data name="ErrorGlobalConfigRemoved" xml:space="preserve">
<value>El fitxer de configuració global s'ha eliminat!</value>
</data>
<data name="IgnoringTrade" xml:space="preserve">
<value>Ignorant intercanvi: {0}</value>
<comment>{0} will be replaced by trade number</comment>
</data>
<data name="LoggingIn" xml:space="preserve">
<value>Iniciant sessió a {0}...</value>
<comment>{0} will be replaced by service's name</comment>
</data>
<data name="NoBotsAreRunning" xml:space="preserve">
<value>No hi ha cap bot en funcionament. Sortint...</value>
</data>
<data name="RefreshingOurSession" xml:space="preserve">
<value>Actualitzant la sessió!</value>
</data>
<data name="RejectingTrade" xml:space="preserve">
<value>Rebutjant l'intercanvi: {0}</value>
<comment>{0} will be replaced by trade number</comment>
</data>
<data name="Restarting" xml:space="preserve">
<value>Reiniciant...</value>
</data>
<data name="Starting" xml:space="preserve">
<value>Iniciant...</value>
</data>
<data name="Success" xml:space="preserve">
<value>Èxit!</value>
</data>
<data name="UnlockingParentalAccount" xml:space="preserve">
<value>Desblocant el compte parental...</value>
</data>
<data name="UpdateCheckingNewVersion" xml:space="preserve">
<value>Cercant una nova versió...</value>
</data>
<data name="UpdateDownloadingNewVersion" xml:space="preserve">
<value>Descarregant nova versió: {0} ({1} MB)... Mentre espereu, considereu fer una donació si aprecieu la nostra tasca! :)</value>
<comment>{0} will be replaced by version string, {1} will be replaced by update size (in megabytes)</comment>
</data>
<data name="UpdateFinished" xml:space="preserve">
<value>Procés d'actualització finalitzat!</value>
</data>
<data name="UserInputSteamLogin" xml:space="preserve">
<value>Si us plau, introduïu el vostre nom d'usuari de Steam: </value>
<comment>Please note that this translation should end with space</comment>
</data>
<data name="UserInputSteamParentalCode" xml:space="preserve">
<value>Si us plau, introduïu el vostre codi de control parental de Steam: </value>
<comment>Please note that this translation should end with space</comment>
</data>
<data name="UserInputSteamPassword" xml:space="preserve">
<value>Si us plau, introduïu la vostra contrasenya de Steam: </value>
<comment>Please note that this translation should end with space</comment>
</data>
<data name="IPCReady" xml:space="preserve">
<value>Servidor IPC preparat!</value>
</data>
<data name="IPCStarting" xml:space="preserve">
<value>Iniciant servidor IPC...</value>
</data>
<data name="BotAlreadyStopped" xml:space="preserve">
<value>Aquest bot ja s'ha aturat!</value>
</data>
<data name="BotNotFound" xml:space="preserve">
<value>No s'ha trobat cap bot anomenat {0}!</value>
<comment>{0} will be replaced by bot's name query (string)</comment>
</data>
<data name="CheckingFirstBadgePage" xml:space="preserve">
<value>Comprovant la primera pàgina d'insígnies...</value>
</data>
<data name="CheckingOtherBadgePages" xml:space="preserve">
<value>Comprovant les altres pàgines d'insígnies...</value>
</data>
<data name="Done" xml:space="preserve">
<value>Fet!</value>
</data>
<data name="BotAddLicense" xml:space="preserve">
<value>ID: {0} | Estat: {1}</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by status string</comment>
</data>
<data name="BotAddLicenseWithItems" xml:space="preserve">
<value>ID: {0} | Estat: {1} | Objectes: {2}</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by status string, {2} will be replaced by list of granted IDs (numbers), separated by a comma</comment>
</data>
<data name="BotAlreadyRunning" xml:space="preserve">
<value>Aquest bot ja està en funcionament!</value>
</data>
<data name="BotAuthenticatorConverting" xml:space="preserve">
<value>Convertint arxiu .maFile a format ASF...</value>
</data>
<data name="BotConnected" xml:space="preserve">
<value>Connectat a Steam!</value>
</data>
<data name="BotDisconnected" xml:space="preserve">
<value>Desconnectat de Steam!</value>
</data>
<data name="BotDisconnecting" xml:space="preserve">
<value>Desconnectant...</value>
</data>
<data name="BotLoggingIn" xml:space="preserve">
<value>Iniciant sessió...</value>
</data>
<data name="BotLootingFailed" xml:space="preserve">
<value>L'oferta d'intercanvi ha fallat!</value>
</data>
<data name="BotLootingSuccess" xml:space="preserve">
<value>Oferta d'intercanvi enviada amb èxit!</value>
</data>
<data name="BotSendingTradeToYourself" xml:space="preserve">
<value>No podeu enviar una oferta d'intercanvi a vosaltres mateixos!</value>
</data>
<data name="BotReconnecting" xml:space="preserve">
<value>Tornant a connectar...</value>
</data>
<data name="BotStatusNotRunning" xml:space="preserve">
<value>El bot no està en funcionament.</value>
</data>
<data name="ErrorIsEmpty" xml:space="preserve">
<value>{0} no conté res!</value>
<comment>{0} will be replaced by object's name</comment>
</data>
<data name="BotConnecting" xml:space="preserve">
<value>S'està connectant...</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>Aturant...</value>
</data>
<data name="Initializing" xml:space="preserve">
<value>Inicialitzant {0}...</value>
<comment>{0} will be replaced by service name that is being initialized</comment>
</data>
<data name="BotVersion" xml:space="preserve">
<value>{0} V{1}</value>
<comment>{0} will be replaced by program's name (e.g. "ASF"), {1} will be replaced by program's version (e.g. "1.0.0.0"). This string typically has nothing to translate and you should leave it as it is, unless you need to change the format, e.g. in RTL languages.</comment>
</data>
<data name="ErrorAccessDenied" xml:space="preserve">
<value>Accés denegat!</value>
</data>
<data name="Executing" xml:space="preserve">
<value>Executant...</value>
</data>
<data name="Result" xml:space="preserve">
<value>Resultat: {0}</value>
<comment>{0} will be replaced by generic result of various functions that use this string</comment>
</data>
</root>

View File

@@ -487,9 +487,6 @@ StackTrace:
<data name="BotHeartBeatFailed" xml:space="preserve">
<value>Selhalo odpojení klienta. Ruší se instance bota.</value>
</data>
<data name="BotSteamDirectoryInitializationFailed" xml:space="preserve">
<value>Nelze inicializovat SteamDirectory: připojení k síti Steam může trvat déle, než je obvyklé.</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>Zastavování...</value>
</data>
@@ -717,7 +714,9 @@ StackTrace:
<data name="ChecksumMissing" xml:space="preserve">
<value>Vzdálený server nezná verzi na kterou se snažíte aktualizovat. Tato situace nastává, pokud verze byla vydána nedávno - aktualizace nebude z bezpečnostních důvodu pokračovat.</value>
</data>
<data name="ChecksumTimeout" xml:space="preserve">
<value>Nepodařilo se načíst kontrolní součet stažených binárních souborů odmítám pokračovat v procesu aktualizace jakožto další bezpečnostní opatření.</value>
</data>
<data name="ChecksumWrong" xml:space="preserve">
<value>Vzdálený server odpověděl s jiným kontrolním součtem, což může naznačovat chybu při stahování nebo útok MITM, proces aktualizace proto nebude pokračovat!</value>
</data>
@@ -740,9 +739,17 @@ StackTrace:
<value>ASF nemůže spustit aplikaci {0}, protože má regionální omezení pro zemi {1}, které trvá do {2}.</value>
<comment>{0} will be replaced by app ID (number), {1} will be replaced by short country code (string, such as "PL"), {2} will be replaced by human-readable date (string).</comment>
</data>
<data name="WarningUnsupportedOfficialPlugins" xml:space="preserve">
<value>Pokoušíte se spustit jinou verzi oficiální pluginu {0}, než se očekávalo (Plugin: {1}, ASF: {2}). To většinou znamená, že děláte něco velmi špatně. Buďto opravte svou instalaci, nebo - pokud opravdu víte, co děláte - použijte při spuštění argument --ignore-unsupported-environment.</value>
<comment>{0} will be replaced by plugin name, {1} will be replaced by plugin's version number, {2} will be replaced by ASF's version number.</comment>
</data>
<data name="ErrorTooManyCrashes" xml:space="preserve">
<value>ASF se v poslední době zhroutilo příliš mnohokrát a byla kvůli tomu vypnuta inicializace procesu. Buďto prozkoumejte příčinu problému, opravte svou instalaci a odeberte ASF.crash soubor ze složky s konfigurací, nebo - pokud opravdu víte, co děláte - použijte při spuštění argument --ignore-unsupported-environment.</value>
</data>
<data name="IdlingGameNotPossiblePrivate" xml:space="preserve">
<value>Farmení {0} ({1}) je aktuálně vypnuté, protože je tato hra označená jako soukromá. Pokud chcete farmit tuto hru pomocí ASF, zvažte změnu jejího nastavení soukromí.</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="WarningSkipping" xml:space="preserve">
<value>Přeskakování: {0}...</value>
<comment>{0} will be replaced by text value (string) of entry being skipped.</comment>
@@ -766,8 +773,14 @@ StackTrace:
<value>Nalezena aktualizace pro zásuvný modul {0} z verze {1} na {2}...</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateNoAssetFound" xml:space="preserve">
<value>Není k dispozici žádný asset pro aktualizaci pluginu {0} z verze {1} na verzi {2}. To většinou znamená, že aktualizace bude dostupná později.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateConflictingAssetsFound" xml:space="preserve">
<value>Nelze určit žádný asset pro aktualizaci pluginu {0} z verze {1} na verzi {2}. To může nastat, když nová verze ještě není hotová - pokud se tato situace opakuje, oznamte to tvůrci pluginu.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateInProgress" xml:space="preserve">
<value>Aktualizuji zásuvný modul {0}...</value>
<comment>{0} will be replaced by plugin name (string).</comment>

View File

@@ -87,7 +87,10 @@ StackTrace:
{2}</value>
<comment>{0} will be replaced by function name, {1} will be replaced by exception message, {2} will be replaced by entire stack trace. Please note that this string should include newlines for formatting.</comment>
</data>
<data name="ErrorExitingWithNonZeroErrorCode" xml:space="preserve">
<value>Afslutter med {0} fejlkode!</value>
<comment>{0} will be replaced by error code (number)</comment>
</data>
<data name="ErrorFailingRequest" xml:space="preserve">
<value>Forespørgsel fejler: {0}</value>
<comment>{0} will be replaced by URL of the request</comment>
@@ -186,7 +189,10 @@ StackTrace:
<value>Lokal version: {0} | Fjernversion: {1}</value>
<comment>{0} will be replaced by current version, {1} will be replaced by remote version</comment>
</data>
<data name="UserInputDeviceConfirmation" xml:space="preserve">
<value>Tjek venligst Steam appen på din telefon, du skulle have modtaget en login godkendelsesmeddelelse. Skriv Y, hvis du har modtaget og godkendt meddelelsen, N hvis du ønsker at angive koden i stedet: </value>
<comment>Please note that this translation should end with space</comment>
</data>
<data name="UserInputSteam2FA" xml:space="preserve">
<value>Venligst indtast din 2FA kode fra din steam autentificering app: </value>
<comment>Please note that this translation should end with space</comment>
@@ -318,7 +324,9 @@ StackTrace:
<value>Acceptere gave: {0}...</value>
<comment>{0} will be replaced by giftID (number)</comment>
</data>
<data name="BotAccountLimited" xml:space="preserve">
<value>Denne konto er begrænset, idling processen er ikke tilgængelig indtil begrænsningen er fjernet!</value>
</data>
<data name="BotAddLicense" xml:space="preserve">
<value>ID: {0} | Status: {1}</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by status string</comment>
@@ -340,10 +348,18 @@ StackTrace:
<value>2FA Token: {0}</value>
<comment>{0} will be replaced by generated 2FA token (string)</comment>
</data>
<data name="BotAutomaticIdlingNowPaused" xml:space="preserve">
<value>Automatisk idling er på pause!</value>
</data>
<data name="BotAutomaticIdlingNowResumed" xml:space="preserve">
<value>Automatisk idling er genoptaget!</value>
</data>
<data name="BotAutomaticIdlingPausedAlready" xml:space="preserve">
<value>Automatisk idling er allerede på pause!</value>
</data>
<data name="BotAutomaticIdlingResumedAlready" xml:space="preserve">
<value>Automatisk idling er allerede genoptaget!</value>
</data>
<data name="BotConnected" xml:space="preserve">
<value>Forbundet til Steam!</value>
</data>
@@ -400,7 +416,10 @@ StackTrace:
<value>Ejes allerede: {0} | {1}</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="BotPointsBalance" xml:space="preserve">
<value>Point saldo: {0}</value>
<comment>{0} will be replaced by the points balance value (integer)</comment>
</data>
<data name="BotRateLimitExceeded" xml:space="preserve">
<value>Rate limit er blevet overskredet, vi prøver igen efter cooldown på {0}...</value>
<comment>{0} will be replaced by translated TimeSpan string (such as "25 minutes")</comment>
@@ -422,7 +441,9 @@ StackTrace:
<data name="BotStatusNotIdling" xml:space="preserve">
<value>Botten idler ikke noget.</value>
</data>
<data name="BotStatusLimited" xml:space="preserve">
<value>Botten er begrænset og kan ikke droppe nogen kort gennem idling.</value>
</data>
<data name="BotStatusConnecting" xml:space="preserve">
<value>Botten er forbundet til Steam-netværket.</value>
</data>
@@ -454,17 +475,18 @@ StackTrace:
<data name="BotConnectionLost" xml:space="preserve">
<value>Forbindelse til Steam-netværket mistede. Opretter forbindelse igen...</value>
</data>
<data name="BotAccountFree" xml:space="preserve">
<value>Konto er ikke længere optaget: idling genoptaget!</value>
</data>
<data name="BotAccountOccupied" xml:space="preserve">
<value>Kontoen bruges i øjeblikket: ASF vil genoptage idling når det er fri...</value>
</data>
<data name="BotConnecting" xml:space="preserve">
<value>Forbinder...</value>
</data>
<data name="BotHeartBeatFailed" xml:space="preserve">
<value>Afbrydelsen af klienten fejlede, afbryder denne bot instans!</value>
</data>
<data name="BotSteamDirectoryInitializationFailed" xml:space="preserve">
<value>Kunne ikke initialisere SteamDirectory: forbinder med Steam-netværket kan tage meget længere tid end normalt!</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>Stopper...</value>
</data>
@@ -493,7 +515,10 @@ StackTrace:
<value>ASF vil forsøge at bruge din foretrukne {0} kultur, men oversættelsen til det pågældende sprog er kun {1} komplet. Måske kan du hjælpe os med at forbedre oversættelsen af ASF til dit sprog?</value>
<comment>{0} will be replaced by culture code, such as "en-US", {1} will be replaced by completeness percentage, such as "78.5%"</comment>
</data>
<data name="IdlingGameNotPossible" xml:space="preserve">
<value>Idling {0} ({1}) er midlertidigt deaktiveret, da ASF ikke er i stand til at spille dette spil i øjeblikket.</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="WarningIdlingGameMismatch" xml:space="preserve">
<value>ASF opdaget ID uoverensstemmelse for {0} ({1}) og bruger ID'ET for {2} i stedet.</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name, {2} will be replaced by game's ID (number)</comment>
@@ -502,8 +527,12 @@ StackTrace:
<value>{0} V{1}</value>
<comment>{0} will be replaced by program's name (e.g. "ASF"), {1} will be replaced by program's version (e.g. "1.0.0.0"). This string typically has nothing to translate and you should leave it as it is, unless you need to change the format, e.g. in RTL languages.</comment>
</data>
<data name="BotAccountLocked" xml:space="preserve">
<value>Denne konto er låst, idling proces er permanent utilgængelig!</value>
</data>
<data name="BotStatusLocked" xml:space="preserve">
<value>Botten er låst og kan ikke droppe nogen kort gennem idling.</value>
</data>
<data name="ErrorFunctionOnlyInHeadlessMode" xml:space="preserve">
<value>Denne funktion er kun tilgængelig i hovedløs tilstand!</value>
</data>
@@ -615,7 +644,10 @@ Processens oppetid: {1}</value>
<value>Behandlede {0} bekræftelser succesfuldt!</value>
<comment>{0} will be replaced by number of confirmations</comment>
</data>
<data name="BotExtraIdlingCooldown" xml:space="preserve">
<value>Venter op til {0} for at sikre at vi er klar til at begynde at idle...</value>
<comment>{0} will be replaced by translated TimeSpan string (such as "1 minute")</comment>
</data>
<data name="UpdateCleanup" xml:space="preserve">
<value>Rydder op i de gamle filer efter opdateringen...</value>
</data>
@@ -647,41 +679,98 @@ Processens oppetid: {1}</value>
<data name="ErrorConfigDirectoryNotFound" xml:space="preserve">
<value>Konfigurationsmappen kunne ikke findes, afbryder!</value>
</data>
<data name="BotIdlingSelectedGames" xml:space="preserve">
<value>Spiller valgt {0}: {1}</value>
<comment>{0} will be replaced by internal name of the config property (e.g. "GamesPlayedWhileIdle"), {1} will be replaced by comma-separated list of appIDs that user has chosen</comment>
</data>
<data name="AutomaticFileMigration" xml:space="preserve">
<value>{0} konfigurationsfil vil blive migreret til den seneste syntaks...</value>
<comment>{0} will be replaced with the relative path to the affected config file</comment>
</data>
<data name="WarningTooShortCryptKey" xml:space="preserve">
<value>Din krypteringsnøgle er for kort. Vi anbefaler at bruge en, der er mindst {0} bytes (tegn) lang.</value>
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
</data>
<data name="WarningRunningAsRoot" xml:space="preserve">
<value>Du forsøger at køre ASF som administrator (root). Dette medfører en betydelig sikkerhedsrisiko for din maskine, og da ASF ikke kræver root-adgang for dens drift, vi anbefaler at køre det som ikke-administrator bruger hvis det er muligt.</value>
</data>
<data name="FetchingChecksumFromRemoteServer" xml:space="preserve">
<value>Henter checksum fra den eksterne server...</value>
</data>
<data name="VerifyingChecksumWithRemoteServer" xml:space="preserve">
<value>Verificerer checksum af den downloadede binary mod den fra den eksterne server...</value>
</data>
<data name="PatchingFiles" xml:space="preserve">
<value>Retter ASF-filer...</value>
</data>
<data name="UserInputCryptkey" xml:space="preserve">
<value>Indtast venligst din krypteringsnøgle: </value>
<comment>Please note that this translation should end with space</comment>
</data>
<data name="ErrorIPNotBanned" xml:space="preserve">
<value>IP-adressen {0} er ikke bandlyst!</value>
<comment>{0} will be replaced by an IP address which was requested to be unbanned from using IPC</comment>
</data>
<data name="WarningNoLicense" xml:space="preserve">
<value>Du har forsøgt at bruge betalt funktion {0} men du har ikke et gyldigt LicenseID sat i ASF global konfiguration. Gennemgå venligst din konfiguration, da funktionaliteten ikke fungerer uden yderligere detaljer.</value>
<comment>{0} will be replaced by feature name (e.g. MatchActively)</comment>
</data>
<data name="WarningRegionRestrictedPackage" xml:space="preserve">
<value>ASF kan ikke bruge app {0}, da den har regionsrelateret begrænsning for {1} der varer indtil {2}.</value>
<comment>{0} will be replaced by app ID (number), {1} will be replaced by short country code (string, such as "PL"), {2} will be replaced by human-readable date (string).</comment>
</data>
<data name="IdlingGameNotPossiblePrivate" xml:space="preserve">
<value>Idling {0} ({1}) er deaktiveret, da spillet i øjeblikket er markeret som privat. Hvis du har til hensigt fra ASF til at idle det spil, så overvej at ændre dine privatlivsindstillinger.</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="WarningSkipping" xml:space="preserve">
<value>Springer over: {0}...</value>
<comment>{0} will be replaced by text value (string) of entry being skipped.</comment>
</data>
<data name="PluginUpdatesChecking" xml:space="preserve">
<value>Søger efter plugin opdateringer...</value>
</data>
<data name="PluginUpdateChecking" xml:space="preserve">
<value>Kontrollerer opdatering for {0} plugin...</value>
<comment>{0} will be replaced by plugin name (string).</comment>
</data>
<data name="PluginUpdateNotFound" xml:space="preserve">
<value>Ingen opdatering tilgængelig for {0} plugin: {1} ≥ {2}.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateNewVersionAvailable" xml:space="preserve">
<value>Ny {0} plugin version er tilgængelig! Overvej at opdatér det selv!</value>
<comment>{0} will be replaced by plugin name (string).</comment>
</data>
<data name="PluginUpdateFound" xml:space="preserve">
<value>Fandt {0} plugin opdatering fra version {1} til {2}...</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateInProgress" xml:space="preserve">
<value>Opdaterer {0} plugin...</value>
<comment>{0} will be replaced by plugin name (string).</comment>
</data>
<data name="PluginUpdateFinished" xml:space="preserve">
<value>Opdatering af {0} plugin er lykkedes, ændringerne vil blive indlæst ved den næste ASF start.</value>
<comment>{0} will be replaced by plugin name (string).</comment>
</data>
<data name="PluginUpdateEnabled" xml:space="preserve">
<value>{0}/{1} plugin er blevet registreret og aktiveret for automatiske opdateringer.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by plugin assembly name (string).</comment>
</data>
<data name="PluginUpdateDisabled" xml:space="preserve">
<value>{0} ({1}) plugin er blevet deaktiveret fra automatiske opdateringer, på trods af at den understøtter den funktion.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by plugin assembly name (string).</comment>
</data>
</root>

View File

@@ -488,9 +488,6 @@ StackTrace:
<data name="BotHeartBeatFailed" xml:space="preserve">
<value>Die Verbindung zum Client konnte nicht getrennt werden. Auf diese Bot-Instanz wird verzichtet!</value>
</data>
<data name="BotSteamDirectoryInitializationFailed" xml:space="preserve">
<value>SteamDirectory konnte nicht initialisiert werden: Die Verbindung mit dem Steam-Netzwerk könnte viel länger dauern als sonst!</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>Anhalten...</value>
</data>

View File

@@ -484,9 +484,6 @@ StackTrace:
<data name="BotHeartBeatFailed" xml:space="preserve">
<value>Αποτυχία αποσύνδεσης προγράμματος-πελάτη. Γίνεται εγκατάλειψη αυτού του bot!</value>
</data>
<data name="BotSteamDirectoryInitializationFailed" xml:space="preserve">
<value>Αδυναμία αρχικοποίησης SteamDirectory: η σύνδεση με το δίκτυο του Steam μπορεί να διαρκέσει πολύ περισσότερο από το συνηθισμένο!</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>Διακοπή...</value>
</data>

View File

@@ -486,9 +486,6 @@ StackTrace:
<data name="BotHeartBeatFailed" xml:space="preserve">
<value>Fallo al desconectar el cliente. ¡Abandonando esta instancia de bot!</value>
</data>
<data name="BotSteamDirectoryInitializationFailed" xml:space="preserve">
<value>No se pudo iniciar SteamDirectory: ¡la conexión con la red de Steam podría tardar más de lo habitual!</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>Deteniendo...</value>
</data>

View File

@@ -60,6 +60,456 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<data name="AcceptingTrade" xml:space="preserve">
<value>موافقت با ترید: {0}</value>
<comment>{0} will be replaced by trade number</comment>
</data>
<data name="AutoUpdateCheckInfo" xml:space="preserve">
<value>برنامه برای نسخه ی جدید هر {0} به صورت خودکار چک خواهد کرد.</value>
<comment>{0} will be replaced by translated TimeSpan string (such as "24 hours")</comment>
</data>
<data name="Content" xml:space="preserve">
<value>محتوا:
{0}</value>
<comment>{0} will be replaced by content string. Please note that this string should include newline for formatting.</comment>
</data>
<data name="ErrorConfigPropertyInvalid" xml:space="preserve">
<value>کانفیگ {0}، مشکل در: {1}</value>
<comment>{0} will be replaced by name of the configuration property, {1} will be replaced by invalid value</comment>
</data>
<data name="ErrorEarlyFatalExceptionInfo" xml:space="preserve">
<value>قبل از لود شدن برنامه ی لاگ کردن ASF نسخه ی {0} کرش شده است!</value>
<comment>{0} will be replaced by version number</comment>
</data>
<data name="ErrorEarlyFatalExceptionPrint" xml:space="preserve">
<value>ارور:
Exception: {0}() {1}
StackTrace:
{2}</value>
<comment>{0} will be replaced by function name, {1} will be replaced by exception message, {2} will be replaced by entire stack trace. Please note that this string should include newlines for formatting.</comment>
</data>
<data name="ErrorExitingWithNonZeroErrorCode" xml:space="preserve">
<value>برنامه به مشکل خورده است، شماره ی ارور: {0}!</value>
<comment>{0} will be replaced by error code (number)</comment>
</data>
<data name="ErrorFailingRequest" xml:space="preserve">
<value>درخواست ناموفق: {0}</value>
<comment>{0} will be replaced by URL of the request</comment>
</data>
<data name="ErrorGlobalConfigNotLoaded" xml:space="preserve">
<value>کانفیگ اصلی قابل لود نیست. مطمئن باشید {0} وجود دارد و فاقد مشکلات می باشد! می توانید در صورت گیج شدن از صفحه ی ویکی برنامه کمک بگیرید.</value>
<comment>{0} will be replaced by file's path</comment>
</data>
<data name="ErrorIsInvalid" xml:space="preserve">
<value>{0} صحیح نیست!</value>
<comment>{0} will be replaced by object's name</comment>
</data>
<data name="ErrorNoBotsDefined" xml:space="preserve">
<value>رباتی ساخته نشده است. آیا فراموش کردید برنامه را کانفیگ کنید؟
می توانید در صورت گیج شدن از صفحه ی ویکی برنامه کمک بگیرید.</value>
</data>
<data name="ErrorObjectIsNull" xml:space="preserve">
<value>{0} فاقد اطلاعات است!</value>
<comment>{0} will be replaced by object's name</comment>
</data>
<data name="ErrorParsingObject" xml:space="preserve">
<value>دریافت {0} ناموفق بود!</value>
<comment>{0} will be replaced by object's name</comment>
</data>
<data name="ErrorRequestFailedTooManyTimes" xml:space="preserve">
<value>درخواست بعد از تعداد {0} تلاش شکست خورد!</value>
<comment>{0} will be replaced by maximum number of tries</comment>
</data>
<data name="ErrorUpdateCheckFailed" xml:space="preserve">
<value>چک کردن آپدیت به مشکل خورد!</value>
</data>
<data name="ErrorUpdateNoAssetForThisVersion" xml:space="preserve">
<value>فایلی منطبق با نسخه ی جدید پیدا نشد، به روز رسانی خودکار به آن نسخه امکان‌پذیر نیست.</value>
</data>
<data name="ErrorUpdateNoAssets" xml:space="preserve">
<value>نتوانستیم به آن نسخه آپدیت کنیم زیرا هیچ گونه فایلی نداشت!</value>
</data>
<data name="ErrorUserInputRunningInHeadlessMode" xml:space="preserve">
<value>درخواستی برای ورودی دریافت شد اما برنامه در حال اجرا در نسخه ی بدون رابط کاربری است!</value>
</data>
<data name="Exiting" xml:space="preserve">
<value>در حال خارج شدن...</value>
</data>
<data name="WarningFailed" xml:space="preserve">
<value>ارور!</value>
</data>
<data name="GlobalConfigChanged" xml:space="preserve">
<value>فایل کانفیگ اصلی تغییر یافته است!</value>
</data>
<data name="ErrorGlobalConfigRemoved" xml:space="preserve">
<value>فایل کانفیگ اصلی حذف شده است!</value>
</data>
<data name="IgnoringTrade" xml:space="preserve">
<value>پاسخ ندادن به درخواست تبادل: {0}</value>
<comment>{0} will be replaced by trade number</comment>
</data>
<data name="LoggingIn" xml:space="preserve">
<value>در حال ورود به {0}...</value>
<comment>{0} will be replaced by service's name</comment>
</data>
<data name="NoBotsAreRunning" xml:space="preserve">
<value>هیچ رباتی در حال اجرا نیست، در حال خارج شدن از برنامه...</value>
</data>
<data name="RefreshingOurSession" xml:space="preserve">
<value>در حال رفرش کردن سشن!</value>
</data>
<data name="RejectingTrade" xml:space="preserve">
<value>در حال رد کردن درخواست تبادل: {0}</value>
<comment>{0} will be replaced by trade number</comment>
</data>
<data name="Restarting" xml:space="preserve">
<value>در حال راه‌اندازی دوباره...</value>
</data>
<data name="Starting" xml:space="preserve">
<value>در حال راه‌اندازی...</value>
</data>
<data name="Success" xml:space="preserve">
<value>موفقیت!</value>
</data>
<data name="UnlockingParentalAccount" xml:space="preserve">
<value>در حال باز کردن parental account...</value>
</data>
<data name="UpdateCheckingNewVersion" xml:space="preserve">
<value>در حال چک کردن برای نسخه ی جدید...</value>
</data>
<data name="UpdateDownloadingNewVersion" xml:space="preserve">
<value>در حال دانلود نسخه ی جدید: {0} ({1} مگابایت})... تا دانلود بشه لطفاً به دونیت کردن فکر کنید اگر از برنامه رضایت دارید! :)</value>
<comment>{0} will be replaced by version string, {1} will be replaced by update size (in megabytes)</comment>
</data>
<data name="UpdateFinished" xml:space="preserve">
<value>عملیات به روز رسانی با موفقیت انجام شد!</value>
</data>
<data name="UpdateNewVersionAvailable" xml:space="preserve">
<value>نسخه ی جدیدی از ASF در دسترس است! آپدیت کردن دستی را در نظر بگیرید!</value>
</data>
<data name="UpdateVersionInfo" xml:space="preserve">
<value>نسخه ی محلی: {0} | نسخه ی آنلاین: {1}</value>
<comment>{0} will be replaced by current version, {1} will be replaced by remote version</comment>
</data>
<data name="UserInputDeviceConfirmation" xml:space="preserve">
<value>لطفاً برنامه ی استیم موبایل خود را چک کنید، باید اعلان لاگین کردن را دریافت کرده باشید. از دکمه Y استفاده کنید اگر اعلان را دریافت نموده و آن را قبول کرده اید، و اما اگر می خواهید کد لاگین وارد کنید از دکمه ی N استفاده کنید: </value>
<comment>Please note that this translation should end with space</comment>
</data>
<data name="UserInputSteam2FA" xml:space="preserve">
<value>لطفاً کد ورود دو مرحله ای را از برنامه ی استیم گوشی وارد کنید: </value>
<comment>Please note that this translation should end with space</comment>
</data>
<data name="UserInputSteamGuard" xml:space="preserve">
<value>لطفاً کد ورودی که به ایمیلتان فرستاده شده را وارد کنید: </value>
<comment>Please note that this translation should end with space</comment>
</data>
<data name="UserInputSteamLogin" xml:space="preserve">
<value>لطفاً یوزرنیم استیم خود را وارد کنید: </value>
<comment>Please note that this translation should end with space</comment>
</data>
<data name="UserInputSteamParentalCode" xml:space="preserve">
<value>لطفا parental code اکانت خود را وارد کنید: </value>
<comment>Please note that this translation should end with space</comment>
</data>
<data name="UserInputSteamPassword" xml:space="preserve">
<value>لطفاً رمز عبور اکانت استیم خود را وارد کنید: </value>
<comment>Please note that this translation should end with space</comment>
</data>
<data name="WarningUnknownValuePleaseReport" xml:space="preserve">
<value>مقداری نامفهوم برای {0} دریافت شده، لطفاً این را گزارش دهید: {1}</value>
<comment>{0} will be replaced by object's name, {1} will be replaced by value for that object</comment>
</data>
<data name="IPCReady" xml:space="preserve">
<value>سرور IPC آماده است!</value>
</data>
<data name="IPCStarting" xml:space="preserve">
<value>در حال راه‌اندازی سرور IPC...</value>
</data>
<data name="BotAlreadyStopped" xml:space="preserve">
<value>این ربات از قبل خاموش بوده است!</value>
</data>
<data name="BotNotFound" xml:space="preserve">
<value>هیچ رباتی با اسم {0} یافت نشد!</value>
<comment>{0} will be replaced by bot's name query (string)</comment>
</data>
<data name="BotStatusOverview" xml:space="preserve">
<value>در حال حاضر {0}/{1} ربات در حال اجرا هستند، تعداد گیم های مانده برای فارم: {2} ({3} کارت).</value>
<comment>{0} will be replaced by number of active bots, {1} will be replaced by total number of bots, {2} will be replaced by total number of games left to farm, {3} will be replaced by total number of cards left to farm</comment>
</data>
<data name="BotStatusIdling" xml:space="preserve">
<value>ربات در حال فارم بازی است: {0} ({1}، تعداد کارت های باقی مانده: {2})، از تعداد {3} بازی است، تعداد کلی کارت های باقی مانده: {4} (تقریباً {5} به طول خواهد انجامید).</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name, {2} will be replaced by number of cards left to farm, {3} will be replaced by total number of games to farm, {4} will be replaced by total number of cards to farm, {5} will be replaced by translated TimeSpan string (such as "1 day, 5 hours and 30 minutes")</comment>
</data>
<data name="BotStatusIdlingList" xml:space="preserve">
<value>ربات در حال فارم کردن بازی است: {0} از تعداد کلی {1} بازی({2} کارت برای فارم مانده) تقریباً {3} به طول خواهد انجامید.</value>
<comment>{0} will be replaced by list of the games (IDs, numbers), {1} will be replaced by total number of games to farm, {2} will be replaced by total number of cards to farm, {3} will be replaced by translated TimeSpan string (such as "1 day, 5 hours and 30 minutes")</comment>
</data>
<data name="CheckingFirstBadgePage" xml:space="preserve">
<value>در حال چک کردن صفحه ی اول بج های اکانت...</value>
</data>
<data name="CheckingOtherBadgePages" xml:space="preserve">
<value>در حال چک کردن صفحه های بعدی بج های اکانت...</value>
</data>
<data name="ChosenFarmingAlgorithm" xml:space="preserve">
<value>الگوریتم فار کردن انتخاب شده: {0}</value>
<comment>{0} will be replaced by the name of chosen farming algorithm</comment>
</data>
<data name="Done" xml:space="preserve">
<value>انجام شد!</value>
</data>
<data name="GamesToIdle" xml:space="preserve">
<value>تعداد بازی های باقی مانده برای فارم {0} است({1} کارت) باقی مانده برای فارم کردن (تقریباً {2} باقی مانده است)...</value>
<comment>{0} will be replaced by number of games, {1} will be replaced by number of cards, {2} will be replaced by translated TimeSpan string (such as "1 day, 5 hours and 30 minutes")</comment>
</data>
<data name="IdlingFinished" xml:space="preserve">
<value>فارم کردن به اتمام رسید!</value>
</data>
<data name="IdlingFinishedForGame" xml:space="preserve">
<value>فارم کردن {0} ({1}) بعد از {2} پلی تایم به اتمام رسید!</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name, {2} will be replaced by translated TimeSpan string (such as "1 day, 5 hours and 30 minutes")</comment>
</data>
<data name="IdlingFinishedForGames" xml:space="preserve">
<value>فارم کردن این بازی ها به پایان رسید: {0}</value>
<comment>{0} will be replaced by list of the games (IDs, numbers), separated by a comma</comment>
</data>
<data name="IdlingStatusForGame" xml:space="preserve">
<value>وضعیت فارم کردن برای {0} ({1}): تعداد کارت های باقی مانده {2} است</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name, {2} will be replaced by number of cards left to farm</comment>
</data>
<data name="IdlingStopped" xml:space="preserve">
<value>فارم کردن متوقف شد!</value>
</data>
<data name="IgnoredPermanentPauseEnabled" xml:space="preserve">
<value>در حال رد کردن این درخواست به دلیل روشن بودن مکث همیشگی(Permanent pause)!</value>
</data>
<data name="NothingToIdle" xml:space="preserve">
<value>ما هیچ چیزی برای فارم کردن در این اکانت نداریم!</value>
</data>
<data name="NowIdling" xml:space="preserve">
<value>در حال فارم کردن: {0} ({1})</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="NowIdlingList" xml:space="preserve">
<value>در حال فارم کردن: {0}</value>
<comment>{0} will be replaced by list of the games (IDs, numbers), separated by a comma</comment>
</data>
<data name="PlayingNotAvailable" xml:space="preserve">
<value>پلی دادن در حال حاضر قابل دسترسی نیست، بعداً دوباره تلاش خواهیم کرد!</value>
</data>
<data name="StillIdling" xml:space="preserve">
<value>همچنان در حال فارم: {0} ({1})</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="StillIdlingList" xml:space="preserve">
<value>همچنان در حال فارم: {0}</value>
<comment>{0} will be replaced by list of the games (IDs, numbers), separated by a comma</comment>
</data>
<data name="StoppedIdling" xml:space="preserve">
<value>فارم کردن {0} ({1}) متوقف شد</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="StoppedIdlingList" xml:space="preserve">
<value>فارم کردن {0} متوقف شد</value>
<comment>{0} will be replaced by list of the games (IDs, numbers), separated by a comma</comment>
</data>
<data name="UnknownCommand" xml:space="preserve">
<value>دستور نامفهوم!</value>
</data>
<data name="WarningCouldNotCheckBadges" xml:space="preserve">
<value>دریافت بج های اکانت با مشکل مواجه شد، بعداً دوباره امتحان خواهیم کرد!</value>
</data>
<data name="WarningCouldNotCheckCardsStatus" xml:space="preserve">
<value>وضعیت کارت های {0} ({1}) را نتوانستیم بررسی کنیم، بعداً دوباره امتحان خواهیم کرد!</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="BotAcceptingGift" xml:space="preserve">
<value>در حال قبول کردن هدیه: {0}...</value>
<comment>{0} will be replaced by giftID (number)</comment>
</data>
<data name="BotAccountLimited" xml:space="preserve">
<value>این اکانت محدود است، امکان فارم کردن تا زمانی که محدودیت از بین برود مقدور نیست!</value>
</data>
<data name="BotAddLicense" xml:space="preserve">
<value>آیدی: {0} | وضعیت: {1}</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by status string</comment>
</data>
<data name="BotAddLicenseWithItems" xml:space="preserve">
<value>آیدی: {0} | وضعیت: {1} | آیتم ها: {2}</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by status string, {2} will be replaced by list of granted IDs (numbers), separated by a comma</comment>
</data>
<data name="BotAlreadyRunning" xml:space="preserve">
<value>این ربات در حال اجرا است!</value>
</data>
<data name="BotAuthenticatorConverting" xml:space="preserve">
<value>درحال تبدیل فایل با فرمت maFile. به فرمت ASF...</value>
</data>
<data name="BotAuthenticatorImportFinished" xml:space="preserve">
<value>وارد کردن تایید کننده موبایل با موفقیت انجام شد!</value>
</data>
<data name="BotAuthenticatorToken" xml:space="preserve">
<value>توکن دو مرحله ای: {0}</value>
<comment>{0} will be replaced by generated 2FA token (string)</comment>
</data>
<data name="BotAutomaticIdlingNowPaused" xml:space="preserve">
<value>فارم کردن خودکار مکث شد!</value>
</data>
<data name="BotAutomaticIdlingNowResumed" xml:space="preserve">
<value>در حال ادامه دادن فارم کردن خودکار!</value>
</data>
<data name="BotAutomaticIdlingPausedAlready" xml:space="preserve">
<value>فارم کردن خودکار در حالت مکث می باشد!</value>
</data>
<data name="BotAutomaticIdlingResumedAlready" xml:space="preserve">
<value>فارم کردن خودکار در حال اجرا می باشد!</value>
</data>
<data name="BotConnected" xml:space="preserve">
<value>به استیم متصل شدیم!</value>
</data>
<data name="BotDisconnected" xml:space="preserve">
<value>از استیم قطع شدیم!</value>
</data>
<data name="BotDisconnecting" xml:space="preserve">
<value>در حال قطع شدن...</value>
</data>
<data name="BotInstanceNotStartingBecauseDisabled" xml:space="preserve">
<value>این ربات را استارت نمی کنیم زیرا در فایل کانفیگ غیر فعال می باشد!</value>
</data>
<data name="BotInvalidAuthenticatorDuringLogin" xml:space="preserve">
<value>ارور کد 2 مرحله ای اشتباه را {0} دفعه پشت هم دریافت کردیم. یا کد 2مرحله ای شما دیگر معتبر نیست، یا ساعت شما تنظیم نیست، در حال کنسل کردن!</value>
<comment>{0} will be replaced by maximum allowed number of failed 2FA attempts</comment>
</data>
<data name="BotLoggedOff" xml:space="preserve">
<value>از استیم خارج شد: {0}</value>
<comment>{0} will be replaced by logging off reason (string)</comment>
</data>
<data name="BotLoggedOn" xml:space="preserve">
<value>{0} با موفقیت وارد شد.</value>
<comment>{0} will be replaced by steam ID (number)</comment>
</data>
<data name="BotLoggingIn" xml:space="preserve">
<value>در حال وارد شدن...</value>
</data>
<data name="BotLogonSessionReplaced" xml:space="preserve">
<value>به نظر می رسید این اکانت در حال استفاده از نمایه ی دیگری از ASF است، در حال خودداری از اجرا کردنش هستیم!</value>
</data>
<data name="BotLootingFailed" xml:space="preserve">
<value>پیشنهاد تبادل ناموفق بود!</value>
</data>
<data name="BotLootingMasterNotDefined" xml:space="preserve">
<value>پیشنهاد تبادل را نتوانستیم ارسال کنیم زیرا هیچ کاربری با پرمیشن مَستِر معرفی نشده است!</value>
</data>
<data name="BotLootingSuccess" xml:space="preserve">
<value>پیشنهاد تبادل با موفقیت ارسال شد!</value>
</data>
<data name="BotSendingTradeToYourself" xml:space="preserve">
<value>شما نمی توانید به خودتان پیشنهاد تبادل ارسال کنید!</value>
</data>
<data name="BotNoASFAuthenticator" xml:space="preserve">
<value>این ربات دارای تاییدیه ی دو مرحله ای نیست! آیا فراموش کرده اید که تاییدیه دو مرحله ای خود را به صورتASF 2FA ایمپورت کنید؟</value>
</data>
<data name="BotNotConnected" xml:space="preserve">
<value>این ربات متصل نیست!</value>
</data>
<data name="BotNotOwnedYet" xml:space="preserve">
<value>هنوز خریداری نشده است: {0}</value>
<comment>{0} will be replaced by query (string)</comment>
</data>
<data name="BotOwnedAlreadyWithName" xml:space="preserve">
<value>قبلاً خریداری شده است: {0} | {1}</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="BotPointsBalance" xml:space="preserve">
<value>موجودی پوینت ها: {0}</value>
<comment>{0} will be replaced by the points balance value (integer)</comment>
</data>
<data name="BotRateLimitExceeded" xml:space="preserve">
<value>حد اتصال به بیش از حد مجاز رسید، تا {0} ی دیگر دوباره امتحان خواهیم کرد...</value>
<comment>{0} will be replaced by translated TimeSpan string (such as "25 minutes")</comment>
</data>
<data name="BotReconnecting" xml:space="preserve">
<value>در حال اتصال دوباره...</value>
</data>
<data name="BotRedeem" xml:space="preserve">
<value>کلید: {0} | وضعیت: {1}</value>
<comment>{0} will be replaced by cd-key (string), {1} will be replaced by status string</comment>
</data>
<data name="BotRedeemWithItems" xml:space="preserve">
<value>کلید: {0} | وضعیت: {1} | آیتم ها: {2}</value>
<comment>{0} will be replaced by cd-key (string), {1} will be replaced by status string, {2} will be replaced by list of key-value pairs, separated by a comma</comment>
</data>
<data name="BotRemovedExpiredLoginKey" xml:space="preserve">
<value>کلید لاگین تاریخ گذشته حذف شد!</value>
</data>
<data name="BotStatusNotIdling" xml:space="preserve">
<value>بات در حال فارم چیزی نیست.</value>
</data>
<data name="BotStatusLimited" xml:space="preserve">
<value>بات محدود شده است و نمی تواند کارتی از طریق فارم کردن دراپ کند.</value>
</data>
<data name="BotStatusConnecting" xml:space="preserve">
<value>بات در حال وصل شدن به شبکه ی استیم است.</value>
</data>
<data name="BotStatusNotRunning" xml:space="preserve">
<value>بات در حال اجرا نیست.</value>
</data>
<data name="BotStatusPaused" xml:space="preserve">
<value>بات در حالت مکث یا دستی در حال اجرا است.</value>
</data>
<data name="BotStatusPlayingNotAvailable" xml:space="preserve">
<value>بات در حال استفاده است.</value>
</data>
<data name="BotUnableToLogin" xml:space="preserve">
<value>لاگین کردن به استیم با شکست مواجه شد: {0}/{1}</value>
<comment>{0} will be replaced by failure reason (string), {1} will be replaced by extended failure reason (string)</comment>
</data>
<data name="ErrorIsEmpty" xml:space="preserve">
<value>خطا: {0} خالی است!</value>
<comment>{0} will be replaced by object's name</comment>
</data>
<data name="UnusedKeys" xml:space="preserve">
<value>کلید های استفاده نشده: {0}</value>
<comment>{0} will be replaced by list of cd-keys (strings), separated by a comma</comment>
</data>
<data name="WarningFailedWithError" xml:space="preserve">
<value>به این دلیل شکست خورد: {0}</value>
<comment>{0} will be replaced by failure reason (string)</comment>
</data>
<data name="BotConnectionLost" xml:space="preserve">
<value>اتصال به شبکه ی استیم قطع شد. در حال اتصال مجدد...</value>
</data>
<data name="BotAccountFree" xml:space="preserve">
<value>اکانت دیگر در دست استفاده نیست: رویه ی فارم کردن در حال ادامه یافتن است!</value>
</data>
<data name="BotAccountOccupied" xml:space="preserve">
<value>اکانت در دست استفاده است: ASF زمانی که اکانت آزاد باشد فارم کردن را شروع می کند...</value>
</data>
<data name="BotConnecting" xml:space="preserve">
<value>در حال اتصال...</value>
</data>
<data name="BotHeartBeatFailed" xml:space="preserve">
<value>قطع شدن این بات با مشکل مواجه شد. بات را ول می کنیم!</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>در حال توقف...</value>
</data>
<data name="ErrorBotConfigInvalid" xml:space="preserve">
<value>کانفیگ بات شما صحیح نیست. لطفاً محتوای {0} را بررسی کنید و دوباره تلاش کنید!</value>
<comment>{0} will be replaced by file's path</comment>
</data>
<data name="ErrorDatabaseInvalid" xml:space="preserve">
<value>لود کردن دیتابیس با مشکل مواجه شد، اگر این مشکل ادامه داشت، لطفاً {0} را حذف کنید تا دوباره دیتابیس ایجاد شود!</value>
<comment>{0} will be replaced by file's path</comment>
</data>
<data name="Initializing" xml:space="preserve">
<value>در حال لود کردن {0}...</value>
<comment>{0} will be replaced by service name that is being initialized</comment>
</data>
<data name="WarningPrivacyPolicy" xml:space="preserve">
<value>لطفاً در صورت نگرانی اینکه برنامه ASF در حال انجام چه کاری است خط مشی ما را در ویکی مطالعه کنید!</value>
</data>
<data name="Welcome" xml:space="preserve">
<value>بنظر می رسد اولین استفاده ی شما از این برنامه باشد، خوش آمدید! 3:</value>
</data>
@@ -80,21 +530,54 @@
<data name="BotWalletBalance" xml:space="preserve">
<value>موجودی والت: {0} {1}</value>
<comment>{0} will be replaced by wallet balance value, {1} will be replaced by currency name</comment>
</data>
<data name="BotHasNoWallet" xml:space="preserve">
<value>بات والتی ندارد.</value>
</data>
<data name="BotLevel" xml:space="preserve">
<value>بات لول {0} است.</value>
<comment>{0} will be replaced by bot's level</comment>
</data>
<data name="ErrorAborted" xml:space="preserve">
<value>کنسل شد!</value>
</data>
<data name="NothingFound" xml:space="preserve">
<value>چیزی پیدا نشد!</value>
</data>
<data name="PleaseWait" xml:space="preserve">
<value>لطفا صبر کنید...</value>
</data>
<data name="EnterCommand" xml:space="preserve">
<value>دستور را وارد کنید: </value>
</data>
<data name="Executing" xml:space="preserve">
<value>در حال اجرا...</value>
</data>
<data name="UpdateCleanup" xml:space="preserve">
<value>درحال پاک سازی فایل های قدیمی بعد از به روزرسانی...</value>
</data>
<data name="Result" xml:space="preserve">
<value>نتایج: {0}</value>
<comment>{0} will be replaced by generic result of various functions that use this string</comment>
</data>
@@ -110,154 +593,23 @@
<data name="PatchingFiles" xml:space="preserve">
<value>در حال پچ کردن فایل های ASF...</value>
</data>
<data name="ErrorIPNotBanned" xml:space="preserve">
<value>آدرس آیپی {0} بن نشده است!</value>
<comment>{0} will be replaced by an IP address which was requested to be unbanned from using IPC</comment>
</data>
<data name="WarningSkipping" xml:space="preserve">
<value>در حال رد کردن: {0}...</value>
<comment>{0} will be replaced by text value (string) of entry being skipped.</comment>
</data>

View File

@@ -484,9 +484,6 @@ StackTrace:
<data name="BotHeartBeatFailed" xml:space="preserve">
<value>Yhteyden katkaisu clienttiin epäonnistui. Hylätään tämä botti instanssi!</value>
</data>
<data name="BotSteamDirectoryInitializationFailed" xml:space="preserve">
<value>Yhteys SteamDirectoryyn epäonnistui: Steam-verkkoon yhdistäminen saattaa kestää paljon kauemmin!</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>Pysäytetään...</value>
</data>

View File

@@ -487,9 +487,6 @@ StackTrace :
<data name="BotHeartBeatFailed" xml:space="preserve">
<value>Impossible de déconnecter le client. Abandon de cette instance de bot !</value>
</data>
<data name="BotSteamDirectoryInitializationFailed" xml:space="preserve">
<value>Impossible d'initialiser SteamDirectory : la connexion au réseau Steam pourrait prendre beaucoup plus longtemps que dhabitude !</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>Arrêt...</value>
</data>

View File

@@ -484,9 +484,6 @@ StackTrace:
<data name="BotHeartBeatFailed" xml:space="preserve">
<value>לא ניתן לנתק את התוכנה. נוטש את בוט זה!</value>
</data>
<data name="BotSteamDirectoryInitializationFailed" xml:space="preserve">
<value>לא ניתן לאתחל את SteamDirectory: התחברות לרשת הסטים עשויה להימשך זמן רב מהרגיל!</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>עוצר...</value>
</data>

View File

@@ -0,0 +1,360 @@
<?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>
<data name="AcceptingTrade" xml:space="preserve">
<value>Prihvaćanje trgovine: {0}</value>
<comment>{0} will be replaced by trade number</comment>
</data>
<data name="AutoUpdateCheckInfo" xml:space="preserve">
<value>ASF će automatski provjeriti novu verziju svakih {0}.</value>
<comment>{0} will be replaced by translated TimeSpan string (such as "24 hours")</comment>
</data>
<data name="Content" xml:space="preserve">
<value>Sadržaj:
{0}</value>
<comment>{0} will be replaced by content string. Please note that this string should include newline for formatting.</comment>
</data>
<data name="ErrorConfigPropertyInvalid" xml:space="preserve">
<value>Postavljena {0} vrijednost nije važeća: {1}</value>
<comment>{0} will be replaced by name of the configuration property, {1} will be replaced by invalid value</comment>
</data>
<data name="ErrorEarlyFatalExceptionInfo" xml:space="preserve">
<value>ASF V{0} je naišla na fatalnu iznimku prije što je jezgreni dnevnik modula uspio izvršiti inicijalizaciju!</value>
<comment>{0} will be replaced by version number</comment>
</data>
<data name="ErrorEarlyFatalExceptionPrint" xml:space="preserve">
<value>Iznimka: {0}() {1}
StackTrace:
{2}</value>
<comment>{0} will be replaced by function name, {1} will be replaced by exception message, {2} will be replaced by entire stack trace. Please note that this string should include newlines for formatting.</comment>
</data>
<data name="ErrorExitingWithNonZeroErrorCode" xml:space="preserve">
<value>Opoziv sa kodom greške broj {0}!</value>
<comment>{0} will be replaced by error code (number)</comment>
</data>
<data name="ErrorFailingRequest" xml:space="preserve">
<value>Zahtjev neuspješan: {0}</value>
<comment>{0} will be replaced by URL of the request</comment>
</data>
<data name="ErrorGlobalConfigNotLoaded" xml:space="preserve">
<value>Globalnu konfiguraciju nije moguće učitati. Provjerite postoji li {0} i da li je valjana!
Zapratite 'postavljanje' uputstva na wiki ukoliko imate nejasnoće.</value>
<comment>{0} will be replaced by file's path</comment>
</data>
<data name="ErrorIsInvalid" xml:space="preserve">
<value>{0} nije valjana!</value>
<comment>{0} will be replaced by object's name</comment>
</data>
<data name="ErrorNoBotsDefined" xml:space="preserve">
<value>Niti jedan bot je definiran. Jeste li zaboravili konfigurirati vaš ASF? Zapratite 'postavljanje' uputstva na wiki ukoliko imate nejasnoće.</value>
</data>
<data name="ErrorObjectIsNull" xml:space="preserve">
<value>{0} je null!</value>
<comment>{0} will be replaced by object's name</comment>
</data>
<data name="ErrorParsingObject" xml:space="preserve">
<value>Rasčlanjivanje {0} neuspješno!</value>
<comment>{0} will be replaced by object's name</comment>
</data>
<data name="ErrorRequestFailedTooManyTimes" xml:space="preserve">
<value>Zahtjevi neuspješni nakon {0} pokušaja!</value>
<comment>{0} will be replaced by maximum number of tries</comment>
</data>
<data name="ErrorUpdateCheckFailed" xml:space="preserve">
<value>Provjera zadnje verzije nauspješna!</value>
</data>
<data name="ErrorUpdateNoAssetForThisVersion" xml:space="preserve">
<value>Ažuriranje ne može započeti jer postoji objekt povezan u trenutno pokrenutoj verzija!
Automatsko ažuriranje na tu verziju nije moguće.</value>
</data>
<data name="ErrorUpdateNoAssets" xml:space="preserve">
<value>Ažuriranje ne može započeti jer ta verzija ne sadrži ni jedan objekt!</value>
</data>
<data name="ErrorUserInputRunningInHeadlessMode" xml:space="preserve">
<value>Zahtjev prihvačen za korisnikov ulaz, ali proces se trenutno izvodi u bezglavnom načinu rada!</value>
</data>
<data name="Exiting" xml:space="preserve">
<value>Izlaz u tijeku...</value>
</data>
<data name="WarningFailed" xml:space="preserve">
<value>Neuspješno!</value>
</data>
<data name="GlobalConfigChanged" xml:space="preserve">
<value>Globalna konfiguracijska datoteka je izmjenjena!</value>
</data>
<data name="ErrorGlobalConfigRemoved" xml:space="preserve">
<value>Globalna konfiguracijska datoteka je uklonjena!</value>
</data>
<data name="IgnoringTrade" xml:space="preserve">
<value>Ignoriranje trgovine: {0}</value>
<comment>{0} will be replaced by trade number</comment>
</data>
<data name="LoggingIn" xml:space="preserve">
<value>Prijava u {0}...</value>
<comment>{0} will be replaced by service's name</comment>
</data>
<data name="NoBotsAreRunning" xml:space="preserve">
<value>Niti jedan bot nije pokrenut, izlazak u tijeku...</value>
</data>
<data name="RefreshingOurSession" xml:space="preserve">
<value>Osvješavanje sesije!</value>
</data>
<data name="RejectingTrade" xml:space="preserve">
<value>Odbijanje trgovine: {0}</value>
<comment>{0} will be replaced by trade number</comment>
</data>
<data name="Restarting" xml:space="preserve">
<value>Ponovno pokretanje u tijeku...</value>
</data>
<data name="Starting" xml:space="preserve">
<value>Pokretanje u tijeku...</value>
</data>
<data name="Success" xml:space="preserve">
<value>Uspijeh!</value>
</data>
<data name="UnlockingParentalAccount" xml:space="preserve">
<value>Otključavanje roditeljskog računa u tijeku...</value>
</data>
<data name="UpdateCheckingNewVersion" xml:space="preserve">
<value>Provjera nove verzije u tijeku...</value>
</data>
<data name="UpdateDownloadingNewVersion" xml:space="preserve">
<value/>
<comment>{0} will be replaced by version string, {1} will be replaced by update size (in megabytes)</comment>
</data>
</root>

View File

@@ -85,7 +85,10 @@
StackTrace: {2}</value>
<comment>{0} will be replaced by function name, {1} will be replaced by exception message, {2} will be replaced by entire stack trace. Please note that this string should include newlines for formatting.</comment>
</data>
<data name="ErrorExitingWithNonZeroErrorCode" xml:space="preserve">
<value>Kilépés {0} hibakóddal!</value>
<comment>{0} will be replaced by error code (number)</comment>
</data>
<data name="ErrorFailingRequest" xml:space="preserve">
<value>Kérés sikertelen: {0}</value>
<comment>{0} will be replaced by URL of the request</comment>
@@ -184,7 +187,10 @@ StackTrace: {2}</value>
<value>Lokális verzió: {0} | Távoli verzió: {1}</value>
<comment>{0} will be replaced by current version, {1} will be replaced by remote version</comment>
</data>
<data name="UserInputDeviceConfirmation" xml:space="preserve">
<value>Nézze meg a Steam alkalmazást, mert kapott egy bejelentkezési jóváhagyási értesítést. Írjon be Y-t ha engedélyezte és megkapta az értesítést, N-t hogyha inkább egy kódot akar hozzáadni: </value>
<comment>Please note that this translation should end with space</comment>
</data>
<data name="UserInputSteam2FA" xml:space="preserve">
<value>Add meg a 2FA kódot a Steam hitelesítő alkalmazásból: </value>
<comment>Please note that this translation should end with space</comment>
@@ -479,9 +485,6 @@ StackTrace: {2}</value>
<data name="BotHeartBeatFailed" xml:space="preserve">
<value>Sikertelen volt a kliensről való lecsatlakozás. Elhagyjuk ezt a bot példányt!</value>
</data>
<data name="BotSteamDirectoryInitializationFailed" xml:space="preserve">
<value>A Steam Könyvtárat nem sikerült inicializálni: a Steam hálózathoz való csatlakozás a szokásosnál tovább is eltarthat!</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>Leállás...</value>
</data>
@@ -686,7 +689,10 @@ Ennyi ideje fut: {1}</value>
<value>A titkosítási kulcs túl rövid. Azt javasoljuk, hogy legalább {0} bájt (karakter) hosszúságú legyen.</value>
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
</data>
<data name="WarningDefaultCryptKeyUsedForHashing" xml:space="preserve">
<value>A {0} beállítást használja a {1} tulajdonsághoz, de nem adott saját --cryptkey-t. hozzá tud adni saját --cryptkey-t fokozott biztonságért ha akar.</value>
<comment>{0} will be replaced by the name of a particular setting (e.g. "SCrypt"), {1} will be replaced by the name of the property (e.g. "IPCPassword")</comment>
</data>
<data name="WarningDefaultCryptKeyUsedForEncryption" xml:space="preserve">
<value>A(z) {1} tulajdonság {0} beállítását használja, de nem adott meg egyéni --cryptkey-t. Ez teljesen megsemmisíti a védelmet, mivel az ASF kénytelen a saját (ismert) kulcsát használni. A beállítás által kínált biztonsági előnyök kihasználásához egyéni --cryptkey-t kell megadnia.</value>
<comment>{0} will be replaced by the name of a particular setting (e.g. "AES"), {1} will be replaced by the name of the property (e.g. "SteamPassword")</comment>
@@ -713,11 +719,29 @@ Ennyi ideje fut: {1}</value>
<data name="PatchingFiles" xml:space="preserve">
<value>ASF-fájlok patchelése...</value>
</data>
<data name="UserInputCryptkey" xml:space="preserve">
<value>Kérem írja be a cryptkey-t: </value>
<comment>Please note that this translation should end with space</comment>
</data>
<data name="ErrorIPNotBanned" xml:space="preserve">
<value>Az {0} IP cím nincs bannolva!</value>
<comment>{0} will be replaced by an IP address which was requested to be unbanned from using IPC</comment>
</data>
<data name="WarningNoLicense" xml:space="preserve">
<value>Megpróbáltad használni a {0} fizetős funkciót, de nincsen érvényes LicenseID-d beállítva az ASF global config-ban. Kérem, nézd át a konfigurációt, mert a funkció nem fog működni több részlet megadása nélkül.</value>
<comment>{0} will be replaced by feature name (e.g. MatchActively)</comment>
</data>
<data name="WarningRegionRestrictedPackage" xml:space="preserve">
<value>ASF nem tudta lejátszani az app {0}-t, mert van helyiséghez kötött korlátozása {1} országra ami {2}-ig tart.</value>
<comment>{0} will be replaced by app ID (number), {1} will be replaced by short country code (string, such as "PL"), {2} will be replaced by human-readable date (string).</comment>
</data>
<data name="WarningUnsupportedOfficialPlugins" xml:space="preserve">
<value>Megpróbáltad futtatni a hivatalos {0} plugint egy rosszul párosított ASF verzióban: {1} (várt: {2}). Ez azt jelenti hogy valami nagyon rosszat próbálsz, próbáld meg megjavítani a felszerelésed -- ignoráld a nem támogatott felszerelést ha tudod mit csinálsz.</value>
<comment>{0} will be replaced by plugin name, {1} will be replaced by plugin's version number, {2} will be replaced by ASF's version number.</comment>
</data>
<data name="ErrorTooManyCrashes" xml:space="preserve">
<value>Az ASF-ed túl sokszor crashelt a közelmúltban, és emiatt a folyamat inicializálás ki lett kapcsolva. Vagy nyomozd ki, vagy javítsd meg a felszerelésedet, aztán töröld az ASF.crash fájlod a beállítás könyvtáradból, vagy lásd el --ignorál a nem támogatott felszerelést ha tudod mit csinálsz.</value>
</data>
@@ -732,8 +756,4 @@ Ennyi ideje fut: {1}</value>
</root>

View File

@@ -484,9 +484,6 @@
<data name="BotHeartBeatFailed" xml:space="preserve">
<value>Gagal untuk memutuskan klien, meninggalkan instansi bot ini!</value>
</data>
<data name="BotSteamDirectoryInitializationFailed" xml:space="preserve">
<value>Tidak dapat menginisialisasi SteamDirectory, menyambung ke Steam Network mungkin memakan waktu lebih lama dari biasanya!</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>Menghentikan...</value>
</data>

View File

@@ -485,9 +485,6 @@
<data name="BotHeartBeatFailed" xml:space="preserve">
<value>Disconnessione del client non riuscita. Abbandonando questa istanza di bot!</value>
</data>
<data name="BotSteamDirectoryInitializationFailed" xml:space="preserve">
<value>Impossibile inizializzare SteamDirectory: il collegamento con la rete di Steam potrebbe richiedere più tempo del solito!</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>Interruzione in corso...</value>
</data>
@@ -750,16 +747,50 @@ Tempo di attività: {1}</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="PluginUpdatesChecking" xml:space="preserve">
<value>Controllo aggiornamenti plugin...</value>
</data>
<data name="PluginUpdateChecking" xml:space="preserve">
<value>Controllo aggiornamento per il plugin {0}...</value>
<comment>{0} will be replaced by plugin name (string).</comment>
</data>
<data name="PluginUpdateNotFound" xml:space="preserve">
<value>Nessun aggiornamento disponibile per il plugin {0} : {1} ≥ {2}.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateNewVersionAvailable" xml:space="preserve">
<value>È disponibile una nuova versione del plugin {0} ! Considera di aggiornare manualmente!</value>
<comment>{0} will be replaced by plugin name (string).</comment>
</data>
<data name="PluginUpdateFound" xml:space="preserve">
<value>Trovato l'aggiornamento del plugin {0} dalla versione {1} a {2}...</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateNoAssetFound" xml:space="preserve">
<value>Nessuna risorsa disponibile per l'aggiornamento del plugin {0} dalla versione {1} a {2}, questo significa di solito che l'aggiornamento sarà disponibile in un momento successivo.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateConflictingAssetsFound" xml:space="preserve">
<value>Non è stato possibile determinare alcuna risorsa per l'aggiornamento del plugin {0} dalla versione {1} a {2}. Questo può accadere se il rilascio non è ancora finito - se continua ad accadere, dovresti informare il creatore del plugin di questa situazione.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateInProgress" xml:space="preserve">
<value>Aggiornamento plugin {0}...</value>
<comment>{0} will be replaced by plugin name (string).</comment>
</data>
<data name="PluginUpdateFinished" xml:space="preserve">
<value>L'aggiornamento del plugin {0} è riuscito, le modifiche saranno caricate al prossimo lancio di ASF.</value>
<comment>{0} will be replaced by plugin name (string).</comment>
</data>
<data name="PluginUpdateEnabled" xml:space="preserve">
<value>Il plugin {0}/{1} è stato registrato e abilitato per gli aggiornamenti automatici.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by plugin assembly name (string).</comment>
</data>
<data name="PluginUpdateDisabled" xml:space="preserve">
<value>Il plugin {0} ({1}) è stato disabilitato dagli aggiornamenti automatici, nonostante il supporto di tale funzionalità.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by plugin assembly name (string).</comment>
</data>
<data name="CustomPluginUpdatesEnabled" xml:space="preserve">
<value>I plugin personalizzati sono stati registrati per aggiornamenti automatici. Il team di ASF vorrebbe ricordarti che, per la tua sicurezza, dovresti abilitare gli aggiornamenti automatici solo da parti fidate. Se non hai intenzione di farlo, puoi disabilitare gli aggiornamenti dei plugin nella configurazione globale di ASF.</value>
</data>
</root>

View File

@@ -84,7 +84,10 @@
<value>例外: {0} () {1} StackTrace: {2}</value>
<comment>{0} will be replaced by function name, {1} will be replaced by exception message, {2} will be replaced by entire stack trace. Please note that this string should include newlines for formatting.</comment>
</data>
<data name="ErrorExitingWithNonZeroErrorCode" xml:space="preserve">
<value>エラーコード {0} で終了します!</value>
<comment>{0} will be replaced by error code (number)</comment>
</data>
<data name="ErrorFailingRequest" xml:space="preserve">
<value>要求が失敗: {0}</value>
<comment>{0} will be replaced by URL of the request</comment>
@@ -481,9 +484,6 @@
<data name="BotHeartBeatFailed" xml:space="preserve">
<value>クライアントとの切断に失敗しました。bot のインスタンスを放棄します!</value>
</data>
<data name="BotSteamDirectoryInitializationFailed" xml:space="preserve">
<value>SteamDirectory を初期化できませんでした。Steam Network との接続が通常より長くかかる可能性があります!</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>停止中...</value>
</data>
@@ -731,8 +731,13 @@ Process uptime: {1}</value>
<data name="WarningSkipping" xml:space="preserve">
<value>スキップ中: {0}...</value>
<comment>{0} will be replaced by text value (string) of entry being skipped.</comment>
</data>
<data name="PluginUpdatesChecking" xml:space="preserve">
<value>プラグインのアップデートを確認しています...</value>
</data>

View File

@@ -281,7 +281,6 @@
</root>

View File

@@ -487,9 +487,6 @@ StackTrace:
<data name="BotHeartBeatFailed" xml:space="preserve">
<value>클라이언트 연결 해제에 실패했습니다. 이 봇 인스턴스를 포기합니다!</value>
</data>
<data name="BotSteamDirectoryInitializationFailed" xml:space="preserve">
<value>SteamDirectory를 초기화할 수 없습니다 : Steam 네트워크 연결에 평소보다 오랜 시간이 걸릴 수 있습니다!</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>중지 중...</value>
</data>

View File

@@ -484,9 +484,6 @@ StackTrace:
<data name="BotHeartBeatFailed" xml:space="preserve">
<value>Nepavyko atjungti kliento. Apleidžiamas šis boto egzempliorius!</value>
</data>
<data name="BotSteamDirectoryInitializationFailed" xml:space="preserve">
<value>Nepavyko inicijuoti „SteamDirectory“: jungiantis su Steam tinklu gali užtrukti daug ilgiau nei įprastai!</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>Stabdoma...</value>
</data>

View File

@@ -61,11 +61,11 @@
</value>
</resheader>
<data name="AcceptingTrade" xml:space="preserve">
<value>Pieņemt darījumu: {0}</value>
<value>Pieņem darījumu: {0}</value>
<comment>{0} will be replaced by trade number</comment>
</data>
<data name="AutoUpdateCheckInfo" xml:space="preserve">
<value>ASF automātiski pārbaudīs jaunas versijas pieejamību katras(u) {0}.</value>
<value>ASF automātiski pārbaudīs jaunas versijas pieejamību katras/u {0}.</value>
<comment>{0} will be replaced by translated TimeSpan string (such as "24 hours")</comment>
</data>
<data name="Content" xml:space="preserve">
@@ -78,7 +78,7 @@
<comment>{0} will be replaced by name of the configuration property, {1} will be replaced by invalid value</comment>
</data>
<data name="ErrorEarlyFatalExceptionInfo" xml:space="preserve">
<value>ASF V{0} saņēma fatālu izņēmumu pirms kodola logšanas modelis bija spējīgs incializēties!</value>
<value>ASF V{0} saņēma fatālu izņēmumu pirms galvenais reģistrēšanās modulis bija spējīgs incializēties!</value>
<comment>{0} will be replaced by version number</comment>
</data>
<data name="ErrorEarlyFatalExceptionPrint" xml:space="preserve">
@@ -87,7 +87,10 @@ StackTrace:
{2}</value>
<comment>{0} will be replaced by function name, {1} will be replaced by exception message, {2} will be replaced by entire stack trace. Please note that this string should include newlines for formatting.</comment>
</data>
<data name="ErrorExitingWithNonZeroErrorCode" xml:space="preserve">
<value>Iziešana ar {0} kļūdas kodu!</value>
<comment>{0} will be replaced by error code (number)</comment>
</data>
<data name="ErrorFailingRequest" xml:space="preserve">
<value>Pieprasījums neizdevās: {0}</value>
<comment>{0} will be replaced by URL of the request</comment>
@@ -116,7 +119,7 @@ StackTrace:
<comment>{0} will be replaced by maximum number of tries</comment>
</data>
<data name="ErrorUpdateCheckFailed" xml:space="preserve">
<value>Nevar pārbaudīt jaunāko vesiju!</value>
<value>Nevar pārbaudīt jaunāko versiju!</value>
</data>
<data name="ErrorUpdateNoAssetForThisVersion" xml:space="preserve">
<value>Nevar veikt atjaunināšanu, jo nav failu kas atsaucās uz šobrīd strādājošo versiju! Automātiskā atjaunināšana uz šo versiju nav iespējama.</value>
@@ -253,7 +256,7 @@ StackTrace:
<value>Darīts!</value>
</data>
<data name="GamesToIdle" xml:space="preserve">
<value>Kopumā vākšanai ir pieejamas {0} spēles ({1} kārtis). Atlikušais laiks ~{2}...</value>
<value>Kopumā vākšanai ir pieejamas {0} spēles ({1} kārtis). Atlikušais laiks (~{2})...</value>
<comment>{0} will be replaced by number of games, {1} will be replaced by number of cards, {2} will be replaced by translated TimeSpan string (such as "1 day, 5 hours and 30 minutes")</comment>
</data>
<data name="IdlingFinished" xml:space="preserve">
@@ -484,9 +487,6 @@ StackTrace:
<data name="BotHeartBeatFailed" xml:space="preserve">
<value>Nav iespējams atvienoties no klienta. Šis bots tiek pamests!</value>
</data>
<data name="BotSteamDirectoryInitializationFailed" xml:space="preserve">
<value>Nevarēja inicializēt SteamDirectory: notiek savienošanās ar Steam Network ilgāk kā parasti!</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>Tiek apturēts...</value>
</data>
@@ -691,7 +691,10 @@ Darbspējas laiks: {1}</value>
<value>Šifrēšanas atslēga ir pārāk īsa. Mēs iesakām izmantot tādu, kas ir vismaz {0} baitus (simbolus) gara.</value>
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
</data>
<data name="WarningDefaultCryptKeyUsedForHashing" xml:space="preserve">
<value>Tu izmanto {0} iestatījumus no {1} vērtības, bet Tu neesi norādījis pielāgotu --šifratslēgu. Ja vēlies, Tu vari norādīt individuāli pielāgotu --šifratslēgu, lai palielinātu drošību.</value>
<comment>{0} will be replaced by the name of a particular setting (e.g. "SCrypt"), {1} will be replaced by the name of the property (e.g. "IPCPassword")</comment>
</data>
<data name="WarningDefaultCryptKeyUsedForEncryption" xml:space="preserve">
<value>Tu lieto {0} iestatījumu {1} vērtībai, bet neesi nodrošinājis speciālu -cryptkey. Šī dēļ šim iestatījumam nav jēga, jo ASF ir spiests lietots pats savu (zināmu) atslēgu. Tev vajag nodrošinās speciālo -cryptkey lai šis iestatījums varētu nodrošināt papildu drošību.</value>
<comment>{0} will be replaced by the name of a particular setting (e.g. "AES"), {1} will be replaced by the name of the property (e.g. "SteamPassword")</comment>
@@ -711,7 +714,9 @@ Darbspējas laiks: {1}</value>
<data name="ChecksumMissing" xml:space="preserve">
<value>Attālinātais serveris neko nezin par versiju uz kuru tiek veikta atjaunināšana. Šāda situācija ir iespējama, ja versija ir svaigi publicēta. Drošības apsvērumu dēļ atjaunināšanas procedūra tiek pārtraukta.</value>
</data>
<data name="ChecksumTimeout" xml:space="preserve">
<value>Neizdevās iegūt lejupielādētā bināra kontrolsummu - atjauninājuma process tiek atteikts šajā brīdi, drošības apsvērumu dēļ.</value>
</data>
<data name="ChecksumWrong" xml:space="preserve">
<value>Attālinātais serveris atbildēja ar citādāku kontrolsummu, tas nozīmē, ka lejupielāde ir bojāta vai ir noticis MITM uzbrukums. Atjaunināšanas procedūra tiek pārtraukta!</value>
</data>
@@ -734,20 +739,65 @@ Darbspējas laiks: {1}</value>
<value>ASF nevar palaist aplikāciju {0}, jo tai ir ar reģionu saistīts ierobežojums {1}  valstī, kas ir spēkā līdz {2}.</value>
<comment>{0} will be replaced by app ID (number), {1} will be replaced by short country code (string, such as "PL"), {2} will be replaced by human-readable date (string).</comment>
</data>
<data name="WarningUnsupportedOfficialPlugins" xml:space="preserve">
<value>Tu mēģini palaist oficiālo spraudni {0}, kas nesakrīt ar ASF versiju: {1} (paredzēts {2}). Tas norāda, ka Tu dari kaut ko nepareizi, vai nu labo iestatījumus, vai piedāvā --ignorēt-neatbalstītu-vidi argumentu, ja patiešām zini, ko dari.</value>
<comment>{0} will be replaced by plugin name, {1} will be replaced by plugin's version number, {2} will be replaced by ASF's version number.</comment>
</data>
<data name="ErrorTooManyCrashes" xml:space="preserve">
<value>Tavs ASF ir avarējis pārāk daudz reižu īsā laika posmā, līdz ar to procesa inicializācija ir apturēta. Izpēti, izlabo savus iestatījumus, tad izdzēs ASF.crash failu no savas konfigurācijas direktorijas, vai piedāvā --ignorēt-neatbalstītu-vidi argumentu, ja patiešām zini, ko dari.</value>
</data>
<data name="IdlingGameNotPossiblePrivate" xml:space="preserve">
<value>Vākšana {0} ({1}) ir atspējota, jo šī spēle pašlaik ir atzīmēta kā privāta. Ja vēlies vākt no spēles caur ASF, tad nomaini spēles privātuma iestatījumus.</value>
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name</comment>
</data>
<data name="WarningSkipping" xml:space="preserve">
<value>Izlaiž: {0}...</value>
<comment>{0} will be replaced by text value (string) of entry being skipped.</comment>
</data>
<data name="PluginUpdatesChecking" xml:space="preserve">
<value>Pārbauda spraudņu atjauninājumus...</value>
</data>
<data name="PluginUpdateChecking" xml:space="preserve">
<value>Pārbauda {0} spraudņa atjauninājumu...</value>
<comment>{0} will be replaced by plugin name (string).</comment>
</data>
<data name="PluginUpdateNotFound" xml:space="preserve">
<value>Nav pieejami atjauninājumi {0} spraudnim: {1} ≥ {2}.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateNewVersionAvailable" xml:space="preserve">
<value>Ir pieejama jauna {0} spraudņa versija! Apsver iespēju atjaunināt sevi!</value>
<comment>{0} will be replaced by plugin name (string).</comment>
</data>
<data name="PluginUpdateFound" xml:space="preserve">
<value>Atrasta {0} spraudņa versijas atjaunināšana no {1} uz {2}...</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateNoAssetFound" xml:space="preserve">
<value>Nav pieejami faili {0} spraudņa atjaunināšanai no versijas {1} uz {2}, tas parasti norāda uz atjauninājumu, kas būs pieejams vēlāk.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateConflictingAssetsFound" xml:space="preserve">
<value>Nevar iegūt failus {0} spraudņa atjaunināšanai no versijas {1} uz {2}. Tas var notikt, ja spraudņa versija nav pabeigta, ja tas tomēr atkārtojās, sazinies ar spraudņa izstrādātāju.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by current plugin's version, {2} will be replaced by remote plugin's version.</comment>
</data>
<data name="PluginUpdateInProgress" xml:space="preserve">
<value>Atjauno {0} spraudni...</value>
<comment>{0} will be replaced by plugin name (string).</comment>
</data>
<data name="PluginUpdateFinished" xml:space="preserve">
<value>Atjaunošana {0} spraudnim izdevās, izmaiņas tiks iespējotas pie nākamās ASF palaišanas.</value>
<comment>{0} will be replaced by plugin name (string).</comment>
</data>
<data name="PluginUpdateEnabled" xml:space="preserve">
<value>{0}/{1} spraudnis ir reģistrēts un iespējots ar automātiskajiem atjauninājumiem.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by plugin assembly name (string).</comment>
</data>
<data name="PluginUpdateDisabled" xml:space="preserve">
<value>{0} ({1}) spraudņa automātiskie atjauninājumi ir atspējoti, neskatoties uz to, ka šī funkcija tiek atbalstīta.</value>
<comment>{0} will be replaced by plugin name (string), {1} will be replaced by plugin assembly name (string).</comment>
</data>
<data name="CustomPluginUpdatesEnabled" xml:space="preserve">
<value>Pielāgotie spraudņi ir reģistrēti automātiskajiem atjauninājumiem. ASF komanda vēlās atgādināt, ka Tavai drošībai, automātiskos atjauninājumus vajag iespējot tikai no uzticamiem izstrādātājiem. Ja to neplānoji darīt, Tu vari atspējot spraudņu atjauninājumus ASF globālajā konfigurācijā.</value>
</data>
</root>

View File

@@ -480,9 +480,6 @@ StackTrace:
<data name="BotHeartBeatFailed" xml:space="preserve">
<value>Verbinding verbreken met de client is mislukt. Bot instantie wordt afgesloten!</value>
</data>
<data name="BotSteamDirectoryInitializationFailed" xml:space="preserve">
<value>Kon SteamDirectory niet initialiseren: verbinden met Steam netwerk gaat mogelijk veel langer duren dan gebruikelijk!</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>Stoppen...</value>
</data>

View File

@@ -304,7 +304,6 @@ StackTrace:
<value>Kobler til...</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>Stopper...</value>
</data>

View File

@@ -487,9 +487,6 @@ StackTrace:
<data name="BotHeartBeatFailed" xml:space="preserve">
<value>Rozłączenie klienta nie powiodło się. Porzucam instancję tego bota!</value>
</data>
<data name="BotSteamDirectoryInitializationFailed" xml:space="preserve">
<value>Nie można zainicjować SteamDirectory: połączenie z siecią Steam może potrwać znacznie dłużej niż zwykle!</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>Zatrzymywanie...</value>
</data>

View File

@@ -487,9 +487,6 @@ StackTrace:
<data name="BotHeartBeatFailed" xml:space="preserve">
<value>Falha ao desconectar o cliente. Abandonando essa instância de bot!</value>
</data>
<data name="BotSteamDirectoryInitializationFailed" xml:space="preserve">
<value>Não foi possível inicializar o SteamDirectory: a conexão com a Rede Steam pode demorar mais do que o normal!</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>Parando...</value>
</data>

View File

@@ -87,7 +87,10 @@ StackTrace:
{2}</value>
<comment>{0} will be replaced by function name, {1} will be replaced by exception message, {2} will be replaced by entire stack trace. Please note that this string should include newlines for formatting.</comment>
</data>
<data name="ErrorExitingWithNonZeroErrorCode" xml:space="preserve">
<value>A sair com o código de erro {0}!</value>
<comment>{0} will be replaced by error code (number)</comment>
</data>
<data name="ErrorFailingRequest" xml:space="preserve">
<value>Falha na solicitação: {0}</value>
<comment>{0} will be replaced by URL of the request</comment>
@@ -484,9 +487,6 @@ StackTrace:
<data name="BotHeartBeatFailed" xml:space="preserve">
<value>Erro ao desconectar o cliente. A abandonar este bot!</value>
</data>
<data name="BotSteamDirectoryInitializationFailed" xml:space="preserve">
<value>Não foi possível inicializar o SteamDirectory: conectar-se com a rede Steam pode levar muito mais tempo do que o normal!</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>A parar...</value>
</data>
@@ -691,7 +691,10 @@ Tempo de execução: {1}</value>
<value>A tua chave de encriptação é demasiado curta. Recomendamos uma que seja pelo menos {0} bytes (carateres) de comprimento.</value>
<comment>{0} will be replaced by the number of bytes (characters) recommended</comment>
</data>
<data name="WarningDefaultCryptKeyUsedForHashing" xml:space="preserve">
<value>Estás a utilizar a definição {0} da propriedade {1}, mas não forneceste uma --cryptkey personalizada. Podes opcionalmente fornecer uma --cryptkey personalizada para aumentar a segurança, se assim o desejares.</value>
<comment>{0} will be replaced by the name of a particular setting (e.g. "SCrypt"), {1} will be replaced by the name of the property (e.g. "IPCPassword")</comment>
</data>
<data name="WarningDefaultCryptKeyUsedForEncryption" xml:space="preserve">
<value>Estás a usar a definição {0} da propriedade {1}, mas não forneceste uma --cryptkey personalizada. Isto futiliza a proteção, pois o ASF é forçado a usar a sua chave (que é conhecida). Deves fornecer uma --cryptkey personalizada para usufruires da segurança oferecida por esta definição.</value>
<comment>{0} will be replaced by the name of a particular setting (e.g. "AES"), {1} will be replaced by the name of the property (e.g. "SteamPassword")</comment>

View File

@@ -487,9 +487,6 @@ STACKTRACE:
<data name="BotHeartBeatFailed" xml:space="preserve">
<value>FAILD 2 DISCONNECT TEH CLIENT. ABANDONIN DIS BOT INSTANCE!</value>
</data>
<data name="BotSteamDirectoryInitializationFailed" xml:space="preserve">
<value>CUD NOT INITIALIZE STEAMDIRECTORY: CONNECTIN WIF STEAM NETWORK MITE TAEK MUTCH LONGR THAN USUAL!</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>STOPPIN...</value>
</data>

View File

@@ -487,9 +487,6 @@ StackTrace:
<data name="BotHeartBeatFailed" xml:space="preserve">
<value>Failed to disconnect the client. Abandoning this bot instance!</value>
</data>
<data name="BotSteamDirectoryInitializationFailed" xml:space="preserve">
<value>Could not initialize SteamDirectory: connecting with Steam Network might take much longer than usual!</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>Stopping...</value>
</data>

View File

@@ -487,9 +487,6 @@ StackTrace:
<data name="BotHeartBeatFailed" xml:space="preserve">
<value>Deconectarea clientului a eșuat. Se abandonează acestă instanță de bot!</value>
</data>
<data name="BotSteamDirectoryInitializationFailed" xml:space="preserve">
<value>Nu a fost posibilă inițializarea SteamDirectory: conectarea cu rețeaua Steam ar putea dura mult mai mult ca de obicei!</value>
</data>
<data name="BotStopping" xml:space="preserve">
<value>Se oprește...</value>
</data>

Some files were not shown because too many files have changed in this diff Show More