From 0e5cb1b48ba9aa8a224ab04195b055a6885dec67 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Tue, 19 Jul 2022 18:24:03 +0200 Subject: [PATCH 1/8] =?UTF-8?q?=E2=9C=A8=20Load=20and=20list=20UOA=20desig?= =?UTF-8?q?ns?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Client/CentrED.lpi | 6 +- Client/UUoaDesigns.pas | 158 +++++++++++++++++++++++++++++++++++++++++ Client/UfrmMain.lfm | 112 +++++++++++++++++++---------- Client/UfrmMain.pas | 62 +++++++++++++++- 4 files changed, 297 insertions(+), 41 deletions(-) create mode 100644 Client/UUoaDesigns.pas diff --git a/Client/CentrED.lpi b/Client/CentrED.lpi index 133db83..496dd86 100644 --- a/Client/CentrED.lpi +++ b/Client/CentrED.lpi @@ -325,7 +325,7 @@ - + @@ -581,6 +581,10 @@ + + + + diff --git a/Client/UUoaDesigns.pas b/Client/UUoaDesigns.pas new file mode 100644 index 0000000..f609f9c --- /dev/null +++ b/Client/UUoaDesigns.pas @@ -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) + 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. + diff --git a/Client/UfrmMain.lfm b/Client/UfrmMain.lfm index 2ac5abe..fd33611 100644 --- a/Client/UfrmMain.lfm +++ b/Client/UfrmMain.lfm @@ -1,12 +1,12 @@ object frmMain: TfrmMain Left = 87 - Height = 961 + Height = 781 Top = 70 - Width = 1180 + Width = 1172 ActiveControl = oglGameWindow Caption = 'UO CentrED' - ClientHeight = 961 - ClientWidth = 1180 + ClientHeight = 781 + ClientWidth = 1172 Constraints.MinHeight = 781 Constraints.MinWidth = 1172 DesignTimePPI = 120 @@ -23,12 +23,12 @@ object frmMain: TfrmMain object pnlBottom: TPanel Left = 0 Height = 49 - Top = 912 - Width = 1180 + Top = 732 + Width = 1172 Align = alBottom BevelOuter = bvNone ClientHeight = 49 - ClientWidth = 1180 + ClientWidth = 1172 TabOrder = 0 object lblX: TLabel Left = 18 @@ -61,7 +61,7 @@ object frmMain: TfrmMain Transparent = False end object lblTip: TLabel - Left = 803 + Left = 795 Height = 49 Top = 0 Width = 365 @@ -75,7 +75,7 @@ object frmMain: TfrmMain Transparent = False end object lblTipC: TLabel - Left = 767 + Left = 759 Height = 49 Top = 0 Width = 36 @@ -118,16 +118,16 @@ object frmMain: TfrmMain end object pcLeft: TPageControl Left = 0 - Height = 874 + Height = 694 Top = 38 Width = 350 - ActivePage = tsTiles + ActivePage = tsUoaDesigns Align = alLeft - TabIndex = 0 + TabIndex = 3 TabOrder = 1 object tsTiles: TTabSheet Caption = 'Tiles' - ClientHeight = 836 + ClientHeight = 656 ClientWidth = 340 object lblFilter: TLabel AnchorSideLeft.Control = cbTerrain @@ -152,7 +152,7 @@ object frmMain: TfrmMain AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = spTileList Left = 6 - Height = 493 + Height = 313 Hint = '-' Top = 74 Width = 328 @@ -213,7 +213,7 @@ object frmMain: TfrmMain AnchorSideBottom.Side = asrBottom Left = 0 Height = 261 - Top = 575 + Top = 395 Width = 340 Anchors = [akTop, akLeft, akRight, akBottom] Caption = 'Random pool' @@ -552,7 +552,7 @@ object frmMain: TfrmMain Cursor = crVSplit Left = 0 Height = 8 - Top = 567 + Top = 387 Width = 340 Align = alNone Anchors = [akLeft, akRight, akBottom] @@ -566,7 +566,7 @@ object frmMain: TfrmMain Left = 172 Height = 38 Hint = 'Append S or T to restrict the search to Statics or Terrain.' - Top = 517 + Top = 337 Width = 150 Anchors = [akRight, akBottom] BorderSpacing.Right = 12 @@ -627,11 +627,11 @@ object frmMain: TfrmMain end object tsClients: TTabSheet Caption = 'Clients' - ClientHeight = 836 + ClientHeight = 656 ClientWidth = 340 object lbClients: TListBox Left = 0 - Height = 836 + Height = 656 Top = 0 Width = 340 Align = alClient @@ -646,7 +646,7 @@ object frmMain: TfrmMain end object tsLocations: TTabSheet Caption = 'Locations' - ClientHeight = 836 + ClientHeight = 656 ClientWidth = 340 object btnClearLocations: TSpeedButton AnchorSideLeft.Control = btnDeleteLocation @@ -655,7 +655,7 @@ object frmMain: TfrmMain Left = 194 Height = 35 Hint = 'Clear' - Top = 795 + Top = 615 Width = 36 BorderSpacing.Left = 6 Glyph.Data = { @@ -706,7 +706,7 @@ object frmMain: TfrmMain Left = 152 Height = 35 Hint = 'Delete' - Top = 795 + Top = 615 Width = 36 Anchors = [akLeft, akBottom] BorderSpacing.Bottom = 6 @@ -756,7 +756,7 @@ object frmMain: TfrmMain Left = 110 Height = 35 Hint = 'Add' - Top = 795 + Top = 615 Width = 36 Anchors = [akTop, akRight] BorderSpacing.Right = 6 @@ -808,7 +808,7 @@ object frmMain: TfrmMain AnchorSideBottom.Control = btnDeleteLocation Cursor = 63 Left = 6 - Height = 783 + Height = 603 Top = 6 Width = 328 Anchors = [akTop, akLeft, akRight, akBottom] @@ -824,7 +824,7 @@ object frmMain: TfrmMain item Position = 1 Text = 'Name' - Width = 206 + Width = 208 end> Header.DefaultHeight = 26 Header.Height = 26 @@ -843,12 +843,46 @@ object frmMain: TfrmMain OnSaveNode = vstLocationsSaveNode 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 object tbMain: TToolBar Left = 0 Height = 38 Top = 0 - Width = 1180 + Width = 1172 Caption = 'tbMain' Images = ImageList1 ParentShowHint = False @@ -1038,13 +1072,13 @@ object frmMain: TfrmMain AnchorSideBottom.Control = spChat Left = 350 Height = 35 - Top = 667 - Width = 830 + Top = 487 + Width = 822 Anchors = [akLeft, akRight, akBottom] BevelInner = bvRaised BevelOuter = bvLowered ClientHeight = 35 - ClientWidth = 830 + ClientWidth = 822 TabOrder = 3 object lblChatHeaderCaption: TLabel Cursor = crHandPoint @@ -1074,12 +1108,12 @@ object frmMain: TfrmMain AnchorSideBottom.Control = pnlBottom Left = 350 Height = 202 - Top = 710 - Width = 830 + Top = 530 + Width = 822 Anchors = [akTop, akLeft, akRight, akBottom] BevelOuter = bvNone ClientHeight = 202 - ClientWidth = 830 + ClientWidth = 822 TabOrder = 4 Visible = False object vstChat: TLazVirtualStringTree @@ -1087,7 +1121,7 @@ object frmMain: TfrmMain Left = 0 Height = 164 Top = 0 - Width = 830 + Width = 822 Align = alClient DefaultText = 'Node' Header.AutoSizeIndex = 2 @@ -1105,7 +1139,7 @@ object frmMain: TfrmMain item Position = 2 Text = 'Message' - Width = 592 + Width = 584 end> Header.DefaultHeight = 26 Header.Height = 26 @@ -1126,7 +1160,7 @@ object frmMain: TfrmMain Left = 0 Height = 38 Top = 164 - Width = 830 + Width = 822 Align = alBottom OnKeyPress = edChatKeyPress TabOrder = 1 @@ -1140,8 +1174,8 @@ object frmMain: TfrmMain Cursor = crVSplit Left = 350 Height = 8 - Top = 702 - Width = 830 + Top = 522 + Width = 822 Align = alNone Anchors = [akLeft, akRight, akBottom] AutoSnap = False @@ -1157,9 +1191,9 @@ object frmMain: TfrmMain AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = pnlChatHeader Left = 350 - Height = 629 + Height = 449 Top = 38 - Width = 830 + Width = 822 Anchors = [akTop, akLeft, akRight, akBottom] OnDblClick = oglGameWindowDblClick OnKeyDown = oglGameWindowKeyDown diff --git a/Client/UfrmMain.pas b/Client/UfrmMain.pas index cb4a749..f0f58be 100644 --- a/Client/UfrmMain.pas +++ b/Client/UfrmMain.pas @@ -37,7 +37,7 @@ uses LCLIntf, UOverlayUI, UStatics, UEnhancedMemoryStream, ActnList, XMLPropStorage, ImagingClasses, dateutils, UPlatformTypes, UMap, UPacket, UGLFont, DOM, XMLRead, XMLWrite, strutils, ULightManager, fgl, UTiledata, - UActions; + UActions, UUoaDesigns; type TAccessChangedListener = procedure(AAccessLevel: TAccessLevel) of object; @@ -97,6 +97,7 @@ type edSearchID: TEdit; gbRandom: TGroupBox; ImageList1: TImageList; + vstUoaDesigns: TLazVirtualStringTree; lblChatHeaderCaption: TLabel; lblFilter: TLabel; lblTipC: TLabel; @@ -162,6 +163,7 @@ type pmViewTerrainSettings: TPopupMenu; spChat: TSplitter; spTileList: TSplitter; + tsUoaDesigns: TTabSheet; tbFilter: TToolButton; tbFlat: TToolButton; tbNoDraw: TToolButton; @@ -320,6 +322,9 @@ type Column: TColumnIndex; const NewText: String); procedure vstLocationsSaveNode(Sender: TBaseVirtualTree; Node: PVirtualNode; Stream: TStream); + procedure vstUoaDesignsGetText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; + var CellText: String); procedure XMLPropStorage1RestoreProperties(Sender: TObject); protected { Members } @@ -357,6 +362,7 @@ type FTileHint: TTileHintInfo; FLightManager: TLightManager; FTileFilter: TTileDataFlags; + FUoaDesigns: TUoaDesigns; { Methods } procedure BuildTileList; function ConfirmAction: Boolean; @@ -369,6 +375,7 @@ type procedure InitSize; procedure LoadLocations; procedure LoadRandomPresets; + procedure LoadUoaDesigns; procedure MoveBy(AOffsetX, AOffsetY: Integer); inline; procedure PrepareMapCell(AMapCell: TMapCell); procedure PrepareScreenBlock(ABlockInfo: PBlockInfo); @@ -1023,6 +1030,8 @@ begin FRandomPresetsFile := FConfigDir + 'RandomPresets.xml'; LoadRandomPresets; + LoadUoaDesigns; + DoubleBuffered := True; pnlBottom.DoubleBuffered := True; @@ -1030,6 +1039,8 @@ begin FSelectionListeners := TSelectionListeners.Create; FLastDraw := Now; + + pcLeft.ActivePage := tsTiles; end; procedure TfrmMain.btnGoToClick(Sender: TObject); @@ -1396,6 +1407,7 @@ begin FreeAndNil(FRandomPresetsDoc); FreeAndNil(FAccessChangedListeners); FreeAndNil(FSelectionListeners); + FreeAndNil(FUoaDesigns); RegisterPacketHandler($0C, nil); end; @@ -1974,6 +1986,34 @@ begin Stream.Write(locationInfo^.Name[1], stringLength); 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); begin FTextureManager.UseAnims := mnuShowAnimations.Checked; @@ -2206,6 +2246,26 @@ begin 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; begin SetPos(EnsureRange(FX + AOffsetX, 0, FLandscape.CellWidth - 1), From 7a67e6239856ecb03c45a6a1c3dfe82b3a922a1b Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Tue, 19 Jul 2022 20:09:24 +0200 Subject: [PATCH 2/8] =?UTF-8?q?=E2=9C=A8=20Draw=20UOA=20designs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Client/UUoaDesigns.pas | 7 ++++--- Client/UfrmMain.lfm | 33 +++++++++++++++++---------------- Client/UfrmMain.pas | 37 ++++++++++++++++++++++++++++++++++++- 3 files changed, 57 insertions(+), 20 deletions(-) diff --git a/Client/UUoaDesigns.pas b/Client/UUoaDesigns.pas index f609f9c..0f21ce0 100644 --- a/Client/UUoaDesigns.pas +++ b/Client/UUoaDesigns.pas @@ -42,7 +42,8 @@ type constructor Create(AIdxFile, ABinFile: String); destructor Destroy; override; - function LoadTiles(AHeader: TUoaDesignHeader; AOffsetX, AOffsetY: Word): TStaticItemList; + function LoadTiles(AHeader: TUoaDesignHeader; AOffsetX, AOffsetY: Word; + AOffsetZ: ShortInt): TStaticItemList; public property Headers: TUoaDesignHeaders read FHeaders; end; @@ -120,7 +121,7 @@ begin end; function TUoaDesigns.LoadTiles(AHeader: TUoaDesignHeader; AOffsetX, - AOffsetY: Word): TStaticItemList; + AOffsetY: Word; AOffsetZ: ShortInt): TStaticItemList; var i: Integer; tile: TStaticItem; @@ -144,7 +145,7 @@ begin tile.TileID := ReadInt; tile.X := AOffsetX + ReadInt; tile.Y := AOffsetY + ReadInt; - tile.Z := ReadInt; + tile.Z := AOffsetZ + ReadInt; ReadInt; // TODO: Level?? if version = 1 then diff --git a/Client/UfrmMain.lfm b/Client/UfrmMain.lfm index fd33611..053aa8b 100644 --- a/Client/UfrmMain.lfm +++ b/Client/UfrmMain.lfm @@ -133,7 +133,7 @@ object frmMain: TfrmMain AnchorSideLeft.Control = cbTerrain AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbTerrain - Left = 114 + Left = 109 Height = 26 Top = 12 Width = 47 @@ -152,9 +152,9 @@ object frmMain: TfrmMain AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = spTileList Left = 6 - Height = 313 + Height = 319 Hint = '-' - Top = 74 + Top = 68 Width = 328 Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Left = 6 @@ -217,7 +217,7 @@ object frmMain: TfrmMain Width = 340 Anchors = [akTop, akLeft, akRight, akBottom] Caption = 'Random pool' - ClientHeight = 234 + ClientHeight = 237 ClientWidth = 338 TabOrder = 1 object btnAddRandom: TSpeedButton @@ -375,7 +375,7 @@ object frmMain: TfrmMain Left = 256 Height = 35 Hint = 'Save Preset' - Top = 186 + Top = 189 Width = 35 Anchors = [akTop, akRight] BorderSpacing.Right = 6 @@ -427,7 +427,7 @@ object frmMain: TfrmMain Left = 297 Height = 35 Hint = 'Delete Preset' - Top = 186 + Top = 189 Width = 35 Anchors = [akTop, akRight] BorderSpacing.Right = 6 @@ -482,7 +482,7 @@ object frmMain: TfrmMain AnchorSideBottom.Control = cbRandomPreset Cursor = 63 Left = 6 - Height = 143 + Height = 146 Top = 37 Width = 326 Anchors = [akTop, akLeft, akRight, akBottom] @@ -532,7 +532,7 @@ object frmMain: TfrmMain AnchorSideBottom.Side = asrBottom Left = 6 Height = 42 - Top = 186 + Top = 189 Width = 244 Anchors = [akLeft, akRight, akBottom] BorderSpacing.Left = 6 @@ -585,10 +585,10 @@ object frmMain: TfrmMain AnchorSideTop.Side = asrBottom AnchorSideRight.Control = tsTiles AnchorSideRight.Side = asrBottom - Left = 114 + Left = 109 Height = 38 Top = 38 - Width = 201 + Width = 206 Anchors = [akTop, akLeft, akRight] BorderSpacing.Right = 25 OnEditingDone = edFilterEditingDone @@ -600,9 +600,9 @@ object frmMain: TfrmMain AnchorSideTop.Control = cbTerrain AnchorSideTop.Side = asrBottom Left = 8 - Height = 28 - Top = 40 - Width = 79 + Height = 25 + Top = 37 + Width = 74 Caption = 'Statics' Checked = True OnChange = cbStaticsChange @@ -613,9 +613,9 @@ object frmMain: TfrmMain AnchorSideLeft.Control = tsTiles AnchorSideTop.Control = tsTiles Left = 6 - Height = 28 + Height = 25 Top = 12 - Width = 83 + Width = 78 BorderSpacing.Left = 6 BorderSpacing.Top = 12 Caption = 'Terrain' @@ -824,7 +824,7 @@ object frmMain: TfrmMain item Position = 1 Text = 'Name' - Width = 208 + Width = 206 end> Header.DefaultHeight = 26 Header.Height = 26 @@ -874,6 +874,7 @@ object frmMain: TfrmMain TreeOptions.MiscOptions = [toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning] TreeOptions.PaintOptions = [toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages] TreeOptions.SelectionOptions = [toFullRowSelect] + OnDblClick = vstUoaDesignsDblClick OnGetText = vstUoaDesignsGetText end end diff --git a/Client/UfrmMain.pas b/Client/UfrmMain.pas index f0f58be..719a92c 100644 --- a/Client/UfrmMain.pas +++ b/Client/UfrmMain.pas @@ -322,6 +322,7 @@ type Column: TColumnIndex; const NewText: String); procedure vstLocationsSaveNode(Sender: TBaseVirtualTree; Node: PVirtualNode; Stream: TStream); + procedure vstUoaDesignsDblClick(Sender: TObject); procedure vstUoaDesignsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); @@ -377,6 +378,7 @@ type procedure LoadRandomPresets; procedure LoadUoaDesigns; procedure MoveBy(AOffsetX, AOffsetY: Integer); inline; + procedure PlaceUoaDesign(AWorldItem: TWorldItem); procedure PrepareMapCell(AMapCell: TMapCell); procedure PrepareScreenBlock(ABlockInfo: PBlockInfo); procedure ProcessToolState; @@ -1986,6 +1988,11 @@ begin Stream.Write(locationInfo^.Name[1], stringLength); end; +procedure TfrmMain.vstUoaDesignsDblClick(Sender: TObject); +begin + RegisterSelectionListener(@PlaceUoaDesign); +end; + procedure TfrmMain.vstUoaDesignsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); @@ -2060,7 +2067,8 @@ end; procedure TfrmMain.RegisterSelectionListener(AListener: TSelectionListener); begin - FSelectionListeners.Add(AListener); + if FSelectionListeners.IndexOf(AListener) = -1 then + FSelectionListeners.Add(AListener); end; procedure TfrmMain.UnregisterAccessChangedListener( @@ -2273,6 +2281,33 @@ begin UpdateCurrentTile; end; +procedure TfrmMain.PlaceUoaDesign(AWorldItem: TWorldItem); +var + selectedNode: PVirtualNode; + header: TUoaDesignHeader; + tiles: TStaticItemList; + newTile: TStaticItem; +begin + UnregisterSelectionListener(@PlaceUoaDesign); + + selectedNode := vstUoaDesigns.GetFirstSelected(); + if selectedNode = nil then + Exit; + + header := FUoaDesigns.Headers[selectedNode^.Index]; + tiles := FUoaDesigns.LoadTiles(header, AWorldItem.X, AWorldItem.Y, AWorldItem.Z); + try + FUndoList.Clear; + for newTile in tiles do + begin + dmNetwork.Send(TInsertStaticPacket.Create(newTile)); + FUndoList.Add(TDeleteStaticPacket.Create(newTile)); + end; + finally + tiles.Free; + end; +end; + procedure TfrmMain.PrepareMapCell(AMapCell: TMapCell); var current, north, east, west: PBlockInfo; From cd983844fa61200daaa97abed0714c3826a90663 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Tue, 19 Jul 2022 20:11:08 +0200 Subject: [PATCH 3/8] =?UTF-8?q?=F0=9F=94=87=20Remove=20debug=20log?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Client/ULightManager.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client/ULightManager.pas b/Client/ULightManager.pas index 3b434e6..84828da 100644 --- a/Client/ULightManager.pas +++ b/Client/ULightManager.pas @@ -370,7 +370,7 @@ var s: string; i, id, col, r, g, b: Integer; begin - writeln('Loading Colors from ', AFileName); //TODO + //writeln('Loading Colors from ', AFileName); //TODO for i := 1 to ColorsCount do begin FLightColors[i].R := 1.0; FLightColors[i].G := 1.0; From 1753c38eea35418e92051f51d8bf3ebedace146d Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Wed, 20 Jul 2022 18:54:00 +0200 Subject: [PATCH 4/8] =?UTF-8?q?=F0=9F=9A=A7=20Preview=20design=20placement?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Client/ULandscape.pas | 9 +++- Client/UUoaDesigns.pas | 93 +++++++++++++++++++++++-------------- Client/UfrmMain.pas | 102 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 166 insertions(+), 38 deletions(-) diff --git a/Client/ULandscape.pas b/Client/ULandscape.pas index d35d4de..3026df9 100644 --- a/Client/ULandscape.pas +++ b/Client/ULandscape.pas @@ -320,6 +320,8 @@ type Hue: Word; end; + TGhostTile = class(TStaticItem); + operator enumerator(AScreenBuffer: TScreenBuffer): TScreenBufferItemEnumerator; implementation @@ -996,6 +998,7 @@ var i, x, y: Integer; tempDrawList: TWorldItemList; staticTileData: TStaticTiledata; + blockInfo: PBlockInfo; begin ADrawList.Clear; tempDrawList := TWorldItemList.Create(False);; @@ -1042,7 +1045,11 @@ begin tempDrawList.Sort(@CompareWorldItems); for i := 0 to tempDrawList.Count - 1 do - ADrawList.Add(TWorldItem(tempDrawList[i])); + begin + blockInfo := ADrawList.Add(TWorldItem(tempDrawList[i])); + if tempDrawList[i] is TGhostTile then + blockInfo^.State := ssGhost; + end; tempDrawList.Free; end; diff --git a/Client/UUoaDesigns.pas b/Client/UUoaDesigns.pas index 0f21ce0..c1008fd 100644 --- a/Client/UUoaDesigns.pas +++ b/Client/UUoaDesigns.pas @@ -32,6 +32,19 @@ type 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 @@ -42,8 +55,7 @@ type constructor Create(AIdxFile, ABinFile: String); destructor Destroy; override; - function LoadTiles(AHeader: TUoaDesignHeader; AOffsetX, AOffsetY: Word; - AOffsetZ: ShortInt): TStaticItemList; + function LoadDesign(AHeader: TUoaDesignHeader): TUoaDesign; public property Headers: TUoaDesignHeaders read FHeaders; end; @@ -65,6 +77,49 @@ begin 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 := ReadInt; + 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); @@ -120,39 +175,9 @@ begin Headers.Free; end; -function TUoaDesigns.LoadTiles(AHeader: TUoaDesignHeader; AOffsetX, - AOffsetY: Word; AOffsetZ: ShortInt): TStaticItemList; -var - i: Integer; - tile: TStaticItem; - version: Int32; - - function ReadInt: Int32; - begin - FData.Read(Result, SizeOf(Result)); - end; - +function TUoaDesigns.LoadDesign(AHeader: TUoaDesignHeader): TUoaDesign; 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 := AOffsetZ + ReadInt; - ReadInt; // TODO: Level?? - - if version = 1 then - tile.Hue := ReadInt; - - Result.Add(tile); - end; + Result := TUoaDesign.Create(AHeader, FData); end; end. diff --git a/Client/UfrmMain.pas b/Client/UfrmMain.pas index 719a92c..f9ce4d7 100644 --- a/Client/UfrmMain.pas +++ b/Client/UfrmMain.pas @@ -47,7 +47,6 @@ type TBlockInfoList = specialize TFPGList; - TGhostTile = class(TStaticItem); TPacketList = specialize TFPGObjectList; TAccessChangedListeners = specialize TFPGList; TSelectionListeners = specialize TFPGList; @@ -360,10 +359,13 @@ type FUndoList: TPacketList; FGLFont: TGLFont; FSelectionListeners: TSelectionListeners; + FHoverListeners: TSelectionListeners; FTileHint: TTileHintInfo; FLightManager: TLightManager; FTileFilter: TTileDataFlags; FUoaDesigns: TUoaDesigns; + FCurrentUoaDesign: TUoaDesign; + FCurrentUoaDesignAnchor: TWorldItem; { Methods } procedure BuildTileList; function ConfirmAction: Boolean; @@ -381,6 +383,7 @@ type procedure PlaceUoaDesign(AWorldItem: TWorldItem); procedure PrepareMapCell(AMapCell: TMapCell); procedure PrepareScreenBlock(ABlockInfo: PBlockInfo); + procedure PreviewUoaDesign(AWorldItem: TWorldItem); procedure ProcessToolState; procedure ProcessAccessLevel; procedure RebuildScreenBuffer; @@ -420,10 +423,12 @@ type procedure InvalidateFilter; procedure InvalidateScreenBuffer; procedure RegisterAccessChangedListener(AListener: TAccessChangedListener); + procedure RegisterHoverListener(AListener: TSelectionListener); procedure RegisterSelectionListener(AListener: TSelectionListener); procedure SetPos(AX, AY: Word); procedure SwitchToSelection; procedure UnregisterAccessChangedListener(AListener: TAccessChangedListener); + procedure UnregisterHoverListener(AListener: TSelectionListener); procedure UnregisterSelectionListener(AListener: TSelectionListener); end; @@ -1038,6 +1043,7 @@ begin pnlBottom.DoubleBuffered := True; FAccessChangedListeners := TAccessChangedListeners.Create; + FHoverListeners := TSelectionListeners.Create; FSelectionListeners := TSelectionListeners.Create; FLastDraw := Now; @@ -1408,6 +1414,7 @@ begin FreeAndNil(FGLFont); FreeAndNil(FRandomPresetsDoc); FreeAndNil(FAccessChangedListeners); + FreeAndNil(FHoverListeners); FreeAndNil(FSelectionListeners); FreeAndNil(FUoaDesigns); @@ -1989,8 +1996,24 @@ begin end; procedure TfrmMain.vstUoaDesignsDblClick(Sender: TObject); +var + selectedNode: PVirtualNode; begin + // Make sure to reset the current view first. + PreviewUoaDesign(nil); + + UnregisterSelectionListener(@PlaceUoaDesign); + UnregisterHoverListener(@PreviewUoaDesign); + + selectedNode := vstUoaDesigns.GetFirstSelected(); + if selectedNode = nil then + Exit; + + FreeAndNil(FCurrentUoaDesign); + FCurrentUoaDesign := FUoaDesigns.LoadDesign(FUoaDesigns.Headers[selectedNode^.Index]); + RegisterSelectionListener(@PlaceUoaDesign); + RegisterHoverListener(@PreviewUoaDesign); end; procedure TfrmMain.vstUoaDesignsGetText(Sender: TBaseVirtualTree; @@ -2065,6 +2088,12 @@ begin FAccessChangedListeners.Add(AListener); end; +procedure TfrmMain.RegisterHoverListener(AListener: TSelectionListener); +begin + if FHoverListeners.IndexOf(AListener) = -1 then + FHoverListeners.Add(AListener); +end; + procedure TfrmMain.RegisterSelectionListener(AListener: TSelectionListener); begin if FSelectionListeners.IndexOf(AListener) = -1 then @@ -2077,6 +2106,11 @@ begin FAccessChangedListeners.Remove(AListener); end; +procedure TfrmMain.UnregisterHoverListener(AListener: TSelectionListener); +begin + FHoverListeners.Remove(Alistener); +end; + procedure TfrmMain.UnregisterSelectionListener(AListener: TSelectionListener); begin FSelectionListeners.Remove(AListener); @@ -2294,7 +2328,9 @@ begin if selectedNode = nil then Exit; - header := FUoaDesigns.Headers[selectedNode^.Index]; + vstUoaDesigns.ClearSelection; + + {header := FUoaDesigns.Headers[selectedNode^.Index]; tiles := FUoaDesigns.LoadTiles(header, AWorldItem.X, AWorldItem.Y, AWorldItem.Z); try FUndoList.Clear; @@ -2305,7 +2341,7 @@ begin end; finally tiles.Free; - end; + end;} end; procedure TfrmMain.PrepareMapCell(AMapCell: TMapCell); @@ -2568,6 +2604,62 @@ begin end; end; +procedure TfrmMain.PreviewUoaDesign(AWorldItem: TWorldItem); +var + offsetX, offsetY, offsetZ: Integer; + newX, newY, newZ: Integer; + i: Integer; + designTile, virtualTile: TStaticItem; + blockInfo: PBlockInfo; +begin + // If nothing has changed, we can keep this short. + if FCurrentUoaDesignAnchor = AWorldItem then + Exit; + + // No design selected? Well then. + if FCurrentUoaDesign = nil then + Exit; + + for i := FVirtualTiles.Count - 1 downto 0 do + begin + if FVirtualTiles[i] is TGhostTile then + begin + FScreenBuffer.Delete(FVirtualTiles[i]); + FVirtualTiles.Delete(i); + end; + end; + + if AWorldItem = nil then + Exit; + + offsetX := AWorldItem.X - FCurrentUoaDesign.Header.Width div 2; + offsetY := AWorldItem.Y - FCurrentUoaDesign.Header.Height div 2; + offsetZ := AWorldItem.Z; + + for designTile in FCurrentUoaDesign.Tiles do + begin + newX := designTile.X + offsetX; + newY := designTile.Y + offsetY; + newZ := designTile.Z + offsetZ; + + if (newX < 0) or (newX >= FLandscape.CellWidth) or + (newY < 0) or (newY >= FLandscape.CellHeight) or + (newZ < -128) or (newZ > 127) then + // We can't render this tile. Skip it. + continue; + + virtualTile := TGhostTile.Create(nil, nil, 0, 0); + virtualTile.X := newX; + virtualTile.Y := newY; + virtualTile.Z := newZ; + virtualTile.TileID := designTile.TileID; + virtualTile.Hue := designTile.Hue; + FVirtualTiles.Add(virtualTile); + end; + + InvalidateScreenBuffer; +end; + procedure TfrmMain.Render; var highlight: Boolean; @@ -3060,6 +3152,7 @@ end; procedure TfrmMain.UpdateCurrentTile(AX, AY: Integer); var blockInfo: PBlockInfo; + listener: TSelectionListener; begin //Logger.EnterMethod([lcClient, lcDebug], 'UpdateCurrentTile'); FOverlayUI.ActiveArrow := FOverlayUI.HitTest(AX, AY); @@ -3077,6 +3170,9 @@ begin else CurrentTile := nil; + for listener in FHoverListeners do + listener(CurrentTile); + //Logger.ExitMethod([lcClient, lcDebug], 'UpdateCurrentTile'); end; From 54e7209c8d02a23e6cc9a2bf8ec42789336a0dd9 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Wed, 20 Jul 2022 19:23:31 +0200 Subject: [PATCH 5/8] =?UTF-8?q?=E2=9C=A8=20Finish=20placement=20as=20per?= =?UTF-8?q?=20preview?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Client/UfrmMain.lfm | 14 ++++++++++++ Client/UfrmMain.pas | 56 +++++++++++++++++++++++++++++++++------------ 2 files changed, 56 insertions(+), 14 deletions(-) diff --git a/Client/UfrmMain.lfm b/Client/UfrmMain.lfm index 053aa8b..1eaa144 100644 --- a/Client/UfrmMain.lfm +++ b/Client/UfrmMain.lfm @@ -877,6 +877,20 @@ object frmMain: TfrmMain OnDblClick = vstUoaDesignsDblClick OnGetText = vstUoaDesignsGetText end + object btnCancelUOAPlacement: TButton + AnchorSideLeft.Control = vstUoaDesigns + AnchorSideLeft.Side = asrCenter + AnchorSideTop.Control = vstUoaDesigns + AnchorSideTop.Side = asrCenter + Left = 103 + Height = 47 + Top = 305 + Width = 134 + Caption = 'Cancel' + OnClick = btnCancelUOAPlacementClick + TabOrder = 1 + Visible = False + end end end object tbMain: TToolBar diff --git a/Client/UfrmMain.pas b/Client/UfrmMain.pas index f9ce4d7..ca2f913 100644 --- a/Client/UfrmMain.pas +++ b/Client/UfrmMain.pas @@ -88,6 +88,7 @@ type btnGoTo: TButton; btnRandomPresetDelete: TSpeedButton; btnRandomPresetSave: TSpeedButton; + btnCancelUOAPlacement: TButton; cbRandomPreset: TComboBox; cbStatics: TCheckBox; cbTerrain: TCheckBox; @@ -219,6 +220,7 @@ type var CanShow: Boolean; var HintInfo: THintInfo); procedure btnAddLocationClick(Sender: TObject); procedure btnAddRandomClick(Sender: TObject); + procedure btnCancelUOAPlacementClick(Sender: TObject); procedure btnClearLocationsClick(Sender: TObject); procedure btnClearRandomClick(Sender: TObject); procedure btnDeleteLocationClick(Sender: TObject); @@ -1157,6 +1159,11 @@ begin vdtRandom.EndUpdate; end; +procedure TfrmMain.btnCancelUOAPlacementClick(Sender: TObject); +begin + PlaceUoaDesign(nil); +end; + procedure TfrmMain.btnClearLocationsClick(Sender: TObject); begin if MessageDlg('Are you sure you want to delete all saved locations?', @@ -2014,6 +2021,9 @@ begin RegisterSelectionListener(@PlaceUoaDesign); RegisterHoverListener(@PreviewUoaDesign); + + vstUoaDesigns.Enabled := False; + btnCancelUOAPlacement.Visible := True; end; procedure TfrmMain.vstUoaDesignsGetText(Sender: TBaseVirtualTree; @@ -2319,29 +2329,47 @@ procedure TfrmMain.PlaceUoaDesign(AWorldItem: TWorldItem); var selectedNode: PVirtualNode; header: TUoaDesignHeader; - tiles: TStaticItemList; - newTile: TStaticItem; + item: TWorldItem; + i: Integer; begin UnregisterSelectionListener(@PlaceUoaDesign); + UnregisterHoverListener(@PreviewUoaDesign); + FreeAndNil(FCurrentUoaDesign); + FCurrentUoaDesignAnchor := nil; + vstUoaDesigns.Enabled := True; + btnCancelUOAPlacement.Visible := False; selectedNode := vstUoaDesigns.GetFirstSelected(); if selectedNode = nil then Exit; - vstUoaDesigns.ClearSelection; - - {header := FUoaDesigns.Headers[selectedNode^.Index]; - tiles := FUoaDesigns.LoadTiles(header, AWorldItem.X, AWorldItem.Y, AWorldItem.Z); - try - FUndoList.Clear; - for newTile in tiles do + if AWorldItem = nil then + begin + for i := FVirtualTiles.Count - 1 downto 0 do begin - dmNetwork.Send(TInsertStaticPacket.Create(newTile)); - FUndoList.Add(TDeleteStaticPacket.Create(newTile)); + if FVirtualTiles[i] is TGhostTile then + begin + FScreenBuffer.Delete(FVirtualTiles[i]); + FVirtualTiles.Delete(i); + end; end; - finally - tiles.Free; - end;} + Exit; + end; + + FUndoList.Clear; + for i := FVirtualTiles.Count - 1 downto 0 do + begin + item := FVirtualTiles[i]; + if item is TGhostTile then + begin + dmNetwork.Send(TInsertStaticPacket.Create(TGhostTile(item))); + FUndoList.Add(TDeleteStaticPacket.Create(TGhostTile(item))); + FVirtualTiles.Delete(i); + FScreenBuffer.Delete(item); + end; + end; + + vstUoaDesigns.ClearSelection; end; procedure TfrmMain.PrepareMapCell(AMapCell: TMapCell); From b83c5f4b2d2aeb3ae57032f9f9114ce4151a4e83 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Wed, 20 Jul 2022 19:29:55 +0200 Subject: [PATCH 6/8] =?UTF-8?q?=F0=9F=9A=B8=20Lock=20actions=20during=20pl?= =?UTF-8?q?acement?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Client/UfrmMain.pas | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Client/UfrmMain.pas b/Client/UfrmMain.pas index ca2f913..c6afe76 100644 --- a/Client/UfrmMain.pas +++ b/Client/UfrmMain.pas @@ -371,6 +371,7 @@ type { Methods } procedure BuildTileList; function ConfirmAction: Boolean; + procedure EnableActions(AEnabled: Boolean); function FindRandomPreset(AName: String): TDOMElement; procedure ForceUpdateCurrentTile; procedure GetDrawOffset(AX, AY: Integer; out DrawX, DrawY: Integer); inline; @@ -2008,6 +2009,8 @@ var begin // Make sure to reset the current view first. PreviewUoaDesign(nil); + acSelect.Checked := True; + EnableActions(False); UnregisterSelectionListener(@PlaceUoaDesign); UnregisterHoverListener(@PreviewUoaDesign); @@ -2338,6 +2341,7 @@ begin FCurrentUoaDesignAnchor := nil; vstUoaDesigns.Enabled := True; btnCancelUOAPlacement.Visible := False; + EnableActions(True); selectedNode := vstUoaDesigns.GetFirstSelected(); if selectedNode = nil then @@ -3629,6 +3633,15 @@ begin oglGameWindowMouseLeave(nil); end; +procedure TfrmMain.EnableActions(AEnabled: Boolean); +begin + acSelect.Enabled := AEnabled; + acMove.Enabled := AEnabled; + acElevate.Enabled := AEnabled; + acDelete.Enabled := AEnabled; + acHue.Enabled := AEnabled; +end; + function TfrmMain.FindRandomPreset(AName: String): TDOMElement; var preset: TDOMElement; From 9f66004c44e36e9c5a13d02988597c79faf74873 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Wed, 20 Jul 2022 20:22:29 +0200 Subject: [PATCH 7/8] =?UTF-8?q?=F0=9F=90=9B=20Fix=20invalid=20Z=20range=20?= =?UTF-8?q?on=20load?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Client/UUoaDesigns.pas | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Client/UUoaDesigns.pas b/Client/UUoaDesigns.pas index c1008fd..ce49ecd 100644 --- a/Client/UUoaDesigns.pas +++ b/Client/UUoaDesigns.pas @@ -62,6 +62,9 @@ type implementation +uses + Math; + function ReadString(AStream: TStream): String; var nonNullFlag: Byte; @@ -104,7 +107,7 @@ begin tile.TileID := ReadInt; tile.X := ReadInt; tile.Y := ReadInt; - tile.Z := ReadInt; + tile.Z := EnsureRange(ReadInt, -128, 127); ReadInt; // Level; unused if version = 1 then From 6aa6496429eb228e2a41d5b78b98758fee0a61cc Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Wed, 20 Jul 2022 20:22:42 +0200 Subject: [PATCH 8/8] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Speed=20up=20preview?= =?UTF-8?q?=20rendering?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Client/ULandscape.pas | 13 +++++ Client/UfrmMain.pas | 107 +++++++++++++++++++++++++----------------- 2 files changed, 76 insertions(+), 44 deletions(-) diff --git a/Client/ULandscape.pas b/Client/ULandscape.pas index 3026df9..2816128 100644 --- a/Client/ULandscape.pas +++ b/Client/ULandscape.pas @@ -322,6 +322,19 @@ type TGhostTile = class(TStaticItem); + { TMovableGhostTile } + + TMovableGhostTile = class(TGhostTile) + private + FOriginalX: Word; + FOriginalY: Word; + FOriginalZ: ShortInt; + public + property OriginalX: Word read FOriginalX write FOriginalX; + property OriginalY: Word read FOriginalY write FOriginalY; + property OriginalZ: ShortInt read FOriginalZ write FOriginalZ; + end; + operator enumerator(AScreenBuffer: TScreenBuffer): TScreenBufferItemEnumerator; implementation diff --git a/Client/UfrmMain.pas b/Client/UfrmMain.pas index c6afe76..0cdef58 100644 --- a/Client/UfrmMain.pas +++ b/Client/UfrmMain.pas @@ -368,6 +368,7 @@ type FUoaDesigns: TUoaDesigns; FCurrentUoaDesign: TUoaDesign; FCurrentUoaDesignAnchor: TWorldItem; + FCurrentUoaTiles: TStaticItemList; { Methods } procedure BuildTileList; function ConfirmAction: Boolean; @@ -383,6 +384,7 @@ type procedure LoadRandomPresets; procedure LoadUoaDesigns; procedure MoveBy(AOffsetX, AOffsetY: Integer); inline; + procedure MoveUoaDesign(AX, AY: Word; AZ: ShortInt); procedure PlaceUoaDesign(AWorldItem: TWorldItem); procedure PrepareMapCell(AMapCell: TMapCell); procedure PrepareScreenBlock(ABlockInfo: PBlockInfo); @@ -2006,6 +2008,8 @@ end; procedure TfrmMain.vstUoaDesignsDblClick(Sender: TObject); var selectedNode: PVirtualNode; + designTile: TStaticItem; + virtualTile: TMovableGhostTile; begin // Make sure to reset the current view first. PreviewUoaDesign(nil); @@ -2020,7 +2024,25 @@ begin Exit; FreeAndNil(FCurrentUoaDesign); + FreeAndNil(FCurrentUoaTiles); FCurrentUoaDesign := FUoaDesigns.LoadDesign(FUoaDesigns.Headers[selectedNode^.Index]); + FCurrentUoaTiles := TStaticItemList.Create(False); + + for designTile in FCurrentUoaDesign.Tiles do + begin + virtualTile := TMovableGhostTile.Create(nil, nil, 0, 0); + virtualTile.X := designTile.X; + virtualTile.Y := designTile.Y; + virtualTile.Z := designTile.Z; + virtualTile.OriginalX := designTile.X; + virtualTile.OriginalY := designTile.Y; + virtualTile.OriginalZ := designTile.Z; + virtualTile.TileID := designTile.TileID; + virtualTile.Hue := designTile.Hue; + FCurrentUoaTiles.Add(virtualTile); + FVirtualTiles.Add(virtualTile); + end; + MoveUoaDesign(FX, FY, FLandscape.GetLandAlt(FX, FY, 0)); RegisterSelectionListener(@PlaceUoaDesign); RegisterHoverListener(@PreviewUoaDesign); @@ -2328,6 +2350,39 @@ begin UpdateCurrentTile; end; +procedure TfrmMain.MoveUoaDesign(AX, AY: Word; AZ: ShortInt); +var + offsetX, offsetY, offsetZ, maxZ: Integer; + item: TStaticItem; +begin + maxZ := Low(Integer); + for item in FCurrentUoaDesign.Tiles do + if item.Z > maxZ then + maxZ := item.Z; + + offsetX := AX - FCurrentUoaDesign.Header.Width div 2; + offsetY := AY - FCurrentUoaDesign.Header.Height div 2; + offsetZ := EnsureRange(AZ, -128, 127); + + if offsetX < 0 then offsetX := 0; + if offsetX + FCurrentUoaDesign.Header.Width > FLandscape.CellWidth then + offsetX := FLandscape.CellWidth - FCurrentUoaDesign.Header.Width; + if offsetY < 0 then offsetY := 0; + if offsetY + FCurrentUoaDesign.Header.Height > FLandscape.CellHeight then + offsetY := FLandscape.CellHeight - FCurrentUoaDesign.Header.Height; + if offsetZ + maxZ > 127 then + offsetZ := 127 - maxZ; + + for item in FCurrentUoaTiles do + begin + item.X := TMovableGhostTile(item).OriginalX + offsetX; + item.Y := TMovableGhostTile(item).OriginalY + offsetY; + item.Z := TMovableGhostTile(item).OriginalZ + offsetZ; + end; + + InvalidateScreenBuffer; +end; + procedure TfrmMain.PlaceUoaDesign(AWorldItem: TWorldItem); var selectedNode: PVirtualNode; @@ -2338,6 +2393,7 @@ begin UnregisterSelectionListener(@PlaceUoaDesign); UnregisterHoverListener(@PreviewUoaDesign); FreeAndNil(FCurrentUoaDesign); + FreeAndNil(FCurrentUoaTiles); FCurrentUoaDesignAnchor := nil; vstUoaDesigns.Enabled := True; btnCancelUOAPlacement.Visible := False; @@ -2637,59 +2693,20 @@ begin end; procedure TfrmMain.PreviewUoaDesign(AWorldItem: TWorldItem); -var - offsetX, offsetY, offsetZ: Integer; - newX, newY, newZ: Integer; - i: Integer; - designTile, virtualTile: TStaticItem; - blockInfo: PBlockInfo; begin // If nothing has changed, we can keep this short. if FCurrentUoaDesignAnchor = AWorldItem then Exit; + FCurrentUoaDesignAnchor := AWorldItem; // No design selected? Well then. if FCurrentUoaDesign = nil then Exit; - for i := FVirtualTiles.Count - 1 downto 0 do - begin - if FVirtualTiles[i] is TGhostTile then - begin - FScreenBuffer.Delete(FVirtualTiles[i]); - FVirtualTiles.Delete(i); - end; - end; - if AWorldItem = nil then Exit; - offsetX := AWorldItem.X - FCurrentUoaDesign.Header.Width div 2; - offsetY := AWorldItem.Y - FCurrentUoaDesign.Header.Height div 2; - offsetZ := AWorldItem.Z; - - for designTile in FCurrentUoaDesign.Tiles do - begin - newX := designTile.X + offsetX; - newY := designTile.Y + offsetY; - newZ := designTile.Z + offsetZ; - - if (newX < 0) or (newX >= FLandscape.CellWidth) or - (newY < 0) or (newY >= FLandscape.CellHeight) or - (newZ < -128) or (newZ > 127) then - // We can't render this tile. Skip it. - continue; - - virtualTile := TGhostTile.Create(nil, nil, 0, 0); - virtualTile.X := newX; - virtualTile.Y := newY; - virtualTile.Z := newZ; - virtualTile.TileID := designTile.TileID; - virtualTile.Hue := designTile.Hue; - FVirtualTiles.Add(virtualTile); - end; - - InvalidateScreenBuffer; + MoveUoaDesign(AWorldItem.X, AWorldItem.Y, AWorldItem.Z); end; procedure TfrmMain.Render; @@ -3404,9 +3421,11 @@ var begin //Logger.EnterMethod([lcClient, lcDebug], 'UpdateSelection'); - //If the current tile is nil, but we still have a selected tile, the - //procedure is pointless - the selection should stay intact. - if (CurrentTile <> nil) or (SelectedTile = nil) then + // If the current tile is nil, but we still have a selected tile, the + // procedure is pointless - the selection should stay intact. + // Same if we are currently placing a UOA design, since we reuse the virtual + // tile and just update its position. + if ((CurrentTile <> nil) or (SelectedTile = nil)) and (FCurrentUoaTiles = nil) then begin if CurrentTile = nil then selectedRect := Rect(-1, -1, -1, -1)