Gra/Midtown Madness 2/PSDL

Z Rainsted
Skocz do: nawigacji, wyszukiwania

Struktura PSDL została opisana na podstawie analiz i eksperymentów w latach 2002/2003.

Struktury pomocnicze

Punkt 3D

Są to współrzędne wierzchołka, który może należeć do wielu trójkątów. Ponieważ współrzędne są zapisywane jako liczba zmiennoprzecinkowa o mantysie 23-bitowej, w odległości 8km od osi niedokładności obliczeń będą rzędu 1mm. Oznacza to, że w sceneriach powyżej 16km średnicy mogą występować zauważalne drgania trójkątów.

Ze względu na dwubajtową numerację wierzchołków, sceneria nie może mieć ich więcej niż 65536. Niemniej część obiektów (np. ściany) można wstawić również w inny sposób.

struct Vertex
{
 float x;
 float y;
 float z;
}

Łańcuch znaków

Posiada zarówno jednobajtowy licznik jak i znacznik końca. Używany do zapisywania nazw tekstur. Licznik obejmuje znacznik końca, ale nie bajt licznika.

struct String
{
 uchar length; //długość łącznie ze znacznikiem końca
 char string[length-1]; //nazwa pliku tekstury
 char terminator; //0x00 znacznik końca
}

Struktury główne

Wysokości

Lista wysokości służy do wyrównania linii zabudowy. Umieszczając fasady budynków i dachy wskazuje się dolną i górną wysokość z listy. Wysokości te podmieniają współrzędną pionową w wierzchołkach o podanych numerach. Dzięki temu nie ma potrzeby definiowania wierzchołków, które miałyby te same współrzędną w planie, a różniły się wysokością.

Bloki terenu

Blok terenu składa się z informacji o sąsiednich blokach oraz atrybutów. Atrybuty ustalają teksturę oraz sposób budowania siatki z wierzchołków - patrz dalej.

struct Block
{
 ulong nPerimeterPoints; //ilość zewnętrznych wierzchołków
 ulong attributeSize; //rozmiar pola atrybutów w dwubajtach
 PerimeterPoint perimeter[nPerimeterPoints]; //lista sąsiadów
 ushort attributes[attributeSize]; //atrybuty
}

Wierzchołek zewnętrzny

Wierzchołek zewnętrzny informuje o styku z sąsiednim blokiem w nim. Nie ma wpływu na tworzenie siatki bloku. Najprawdopodobniej służy do "uszczelniania" połączeń pomiędzy blokami i wyliczania przejścia z jednego bloku na inny. Dla każdego z zewnętrznych wierzchołków należy podać numer+1 sąsiedniego bloku. Jeśli w danym wierzchołku jest styk z kilkoma innymi blokami, numer wierzchołka należy powtórzyć osobno dla każdego bloku. Wartość 0 oznacza brak sąsiedniego bloku (np. krawędź). Wierzchołki podaje się w kolejności zgodnej z ruchem wskazówek zegara.

struct PerimeterPoint
{
 ushort vertex; //numer wierzchołka
 ushort block; //numer+1 sąsiedniego bloku w tym wierzchołku
}

Droga

Informacje o drogach nie są wymagane do zwykłego działania scenerii. Służą one do ustawiania obiektów wzdłuż dróg, takich jak latarnie. Nie mają one znaczenia dla ruchu sterowanego przez komputer (tzw. ruch uliczny).

struct Road
{
 ushort unknown4;
 ushort unknown5;
 ubyte nFLanes; //ilość rzędów po lewej stronie?
 ubyte nBLanes; //ilość rzędów po prawej stronie?
 float density[nFLanes+nBLanes]; //zagęszczenie obiektów?
 ushort unknown6; //wygląda na flagi bitowe
 ushort startCrossroads[4]; //wierzchołki na początku drogi
 ushort endCrossroads[4]; //wierzchołki na końcu drogi
 uchar nRoadBlocks; //ilość bloków składających się na drogę
 ushort roadBlocks[nRoadBlocks]; //numer+1 każdego z bloków
}

Plik PSDL

Plik ten zawiera informacje o wierzchołkach, wysokościach (dla fasad i dachów budynków), turach, blokach oraz drogach, składających się na scenerię. Dane są rozmieszczane z dokładnością bajtową (nie ma bajtów wypełniających do okrągłych adresów).

struct PSDL
{
 char identifier[4] = "PSD0";
 ulong targetSize = 2; //unknown
 ulong nVertices; //ilość wierzchołków
 Vertex vertices[nVertices]; //wierzchołki (współrzędne XYZ)
 ulong nHeights; //ilość wysokości
 float heights[nHeights]; //wysokości
 ulong nTextures; //ilość+1 tekstur
 String textures[nTextures]; //nazwy tekstur
 ulong nBlocks; //ilość+1 bloków
 ulong unknown0; //ilość połączeń?
 Block blocks[nBlocks-1]; //informacje o blokach
 char blockType[]; //list of bytes with block type flags Starting with 0x00 and ending with 0xCD
 char unknown2[nBlocks-1]; //list of bytes

 //wymiary terenu:
 Vertex min; //skrajne wierzchołki definiujące prostopadłościan
 Vertex max; //obejmujący cały teren
 Vertex center; //unknown
 float unknown3;

 //informacje o drogach dla automatycznego ruchu
 ulong nRoads; //ilość dróg
 Road roads[nRoads]; //definicje dróg
}

Atrybuty

Atrybuty są strukturami o zmiennej wielkości (dla każdego typu atrybutu jest stała wielkość struktury, dla różnych typów, mogą się różnić).

Jeśli atrybut posiada ustawiony bit 7 (0x0080), oznacza to, że jest ostatnim. Wszelkie atrybuty umieszczone za nim, nie będą używane.

Bity w masce 0x0007 są dodatkowymi danymi. Dla dróg jest to liczba przekrojów (0 - liczba podana w następnym dwubajcie), dla tekstur dodatkowe 3 bity indeksu tekstury.

Numer tekstury

  • 0x0050 - numer tekstury odniesienia

Poszczególny blok może używać kilku tekstur, podaje się numer tylko pierwszej. Automatycznie używane są kolejne, np. +1 i +2. Ponieważ wartość index może pomieścić tylko wartości 0..255, trzy bity starszego bajtu pobierane są z kodu atrybutu (maska 0x0007).

struct BlockAttribute_5n
{
 short id; //0x0050..0x0057
 short index; //indeks tekstury+1
}

Segmenty drogi

Dostępne są 3 rodzaje przekrojów drogi:

  • o 2 wierzchołkach - drogi bez chodnika albo chodniki
  • o 4 wierzchołkach - drogi z chodnikiem
  • o 6 wierzchołkach - drogi dwujezdniowe z chodnikiem

Poszczególne wierzchołki podawane są od lewej strony

struct RoadSection2
{
 short p[2];
}

struct RoadSection4
{
 short p[4];
}

struct RoadSection6
{
 short p[6];
}


  • 0x0000 - droga o 4 punktach przekroju (pojedyncza z chodnikiem)
struct BlockAttribute_00
{
 short id; //0x0000 albo 0x0080
 short counter; //ilość wierzchołków
 RoadSection4 crossection[counter];
}
  • 0x0002 - 0x0007 - droga o kilku punktach przekroju

Najmłodsze 3 bity określają ilość przekrojów z przedziału 2..7. Przykładowo, dla 0x0004 są 4 przekroje, czyli 16 wierzchołków.

struct BlockAttribute_00n
{
 short id; //0x0002..0x0007 albo 0x0082..0x0087
 RoadSection4 crossection[n];
}
  • 0x0008 - droga bez chodnika (2 punkty), dowolna liczba przekrojów
  • 0x000A..0x000F - droga bez chodnika, kilka przekrojów
struct BlockAttribute_08
{
 short id; //0x0009..0x000F albo 0x0089..0x008F
 short RoadSection2 crossection[n];
}
  • 0x0040 - podwójna droga (6 punktów)
  • 0x0042-0x0047 - podwójna droga (6 punktów)
struct BlockAttribute_40n
{
 ushort attributeID; //0x0042..0x0047 albo 0x00C2..0x00C7
 ushort unknown1; //typ wypełnienia pomiędzy jezdniami
 ushort unknown2;
 RoadSection6 crossection[n];
}

Wachlarz trójkątów

Trójkąty zgodnie z kierunkiem ruchu wskazówek zegara. Dla zapewnienia co najmniej jednego trójkąta, na końcu są dwa powtórzone wierzchołki.

  • 0x0030 - wachlarz o dowolnej liczbie trójkątów
struct BlockAttribute_30
{
 short id; //0x0030 albo 0x00B0
 short nVertices; //ilość wierzchołków
 short vertices[nVertices]; //indeksy wierzchołków
 short lastVertex; //indeks ostatniego wierzchołka
 short pivot; //indeks wierzchołka wspólnego, taki sam jak vertices[0]
}
  • 0x0031 - wachlarz o kilku trójkątach
struct BlockAttribute_30n
{
 short id; //0x0031..0x0037 albo 0x00B1..0x00B7
 short vertices[n]; //indeksy wierzchołków
}

Nieznane atrybuty

  • 0x0024 - crosswalk strip, four vertices
struct BlockAttribute_0024
{
 short id; // 0x0024
 short[4] unknown;
}
  • 0x002A - road triangle fan, four vertices
struct BlockAttribute_002A
{
 short id; // 0x002A
 short[4] unknown;
}
  • 0x002E - road triangle fan

Linki

Opis struktury (ang.)

Opis struktury (ang.)