From fd5c251e9fc89065b47701fdfc4b94aa0b53073a Mon Sep 17 00:00:00 2001 From: Panakotta00 Date: Tue, 27 Sep 2022 23:28:25 +0200 Subject: [PATCH] Adding Satisfactory Modding Crash Reporter --- .../CrashEndpointPromtListEntry.uasset | Bin 0 -> 41744 bytes .../Widget_CrashReportEndpointPrompt.uasset | Bin 0 -> 103883 bytes .../Widget_EndpointPromtListEntry.uasset | Bin 0 -> 73763 bytes .../ModdingCrashReporter/Build_Windows.bat | 5 + Plugins/SML/ModdingCrashReporter/Cargo.lock | 985 ++++++++++++++++++ Plugins/SML/ModdingCrashReporter/Cargo.toml | 16 + Plugins/SML/ModdingCrashReporter/rustfmt.toml | 2 + Plugins/SML/ModdingCrashReporter/src/main.rs | 180 ++++ Plugins/SML/SML.uplugin | 7 +- .../SMLCrashReportEndpointPrompt.cpp | 71 ++ .../CrashReporting/SMLCrashReporter.cpp | 24 + .../Private/ModLoading/ModLoadingLibrary.cpp | 11 +- .../Private/Patching/Patch/MainMenuPatch.cpp | 2 + .../Source/SML/Private/SMLConfiguration.cpp | 40 + .../SML/Private/SatisfactoryModLoader.cpp | 35 +- .../SMLCrashReportEndpointPrompt.h | 41 + .../Public/CrashReporting/SMLCrashReporter.h | 8 + .../SML/Public/ModLoading/ModLoadingLibrary.h | 7 + .../SML/Source/SML/Public/SMLConfiguration.h | 21 + .../Source/SML/Public/SatisfactoryModLoader.h | 5 +- 20 files changed, 1443 insertions(+), 17 deletions(-) create mode 100644 Plugins/SML/Content/CrashReporEndpointPrompt/CrashEndpointPromtListEntry.uasset create mode 100644 Plugins/SML/Content/CrashReporEndpointPrompt/Widget_CrashReportEndpointPrompt.uasset create mode 100644 Plugins/SML/Content/CrashReporEndpointPrompt/Widget_EndpointPromtListEntry.uasset create mode 100644 Plugins/SML/ModdingCrashReporter/Build_Windows.bat create mode 100644 Plugins/SML/ModdingCrashReporter/Cargo.lock create mode 100644 Plugins/SML/ModdingCrashReporter/Cargo.toml create mode 100644 Plugins/SML/ModdingCrashReporter/rustfmt.toml create mode 100644 Plugins/SML/ModdingCrashReporter/src/main.rs create mode 100644 Plugins/SML/Source/SML/Private/CrashReporting/SMLCrashReportEndpointPrompt.cpp create mode 100644 Plugins/SML/Source/SML/Private/CrashReporting/SMLCrashReporter.cpp create mode 100644 Plugins/SML/Source/SML/Public/CrashReporting/SMLCrashReportEndpointPrompt.h create mode 100644 Plugins/SML/Source/SML/Public/CrashReporting/SMLCrashReporter.h diff --git a/Plugins/SML/Content/CrashReporEndpointPrompt/CrashEndpointPromtListEntry.uasset b/Plugins/SML/Content/CrashReporEndpointPrompt/CrashEndpointPromtListEntry.uasset new file mode 100644 index 0000000000000000000000000000000000000000..03440fc6f2b0ed17bcf11cfb4a0351ed1ac1e1d1 GIT binary patch literal 41744 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 V!&6WcC@Js;iW4M%;`~Y1{XYf=Vy6HA literal 0 HcmV?d00001 diff --git a/Plugins/SML/Content/CrashReporEndpointPrompt/Widget_CrashReportEndpointPrompt.uasset b/Plugins/SML/Content/CrashReporEndpointPrompt/Widget_CrashReportEndpointPrompt.uasset new file mode 100644 index 0000000000000000000000000000000000000000..6a2ab878c009bd507ac8d88fb8c0b3eb84265ab4 GIT binary patch literal 103883 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 bCp3Euozv-@O6N2>r_gEc!9&OGbNT-R?DgqW literal 0 HcmV?d00001 diff --git a/Plugins/SML/Content/CrashReporEndpointPrompt/Widget_EndpointPromtListEntry.uasset b/Plugins/SML/Content/CrashReporEndpointPrompt/Widget_EndpointPromtListEntry.uasset new file mode 100644 index 0000000000000000000000000000000000000000..5896df06cb45ea45dc88f4b2055b772be95271ac GIT binary patch literal 73763 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 w(J3Szenul 2>nul +IF %ERRORLEVEL% EQU 0 ( + cargo build --release 2>&1 + copy target\release\ModdingCrashReporter.exe ..\Resources +) diff --git a/Plugins/SML/ModdingCrashReporter/Cargo.lock b/Plugins/SML/ModdingCrashReporter/Cargo.lock new file mode 100644 index 0000000000..d00125ddd7 --- /dev/null +++ b/Plugins/SML/ModdingCrashReporter/Cargo.lock @@ -0,0 +1,985 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ModdingCrashReporter" +version = "0.1.0" +dependencies = [ + "futures", + "hyper", + "hyper-tls", + "json", + "log", + "rand", + "simple-error", + "simple_logger", + "tokio", + "url", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bytes" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "colored" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +dependencies = [ + "atty", + "lazy_static", + "winapi", +] + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "fastrand" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +dependencies = [ + "instant", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f21eda599937fba36daeb58a22e8f5cee2d14c4a17b5b7739c7c8e5e3b8230c" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30bdd20c28fadd505d0fd6712cdfcb0d4b5648baf45faef7f852afb2399bb050" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf" + +[[package]] +name = "futures-executor" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ff63c23854bee61b6e9cd331d523909f238fc7636290b96826e9cfa5faa00ab" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68" + +[[package]] +name = "futures-macro" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42cd15d1c7456c04dbdf7e88bcd69760d74f3a798d6444e16974b505b0e62f17" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b20ba5a92e727ba30e72834706623d94ac93a725410b6a6b6fbc1b07f7ba56" + +[[package]] +name = "futures-task" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6508c467c73851293f390476d4491cf4d227dbabcd4170f3bb6044959b294f1" + +[[package]] +name = "futures-util" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "h2" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca32592cf21ac7ccab1825cd87f6c9b3d9022c44d086172ed0966bec8af30be" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "http" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "itoa" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" + +[[package]] +name = "json" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.133" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f80d65747a3e43d1596c7c5492d95d5edddaabd45a7fcdb02b95f644164966" + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "mio" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys", +] + +[[package]] +name = "native-tls" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd7e2f3618557f980e0b17e8856252eee3c97fa12c54dff0ca290fb6266ca4a9" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + +[[package]] +name = "once_cell" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" + +[[package]] +name = "openssl" +version = "0.10.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "618febf65336490dfcf20b73f885f5651a0c89c64c2d4a8c3662585a70bf5bd0" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5f9bd0c2710541a3cda73d6f9ac4f1b240de4ae261065d309dbe73d9dceb42f" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "proc-macro2" +version = "1.0.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "schannel" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +dependencies = [ + "lazy_static", + "windows-sys", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "security-framework" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + +[[package]] +name = "simple-error" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc47a29ce97772ca5c927f75bac34866b16d64e07f330c3248e2d7226623901b" + +[[package]] +name = "simple_logger" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48047e77b528151aaf841a10a9025f9459da80ba820e425ff7eb005708a76dc7" +dependencies = [ + "atty", + "colored", + "log", + "time", + "winapi", +] + +[[package]] +name = "slab" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" + +[[package]] +name = "socket2" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "syn" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "time" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3f9a28b618c3a6b9251b6908e9c99e04b9e5c02e6581ccbb67d59c34ef7f9b" +dependencies = [ + "itoa", + "libc", + "num_threads", + "time-macros", +] + +[[package]] +name = "time-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0020c875007ad96677dcc890298f4b942882c5d4eb7cc8f439fc3bf813dc9c95" +dependencies = [ + "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" diff --git a/Plugins/SML/ModdingCrashReporter/Cargo.toml b/Plugins/SML/ModdingCrashReporter/Cargo.toml new file mode 100644 index 0000000000..6330ca2b8d --- /dev/null +++ b/Plugins/SML/ModdingCrashReporter/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "ModdingCrashReporter" +version = "0.1.0" +edition = "2022" + +[dependencies] +log = "0.4" +hyper = { version = "0.14", features = ["full"] } +hyper-tls = "0.5.0" +tokio = { version = "1", features = ["full"] } +futures = "0.3" +simple_logger = "2.3.0" +json = "0.12.4" +url = "2.3.1" +simple-error = "0.2.3" +rand = "0.8.5" \ No newline at end of file diff --git a/Plugins/SML/ModdingCrashReporter/rustfmt.toml b/Plugins/SML/ModdingCrashReporter/rustfmt.toml new file mode 100644 index 0000000000..c8f3d8ab9e --- /dev/null +++ b/Plugins/SML/ModdingCrashReporter/rustfmt.toml @@ -0,0 +1,2 @@ +edition = "2018" +hard_tabs = true \ No newline at end of file diff --git a/Plugins/SML/ModdingCrashReporter/src/main.rs b/Plugins/SML/ModdingCrashReporter/src/main.rs new file mode 100644 index 0000000000..8cbb5d291b --- /dev/null +++ b/Plugins/SML/ModdingCrashReporter/src/main.rs @@ -0,0 +1,180 @@ +use log::{error, info, warn}; +use std::path::{PathBuf}; +use std::{env, fs}; +use std::io::Write; + +use hyper::client::ResponseFuture; +use hyper::{Body, Client}; +use hyper::header::CONTENT_TYPE; +use hyper::Request; + +use rand::{thread_rng, Rng}; +use rand::distributions::Alphanumeric; + +#[tokio::main] +async fn main() { + simple_logger::SimpleLogger::new().env().init().unwrap(); + + info!("Satisfactory Modding Crash Reporter Launched!"); + + let log_text = match read_log() { + Some(log) => log, + None => return, + }; + + let endpoints = get_endpoints(); + + send_log_to_endpoints(&endpoints, &log_text).await; + + warn!("done!"); +} + +macro_rules! skip_fail { + ($res:expr) => { + match $res { + Ok(val) => val, + Err(_) => { + continue; + } + } + }; +} + +fn get_endpoints() -> Vec { + let args: Vec<_> = std::env::args().collect(); + if args.len() < 3 { + error!("No Mods-Path and/or SML-Config-Path Argument given!"); + return vec![]; + } + let mods_path = PathBuf::from(&args[1]); + let sml_config_path = PathBuf::from(&args[2]); + + let sml_config = std::fs::read_to_string(sml_config_path).expect("Failed to read SML config!"); + let sml_config = json::parse(&sml_config).expect("Failed to parse SML config!"); + let accepted_endpoints: Vec<_> = sml_config["acceptedCrashReportingEndpoints"].members().map(|endpoint| { + match endpoint.as_str() { + Some(str) => str, + None => "" + } + }).filter(|endpoint| endpoint.len() > 0).collect(); + + let mut endpoints = Vec::new(); + for entry in fs::read_dir(mods_path).expect("Invalid Mods folder path!") { + let entry = skip_fail!(entry); + if !skip_fail!(entry.file_type()).is_dir() { + continue + } + let mod_name = entry.file_name().to_str().unwrap().to_owned(); + let plugin_path = entry + .path() + .join(entry.file_name()) + .with_extension("uplugin"); + let plugin_json = skip_fail!(std::fs::read_to_string(plugin_path)); + let plugin_descriptor = skip_fail!(json::parse(&plugin_json)); + let endpoint = &plugin_descriptor["CrashReporterEndpoint"]; + endpoints.push(match endpoint.as_str() { + Some(str) => { + if accepted_endpoints.contains(&str) { + info!( + "Found accepted endpoint '{}' for Mod '{}'", + str, + mod_name + ); + String::from(str) + } else { + info!("Found rejected endpoint '{}' for Mod '{}'", str, mod_name); + continue + } + } + None => continue, + }); + } + + endpoints +} + +fn get_log_path() -> Option { + let key = "LOCALAPPDATA"; + match env::var_os(key) { + Some(val) => Some(PathBuf::from(val).join("FactoryGame/Saved/Logs/FactoryGame.log")), + None => { + error!("Environment variable '{key}' is not defined."); + None + } + } +} + +fn read_log() -> Option { + match std::fs::read_to_string(get_log_path()?) { + Ok(log) => Some(log), + Err(_) => { + error!("Should have been able to read the file"); + None + } + } +} + +async fn send_log_to_endpoints(endpoints: &Vec, log_text: &str) { + let client = Client::builder().build(hyper_tls::HttpsConnector::new()); + + let futures: Vec = endpoints + .iter() + .map(|endpoint| { + let request = create_request_for_endpoint(endpoint.as_str(), log_text); + client.request(request) + }) + .collect(); + + let responses = futures::future::join_all(futures).await; + for (i, response) in responses.iter().enumerate() { + match response { + Ok(_) => info!("Report successfully sent to: '{}'", endpoints[i]), + Err(e) => warn!("Failed to send report to '{}'!\n{}", endpoints[i], e), + } + } +} + +fn create_request_for_endpoint(endpoint: &str, log_text: &str) -> Request { + match try_create_request_for_endpoint(endpoint, log_text) { + Ok(req) => req, + Err(_) => { + Request::post(endpoint) + .body(log_text.to_owned().into()) + .unwrap() + } + } +} + +fn try_create_request_for_endpoint(endpoint: &str, log_text: &str) -> Result, Box> { + let url = url::Url::parse(endpoint)?; + if url.host_str().ok_or(simple_error::SimpleError::new(""))?.ends_with("discord.com") { + let boundary: String = thread_rng() + .sample_iter(&Alphanumeric) + .take(30) + .map(char::from) + .collect(); + + let mut body: Vec = Vec::new(); + write!(body, "--{}\r\n", boundary)?; + write!(body, "Content-Disposition: form-data; name=\"payload_json\"\r\n")?; + write!(body, "Content-Type: application/json\r\n\r\n")?; + write!(body, "{}\r\n", json::object!{ + "attachments": [{ + "id": 0u64, + "description": "A Satisfactory Log File after a Game Crash", + "filename": "FactoryGame.log" + }] + }.dump())?; + write!(body, "--{}\r\n", boundary)?; + write!(body, "Content-Disposition: form-data; name=\"files[0]\"; filename=\"FactoryGame.log\"\r\n")?; + write!(body, "Content-Type: text/plain\r\n\r\n")?; + write!(body, "{}\r\n", log_text)?; + write!(body, "--{}--\r\n", boundary)?; + Ok(Request::post(endpoint) + .header(CONTENT_TYPE, &*format!("multipart/form-data; boundary={}", boundary)) + .body(body.into()) + .unwrap()) + } else { + Err(Box::new(simple_error::SimpleError::new(""))) + } +} diff --git a/Plugins/SML/SML.uplugin b/Plugins/SML/SML.uplugin index 7f2479a788..70ed3bcf44 100644 --- a/Plugins/SML/SML.uplugin +++ b/Plugins/SML/SML.uplugin @@ -21,5 +21,10 @@ "Type": "Runtime", "LoadingPhase": "PostDefault" } - ] + ], + "PreBuildSteps": { + "Win64": [ + "cd $(PluginDir)\\ModdingCrashReporter && Build_Windows.bat" + ] + } } \ No newline at end of file diff --git a/Plugins/SML/Source/SML/Private/CrashReporting/SMLCrashReportEndpointPrompt.cpp b/Plugins/SML/Source/SML/Private/CrashReporting/SMLCrashReportEndpointPrompt.cpp new file mode 100644 index 0000000000..bd412b17c3 --- /dev/null +++ b/Plugins/SML/Source/SML/Private/CrashReporting/SMLCrashReportEndpointPrompt.cpp @@ -0,0 +1,71 @@ +#include "CrashReporting/SMLCrashReportEndpointPrompt.h" +#include "SatisfactoryModLoader.h" +#include "Components/Overlay.h" +#include "Components/OverlaySlot.h" +#include "ModLoading/ModLoadingLibrary.h" +#include "Reflection/ReflectionHelper.h" + +#define SML_CRASH_REPORT_ENDPOINT_PROMPT TEXT("/SML/CrashReporEndpointPrompt/Widget_CrashReportEndpointPrompt.Widget_CrashReportEndpointPrompt_C") + +void USMLCrashReportEndpointPrompt::ApplyMainMenuPatch(UUserWidget* MainMenu) { + FSMLConfiguration Configuration = FSatisfactoryModLoader::GetSMLConfiguration(); + if (Configuration.bDisableModdingCrashReporter) return; + + UUserWidget* InviteNotification = FReflectionHelper::GetObjectPropertyValue(MainMenu, TEXT("Widget_InviteNotification")); + UOverlay* Overlay = Cast(InviteNotification->GetParent()); + checkf(Overlay, TEXT("Widget_InviteNotification parent is not a overlay")); + + UClass* MenuBaseClass = LoadObject(NULL, SML_CRASH_REPORT_ENDPOINT_PROMPT); + checkf(MenuBaseClass, TEXT("Failed to load SML menu page asset from path '%s'"), SML_CRASH_REPORT_ENDPOINT_PROMPT); + + USMLCrashReportEndpointPrompt* NewWidget = Cast(CreateWidgetInstance(*MainMenu->GetWorld(), MenuBaseClass, TEXT("ModListSubMenu"))); + NewWidget->LoadEndpointSelections(); + if (NewWidget->EndpointSelections.Num() > 0) { + UOverlaySlot* Slot = Overlay->AddChildToOverlay(NewWidget); + Slot->SetVerticalAlignment(VAlign_Fill); + Slot->SetHorizontalAlignment(HAlign_Fill); + } +} + +void USMLCrashReportEndpointPrompt::LoadEndpointSelections() { + FSMLConfiguration Configuration = FSatisfactoryModLoader::GetSMLConfiguration(); + + UModLoadingLibrary* SubSys = GEngine->GetEngineSubsystem(); + TArray Mods = SubSys->GetLoadedMods(); + + EndpointSelections.Empty(); + + for (const FModInfo& Mod : Mods) { + FString URL = Mod.CrashReportingEndpoint; + if (URL.IsEmpty()) continue; + if (Configuration.AcceptedCrashReportingEndpoints.Contains(URL)) continue; + if (Configuration.RejectedCrashReportingEndpoints.Contains(URL)) continue; + + EndpointSelections.Add(FSMLCrashReportEndpointSelection(Mod)); + } +} + +void USMLCrashReportEndpointPrompt::SaveEndpointSelections() { +#if !WITH_EDITOR + FSMLConfiguration& Configuration = FSatisfactoryModLoader::GetSMLConfiguration(); + + for (const FSMLCrashReportEndpointSelection& Selection : EndpointSelections) { + const FString& URL = Selection.ModInfo.CrashReportingEndpoint; + if (Selection.bAccepted) { + Configuration.AcceptedCrashReportingEndpoints.AddUnique(URL); + Configuration.RejectedCrashReportingEndpoints.Remove(URL); + } else { + Configuration.RejectedCrashReportingEndpoints.AddUnique(URL); + Configuration.AcceptedCrashReportingEndpoints.Remove(URL); + } + } + + FSatisfactoryModLoader::SaveSMLConfiguration(); +#endif +} + +void USMLCrashReportEndpointPrompt::DisableCrashReporter() { + FSMLConfiguration& Configuration = FSatisfactoryModLoader::GetSMLConfiguration(); + Configuration.bDisableModdingCrashReporter = true; + FSatisfactoryModLoader::SaveSMLConfiguration(); +} diff --git a/Plugins/SML/Source/SML/Private/CrashReporting/SMLCrashReporter.cpp b/Plugins/SML/Source/SML/Private/CrashReporting/SMLCrashReporter.cpp new file mode 100644 index 0000000000..a9fee06811 --- /dev/null +++ b/Plugins/SML/Source/SML/Private/CrashReporting/SMLCrashReporter.cpp @@ -0,0 +1,24 @@ +#include "CrashReporting/SMLCrashReporter.h" + +#include "SatisfactoryModLoader.h" +#include "SMLConfiguration.h" + +void FSmlCrashReporter::ApplyCrashReporterPatch() { + FSMLConfiguration Config = FSatisfactoryModLoader::GetSMLConfiguration(); + if (Config.bDisableModdingCrashReporter) return; + + FCoreDelegates::OnShutdownAfterError.AddStatic([]() { + static bool bAlreadyLaunched = false; + if (bAlreadyLaunched) return; + bAlreadyLaunched = true; + + UE_LOG(LogSatisfactoryModLoader, Warning, TEXT("Launch Satisfactory Modding Crash Reporter")); + + FString Path = FPlatformMisc::RootDir(); + FString ModsFolderPath = FPaths::ConvertRelativePathToFull(FPaths::ProjectModsDir()); + FString CrashReporterPath = FPaths::Combine(ModsFolderPath, TEXT("SML/Resources/ModdingCrashReporter.exe")); + FString SMLConfigPath = FPaths::Combine(ModsFolderPath, TEXT("../Configs/SML.cfg")); + + FPlatformProcess::CreateProc(*CrashReporterPath, *("\"" + ModsFolderPath + "\" \"" + SMLConfigPath + "\""), true, false, false, NULL, 0, NULL, NULL); + }); +} diff --git a/Plugins/SML/Source/SML/Private/ModLoading/ModLoadingLibrary.cpp b/Plugins/SML/Source/SML/Private/ModLoading/ModLoadingLibrary.cpp index 3fe5427994..baf70b8451 100644 --- a/Plugins/SML/Source/SML/Private/ModLoading/ModLoadingLibrary.cpp +++ b/Plugins/SML/Source/SML/Private/ModLoading/ModLoadingLibrary.cpp @@ -56,13 +56,19 @@ void FSMLPluginDescriptorMetadata::Load(const FString& PluginName, const TShared } } + //Try getting Crash-Reporter-Server Endpoint + FString CrashReporterEndpointString; + if (Source->TryGetStringField(TEXT("CrashReporterEndpoint"), CrashReporterEndpointString)) { + this->CrashReporterEndpoint = CrashReporterEndpointString; + } + //Loop plugins specified in the plugin manifest and detect version predicate inside of them const TArray>* PluginsArray; if (Source->TryGetArrayField(TEXT("Plugins"), PluginsArray)) { for (const TSharedPtr& Item : *PluginsArray) { const TSharedPtr* ObjectPtr; - if (Item.IsValid() && Item->TryGetObject(ObjectPtr)) { + if (Item.IsValid() && Item->TryGetObject(ObjectPtr)) { const FString DependencyName = (*ObjectPtr)->GetStringField(TEXT("Name")); FString DependencyVersionRangeString; if ((*ObjectPtr)->TryGetStringField(TEXT("SemVersion"), DependencyVersionRangeString)) { @@ -77,7 +83,6 @@ void FSMLPluginDescriptorMetadata::Load(const FString& PluginName, const TShared } } } - } } } @@ -250,6 +255,8 @@ void UModLoadingLibrary::PopulatePluginModInfo(IPlugin& Plugin, FModInfo& OutMod OutModInfo.bAcceptsAnyRemoteVersion = PluginDescriptorMetadata.bAcceptsAnyRemoteVersion; OutModInfo.RemoteVersionRange = PluginDescriptorMetadata.RemoteVersionRange; + + OutModInfo.CrashReportingEndpoint = PluginDescriptorMetadata.CrashReporterEndpoint.Get(""); } void UModLoadingLibrary::OnNewPluginCreated(IPlugin& Plugin) { diff --git a/Plugins/SML/Source/SML/Private/Patching/Patch/MainMenuPatch.cpp b/Plugins/SML/Source/SML/Private/Patching/Patch/MainMenuPatch.cpp index 5969ff6b65..63d4610e16 100644 --- a/Plugins/SML/Source/SML/Private/Patching/Patch/MainMenuPatch.cpp +++ b/Plugins/SML/Source/SML/Private/Patching/Patch/MainMenuPatch.cpp @@ -6,6 +6,7 @@ #include "Components/TextBlock.h" #include "Components/VerticalBox.h" #include "Blueprint/WidgetBlueprintLibrary.h" +#include "CrashReporting/SMLCrashReportEndpointPrompt.h" #include "Engine/Engine.h" #include "ModLoading/ModLoadingLibrary.h" @@ -83,6 +84,7 @@ void FMainMenuPatch::RegisterPatch() { UBlueprintHookManager* HookManager = GEngine->GetEngineSubsystem(); HookManager->HookBlueprintFunction(ConstructFunction, [](FBlueprintHookHelper& HookHelper) { FMainMenuPatch::ApplyMainMenuPatch(CastChecked(HookHelper.GetContext())); + USMLCrashReportEndpointPrompt::ApplyMainMenuPatch(CastChecked(HookHelper.GetContext())); }, EPredefinedHookOffset::Return); } diff --git a/Plugins/SML/Source/SML/Private/SMLConfiguration.cpp b/Plugins/SML/Source/SML/Private/SMLConfiguration.cpp index 2ae14665be..65477477ee 100644 --- a/Plugins/SML/Source/SML/Private/SMLConfiguration.cpp +++ b/Plugins/SML/Source/SML/Private/SMLConfiguration.cpp @@ -38,6 +38,32 @@ void FSMLConfiguration::ReadFromJson(const TSharedPtr& Json, FSMLCo bIsMissingSectionsInternal = true; } + if (Json->HasTypedField(TEXT("acceptedCrashReportingEndpoints"))) { + const TArray>& AcceptedCrashReportingEndpoints = Json->GetArrayField(TEXT("acceptedCrashReportingEndpoints")); + for (const TSharedPtr& Value : AcceptedCrashReportingEndpoints) { + if (Value->Type == EJson::String) + OutConfiguration.AcceptedCrashReportingEndpoints.Add(Value->AsString()); + } + } else { + bIsMissingSectionsInternal = true; + } + + if (Json->HasTypedField(TEXT("rejectedCrashReportingEndpoints"))) { + const TArray>& RejectedCrashReportingEndpoints = Json->GetArrayField(TEXT("rejectedCrashReportingEndpoints")); + for (const TSharedPtr& Value : RejectedCrashReportingEndpoints) { + if (Value->Type == EJson::String) + OutConfiguration.RejectedCrashReportingEndpoints.Add(Value->AsString()); + } + } else { + bIsMissingSectionsInternal = true; + } + + if (Json->HasTypedField(TEXT("disableModdingCrashReporter"))) { + OutConfiguration.bDisableModdingCrashReporter = Json->GetBoolField(TEXT("disableModdingCrashReporter")); + } else { + bIsMissingSectionsInternal = true; + } + if (OutIsMissingSections) { *OutIsMissingSections = bIsMissingSectionsInternal; } @@ -53,4 +79,18 @@ void FSMLConfiguration::WriteToJson(const TSharedPtr& OutJson, cons DisabledChatCommands.Add(MakeShareable(new FJsonValueString(Value))); } OutJson->SetArrayField(TEXT("disabledChatCommands"), DisabledChatCommands); + + TArray> AcceptedCrashReportingEndpoints; + for (const FString& Value : Configuration.AcceptedCrashReportingEndpoints) { + AcceptedCrashReportingEndpoints.Add(MakeShared(Value)); + } + OutJson->SetArrayField(TEXT("acceptedCrashReportingEndpoints"), AcceptedCrashReportingEndpoints); + + TArray> RejectedCrashReportingEndpoints; + for (const FString& Value : Configuration.RejectedCrashReportingEndpoints) { + RejectedCrashReportingEndpoints.Add(MakeShared(Value)); + } + OutJson->SetArrayField(TEXT("rejectedCrashReportingEndpoints"), RejectedCrashReportingEndpoints); + + OutJson->SetBoolField(TEXT("disableModdingCrashReporter"), Configuration.bDisableModdingCrashReporter); } diff --git a/Plugins/SML/Source/SML/Private/SatisfactoryModLoader.cpp b/Plugins/SML/Source/SML/Private/SatisfactoryModLoader.cpp index 34cc2e73bb..a57a58538f 100644 --- a/Plugins/SML/Source/SML/Private/SatisfactoryModLoader.cpp +++ b/Plugins/SML/Source/SML/Private/SatisfactoryModLoader.cpp @@ -1,6 +1,7 @@ #include "SatisfactoryModLoader.h" #include "FGPlayerController.h" #include "Configuration/ConfigManager.h" +#include "CrashReporting/SMLCrashReporter.h" #include "Tooltip/ItemTooltipSubsystem.h" #include "Registry/ModContentRegistry.h" #include "Network/NetworkHandler.h" @@ -70,22 +71,28 @@ void FSatisfactoryModLoader::LoadSMLConfiguration(bool bAllowSave) { } if (bShouldWriteConfiguration) { - const TSharedRef JsonObject = MakeShareable(new FJsonObject()); - FSMLConfiguration::WriteToJson(JsonObject, SMLConfigurationPrivate); + SaveSMLConfiguration(); + } +} - FString OutSerializedConfiguration; - const TSharedRef> JsonWriter = TJsonWriterFactory<>::Create(&OutSerializedConfiguration); - FJsonSerializer::Serialize(JsonObject, JsonWriter); +void FSatisfactoryModLoader::SaveSMLConfiguration() { + const FString ConfigLocation = UConfigManager::GetConfigurationFilePath(FConfigId{TEXT("SML")}); + + const TSharedRef JsonObject = MakeShareable(new FJsonObject()); + FSMLConfiguration::WriteToJson(JsonObject, SMLConfigurationPrivate); - //Make sure configuration directory exists - FPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(*FPaths::GetPath(ConfigLocation)); + FString OutSerializedConfiguration; + const TSharedRef> JsonWriter = TJsonWriterFactory<>::Create(&OutSerializedConfiguration); + FJsonSerializer::Serialize(JsonObject, JsonWriter); - //Write file onto the disk now - if (FFileHelper::SaveStringToFile(OutSerializedConfiguration, *ConfigLocation)) { - UE_LOG(LogSatisfactoryModLoader, Display, TEXT("Successfully saved SML configuration")); - } else { - UE_LOG(LogSatisfactoryModLoader, Error, TEXT("Failed to save SML configuration to %s"), *ConfigLocation); - } + //Make sure configuration directory exists + FPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(*FPaths::GetPath(ConfigLocation)); + + //Write file onto the disk now + if (FFileHelper::SaveStringToFile(OutSerializedConfiguration, *ConfigLocation)) { + UE_LOG(LogSatisfactoryModLoader, Display, TEXT("Successfully saved SML configuration")); + } else { + UE_LOG(LogSatisfactoryModLoader, Error, TEXT("Failed to save SML configuration to %s"), *ConfigLocation); } } @@ -127,6 +134,8 @@ void FSatisfactoryModLoader::RegisterSubsystemPatches() { //Only register these patches in shipping, where bodies of the ACharacter::Cheat methods are stripped #if UE_BUILD_SHIPPING FCheatManagerPatch::RegisterPatch(); + + FSmlCrashReporter::ApplyCrashReporterPatch(); #endif } diff --git a/Plugins/SML/Source/SML/Public/CrashReporting/SMLCrashReportEndpointPrompt.h b/Plugins/SML/Source/SML/Public/CrashReporting/SMLCrashReportEndpointPrompt.h new file mode 100644 index 0000000000..b55083e89b --- /dev/null +++ b/Plugins/SML/Source/SML/Public/CrashReporting/SMLCrashReportEndpointPrompt.h @@ -0,0 +1,41 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Blueprint/UserWidget.h" +#include "ModLoading/ModLoadingLibrary.h" +#include "SMLCrashReportEndpointPrompt.generated.h" + +USTRUCT(BlueprintType) +struct FSMLCrashReportEndpointSelection { + GENERATED_BODY() + + UPROPERTY(BlueprintReadWrite, EditAnywhere) + FModInfo ModInfo; + + UPROPERTY(BlueprintReadWrite, EditAnywhere) + bool bAccepted = true; + + FSMLCrashReportEndpointSelection() = default; + FSMLCrashReportEndpointSelection(const FModInfo& ModInfo) : ModInfo(ModInfo) {} +}; + +UCLASS(Blueprintable) +class SML_API USMLCrashReportEndpointPrompt : public UUserWidget { + GENERATED_BODY() + +public: + static void ApplyMainMenuPatch(UUserWidget* MainMenu); + +protected: + UPROPERTY(BlueprintReadOnly) + TArray EndpointSelections; + + UFUNCTION(BlueprintCallable) + void LoadEndpointSelections(); + + UFUNCTION(BlueprintCallable) + void SaveEndpointSelections(); + + UFUNCTION(BlueprintCallable) + void DisableCrashReporter(); +}; diff --git a/Plugins/SML/Source/SML/Public/CrashReporting/SMLCrashReporter.h b/Plugins/SML/Source/SML/Public/CrashReporting/SMLCrashReporter.h new file mode 100644 index 0000000000..d90d45d3f8 --- /dev/null +++ b/Plugins/SML/Source/SML/Public/CrashReporting/SMLCrashReporter.h @@ -0,0 +1,8 @@ +#pragma once + +#include "CoreMinimal.h" + +class SML_API FSmlCrashReporter { +public: + static void ApplyCrashReporterPatch(); +}; \ No newline at end of file diff --git a/Plugins/SML/Source/SML/Public/ModLoading/ModLoadingLibrary.h b/Plugins/SML/Source/SML/Public/ModLoading/ModLoadingLibrary.h index 361df99cfc..d4b3e766f4 100644 --- a/Plugins/SML/Source/SML/Public/ModLoading/ModLoadingLibrary.h +++ b/Plugins/SML/Source/SML/Public/ModLoading/ModLoadingLibrary.h @@ -62,6 +62,10 @@ struct SML_API FModInfo { /** Range of the remote versions accepted by this mod. Defaults to >=CurrentVersion, unless explicitly defined */ UPROPERTY(EditDefaultsOnly, BlueprintReadOnly) FVersionRange RemoteVersionRange; + + /** If set, URL of the crash reporting endpoint at witch the mod developer wants to receive crash reports. Otherwise Empty. */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly) + FString CrashReportingEndpoint; }; @@ -80,6 +84,9 @@ struct SML_API FSMLPluginDescriptorMetadata { /** Version constraints for dependencies as specified in plugin refs */ TMap DependenciesVersions; + /** Crash-Report-Server Endpoint to where crash reports should get sent to if accepted by the user */ + TOptional CrashReporterEndpoint; + /** Setups defaults for metadata from normal plugin descriptor */ void SetupDefaults(const struct FPluginDescriptor& PluginDescriptor); diff --git a/Plugins/SML/Source/SML/Public/SMLConfiguration.h b/Plugins/SML/Source/SML/Public/SMLConfiguration.h index dd3cc98aeb..b3ecbd057e 100644 --- a/Plugins/SML/Source/SML/Public/SMLConfiguration.h +++ b/Plugins/SML/Source/SML/Public/SMLConfiguration.h @@ -34,6 +34,27 @@ struct SML_API FSMLConfiguration { * See UFGCheatManager for command list */ bool bEnableCheatConsoleCommands; + + /** + * List of all user accepted crash reporting endpoints. + * If any mod defines a Crash Reporting Endpoint URL that is contained within this list, + * the modding crash reporter will send a crash report to the URL if possible without further notice to the user. + */ + TArray AcceptedCrashReportingEndpoints; + + /** + * List of user rejected crash reporting endpoints. + * Opposite to AcceptedCrashReportingEndpoints. + * Necessary to not repeat asking a user for the same endpoint multiple times between sessions. + */ + TArray RejectedCrashReportingEndpoints; + + /** + * If enabled, disables the custom satisfactory modding crash reporter and no crash reports will ever be sent + * to any of the mods nor the modding infrastructure maintainers. + */ + bool bDisableModdingCrashReporter; + public: /** Deserializes configuration from JSON object */ static void ReadFromJson(const TSharedPtr& Json, FSMLConfiguration& OutConfiguration, bool* OutIsMissingSections = NULL); diff --git a/Plugins/SML/Source/SML/Public/SatisfactoryModLoader.h b/Plugins/SML/Source/SML/Public/SatisfactoryModLoader.h index dfaedae520..93768f63e0 100644 --- a/Plugins/SML/Source/SML/Public/SatisfactoryModLoader.h +++ b/Plugins/SML/Source/SML/Public/SatisfactoryModLoader.h @@ -23,7 +23,10 @@ class SML_API FSatisfactoryModLoader { static TMap GetExtraAttributes(); /** Returns active SML configuration. If not loaded, it will return empty struct */ - FORCEINLINE static FSMLConfiguration GetSMLConfiguration() { return SMLConfigurationPrivate; } + FORCEINLINE static FSMLConfiguration& GetSMLConfiguration() { return SMLConfigurationPrivate; } + + /** Saves SML configuration to file. */ + static void SaveSMLConfiguration(); private: friend class FSMLModule;