mirror of
https://gitlab.com/kholdfuzion/goldeneye_src
synced 2026-08-19 05:22:11 -04:00
update to current private
This commit is contained in:
@@ -0,0 +1,497 @@
|
||||
|
||||
# GoldenEye C Style Guide
|
||||
|
||||
## Background
|
||||
|
||||
GE/PD mostly uses cammelCase namespaceFunctionName()
|
||||
```C
|
||||
// joy.c -> Tick Retrace
|
||||
joyTickRetrace();
|
||||
// chrai.c -> If Opertunity Fire Jump F(orward)
|
||||
aiIfOpportunityFireJumpF();
|
||||
```
|
||||
with occasional Pascal_Snake_Case
|
||||
```C
|
||||
// snd.c -> Play Universal
|
||||
Snd_Play_Universal();
|
||||
```
|
||||
and snake_case
|
||||
```C
|
||||
// font.c -> Make G(reater) T(han)
|
||||
font_makegt();
|
||||
```
|
||||
however sometimes its Prefix_SnakePascalCase
|
||||
```C
|
||||
// pak.c -> Add One Camera File
|
||||
Pak_AddOneCameraFile();
|
||||
```
|
||||
|
||||
GE Constant example
|
||||
```C
|
||||
#define MAX_FUDGE_DATA_SIZE
|
||||
```
|
||||
|
||||
Basically, Rare had no style guide!
|
||||
Each mamber of the team was free to do whatever - which is fine for a closed
|
||||
source game with only a few members.
|
||||
|
||||
Nintendo had a much better handle on the situation (though not perfect either
|
||||
with a couple of deviations here and there) where the SDK also mostly uses
|
||||
namespaceFunctionName() in camelCase
|
||||
```C
|
||||
// Audio Library (libaudio.h) -> Sound P(layer) -> Play/Stop
|
||||
alSndpPlay();
|
||||
alSndpStop();
|
||||
// OS (os.h) -> P(arallel) I(interface) -> Get Status
|
||||
osPiGetStatus();
|
||||
```
|
||||
|
||||
Since this project is open to more people and the code has to be written from scratch
|
||||
we can set out some basic guides so that we are all following the same standard
|
||||
and can read what others have done.
|
||||
|
||||
HOWEVER
|
||||
|
||||
Since we are going for a matching project as best we can - If an original (canonical) name is known - Use it! (unless there is a really good reason not to)
|
||||
|
||||
In all other cases follow this guide.
|
||||
|
||||
---
|
||||
|
||||
## Bracing
|
||||
Allman Style bracing should be followed - though single line If's are acceptable
|
||||
This keeps in line with SDK style too and maximizes readability as all "blocks" have a clear
|
||||
start and end brace.
|
||||
The only exception to this is Array Definitions, which should open on the same line as the '='.
|
||||
```C
|
||||
void SomeFunctionScope()
|
||||
{
|
||||
int i;
|
||||
char *a = {
|
||||
'a',
|
||||
'b',
|
||||
2,
|
||||
3
|
||||
};
|
||||
|
||||
for (i=0; i < 10; i++)
|
||||
{
|
||||
doSomething(i);
|
||||
if (i = 2)
|
||||
{
|
||||
i = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = 9;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Prefix/Suffix Tables
|
||||
|
||||
| Prefix | Meaning | Example | Notes
|
||||
|-------- |---------------- |-------------------------------------- |--------------------------------------------
|
||||
| g_ | global | g_PrefService | Not needed if already prefixed "Global"
|
||||
| s | static member | sPrefChecked | Static Local retains value over App life, but remains local
|
||||
| m | private member | mLength | Static mLength can only be accessed within same file. External files require Get/Set
|
||||
| | enum constants | enum FOO<br>`{`<br>` FOO_BAR,`<br>` FOO_BAZ`<br>`}` | Also prefix with Enum Name.
|
||||
| _ <br>__ | Implementation Reserved | __osThingy | Underscore prefix should NOT be used in game code. However, expect to find them as Internal Identifiers but no Accessable Identifier will start with _ or __.
|
||||
| is | Boolean Result | isAlive | To ask a True/False question. Either a function or variable - where this should be the only non-noun variable name.
|
||||
|
||||
|
||||
| Sufix | Meaning | Example | Notes
|
||||
|-------- |---------------- |-------------------------------------- |--------------------------------------------
|
||||
| p | Pointer | glistp | Pointer to glist
|
||||
|
||||
|
||||
## TYPES
|
||||
Use SDK types (`u8`, `s32` etc) rather than C Types (`unsigned char`, `int` etc)
|
||||
Remember to include `<ultra64.h>`
|
||||
|
||||
Bond Types use the "typedef" keyword
|
||||
|
||||
|
||||
While typedefs are used to avoid typing "struct" and to help intellisence
|
||||
they are not foolproof.
|
||||
|
||||
Using structs before they are declaired need to have the struct keyword (forward declairation) or
|
||||
be re-ordered.
|
||||
|
||||
Example:
|
||||
```C
|
||||
typedef struct ARecord
|
||||
{
|
||||
BRecord *Child; // This will not work since IDO doenst know it exists
|
||||
Struct BRecord *Next; //Forward declairation OK
|
||||
} ARecord;
|
||||
|
||||
typedef struct BRecord
|
||||
{
|
||||
ARecord Parent; // This is ok because it exists.
|
||||
} BRecord;
|
||||
```
|
||||
|
||||
## INHERITANCE
|
||||
Bond Struct Types that "Inherit" from another Struct should use the provided 'Inherits' keyword.
|
||||
Example:
|
||||
```C
|
||||
// Base Struct has members A and B and can be accessed by var.A or var.B.
|
||||
typedef struct ARecord
|
||||
{
|
||||
u8 A;
|
||||
u8 B;
|
||||
} ARecord;
|
||||
|
||||
// Child Struct adds member C, all three members can be
|
||||
// accessed by var.A, var.B, var.C
|
||||
typedef struct CRecord
|
||||
{
|
||||
Inherits ARecord; // Does not have to be first, but makes sense to be first
|
||||
u8 C;
|
||||
} CRecord;
|
||||
```
|
||||
|
||||
|
||||
|
||||
## CONSTANTS
|
||||
ALL_CAPS_SNAKE_CASE for constants and enums eg.
|
||||
```c
|
||||
#define NULL 0
|
||||
enum HIT
|
||||
{
|
||||
HIT_WOOD,
|
||||
HIT_STONE
|
||||
};
|
||||
```
|
||||
|
||||
Examples from GE:
|
||||
```C
|
||||
stick<XUSER_MAX_COUNT
|
||||
p->type==prop_type_chr //should be caps
|
||||
currentplayer->gunmemused[GUNRIGHT]==0
|
||||
prevblock<MAXBLOCKS
|
||||
```
|
||||
|
||||
## INCLUDE UNITS IN NAMES
|
||||
If a variable represents time, weight, or some other unit then include the unit
|
||||
in the name so developers can more easily spot problems.
|
||||
For example:
|
||||
```C
|
||||
int timeout_msecs;
|
||||
int MyWeight_lbs;
|
||||
```
|
||||
|
||||
|
||||
## VARIABLE NAMES
|
||||
Should be nouns (as they represent state). The name should be camelCase
|
||||
(e.g. index, currentEnvironment or bond).
|
||||
|
||||
Prefixes are sometimes usefull, please refer to prefix table above
|
||||
|
||||
Suffixes are sometimes useful eg:
|
||||
* `max` - to mean the maximum value something can have.
|
||||
* `cnt` - the current count of a running count variable.
|
||||
* `key` - key value.
|
||||
|
||||
For example: `retry_max` to mean the maximum number of retries, `retry_cnt` to mean
|
||||
the current retry count.
|
||||
|
||||
Examples from GE:
|
||||
```C
|
||||
num < MAX_STARTPADS
|
||||
mFilteredNum==0
|
||||
numBits<=32
|
||||
p->type //where p is a pad
|
||||
inst->obj->nummatrices //where inst is an object instance
|
||||
PadData[stick].numPos[xy]
|
||||
|
||||
```
|
||||
### Global (Public) Variables
|
||||
Should be prefixed by `g_` eg:
|
||||
* `g_chraiCurrentSetup` global Current Setup defined in file chrai.c
|
||||
|
||||
Public Global Variables must be declaired (not defined) in a header file that is included by all C files
|
||||
that use the variable, and use the `extern` keyword eg:
|
||||
* `extern stagesetup g_chraiCurrentSetup;`
|
||||
Global Variables should only be defined once in their own C file.
|
||||
|
||||
### Global (Private) Variables
|
||||
Should be prefixed by `m_` eg:
|
||||
* `m_numGuards` global Number of Guards defined in file chr.c
|
||||
|
||||
Private Global Variables must be defined (implicitly declaired) in the C file
|
||||
that use the variable (Not in a header).
|
||||
|
||||
Access to Private Variables from outside the C file should be done via Get/Set functions (declaired in a h file)
|
||||
|
||||
## FUNCTION NAMES
|
||||
Should be verb phrases (as they represent actions), and command-like functions
|
||||
should be imperative.
|
||||
The name should make clear what it does:
|
||||
`CheckForErrors()` instead of `error_check(),`
|
||||
`DumpDataToFile()` instead of `data_file().`
|
||||
This will also make functions and data objects more distinguishable.
|
||||
|
||||
Prefixes are sometimes useful:
|
||||
|
||||
* `is` - to ask a question about something. Usually TRUE/FALSE
|
||||
* `get` - Get a value.
|
||||
* `set` - Set a value.
|
||||
|
||||
For example: `isAlive`
|
||||
```C
|
||||
//Only do something if we are alive
|
||||
if(isAlive())
|
||||
{
|
||||
doSomething();
|
||||
}
|
||||
```
|
||||
|
||||
Functions, especually Public, should be prefixed by "class" or "namespace"
|
||||
```C
|
||||
chrResetNearMiss()
|
||||
chrIsAlive()
|
||||
```
|
||||
|
||||
Examples from GE:
|
||||
```C
|
||||
IsBadMtx44()
|
||||
GetState()
|
||||
getCurrent()
|
||||
skeletonGetNumJoints( skel )
|
||||
```
|
||||
|
||||
### Private Functions
|
||||
Private functions that only serve a purpose __within__ a single C file should NOT be declaired
|
||||
in a h file, and should only be declaired ahead of definition (forward decleration) if it is to be used before
|
||||
it is defined.
|
||||
|
||||
### Public Functions
|
||||
Public Functions MUST be declaired in a h file to be included in any C that uses the function.
|
||||
the `extern` keyword has no effect on functions but it may be of use to highlight the public
|
||||
nature/intention of the function.
|
||||
Public functions MUST have a namespace as the first part of the name.
|
||||
|
||||
## STRUCT NAMES
|
||||
Structs are often nouns and should be PascalCase
|
||||
Database like structs should not be named "data" - which should be reserved for
|
||||
the variable wich uses the struct. Instead "Record" is suggested eg:
|
||||
```C
|
||||
typedef struct PadRecord
|
||||
{
|
||||
coord3d pos;
|
||||
coord3d up;
|
||||
coord3d look;
|
||||
char *plink;
|
||||
StandTile *stan;
|
||||
} PadRecord;
|
||||
|
||||
PadRecord padData; //variable holding data for pad
|
||||
```
|
||||
Examples from GE:
|
||||
```C
|
||||
```
|
||||
|
||||
## POINTERS
|
||||
Pointers should be declaired with the * right-aligned eg:
|
||||
```C
|
||||
ChrData *ChrAp, *ChrBp;
|
||||
```
|
||||
instead of:
|
||||
```C
|
||||
ChrData* ChrAp, ChrBp; //this would not make ChrB a pointer.
|
||||
```
|
||||
Pointers _should_ be suffixed by p following sdk style eg: `glistp // pointer to glist` however GE also
|
||||
prefixed with p and suffixed in Ptr (see note about GE being inconsistent haha)
|
||||
|
||||
Examples from GE:
|
||||
```C
|
||||
pPlayback
|
||||
ppFileData
|
||||
tagNamePtr
|
||||
((void*)assetPtr != NULL)
|
||||
((void*)nodePtr != NULL)
|
||||
```
|
||||
## COMMENTS
|
||||
Comments should be C style / * * / for block comments and header documentation.
|
||||
|
||||
Comments _can_ be C++ style / / for inline comments documenting single items.
|
||||
|
||||
Function documentation should precede functions directly
|
||||
without extra line breaks and begin with a double asterix - Left aligned astrices are optional
|
||||
```C
|
||||
int var; //This is an integer
|
||||
|
||||
/** Take an integer and convert it to a float of half its size
|
||||
* @param in: Integer to convert
|
||||
* @return A float of half the input size
|
||||
*/
|
||||
float mathHalfMe(int in)
|
||||
{
|
||||
return in/2;
|
||||
}
|
||||
```
|
||||
`@param`, `@return` help with editors that support function hinting by showing these values in a
|
||||
tooltip.
|
||||
|
||||
|
||||
## SCOPE
|
||||
Variables inside braces have "Block" scope and end when the block ends (unless
|
||||
declared static where they retain their value till program ends).
|
||||
```C
|
||||
if(1)
|
||||
{
|
||||
int a = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int a = 0;
|
||||
}
|
||||
|
||||
//a is undefined hereafter
|
||||
```
|
||||
Variables Outside functions, usually at top of file (NOT in header) have by
|
||||
default Global (Private) Scope.
|
||||
If declaired as extern they are promoted to Public Scope - provided the declairation is in a
|
||||
h file and the h file is included by all C files that use the Global.
|
||||
Both extern and static have Static Duration - they end when the program ends.
|
||||
```C
|
||||
//Initial Declaration in h (all initial declairations within
|
||||
// a C will work for that C)
|
||||
int gi4; // tentative defnition, unknown linkage (Private/Public)
|
||||
// Including this header in another C file will fail.
|
||||
static int mi5; // tentative defnition, internal linkage (Private)
|
||||
// Including this header in another C file ends up with its
|
||||
// own private version of the 'global' variable
|
||||
extern int gi6; // tentative defnition, external linkage (Public)
|
||||
// Including this header in another C file
|
||||
// Use the Global as expected
|
||||
|
||||
//Initial Definition in h - Fail (all initial definitions within
|
||||
// a C will work for that C)
|
||||
|
||||
int gi1 = 1; // defnition, Unknown linkage (Private/Public)
|
||||
// Including this header in more than 1 C file will fail.
|
||||
static int mi2 = 2; // defnition, internal linkage (Private)
|
||||
// Including this header in another C file ends up with its
|
||||
// own private version of the 'global' variable
|
||||
extern int gi3 = 3; // defnition, external linkage (Public)
|
||||
// Including this header in another C file will fail.
|
||||
```
|
||||
### Headers
|
||||
A header file only contains extern declarations of variables - never static or unqualified variable definitions.
|
||||
|
||||
For any given variable, only one header file declares it (SPOT - Single Point of Truth).
|
||||
|
||||
A source file never contains extern declarations of variables - source files always include the (sole) header that declares them.
|
||||
|
||||
For any given variable, exactly one source file defines the variable, preferably initializing it too.
|
||||
|
||||
The source file that defines the variable also includes the header to ensure that the definition and the declaration are consistent.
|
||||
|
||||
A function should never need to declare a variable using extern.
|
||||
|
||||
---
|
||||
|
||||
## EXAMPLE C
|
||||
|
||||
|
||||
### FILE1.c
|
||||
```C
|
||||
#include "file1.h" // Prove my definitions are the same as declaired to others
|
||||
|
||||
static f32 mAiTime; // Static, holds value for duration of program, scoped to file 1 (Private)
|
||||
|
||||
/**
|
||||
* @returns the time
|
||||
*/
|
||||
f32 f1GetTime() // Public Function, make sure its declaired in a header
|
||||
{
|
||||
return mAiTime; // Gets time from private mTime
|
||||
}
|
||||
|
||||
/**
|
||||
* @param time: Integer to Set time as
|
||||
*/
|
||||
void setTime(u32 time) // Private Function, make sure its NOT declaired in a header
|
||||
{
|
||||
mAiTime = time / 60; // Sets time to mTime format
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### FILE1.h (File 1 Public Vars/Funcs)
|
||||
```C
|
||||
extern int f1GetTime(); // Gets time from private mTime (Public Func, Includes "Namespace")
|
||||
extern u32 g_f2GlobalData // Public Global Data
|
||||
|
||||
```
|
||||
|
||||
### FILE2.c
|
||||
|
||||
```C
|
||||
#include "file1.h" // Brings into scope "Public" Variables and functions
|
||||
|
||||
s32 D_80000000; // Unknown label data (Private by default)
|
||||
g_f2GlobalData = 0; // camelCasedNaming and defined as early as possible
|
||||
|
||||
typedef enum ID
|
||||
{
|
||||
ID_AGENT, // prefix with enum name
|
||||
ID_SECRETAGENT,
|
||||
ID_00AGENT
|
||||
}ID;
|
||||
|
||||
typedef struct Person // structs themselves should use PascalCase and be Nouns
|
||||
{
|
||||
ID ID; // struct member Noun and PascalCase
|
||||
char *Name;
|
||||
int Age;
|
||||
} Person;
|
||||
|
||||
Person gTrevor = {ID_00AGENT, "Trevor", 30}; // Global Person defined early
|
||||
|
||||
// This can be done, but its pointless since gGlobalData has global scope and nothing special is being done
|
||||
// Also, unless this is declaired in a header, the function is Private
|
||||
int getGlobalData()
|
||||
{
|
||||
return g_f2GlobalData;
|
||||
}
|
||||
|
||||
/**
|
||||
* functions should be camelCase
|
||||
* further documentation
|
||||
* @param parameter1: defines the number of xxx
|
||||
*/
|
||||
void functionNameSample(int Parameter1)
|
||||
{ // newline for opening braces (ALLMAN)
|
||||
u32 tempvar; // Use SDK Types
|
||||
|
||||
if (g_f2GlobalData == 1)
|
||||
{
|
||||
gGlobalData = 2;
|
||||
D_80000000 = 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
tempVar = getGlobalData(); // wastes cpu instructions switching funcs
|
||||
tempVar = g_f2GlobalData(); // This works equally as well
|
||||
}
|
||||
|
||||
if (g_f2GlobalData == 4)
|
||||
g_f2GlobalData = 2; // this syntex may be used
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
int time = f1GetTime(); // Access Global Getter
|
||||
//time = mAiTime; // This fails as mAiTime is not visible in this file (Scope limited to file1)
|
||||
functionNameSample(time);
|
||||
//setTime(23); // This fails as setTime is not visible in this file (Scope limited to file1)
|
||||
}
|
||||
|
||||
```
|
||||
Reference in New Issue
Block a user