Skip to content

Commit

Permalink
Remove union in struct Settings (type punning is UB in C++).
Browse files Browse the repository at this point in the history
  • Loading branch information
Jarod42 committed Apr 24, 2024
1 parent 14822e1 commit 32bb8f1
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 19 deletions.
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

0 comments on commit 32bb8f1

Please sign in to comment.