Load and list UOA designs

This commit is contained in:
Andreas Schneider 2022-07-19 18:24:03 +02:00
parent d75a85d269
commit 0e5cb1b48b
4 changed files with 297 additions and 41 deletions

View File

@ -325,7 +325,7 @@
<MinVersion Minor="5" Release="3" Valid="True"/> <MinVersion Minor="5" Release="3" Valid="True"/>
</Item6> </Item6>
</RequiredPackages> </RequiredPackages>
<Units Count="48"> <Units Count="49">
<Unit0> <Unit0>
<Filename Value="CentrED.lpr"/> <Filename Value="CentrED.lpr"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
@ -581,6 +581,10 @@
<Filename Value="UActions.pas"/> <Filename Value="UActions.pas"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
</Unit47> </Unit47>
<Unit48>
<Filename Value="UUoaDesigns.pas"/>
<IsPartOfProject Value="True"/>
</Unit48>
</Units> </Units>
</ProjectOptions> </ProjectOptions>
<CompilerOptions> <CompilerOptions>

158
Client/UUoaDesigns.pas Normal file
View File

@ -0,0 +1,158 @@
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;
{ TUoaDesigns }
TUoaDesigns = class
private
FHeaders: TUoaDesignHeaders;
FData: TFileStream;
public
constructor Create(AIdxFile, ABinFile: String);
destructor Destroy; override;
function LoadTiles(AHeader: TUoaDesignHeader; AOffsetX, AOffsetY: Word): TStaticItemList;
public
property Headers: TUoaDesignHeaders read FHeaders;
end;
implementation
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;
{ 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.LoadTiles(AHeader: TUoaDesignHeader; AOffsetX,
AOffsetY: Word): TStaticItemList;
var
i: Integer;
tile: TStaticItem;
version: Int32;
function ReadInt: Int32;
begin
FData.Read(Result, SizeOf(Result));
end;
begin
Result := TStaticItemList.Create(True);
FData.Seek(AHeader.FilePosition, soFromBeginning);
for i := 0 to AHeader.TileCount - 1 do
begin
FData.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 := AOffsetX + ReadInt;
tile.Y := AOffsetY + ReadInt;
tile.Z := ReadInt;
ReadInt; // TODO: Level??
if version = 1 then
tile.Hue := ReadInt;
Result.Add(tile);
end;
end;
end.

View File

@ -1,12 +1,12 @@
object frmMain: TfrmMain object frmMain: TfrmMain
Left = 87 Left = 87
Height = 961 Height = 781
Top = 70 Top = 70
Width = 1180 Width = 1172
ActiveControl = oglGameWindow ActiveControl = oglGameWindow
Caption = 'UO CentrED' Caption = 'UO CentrED'
ClientHeight = 961 ClientHeight = 781
ClientWidth = 1180 ClientWidth = 1172
Constraints.MinHeight = 781 Constraints.MinHeight = 781
Constraints.MinWidth = 1172 Constraints.MinWidth = 1172
DesignTimePPI = 120 DesignTimePPI = 120
@ -23,12 +23,12 @@ object frmMain: TfrmMain
object pnlBottom: TPanel object pnlBottom: TPanel
Left = 0 Left = 0
Height = 49 Height = 49
Top = 912 Top = 732
Width = 1180 Width = 1172
Align = alBottom Align = alBottom
BevelOuter = bvNone BevelOuter = bvNone
ClientHeight = 49 ClientHeight = 49
ClientWidth = 1180 ClientWidth = 1172
TabOrder = 0 TabOrder = 0
object lblX: TLabel object lblX: TLabel
Left = 18 Left = 18
@ -61,7 +61,7 @@ object frmMain: TfrmMain
Transparent = False Transparent = False
end end
object lblTip: TLabel object lblTip: TLabel
Left = 803 Left = 795
Height = 49 Height = 49
Top = 0 Top = 0
Width = 365 Width = 365
@ -75,7 +75,7 @@ object frmMain: TfrmMain
Transparent = False Transparent = False
end end
object lblTipC: TLabel object lblTipC: TLabel
Left = 767 Left = 759
Height = 49 Height = 49
Top = 0 Top = 0
Width = 36 Width = 36
@ -118,16 +118,16 @@ object frmMain: TfrmMain
end end
object pcLeft: TPageControl object pcLeft: TPageControl
Left = 0 Left = 0
Height = 874 Height = 694
Top = 38 Top = 38
Width = 350 Width = 350
ActivePage = tsTiles ActivePage = tsUoaDesigns
Align = alLeft Align = alLeft
TabIndex = 0 TabIndex = 3
TabOrder = 1 TabOrder = 1
object tsTiles: TTabSheet object tsTiles: TTabSheet
Caption = 'Tiles' Caption = 'Tiles'
ClientHeight = 836 ClientHeight = 656
ClientWidth = 340 ClientWidth = 340
object lblFilter: TLabel object lblFilter: TLabel
AnchorSideLeft.Control = cbTerrain AnchorSideLeft.Control = cbTerrain
@ -152,7 +152,7 @@ object frmMain: TfrmMain
AnchorSideRight.Side = asrBottom AnchorSideRight.Side = asrBottom
AnchorSideBottom.Control = spTileList AnchorSideBottom.Control = spTileList
Left = 6 Left = 6
Height = 493 Height = 313
Hint = '-' Hint = '-'
Top = 74 Top = 74
Width = 328 Width = 328
@ -213,7 +213,7 @@ object frmMain: TfrmMain
AnchorSideBottom.Side = asrBottom AnchorSideBottom.Side = asrBottom
Left = 0 Left = 0
Height = 261 Height = 261
Top = 575 Top = 395
Width = 340 Width = 340
Anchors = [akTop, akLeft, akRight, akBottom] Anchors = [akTop, akLeft, akRight, akBottom]
Caption = 'Random pool' Caption = 'Random pool'
@ -552,7 +552,7 @@ object frmMain: TfrmMain
Cursor = crVSplit Cursor = crVSplit
Left = 0 Left = 0
Height = 8 Height = 8
Top = 567 Top = 387
Width = 340 Width = 340
Align = alNone Align = alNone
Anchors = [akLeft, akRight, akBottom] Anchors = [akLeft, akRight, akBottom]
@ -566,7 +566,7 @@ object frmMain: TfrmMain
Left = 172 Left = 172
Height = 38 Height = 38
Hint = 'Append S or T to restrict the search to Statics or Terrain.' Hint = 'Append S or T to restrict the search to Statics or Terrain.'
Top = 517 Top = 337
Width = 150 Width = 150
Anchors = [akRight, akBottom] Anchors = [akRight, akBottom]
BorderSpacing.Right = 12 BorderSpacing.Right = 12
@ -627,11 +627,11 @@ object frmMain: TfrmMain
end end
object tsClients: TTabSheet object tsClients: TTabSheet
Caption = 'Clients' Caption = 'Clients'
ClientHeight = 836 ClientHeight = 656
ClientWidth = 340 ClientWidth = 340
object lbClients: TListBox object lbClients: TListBox
Left = 0 Left = 0
Height = 836 Height = 656
Top = 0 Top = 0
Width = 340 Width = 340
Align = alClient Align = alClient
@ -646,7 +646,7 @@ object frmMain: TfrmMain
end end
object tsLocations: TTabSheet object tsLocations: TTabSheet
Caption = 'Locations' Caption = 'Locations'
ClientHeight = 836 ClientHeight = 656
ClientWidth = 340 ClientWidth = 340
object btnClearLocations: TSpeedButton object btnClearLocations: TSpeedButton
AnchorSideLeft.Control = btnDeleteLocation AnchorSideLeft.Control = btnDeleteLocation
@ -655,7 +655,7 @@ object frmMain: TfrmMain
Left = 194 Left = 194
Height = 35 Height = 35
Hint = 'Clear' Hint = 'Clear'
Top = 795 Top = 615
Width = 36 Width = 36
BorderSpacing.Left = 6 BorderSpacing.Left = 6
Glyph.Data = { Glyph.Data = {
@ -706,7 +706,7 @@ object frmMain: TfrmMain
Left = 152 Left = 152
Height = 35 Height = 35
Hint = 'Delete' Hint = 'Delete'
Top = 795 Top = 615
Width = 36 Width = 36
Anchors = [akLeft, akBottom] Anchors = [akLeft, akBottom]
BorderSpacing.Bottom = 6 BorderSpacing.Bottom = 6
@ -756,7 +756,7 @@ object frmMain: TfrmMain
Left = 110 Left = 110
Height = 35 Height = 35
Hint = 'Add' Hint = 'Add'
Top = 795 Top = 615
Width = 36 Width = 36
Anchors = [akTop, akRight] Anchors = [akTop, akRight]
BorderSpacing.Right = 6 BorderSpacing.Right = 6
@ -808,7 +808,7 @@ object frmMain: TfrmMain
AnchorSideBottom.Control = btnDeleteLocation AnchorSideBottom.Control = btnDeleteLocation
Cursor = 63 Cursor = 63
Left = 6 Left = 6
Height = 783 Height = 603
Top = 6 Top = 6
Width = 328 Width = 328
Anchors = [akTop, akLeft, akRight, akBottom] Anchors = [akTop, akLeft, akRight, akBottom]
@ -824,7 +824,7 @@ object frmMain: TfrmMain
item item
Position = 1 Position = 1
Text = 'Name' Text = 'Name'
Width = 206 Width = 208
end> end>
Header.DefaultHeight = 26 Header.DefaultHeight = 26
Header.Height = 26 Header.Height = 26
@ -843,12 +843,46 @@ object frmMain: TfrmMain
OnSaveNode = vstLocationsSaveNode OnSaveNode = vstLocationsSaveNode
end end
end end
object tsUoaDesigns: TTabSheet
Caption = 'UOA Designs'
ClientHeight = 656
ClientWidth = 340
object vstUoaDesigns: TLazVirtualStringTree
Cursor = 63
Left = 8
Height = 640
Top = 8
Width = 324
Align = alClient
BorderSpacing.Around = 8
DefaultNodeHeight = 26
DefaultText = 'Node'
Header.AutoSizeIndex = 0
Header.Columns = <
item
Position = 0
Text = 'Name'
Width = 200
end
item
Position = 1
Text = 'Category'
Width = 100
end>
Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible]
TabOrder = 0
TreeOptions.MiscOptions = [toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning]
TreeOptions.PaintOptions = [toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages]
TreeOptions.SelectionOptions = [toFullRowSelect]
OnGetText = vstUoaDesignsGetText
end
end
end end
object tbMain: TToolBar object tbMain: TToolBar
Left = 0 Left = 0
Height = 38 Height = 38
Top = 0 Top = 0
Width = 1180 Width = 1172
Caption = 'tbMain' Caption = 'tbMain'
Images = ImageList1 Images = ImageList1
ParentShowHint = False ParentShowHint = False
@ -1038,13 +1072,13 @@ object frmMain: TfrmMain
AnchorSideBottom.Control = spChat AnchorSideBottom.Control = spChat
Left = 350 Left = 350
Height = 35 Height = 35
Top = 667 Top = 487
Width = 830 Width = 822
Anchors = [akLeft, akRight, akBottom] Anchors = [akLeft, akRight, akBottom]
BevelInner = bvRaised BevelInner = bvRaised
BevelOuter = bvLowered BevelOuter = bvLowered
ClientHeight = 35 ClientHeight = 35
ClientWidth = 830 ClientWidth = 822
TabOrder = 3 TabOrder = 3
object lblChatHeaderCaption: TLabel object lblChatHeaderCaption: TLabel
Cursor = crHandPoint Cursor = crHandPoint
@ -1074,12 +1108,12 @@ object frmMain: TfrmMain
AnchorSideBottom.Control = pnlBottom AnchorSideBottom.Control = pnlBottom
Left = 350 Left = 350
Height = 202 Height = 202
Top = 710 Top = 530
Width = 830 Width = 822
Anchors = [akTop, akLeft, akRight, akBottom] Anchors = [akTop, akLeft, akRight, akBottom]
BevelOuter = bvNone BevelOuter = bvNone
ClientHeight = 202 ClientHeight = 202
ClientWidth = 830 ClientWidth = 822
TabOrder = 4 TabOrder = 4
Visible = False Visible = False
object vstChat: TLazVirtualStringTree object vstChat: TLazVirtualStringTree
@ -1087,7 +1121,7 @@ object frmMain: TfrmMain
Left = 0 Left = 0
Height = 164 Height = 164
Top = 0 Top = 0
Width = 830 Width = 822
Align = alClient Align = alClient
DefaultText = 'Node' DefaultText = 'Node'
Header.AutoSizeIndex = 2 Header.AutoSizeIndex = 2
@ -1105,7 +1139,7 @@ object frmMain: TfrmMain
item item
Position = 2 Position = 2
Text = 'Message' Text = 'Message'
Width = 592 Width = 584
end> end>
Header.DefaultHeight = 26 Header.DefaultHeight = 26
Header.Height = 26 Header.Height = 26
@ -1126,7 +1160,7 @@ object frmMain: TfrmMain
Left = 0 Left = 0
Height = 38 Height = 38
Top = 164 Top = 164
Width = 830 Width = 822
Align = alBottom Align = alBottom
OnKeyPress = edChatKeyPress OnKeyPress = edChatKeyPress
TabOrder = 1 TabOrder = 1
@ -1140,8 +1174,8 @@ object frmMain: TfrmMain
Cursor = crVSplit Cursor = crVSplit
Left = 350 Left = 350
Height = 8 Height = 8
Top = 702 Top = 522
Width = 830 Width = 822
Align = alNone Align = alNone
Anchors = [akLeft, akRight, akBottom] Anchors = [akLeft, akRight, akBottom]
AutoSnap = False AutoSnap = False
@ -1157,9 +1191,9 @@ object frmMain: TfrmMain
AnchorSideRight.Side = asrBottom AnchorSideRight.Side = asrBottom
AnchorSideBottom.Control = pnlChatHeader AnchorSideBottom.Control = pnlChatHeader
Left = 350 Left = 350
Height = 629 Height = 449
Top = 38 Top = 38
Width = 830 Width = 822
Anchors = [akTop, akLeft, akRight, akBottom] Anchors = [akTop, akLeft, akRight, akBottom]
OnDblClick = oglGameWindowDblClick OnDblClick = oglGameWindowDblClick
OnKeyDown = oglGameWindowKeyDown OnKeyDown = oglGameWindowKeyDown

View File

@ -37,7 +37,7 @@ uses
LCLIntf, UOverlayUI, UStatics, UEnhancedMemoryStream, ActnList, LCLIntf, UOverlayUI, UStatics, UEnhancedMemoryStream, ActnList,
XMLPropStorage, ImagingClasses, dateutils, UPlatformTypes, UMap, UPacket, XMLPropStorage, ImagingClasses, dateutils, UPlatformTypes, UMap, UPacket,
UGLFont, DOM, XMLRead, XMLWrite, strutils, ULightManager, fgl, UTiledata, UGLFont, DOM, XMLRead, XMLWrite, strutils, ULightManager, fgl, UTiledata,
UActions; UActions, UUoaDesigns;
type type
TAccessChangedListener = procedure(AAccessLevel: TAccessLevel) of object; TAccessChangedListener = procedure(AAccessLevel: TAccessLevel) of object;
@ -97,6 +97,7 @@ type
edSearchID: TEdit; edSearchID: TEdit;
gbRandom: TGroupBox; gbRandom: TGroupBox;
ImageList1: TImageList; ImageList1: TImageList;
vstUoaDesigns: TLazVirtualStringTree;
lblChatHeaderCaption: TLabel; lblChatHeaderCaption: TLabel;
lblFilter: TLabel; lblFilter: TLabel;
lblTipC: TLabel; lblTipC: TLabel;
@ -162,6 +163,7 @@ type
pmViewTerrainSettings: TPopupMenu; pmViewTerrainSettings: TPopupMenu;
spChat: TSplitter; spChat: TSplitter;
spTileList: TSplitter; spTileList: TSplitter;
tsUoaDesigns: TTabSheet;
tbFilter: TToolButton; tbFilter: TToolButton;
tbFlat: TToolButton; tbFlat: TToolButton;
tbNoDraw: TToolButton; tbNoDraw: TToolButton;
@ -320,6 +322,9 @@ type
Column: TColumnIndex; const NewText: String); Column: TColumnIndex; const NewText: String);
procedure vstLocationsSaveNode(Sender: TBaseVirtualTree; procedure vstLocationsSaveNode(Sender: TBaseVirtualTree;
Node: PVirtualNode; Stream: TStream); Node: PVirtualNode; Stream: TStream);
procedure vstUoaDesignsGetText(Sender: TBaseVirtualTree;
Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
var CellText: String);
procedure XMLPropStorage1RestoreProperties(Sender: TObject); procedure XMLPropStorage1RestoreProperties(Sender: TObject);
protected protected
{ Members } { Members }
@ -357,6 +362,7 @@ type
FTileHint: TTileHintInfo; FTileHint: TTileHintInfo;
FLightManager: TLightManager; FLightManager: TLightManager;
FTileFilter: TTileDataFlags; FTileFilter: TTileDataFlags;
FUoaDesigns: TUoaDesigns;
{ Methods } { Methods }
procedure BuildTileList; procedure BuildTileList;
function ConfirmAction: Boolean; function ConfirmAction: Boolean;
@ -369,6 +375,7 @@ type
procedure InitSize; procedure InitSize;
procedure LoadLocations; procedure LoadLocations;
procedure LoadRandomPresets; procedure LoadRandomPresets;
procedure LoadUoaDesigns;
procedure MoveBy(AOffsetX, AOffsetY: Integer); inline; procedure MoveBy(AOffsetX, AOffsetY: Integer); inline;
procedure PrepareMapCell(AMapCell: TMapCell); procedure PrepareMapCell(AMapCell: TMapCell);
procedure PrepareScreenBlock(ABlockInfo: PBlockInfo); procedure PrepareScreenBlock(ABlockInfo: PBlockInfo);
@ -1023,6 +1030,8 @@ begin
FRandomPresetsFile := FConfigDir + 'RandomPresets.xml'; FRandomPresetsFile := FConfigDir + 'RandomPresets.xml';
LoadRandomPresets; LoadRandomPresets;
LoadUoaDesigns;
DoubleBuffered := True; DoubleBuffered := True;
pnlBottom.DoubleBuffered := True; pnlBottom.DoubleBuffered := True;
@ -1030,6 +1039,8 @@ begin
FSelectionListeners := TSelectionListeners.Create; FSelectionListeners := TSelectionListeners.Create;
FLastDraw := Now; FLastDraw := Now;
pcLeft.ActivePage := tsTiles;
end; end;
procedure TfrmMain.btnGoToClick(Sender: TObject); procedure TfrmMain.btnGoToClick(Sender: TObject);
@ -1396,6 +1407,7 @@ begin
FreeAndNil(FRandomPresetsDoc); FreeAndNil(FRandomPresetsDoc);
FreeAndNil(FAccessChangedListeners); FreeAndNil(FAccessChangedListeners);
FreeAndNil(FSelectionListeners); FreeAndNil(FSelectionListeners);
FreeAndNil(FUoaDesigns);
RegisterPacketHandler($0C, nil); RegisterPacketHandler($0C, nil);
end; end;
@ -1974,6 +1986,34 @@ begin
Stream.Write(locationInfo^.Name[1], stringLength); Stream.Write(locationInfo^.Name[1], stringLength);
end; end;
procedure TfrmMain.vstUoaDesignsGetText(Sender: TBaseVirtualTree;
Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
var CellText: String);
var
header: TUoaDesignHeader;
function BuildCategoryName: String;
begin
if header.Category <> EmptyStr then
Result := header.Category;
if header.Subcategory <> EmptyStr then
begin
if Result <> EmptyStr then
Result := Result + '/';
Result := Result + header.Subcategory;
end;
end;
begin
header := FUoaDesigns.Headers[Node^.Index];
case Column of
0: CellText := header.Name;
1: CellText := BuildCategoryName;
end;
end;
procedure TfrmMain.XMLPropStorage1RestoreProperties(Sender: TObject); procedure TfrmMain.XMLPropStorage1RestoreProperties(Sender: TObject);
begin begin
FTextureManager.UseAnims := mnuShowAnimations.Checked; FTextureManager.UseAnims := mnuShowAnimations.Checked;
@ -2206,6 +2246,26 @@ begin
end; end;
end; end;
procedure TfrmMain.LoadUoaDesigns;
var
idxFile, binFile: String;
i: Integer;
begin
idxFile := FAppDir + 'Designs.idx';
binFile := FAppDir + 'Designs.bin';
if (not FileExists(idxFile)) or (not FileExists(binFile)) then
begin
tsUoaDesigns.TabVisible := False;
Exit;
end;
FUoaDesigns := TUoaDesigns.Create(idxFile, binFile);
tsUoaDesigns.TabVisible := True;
for i := 1 to FUoaDesigns.Headers.Count do
vstUoaDesigns.AddChild(nil);
end;
procedure TfrmMain.MoveBy(AOffsetX, AOffsetY: Integer); inline; procedure TfrmMain.MoveBy(AOffsetX, AOffsetY: Integer); inline;
begin begin
SetPos(EnsureRange(FX + AOffsetX, 0, FLandscape.CellWidth - 1), SetPos(EnsureRange(FX + AOffsetX, 0, FLandscape.CellWidth - 1),