Difference between revisions of "Fastman92 Path Format"
(Split from "Paths (GTA SA)" because it doubles the length of that page and isn't native) |
(No difference)
|
Latest revision as of 16:40, 5 June 2021
This article may need to be rewritten. Please help improve this article. The discussion page may contain suggestions. |
Each file starts with a header, followed by 7 distinct sections.
Paths are stored as double-linked (thus undirected) graphs in adjacency list representation. There can be connections between separate areas.
The following data types and structures are used within this article:
- INT8/UINT8 - signed/unsigned 8 bit integer (1 byte)
- INT16/UINT16 - signed/unsigned 16 bit integer (2 byte)
- INT32/UINT32 - signed/unsigned 32 bit integer (4 byte)
- FLOAT - single precision floating point number (4 byte)
Contents
Structures
Go here to see the C++ structures used in new format of path file: http://pastebin.com/7hpLZmJJ
Compressed vector
Compressed vector is the way to save some memory in GTA games. It's a structure with __int16 values of x, y, z coordinates. GTA uses accuracy of 8 parts per whole number. To convert __int16 or __int32 value back into float value, you have to cast it into float value, then divide by 8.
#pragma pack(push, 1) class CompressedVector { public: signed __int16 x; signed __int16 y; signed __int16 z; }; #pragma pack(pop)
Extended version of CompressedVector is used in new format of path files. __int16 values were replaced into __int32 values. __int16 was making a limit of (-2^15/8 = -4096) to ((2^15) - 1) / 8 = 4 095,875
#pragma pack(push, 1) class CompressedVector_extended { public: signed __int32 x; signed __int32 y; signed __int32 z; }; #pragma pack(pop)
Node address
#pragma pack(push, 1) struct CNodeAddress { unsigned __int16 areaId; unsigned __int16 nodeId; }; #pragma pack(pop)
Node address structure hold area ID and node ID.
Header
The header contains information about the content of the various sections in the file..
4b - UINT32 - is different format? Should have a value of 0xFFFFFFFF 4b - UINT32 - format, should have a value "FM92" 1b - UINT8 - n, size of nickname char[n] - nickname, should have a value ( "\x00" "fastman92" "\x00" ) 4b - UINT32 - format version, should have a value "VER2" or "VER3" 4b - UINT32 - number of nodes (section 1) 4b - UINT32 - number of vehicle nodes (section 1a) 4b - UINT32 - number of ped nodes (section 1b) 4b - UINT32 - number of navi nodes (section 2) 4b - UINT32 - number of links (section 3/5/6)
Note: Sections related to links (3/5/6) have the same number of entries. These entries belong together and can be treated as one record by editors.
Section 1 - Path Nodes
The first section contains the node data for the paths. They are grouped by type: the list of vehicle nodes (cars, boats, race tracks) is followed by the ped nodes. Size of CPathNode_extended equals to 40 bytes.
// standard GTA SA #pragma pack(push, 1) struct CPathNode { CPathNode *m_pPrev; CPathNode **m_ppNext; CompressedVector m_posn; int16_t m_wSearchList; int16_t m_wConnectedNodesStartId; // ID into link array CNodeAddress m_nodeInfo; char m_nPathWidth; uint8_t m_nFloodID; // unused when fastman92 path format VER3 is used uint32_t m_dwFlags; // Returns number of links int GetNumberOfLinks() { return this -> m_dwFlags & 0xF; } }; #pragma pack(pop) VALIDATE_SIZE(CPathNode, 0x1C); // fastman92 path format VER2 struct CPathNode_extended : public CPathNode { CompressedVector_extended m_extended_posn; // Sets the position in vector void GetExPosition(CVector& out) { out.x = (float)this->m_extended_posn.x / PATH_COORD_MULTIPLIER; out.y = (float)this->m_extended_posn.y / PATH_COORD_MULTIPLIER; out.z = (float)this -> m_extended_posn.z / PATH_COORD_MULTIPLIER; } }; VALIDATE_SIZE(CPathNode_extended, 0x28); // fastman92 path format VER3 #pragma pack(push, 1) struct CPathNode_extended2 : public CPathNode_extended { int16_t m_nExFloodID; }; #pragma pack(pop) VALIDATE_SIZE(CPathNode_extended2, 0x2A);
Path Node Flags
The second section contains additional nodes, referred to as navigational nodes (navi nodes) in this article. Size of CCarPathLink_extended equals to 22 bytes.
Navi nodes are used to define additional information for vehicle path segments; they are not used by ped paths. They are usually positioned between two adjacent vehicle nodes on an interpolated curve.
There may be bugs if you don't connect navi nodes correctly. The order to connect them is to check first which of the 2 linked nodes is 'higher'. That means which one has the higher node ID or area ID. The direction of linking is allways from higher to lower node. So the target node of the navi nodes is allways the lower node. (Especially on area boundaries!)
#pragma pack(push, 1) struct CCarPathLink { __int16 posX; // deprecated field __int16 posY; // deprecated field CNodeAddress info; char dirX; char dirY; char m_nPathNodeWidth; char m_nFlags[2]; char field_D; }; #pragma pack(pop) #pragma pack(push, 1) struct CCarPathLink_extended : public CCarPathLink { signed __int32 extended_posX; signed __int32 extended_posY; }; #pragma pack(pop)
- Area ID and Node ID
- These identify the target node a navi node is attached to.
- Direction
- This is a normalized vector pointing towards above mentioned target node, thus defining the general direction of the path segment. The vector components are represented by signed bytes with values within the interval [-100, 100], which corresponds to floating point values [-1.0, 1.0].
- Extended position
- This is the position of the navi node in world coordinates. To convert the signed dwords to floating point values divide them by 8.
These are used to characterize path segment behavior, for more information see the table below.
0- 7 - path node width, usually a copy of the linked node's path width (byte) 8-10 - number of left lanes 11-13 - number of right lanes 14 - traffic light direction behavior 15 - zero/unused 16,17 - traffic light behavior 18 - train crossing 19-31 - zero/unused
- Right (forward) and left (backward) lanes are relative to the direction vector.
- Experience has shown that navi nodes with attachments across area borders don't work too well. A possible solution is to attach them to the last instead of the next node, reverse the direction and exchange the lane numbers (if different) and other direction dependent flags. However, this will never work if previous, navi and next node are located in different areas each. (*)
- Traffic light behavior can be a value from 0 to 2, where 1 and 2 are related to North-South and West-East cycles for traffic light synchronization.
- The traffic light direction behavior is 1 if the navi node has the same direction as the traffic light and 0 if the navi node points somewhere else.
( (*) Gots clear after knowing how Navis are linked exactly. So you may use this but it is not obligation.)
Section 3 - Links
These are links to adjacent nodes, 4 bytes per entry.
2b - UINT16 - Area ID 2b - UINT16 - Node ID
Section 4 - Filler
This section hold data of constant size and content; its purpose is unknown. These 768 bytes are filled with the repeating data pattern 0xFF,0xFF,0x00,0x00
(192x), but this can be filled with zeros as well.
These are links to adjacent navi nodes, 4 bytes per entry. For indices from ped nodes (in section 1b) these are zero (unused).
4b - UINT32 - lower 16 bit are the Navi Node ID, upper 16 bit the corresponding Area ID
Section 6 - Link Lengths
These are the distances between linked nodes in full units, 1 byte per entry. They are essential for path finding algorithms.
1b - UINT8 - Length
Section 7 - Path Intersection Flags
This section consists of intersection flag values for each node address (i.e. node link).
class CPathIntersectionInfo { public: unsigned char m_bRoadCross : 1; unsigned char m_bPedTrafficLight : 1; };
The size of section is equal to count of node addresses. The section is followed by 192 bytes of unknown data.
EOF
Path file should be terminated by a DWORD value "EOF". Otherwise, it's considered invalid.
4b - UINT32 - Last value of path file - "EOF"