-
Notifications
You must be signed in to change notification settings - Fork 21
Programming Standards
"Soft tabs" consisting of 4
spaces should be used instead of a hard tab character.
The reason for this is that different programs and platforms handle and display tabs differently, meaning a space is always a space, but a tab is not always a tab!
Keeping indentation consistent, while syntactically irrelevant, is highly important for maintaining readability.
Braces should always appear around any scope change, with each brace being on a separate line.
if (Foo())
{
for (i = 0; i < 10; ++i)
{
Bar();
}
}
else
{
i = Goo();
switch (i)
{
case 0:
Car();
break;
default:
break;
}
}
NOTE:
switch
case
s do not need separate bracing since separate cases don't generate nested scopes.
Consistent naming of variables, classes and functions is incredibly important.
Borrowing from existing standards, all names must employ CamelCase for consistency.
Avoid using abbreviations whenever possible, as it can make code more difficult to understand for newcomers and can obfuscate meaning.
All Darkest Hour: Europe '44-'45 classes must be prefixed with DH
. For example:
class DHPlayerReplicationInfo
Currently, as in the past, there is a bit of a hodge-podge of naming conventions depending on what package you're in. A while back, we made an effort to try and convert all of the hundreds of classes to use a new naming convention, but we soon realized that in order to maintain backwards compatibility, we could only do this in half-measures.
Going forward, when making new classes, simply try to stick to the naming conventions established in the particular package you're working in.
All bool
variable and function names should be in the form of a question. Rather than:
bDirty
bCleanRoom
Protected()
we use:
bIsDirty
bShouldCleanRoom
IsProtected()
Additionally, there exists a convention in UnrealScript to prefix all bool
variables with a b
character (eg. bIsFoobar
). While I personally dislike the practice, there are already mountains of code in use that adheres to this convention; we therefore adopt it as a de-facto standard.
All UnrealScript keywords such as if
, for
, string
, quat
, none
etc. should be lower case so they are differentiated from named symbols.
There is a ton of terrible, awful, nasty, despicable, dirty, wretched pre-existing code in Darkest Hour and Red Orchestra, there's no question about it. However, for the most part that code works, which means we should treat it carefully and with a certain level of begrudging respect.
Re-factoring is encouraged, but only when the changes are within the scope of code that is already being rigorously tested. Major re-factoring simply for the sake of doing so is highly discouraged, as it has a high likelihood of creating knock-on bugs that may get into a live build without ever having been identified.
When writing code, employ defensive programming techniques to ensure that likely and unlikely errors are guarded against and handled gracefully. Keeping on the defensive will ensure robust and high quality code.
Never assume that an array index will be valid. For example:
local array<int> A;
local int j;
j = Foo();
Bar(A[j]);
In this case, if Foo
returns an integer that is not a valid index into the A
array, an error will be thrown.
To avoid this situation, this following method is preferred:
j = Foo();
if (j >= 0 && j < A.Length)
{
Bar(A[j]);
}
When casting an object, always ensure that the result of a cast is not used before being checked against none
. For example:
if (DHPawn(Owner).IsSpawnProtected())
{
DHPawn(Owner).Foo();
DHPawn(Owner).Bar = 42;
}
In this case, if Owner
is not a DHPawn
or the underlying reference is none
, the cast will fail, returning none
. The script will attempt to run the IsSpawnProtected
on a null instance of DHPawn
, resulting in an accessed none error.
To avoid this problem, check that result of the cast to ensure that it succeeded:
local DHPawn P;
P = DHPawn(Owner);
if (P != none && P.IsSpawnProtected())
{
P.Foo();
P.Bar = 42;
}
It is also encouraged to avoid casting duplication (ie. casting the same object to another type multiple times within the same scope). If you have to use a casted value more than once, you should simply store the result of the cast in a local
variable and reference that variable instead.
All official Darkest Hour: Europe '44-'45 *.uc
files should contain the following header:
//==============================================================================
// Darkest Hour: Europe '44-'45
// Darklight Games (c) 2008-2023
//==============================================================================
Ideally, code you write should be self-documenting, however in practice comments are needed to aid the maintainer in understanding the implementation and design of code.
This wiki is a work in progress. If you require more in-depth support, please contact us on Discord.
- IMPORTANT: Disclaimer For Server Owners
- Dedicated Server Installation
- Basic Server Configuration
- Server Troubleshooting
- Debug & Admin Commands
- Programming Standards
- WOTgreal Installation
- WOTgreal Debugging
- Creating a Mutator
- Creating Custom Constructions