Compare commits

...

10 Commits

Author SHA1 Message Date
Tixx a9faac25fc Bump version to v2.8.1 2026-08-11 22:19:49 +02:00
Tixx f532e58ee0 avoid exposing game to partially written mod files during first download (#250)
This avoids mod loading failure messages caused by partially copied mod
files after initial download, the same way it is already avoided while
loading files from cache.

Addresses some instances of
https://github.com/BeamMP/BeamMP-Launcher/issues/91

---

By creating this pull request, I understand that code that is AI
generated or otherwise automatically generated may be rejected without
further discussion.
I declare that I fully understand all code I pushed into this PR, and
wrote all this code myself and own the rights to this code.
2026-08-02 22:22:48 +02:00
Katharine Chui 8b4fefd518 avoid exposing game to partially written mod files during first download
This avoids mod loading failure messages caused by partially
copied mod files after initial download, the same way it is
already avoided while loading files from cache.
2026-08-02 18:52:26 +02:00
Tixx 5fc8f580f4 Fix download size int casting (#244)
Fixed an int casting issue that caused weird download failures, improve
error handling and added missing return statement which unintentionally
forwarded data to the game (without the socket even being there)

---

By creating this pull request, I understand that code that is AI
generated or otherwise automatically generated may be rejected without
further discussion.
I declare that I fully understand all code I pushed into this PR, and
wrote all this code myself and own the rights to this code.
2026-08-02 13:54:54 +02:00
Tixx 6334a0a915 prevent GameSend send() call on invalid socket (#240)
prevents WSAENOTSOCK by not allowing a `send()` call on an
invalid/closed socket when the game client isn't connected

---

By creating this pull request, I understand that code that is AI
generated or otherwise automatically generated may be rejected without
further discussion.
I declare that I fully understand all code I pushed into this PR, and
wrote all this code myself and own the rights to this code.
2026-08-02 13:53:30 +02:00
Tixx 44211e7235 Fix incorrect string_view usage in log message
and I somehow forgot the semicolon
2026-08-02 13:18:59 +02:00
Tixx 901b7df809 Log debug message on GameSend connection check 2026-08-02 13:06:33 +02:00
Tixx a6e3db6b08 Merge branch 'master' into download-fix 2026-08-02 13:04:25 +02:00
Tixx eeca50b37e Fix download size int casting 2026-04-21 17:14:42 +02:00
galacticlemonade 2a92a08587 guard GameSend when game is not connected
prevents WSAENOTSOCK
2026-04-08 15:05:58 -06:00
3 changed files with 42 additions and 6 deletions
+5
View File
@@ -51,6 +51,10 @@ int KillSocket(uint64_t Dead) {
}
void GameSend(std::string_view Data) {
if (!GConnected) {
debug("Tried to call GameSend but socket was not connected. Data: " + std::string(Data));
return;
}
static std::mutex Lock;
std::scoped_lock Guard(Lock);
auto ToSend = Utils::PrependHeader<std::string_view>(Data);
@@ -195,6 +199,7 @@ void ParserAsync(std::string_view Data) {
return;
case 'U':
magic = Data.substr(1);
return;
default:
break;
}
+36 -5
View File
@@ -163,7 +163,12 @@ std::vector<char> TCPRcvRaw(SOCKET Sock, uint64_t& GRcv, uint64_t Size) {
int i = 0;
do {
// receive at most some MB at a time
int Len = std::min(int(Size - Rcv), 1 * 1024 * 1024);
uint64_t Len = std::min<uint64_t>((Size - Rcv), 1 * 1024 * 1024);
if (Len == 0) {
error("Download size miscalculation");
break;
}
int Temp = RecvWaitAll(Sock, &File[Rcv], Len);
if (Temp == -1 || Temp == 0) {
debug("Recv returned: " + std::to_string(Temp));
@@ -302,7 +307,7 @@ void InvalidResource(const std::string& File) {
}
struct ModInfo {
static std::pair<bool, std::vector<ModInfo>> ParseModInfosFromPacket(const std::string& packet) {
static std::optional<std::pair<bool, std::vector<ModInfo>>> ParseModInfosFromPacket(const std::string& packet) {
bool success = false;
std::vector<ModInfo> modInfos;
try {
@@ -323,6 +328,12 @@ struct ModInfo {
modInfo.Protected = entry["protected"];
}
if (auto fsFile = std::filesystem::path(modInfo.FileName);
!fsFile.has_filename() || fsFile.filename().string() != modInfo.FileName ||
!fsFile.filename().has_extension() || fsFile.filename().extension() != ".zip"){
return std::nullopt;
}
modInfos.push_back(modInfo);
success = true;
}
@@ -578,8 +589,17 @@ void NewSyncResources(SOCKET Sock, const std::string& Mods, const std::vector<Mo
c = ::tolower(c);
}
#endif
auto name = std::filesystem::path(GetGamePath()) / "mods/multiplayer" / FName;
auto tmp_name = name;
tmp_name += ".tmp";
fs::copy_file(PathToSaveTo, std::filesystem::path(GetGamePath()) / "mods/multiplayer" / FName, fs::copy_options::overwrite_existing);
std::error_code ec;
fs::copy_file(PathToSaveTo, tmp_name, fs::copy_options::overwrite_existing, ec);
if (ec) {
error(beammp_wide("Error in copy_file during download of ") + beammp_fs_string(PathToSaveTo) + beammp_wide(": ") + Utils::ToWString(ec.message()));
break;
}
fs::rename(tmp_name, name);
UpdateModUsage(FName);
}
WaitForConfirm();
@@ -602,7 +622,13 @@ void SyncResources(SOCKET Sock) {
if (Ret.starts_with("R")) {
debug("This server is likely outdated, not trying to parse new mod info format");
} else {
auto [success, modInfo] = ModInfo::ParseModInfosFromPacket(Ret);
auto ParsedInfo = ModInfo::ParseModInfosFromPacket(Ret);
if (!ParsedInfo.has_value()) {
error("Invalid mod info");
Terminate = true;
return;
}
auto [success, modInfo] = ParsedInfo.value();
if (success) {
NewSyncResources(Sock, Ret, modInfo);
@@ -738,7 +764,12 @@ void SyncResources(SOCKET Sock) {
}
#endif
fs::copy_file(PathToSaveTo, GetGamePath() / beammp_wide("mods/multiplayer") / Utils::ToWString(FName), fs::copy_options::overwrite_existing);
auto name = GetGamePath() / beammp_wide("mods/multiplayer") / Utils::ToWString(FName);
auto tmp_name = name;
tmp_name += L".tmp";
fs::copy_file(PathToSaveTo, tmp_name, fs::copy_options::overwrite_existing);
fs::rename(tmp_name, name);
UpdateModUsage(FN->substr(pos));
}
WaitForConfirm();
+1 -1
View File
@@ -86,7 +86,7 @@ std::string GetVer() {
return "2.8";
}
std::string GetPatch() {
return ".0";
return ".1";
}
beammp_fs_string GetEP(const beammp_fs_char* P) {