Replies: 9 comments 19 replies
-
My two cents, using Clang will allow for enforcement of formatting rules across a variety of different IDEs, and I also assume that by working on VC22 where we no longer worry about compatibility with 1.04, we will be able to apply design rules to the original current code as well. |
Beta Was this translation helpful? Give feedback.
-
Regarding line endings CRLF or LF, don't worry about it. Git by default converts to CRLF on checkout on windows and converts to LF on push so the repo is almost certainly LF already and locally will depend on if you are on Windows or not. I'm also in favour of automated formatting because ultimately manual formatting will have inconsistencies fall through the cracks. For blocks of code the author wants a particular way, they can use clang-format off/clang-format on comments to book end the code. The downside of it not being consistent between versions of clang-format is very furstrating though as at some point we will need to bump the format version due to deprecation and deal with any slight changes it makes. |
Beta Was this translation helpful? Give feedback.
-
Can we check with W3DHub what formatting direction they want to go? Perhaps we can sync on it, then collaboration will be better. Can someone link them here? I do not know anyone from W3DHub. |
Beta Was this translation helpful? Give feedback.
-
What was the reason for Thyme to use old clang format version 10, when the newest is at version 20 or so? |
Beta Was this translation helpful? Give feedback.
-
As far as W3DHub renegade goes I intend on rolling clang format, but we should align together to ease code sharing. You can disable clang format for a section of code with a simple // clang-format off // clang-format on. So if you want to format a table for readability or something then you have that option. As for it making seemingly infuriating changes, well, I personally can't stand having it format as I'm typing. Format on save tends to work fine though. I've been using it personally and professionally for years with no problem. |
Beta Was this translation helpful? Give feedback.
-
My personal clang format pain pointsHere are my observations from working with the clang format setup from the Thyme project and its descendants. It may be incomplete. constructor initializerColon and comma ideally preceed the variable initializer on the same line. Otherwise it looks unholy when adding a macro for example. It also means adding a new initializer at the end of the list requires touching 2 lines instead of 1. badBaseHeightMapRenderObjClass::BaseHeightMapRenderObjClass() :
m_x(0),
m_y(0),
m_vertexScorch(nullptr),
m_indexScorch(nullptr),
m_scorchTexture(nullptr),
m_cliffAngle(45.0f)
#if CONDITION
,
m_map(nullptr)
#endif
{
} betterBaseHeightMapRenderObjClass::BaseHeightMapRenderObjClass()
: m_x(0)
, m_y(0)
, m_vertexScorch(nullptr)
, m_indexScorch(nullptr)
, m_scorchTexture(nullptr)
, m_cliffAngle(45.0f)
#if CONDITION
, m_map(nullptr)
#endif
{
} argument packingbadThyme's clang format setup has 3 or 4 argument packing variations for functions declations and function calls, depending on the length of the line. This is not good, because it presents too many kinds of variations. class MyClass
{
int Get_Static_Diffuse(int x, int y); // <----- STANDARD
float Get_Max_Cell_Height(float x, float y) const;
void Set_Time_Of_Day(TimeOfDayType time);
void Do_The_Light(VertexFormatXYZDUV2 *vb, // <----- PACKING VARIATION 1
Vector3 *light,
Vector3 *normal,
RefMultiListIterator<RenderObjClass> *lights,
unsigned char alpha);
float Get_Height_Map_Height(float x, float y, Coord3D *pos) const;
void Notify_Shroud_Changed();
void Add_Tree( // <----- PACKING VARIATION 2
DrawableID drawable, Coord3D location, float scale, float angle, float random, W3DTreeDrawModuleData const *module);
void Add_Prop(int id, Coord3D location, float orientation, float scale, const Utf8String &name);
void Add_Scorch(Vector3 location, float radius, Scorches type);
} betterSettle on 2 packing variants only, with consistent indentation for arguments. class MyClass
{
int Get_Static_Diffuse(int x, int y);
float Get_Max_Cell_Height(float x, float y) const;
void Set_Time_Of_Day(TimeOfDayType time);
void Do_The_Light(
VertexFormatXYZDUV2 *vb,
Vector3 *light,
Vector3 *normal,
RefMultiListIterator<RenderObjClass> *lights,
unsigned char alpha);
float Get_Height_Map_Height(float x, float y, Coord3D *pos) const;
void Notify_Shroud_Changed();
void Add_Tree(
DrawableID drawable,
Coord3D location,
float scale,
float angle,
float random,
W3DTreeDrawModuleData const *module);
void Add_Prop(int id, Coord3D location, float orientation, float scale, const Utf8String &name);
void Add_Scorch(Vector3 location, float radius, Scorches type);
} badHere is another example of too many packing variations making it harder to look at: void function()
{
...
g_thePartitionManager->Reveal_Map_For_Player_Permanently( // <----- PACKING VARIATION 1
g_thePlayerList->Find_Player_With_NameKey(g_theNameKeyGenerator->Name_To_Key("ReplayObserver"))->Get_Player_Index());
captainslog_debug("Reveal shroud for %ls whose index is %d", // <----- PACKING VARIATION 2
g_thePlayerList->Find_Player_With_NameKey(g_theNameKeyGenerator->Name_To_Key("ReplayObserver"))
->Get_Player_Display_Name()
.Str(),
g_thePlayerList->Find_Player_With_NameKey(g_theNameKeyGenerator->Name_To_Key("ReplayObserver"))->Get_Player_Index());
if (game_info != nullptr) {
for (int slot_idx = 0; slot_idx < GameInfo::MAX_SLOTS; slot_idx++) {
GameSlot *slot = game_info->Get_Slot(slot_idx);
if (slot != nullptr && slot->Is_Occupied()) {
Utf8String player_name;
player_name.Format("player%d", slot_idx);
Player *player = // <----- UNPLEASANT PACKING
g_thePlayerList->Find_Player_With_NameKey(g_theNameKeyGenerator->Name_To_Key(player_name.Str()));
if (slot->Get_Player_Template() == -2) {
captainslog_debug("Clearing shroud for observer %s in playerList slot %d",
player_name.Str(),
player->Get_Player_Index());
...
} bettervoid function()
{
...
g_thePartitionManager->Reveal_Map_For_Player_Permanently(
g_thePlayerList->Find_Player_With_NameKey(g_theNameKeyGenerator->Name_To_Key("ReplayObserver"))->Get_Player_Index());
captainslog_debug(
"Reveal shroud for %ls whose index is %d",
g_thePlayerList->Find_Player_With_NameKey(g_theNameKeyGenerator->Name_To_Key("ReplayObserver"))->Get_Player_Display_Name().Str(),
g_thePlayerList->Find_Player_With_NameKey(g_theNameKeyGenerator->Name_To_Key("ReplayObserver"))->Get_Player_Index());
if (game_info != nullptr)
{
for (int slot_idx = 0; slot_idx < GameInfo::MAX_SLOTS; slot_idx++)
{
GameSlot *slot = game_info->Get_Slot(slot_idx);
if (slot != nullptr && slot->Is_Occupied())
{
Utf8String player_name;
player_name.Format("player%d", slot_idx);
Player *player = g_thePlayerList->Find_Player_With_NameKey(
g_theNameKeyGenerator->Name_To_Key(player_name.Str()));
if (slot->Get_Player_Template() == -2)
{
captainslog_debug(
"Clearing shroud for observer %s in playerList slot %d",
player_name.Str(),
player->Get_Player_Index());
...
} indentation spacesThyme uses 4 spaces as indentation. I recommend that leading indentation is made with tabs, because this allows the user to configure the tab size in his text editor. Some user may prefer 2 character wide indentation while another user may prefer 4 characters. code densityHere the code uses compacted scopes which condense the code. This makes the code more difficult to look at because everything is so tightly packed together. It also greatly mismatches with the formatting of the original EA source code, which presents the code with much more generous spacing, easing the work on the eyes. bad if (g_theNetwork != nullptr) {
if (g_theLAN != nullptr) {
captainslog_debug("Starting network game");
game_info = g_theLAN->Get_My_Game();
g_theGameInfo = game_info;
} else {
captainslog_debug("Starting gamespy game");
game_info = g_theGameSpyGame;
g_theGameInfo = g_theGameSpyGame;
}
} else if (g_theRecorder != nullptr && g_theRecorder->Get_Mode() == RECORDERMODETYPE_PLAYBACK) {
game_info = g_theRecorder->Get_Game_Info();
g_theGameInfo = game_info;
} else if (m_gameMode == GAME_SKIRMISH) {
game_info = g_theSkirmishGameInfo;
g_theGameInfo = g_theSkirmishGameInfo;
} else if (is_challenge_campaign) {
game_info = g_theChallengeGameInfo;
g_theGameInfo = g_theChallengeGameInfo;
} better if (g_theNetwork != nullptr)
{
if (g_theLAN != nullptr)
{
captainslog_debug("Starting network game");
game_info = g_theLAN->Get_My_Game();
g_theGameInfo = game_info;
}
else
{
captainslog_debug("Starting gamespy game");
game_info = g_theGameSpyGame;
g_theGameInfo = g_theGameSpyGame;
}
}
else if (g_theRecorder != nullptr && g_theRecorder->Get_Mode() == RECORDERMODETYPE_PLAYBACK)
{
game_info = g_theRecorder->Get_Game_Info();
g_theGameInfo = game_info;
}
else if (m_gameMode == GAME_SKIRMISH)
{
game_info = g_theSkirmishGameInfo;
g_theGameInfo = g_theSkirmishGameInfo;
}
else if (is_challenge_campaign)
{
game_info = g_theChallengeGameInfo;
g_theGameInfo = g_theChallengeGameInfo;
} empty function scopes in cppclang format may be configured to do this in a cpp: void W3DModelDraw::React_To_Geometry_Change() {}
void W3DModelDraw::Notify_Draw_Module_Dependency_Cleared() {}
void W3DModelDraw::On_Render_Obj_Recreated() {} This means if a user types a function body, then plans to write something in but applies formatting by saving the file before that, then the function body {} characters collapse like that. It is not convenient. I suggest that empty functions in cpp always look like this: void W3DModelDraw::React_To_Geometry_Change()
{
}
void W3DModelDraw::Notify_Draw_Module_Dependency_Cleared()
{
}
void W3DModelDraw::On_Render_Obj_Recreated()
{
} |
Beta Was this translation helpful? Give feedback.
-
These are fair points. Whitespace wise I would suggest tabs to indent and spaces to align. I don't really have an opinion on the function stubs. As for params, I believe we have a few options to control where it puts the braces and line breaks. If you get a function with that many params it should probably be a struct though. |
Beta Was this translation helpful? Give feedback.
-
I like tabs for the exact reason that the user can configure the depth of
indents.
I don't really have a strong opinion on it though 😄
…On Thu, 13 Mar 2025, 09:46 OmniBlade, ***@***.***> wrote:
I agree with the empty scopes and initlializers.
Can't say I agree with the tab based indentation. In practice it only
looks right when indentation is the same as the author intended so why
allow it to be altered at all, just make it spaces and it looks consistent
for everyone regardless of how their editor is configured. Make it 2, make
it 4, but make it spaces. That said, if the formatting is automated it will
take care of most stuff anyhow.
I personally prefer the denser code style, the extra space to my eyes
looks wasted and redundant and doesn't really impact my ability to read the
code. However I don't actually care that much and if that is the prevailing
style in the current code I can live with it.
—
Reply to this email directly, view it on GitHub
<#409 (reply in thread)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AALJLQLSHRM7D3WYE262BCT2UFHYXAVCNFSM6AAAAABYZ5KKY6VHI2DSMVQWIX3LMV43URDJONRXK43TNFXW4Q3PNVWWK3TUHMYTENBYGU4DSNI>
.
You are receiving this because you commented.Message ID:
<TheSuperHackers/GeneralsGameCode/repo-discussions/409/comments/12485895@
github.com>
|
Beta Was this translation helpful? Give feedback.
-
Personalty, I prefer block code solely because of syntax like parenthesis and colons. (◔‿◔) |
Beta Was this translation helpful? Give feedback.
-
It was not clear to me from the meeting what we now do with the code formatting. We did agree that changing all formatting can make integrations more difficult. Some points:
Manual format
CRLF
Line endings are
\r\n
. Are we ok with this? Is Linux ok with this? Generally, my understanding is that one settles on\n
. Do we want to change it for all files. Or not?Tabs vs Spaces
The code uses 2 space characters or tabs as 2 space character equivalent to do indentation. It is not possible to comfortably switch to 4 space character wide tabs. How about we apply a format pass to make all whitespacing consistent? Leading tabs or leading spaces everywhere, no tabs after code words.
Whitespace difference across forks should cause no merge conflicts, because merge tools should have the ability to ignore whitespace differences on merge.
Sample image from P4Merge
Format for new code written
If we do not apply code formatting on the original code, how about we at least try to apply formatting on all new code? How can we do this?
One way to do it for Visual Studio is the editorconfig. It is unclear however how well this will work in practice. https://learn.microsoft.com/en-us/visualstudio/ide/create-portable-custom-editor-options?view=vs-
Disadvantages of manual formatting
Advantages of manual formatting
Clang Format
Or do we want to apply clang formatting, closely matching the original code style? It will incur merge conflicts, unless the author applies clang format with our formatting rules before attempting the merge. Does it work? Is this practical? Do we need a guide?
Disadvantage of clang format
Advantages of clang format
Beta Was this translation helpful? Give feedback.
All reactions