diff --git a/openrct2.vcxproj b/openrct2.vcxproj
index 9615badaff..5952fcceda 100644
--- a/openrct2.vcxproj
+++ b/openrct2.vcxproj
@@ -314,6 +314,7 @@
+
diff --git a/src/core/Nullable.hpp b/src/core/Nullable.hpp
new file mode 100644
index 0000000000..37e3393cfe
--- /dev/null
+++ b/src/core/Nullable.hpp
@@ -0,0 +1,55 @@
+#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers
+/*****************************************************************************
+ * OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
+ *
+ * OpenRCT2 is the work of many authors, a full list can be found in contributors.md
+ * For more information, visit https://github.com/OpenRCT2/OpenRCT2
+ *
+ * OpenRCT2 is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * A full copy of the GNU General Public License can be found in licence.txt
+ *****************************************************************************/
+#pragma endregion
+
+#pragma once
+
+#include "../common.h"
+
+template
+struct Nullable
+{
+public:
+ Nullable()
+ {
+ _value = T();
+ _hasValue = false;
+ }
+
+ Nullable(const T &value)
+ {
+ _value = value;
+ _hasValue = true;
+ }
+
+ bool HasValue() const
+ {
+ return _hasValue;
+ }
+
+ T GetValue() const
+ {
+ return _value;
+ }
+
+ T GetValueOrDefault(T defaultValue) const
+ {
+ return _hasValue ? _value : defaultValue;
+ }
+
+private:
+ T _value;
+ bool _hasValue;
+};
diff --git a/src/network/network.cpp b/src/network/network.cpp
index d7b2f839d3..e77556cada 100644
--- a/src/network/network.cpp
+++ b/src/network/network.cpp
@@ -1318,7 +1318,8 @@ uint8 Network::GetGroupIDByHash(const std::string &keyhash)
{
auto it = key_group_map.find(keyhash);
if (it != key_group_map.end()) {
- return it->second.GroupId;
+ auto groupId = it->second.GroupId;
+ return groupId.GetValueOrDefault(GetDefaultGroup());
} else {
return GetDefaultGroup();
}
@@ -1429,7 +1430,15 @@ void Network::SaveKeyMappings()
for (auto it = key_group_map.cbegin(); it != key_group_map.cend(); it++) {
json_t *keyMapping = json_object();
json_object_set_new(keyMapping, "hash", json_string(it->first.c_str()));
- json_object_set_new(keyMapping, "groupId", json_integer(it->second.GroupId));
+
+ json_t *jsonGroupId;
+ if (it->second.GroupId.HasValue()) {
+ jsonGroupId = json_integer(it->second.GroupId.GetValue());
+ } else {
+ jsonGroupId = json_null();
+ }
+ json_object_set_new(keyMapping, "groupId", jsonGroupId);
+
json_array_append_new(jsonKeyMappings, keyMapping);
}
bool result;
@@ -1466,11 +1475,14 @@ void Network::LoadKeyMappings()
const char *hash = json_string_value(json_object_get(jsonKeyMapping, "hash"));
const char *name = json_string_value(json_object_get(jsonKeyMapping, "name"));
+ const json_t *jsonGroupId = json_object_get(jsonKeyMapping, "groupId");
if (hash != nullptr && name != nullptr) {
KeyMapping keyMapping;
keyMapping.Hash = std::string(hash);
keyMapping.Name = std::string(name);
- keyMapping.GroupId = (uint8)json_integer_value(json_object_get(jsonKeyMapping, "groupId"));
+ if (!json_is_null(jsonGroupId)) {
+ keyMapping.GroupId = (uint8)json_integer_value(jsonGroupId);
+ }
key_group_map[keyMapping.Hash] = keyMapping;
}
}
@@ -1507,7 +1519,14 @@ void Network::UpdateKeyMappings()
std::string hash(json_string_value(json_object_get(jsonKeyMapping, "hash")));
decltype(local_key_map.begin()) it;
if ((it = local_key_map.find(hash)) != local_key_map.end()) {
- json_object_set_new(jsonKeyMapping, "groupId", json_integer(it->second.GroupId));
+ json_t *jsonGroupId;
+ if (it->second.GroupId.HasValue()) {
+ jsonGroupId = json_integer(it->second.GroupId.GetValue());
+ } else {
+ jsonGroupId = json_null();
+ }
+ json_object_set_new(jsonKeyMapping, "groupId", jsonGroupId);
+
// remove item once it was found and set
local_key_map.erase(it);
}
@@ -1521,7 +1540,15 @@ void Network::UpdateKeyMappings()
json_t *keyMapping = json_object();
json_object_set(keyMapping, "hash", json_string(it->first.c_str()));
json_object_set(keyMapping, "name", json_string(it->second.Name.c_str()));
- json_object_set(keyMapping, "groupId", json_integer(it->second.GroupId));
+
+ json_t *jsonGroupId;
+ if (it->second.GroupId.HasValue()) {
+ jsonGroupId = json_integer(it->second.GroupId.GetValue());
+ } else {
+ jsonGroupId = json_null();
+ }
+ json_object_set(keyMapping, "groupId", jsonGroupId);
+
json_array_append(jsonKeyMappings, keyMapping);
}
@@ -1946,7 +1973,7 @@ NetworkPlayer* Network::AddPlayer(const utf8 *name, const std::string &keyhash)
player->SetName(MakePlayerNameUnique(std::string(name)));
}
} else {
- player->group = keyMapping->GroupId;
+ player->group = keyMapping->GroupId.GetValueOrDefault(GetDefaultGroup());
player->SetName(keyMapping->Name);
}
diff --git a/src/network/network.h b/src/network/network.h
index 7bf71b183f..b19c27553d 100644
--- a/src/network/network.h
+++ b/src/network/network.h
@@ -121,6 +121,7 @@ extern "C" {
#include