Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove union in struct Settings (type punning is UB in C++). #656

Merged
merged 1 commit into from
Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 27 additions & 15 deletions src/include/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,18 +241,14 @@ struct Settings {
FieldOfViewTypes FoV; /// Which field of view is used - important to be shared for unit sight
MapRevealModes RevealMap; /// Reveal map kind
RevealTypes DefeatReveal;
union {
struct {
unsigned NoFogOfWar:1; /// if dynamic fog of war is disabled
unsigned Inside:1; /// if game uses interior tileset or is generally "inside" for the purpose of obstacles
unsigned AiExplores:1; /// If true, AI sends explorers to search for resources (almost useless thing)
unsigned SimplifiedAutoTargeting:1; /// Use alternate target choosing algorithm for auto attack mode (idle, attack-move, patrol, etc.)
unsigned AiChecksDependencies:1; /// If false, the AI can do upgrades even if the dependencies are not met. This can be desirable to simplify AI scripting.
unsigned AllyDepositsAllowed:1; /// If false, the AI does not consider allied player's townhalls as deposits, so it will prefer harvesting gold closer to their own base
unsigned UserGameSettings:26; /// A bitfield for use by games and their settings
};
uint32_t _Bitfield;
};

unsigned NoFogOfWar:1; /// if dynamic fog of war is disabled
unsigned Inside:1; /// if game uses interior tileset or is generally "inside" for the purpose of obstacles
unsigned AiExplores:1; /// If true, AI sends explorers to search for resources (almost useless thing)
unsigned SimplifiedAutoTargeting:1; /// Use alternate target choosing algorithm for auto attack mode (idle, attack-move, patrol, etc.)
unsigned AiChecksDependencies:1; /// If false, the AI can do upgrades even if the dependencies are not met. This can be desirable to simplify AI scripting.
unsigned AllyDepositsAllowed:1; /// If false, the AI does not consider allied player's townhalls as deposits, so it will prefer harvesting gold closer to their own base
unsigned UserGameSettings:26; /// A bitfield for use by games and their settings

bool GetUserGameSetting(int i) {
return std::bitset<26>(UserGameSettings).test(i);
Expand All @@ -264,6 +260,22 @@ struct Settings {
UserGameSettings = bs.to_ulong();
}

std::uint32_t getBitfield() const
{
return NoFogOfWar | (Inside << 1) | (AiExplores << 2) | (SimplifiedAutoTargeting << 3)
| (AiChecksDependencies << 4) | (AllyDepositsAllowed << 5) | (UserGameSettings << 6);
}
void setBitfield(std::uint32_t bitfield)
{
NoFogOfWar = bitfield & 1;
Inside = (bitfield >> 1) & 0x1;
AiExplores = (bitfield >> 2) & 0x1;
SimplifiedAutoTargeting = (bitfield >> 3) & 0x1;
AiChecksDependencies = (bitfield >> 4) & 0x1;
AllyDepositsAllowed = (bitfield >> 5) & 0x1;
UserGameSettings = bitfield >> 6;
}

bool operator==(const Settings &other) const {
for (int i = 0; i < PlayerMax; i++) {
if (Presets[i] == other.Presets[i]) {
Expand All @@ -281,7 +293,7 @@ struct Settings {
FoV == other.FoV &&
RevealMap == other.RevealMap &&
DefeatReveal == other.DefeatReveal &&
_Bitfield == other._Bitfield;
getBitfield() == other.getBitfield();
}

void Save(const std::function <void (std::string)>& f, bool withPlayers = true) {
Expand All @@ -301,7 +313,7 @@ struct Settings {
f(std::string("FoV = ") + std::to_string(static_cast<int>(FoV)));
f(std::string("RevealMap = ") + std::to_string(static_cast<int>(RevealMap)));
f(std::string("DefeatReveal = ") + std::to_string(static_cast<int>(DefeatReveal)));
f(std::string("Flags = ") + std::to_string(_Bitfield));
f(std::string("Flags = ") + std::to_string(getBitfield()));
}

bool SetField(std::string field, int value) {
Expand All @@ -324,7 +336,7 @@ struct Settings {
} else if (field == "DefeatReveal") {
DefeatReveal = static_cast<RevealTypes>(value);
} else if (field == "Flags") {
_Bitfield = value;
setBitfield(value);
} else {
return false;
}
Expand Down
7 changes: 4 additions & 3 deletions src/network/net_message.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ size_t CServerSetup::Serialize(unsigned char *buf) const
p += serialize8(p, static_cast<int8_t>(this->ServerGameSettings.Resources));
p += serialize8(p, static_cast<int8_t>(this->ServerGameSettings.RevealMap));
// The bitfield contains Inside and NoFogOfWar, as well as game-defined settings
p += serialize32(p, this->ServerGameSettings._Bitfield);
p += serialize32(p, this->ServerGameSettings.getBitfield());

for (const auto &preset : this->ServerGameSettings.Presets) {
p += serialize8(p, static_cast<int8_t>(preset.Race));
Expand Down Expand Up @@ -293,8 +293,9 @@ size_t CServerSetup::Deserialize(const unsigned char *p)
p += deserialize8(p, reinterpret_cast<int8_t*>(&this->ServerGameSettings.Resources));
p += deserialize8(p, reinterpret_cast<int8_t*>(&this->ServerGameSettings.RevealMap));
// The bitfield contains Inside and NoFogOfWar, as well as game-defined settings
p += deserialize32(p, &this->ServerGameSettings._Bitfield);

std::uint32_t bitfield = 0;
p += deserialize32(p, &bitfield);
this->ServerGameSettings.setBitfield(bitfield);
for (auto &preset : this->ServerGameSettings.Presets) {
p += deserialize8(p, reinterpret_cast<int8_t*>(&preset.Race));
p += deserialize8(p, reinterpret_cast<int8_t*>(&preset.PlayerColor));
Expand Down
1 change: 0 additions & 1 deletion src/tolua/game.pkg
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ class Settings {
bool Inside;
bool AiExplores;
bool SimplifiedAutoTargeting;
int _Bitfield @ Flags;

bool GetUserGameSetting(int i);
void SetUserGameSetting(int i, bool v);
Expand Down
Loading