CentrED/Client/UUoaDesigns.pas

188 lines
3.9 KiB
Plaintext

unit UUoaDesigns;
{$mode ObjFPC}{$H+}
{$modeSwitch advancedRecords}
interface
uses
Classes, SysUtils, Generics.Collections, UStatics;
type
{ TUoaDesignHeader }
TUoaDesignHeader = record
Name: String;
Category: String;
Subcategory: String;
Width: Int32;
Height: Int32;
UserWidth: Int32;
UserHeight: Int32;
FilePosition: Int64;
TileCount: Int32;
public
constructor CreateFromStream(AStream: TStream);
end;
{ TUoaDesignHeaders }
TUoaDesignHeaders = class(specialize TList<TUoaDesignHeader>)
constructor CreateFromStream(AStream: TStream);
end;
TUoaDesign = class
private
FHeader: TUoaDesignHeader;
FTiles: TStaticItemList;
constructor Create(AHeader: TUoaDesignHeader; AData: TStream);
public
property Header: TUoaDesignHeader read FHeader;
property Tiles: TStaticItemList read Ftiles;
destructor Destroy; override;
end;
{ TUoaDesigns }
TUoaDesigns = class
private
FHeaders: TUoaDesignHeaders;
FData: TFileStream;
public
constructor Create(AIdxFile, ABinFile: String);
destructor Destroy; override;
function LoadDesign(AHeader: TUoaDesignHeader): TUoaDesign;
public
property Headers: TUoaDesignHeaders read FHeaders;
end;
implementation
uses
Math;
function ReadString(AStream: TStream): String;
var
nonNullFlag: Byte;
length: Byte;
begin
nonNullFlag := AStream.ReadByte;
if nonNullFlag = 1 then
begin
length := AStream.ReadByte;
SetLength(Result, length);
if length > 0 then
AStream.Read(PChar(Result)^, length);
end;
end;
{ TUoaDesign }
constructor TUoaDesign.Create(AHeader: TUoaDesignHeader; AData: TStream);
var
i: Integer;
tile: TStaticItem;
version: Int32;
function ReadInt: Int32;
begin
AData.Read(Result, SizeOf(Result));
end;
begin
FHeader := AHeader;
FTiles := TStaticItemList.Create(True);
AData.Seek(FHeader.FilePosition, soFromBeginning);
for i := 0 to FHeader.TileCount - 1 do
begin
AData.Read(version, SizeOf(version));
if (version < 0) or (version > 1) then
raise Exception.Create('Unsupported binary version');
tile := TStaticItem.Create(nil);
tile.TileID := ReadInt;
tile.X := ReadInt;
tile.Y := ReadInt;
tile.Z := EnsureRange(ReadInt, -128, 127);
ReadInt; // Level; unused
if version = 1 then
tile.Hue := ReadInt;
FTiles.Add(tile);
end;
end;
destructor TUoaDesign.Destroy;
begin
FTiles.Free;
inherited Destroy;
end;
{ TUoaDesignHeaders }
constructor TUoaDesignHeaders.CreateFromStream(AStream: TStream);
var
headerCount, version: Int32;
i: Integer;
begin
AStream.Read(headerCount, SizeOf(headerCount));
AStream.Read(version, SizeOf(version));
if version <> 0 then
raise Exception.Create('Unknown UOA design index version');
inherited Create;
for i := 0 to headerCount-1 do
Add(TUoaDesignHeader.CreateFromStream(AStream));
end;
{ TUoaDesignHeader }
constructor TUoaDesignHeader.CreateFromStream(AStream: TStream);
begin
Name := ReadString(AStream);
Category := ReadString(AStream);
Subcategory := ReadString(AStream);
AStream.Read(Width, SizeOf(Width));
AStream.Read(Height, SizeOf(Height));
AStream.Read(UserWidth, SizeOf(UserWidth));
AStream.Read(UserHeight, SizeOf(UserHeight));
AStream.Read(FilePosition, SizeOf(FilePosition));
AStream.Read(TileCount, SizeOf(TileCount));
end;
{ TUoaDesigns }
constructor TUoaDesigns.Create(AIdxFile, ABinFile: String);
var
idxStream: TFileStream;
begin
idxStream := TFileStream.Create(AIdxFile, fmOpenRead);
try
FHeaders := TUoaDesignHeaders.CreateFromStream(idxStream);
finally
idxStream.Free;
end;
FData := TFileStream.Create(ABinFile, fmOpenRead);
end;
destructor TUoaDesigns.Destroy;
begin
Headers.Free;
end;
function TUoaDesigns.LoadDesign(AHeader: TUoaDesignHeader): TUoaDesign;
begin
Result := TUoaDesign.Create(AHeader, FData);
end;
end.