🚧 Preview design placement

This commit is contained in:
Andreas Schneider 2022-07-20 18:54:00 +02:00
parent cd983844fa
commit 1753c38eea
3 changed files with 166 additions and 38 deletions

View File

@ -320,6 +320,8 @@ type
Hue: Word; Hue: Word;
end; end;
TGhostTile = class(TStaticItem);
operator enumerator(AScreenBuffer: TScreenBuffer): TScreenBufferItemEnumerator; operator enumerator(AScreenBuffer: TScreenBuffer): TScreenBufferItemEnumerator;
implementation implementation
@ -996,6 +998,7 @@ var
i, x, y: Integer; i, x, y: Integer;
tempDrawList: TWorldItemList; tempDrawList: TWorldItemList;
staticTileData: TStaticTiledata; staticTileData: TStaticTiledata;
blockInfo: PBlockInfo;
begin begin
ADrawList.Clear; ADrawList.Clear;
tempDrawList := TWorldItemList.Create(False);; tempDrawList := TWorldItemList.Create(False);;
@ -1042,7 +1045,11 @@ begin
tempDrawList.Sort(@CompareWorldItems); tempDrawList.Sort(@CompareWorldItems);
for i := 0 to tempDrawList.Count - 1 do 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; tempDrawList.Free;
end; end;

View File

@ -32,6 +32,19 @@ type
constructor CreateFromStream(AStream: TStream); constructor CreateFromStream(AStream: TStream);
end; 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 }
TUoaDesigns = class TUoaDesigns = class
@ -42,8 +55,7 @@ type
constructor Create(AIdxFile, ABinFile: String); constructor Create(AIdxFile, ABinFile: String);
destructor Destroy; override; destructor Destroy; override;
function LoadTiles(AHeader: TUoaDesignHeader; AOffsetX, AOffsetY: Word; function LoadDesign(AHeader: TUoaDesignHeader): TUoaDesign;
AOffsetZ: ShortInt): TStaticItemList;
public public
property Headers: TUoaDesignHeaders read FHeaders; property Headers: TUoaDesignHeaders read FHeaders;
end; end;
@ -65,6 +77,49 @@ begin
end; end;
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 } { TUoaDesignHeaders }
constructor TUoaDesignHeaders.CreateFromStream(AStream: TStream); constructor TUoaDesignHeaders.CreateFromStream(AStream: TStream);
@ -120,39 +175,9 @@ begin
Headers.Free; Headers.Free;
end; end;
function TUoaDesigns.LoadTiles(AHeader: TUoaDesignHeader; AOffsetX, function TUoaDesigns.LoadDesign(AHeader: TUoaDesignHeader): TUoaDesign;
AOffsetY: Word; AOffsetZ: ShortInt): TStaticItemList;
var
i: Integer;
tile: TStaticItem;
version: Int32;
function ReadInt: Int32;
begin
FData.Read(Result, SizeOf(Result));
end;
begin begin
Result := TStaticItemList.Create(True); Result := TUoaDesign.Create(AHeader, FData);
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;
end; end;
end. end.

View File

@ -47,7 +47,6 @@ type
TBlockInfoList = specialize TFPGList<PBlockInfo>; TBlockInfoList = specialize TFPGList<PBlockInfo>;
TGhostTile = class(TStaticItem);
TPacketList = specialize TFPGObjectList<TPacket>; TPacketList = specialize TFPGObjectList<TPacket>;
TAccessChangedListeners = specialize TFPGList<TAccessChangedListener>; TAccessChangedListeners = specialize TFPGList<TAccessChangedListener>;
TSelectionListeners = specialize TFPGList<TSelectionListener>; TSelectionListeners = specialize TFPGList<TSelectionListener>;
@ -360,10 +359,13 @@ type
FUndoList: TPacketList; FUndoList: TPacketList;
FGLFont: TGLFont; FGLFont: TGLFont;
FSelectionListeners: TSelectionListeners; FSelectionListeners: TSelectionListeners;
FHoverListeners: TSelectionListeners;
FTileHint: TTileHintInfo; FTileHint: TTileHintInfo;
FLightManager: TLightManager; FLightManager: TLightManager;
FTileFilter: TTileDataFlags; FTileFilter: TTileDataFlags;
FUoaDesigns: TUoaDesigns; FUoaDesigns: TUoaDesigns;
FCurrentUoaDesign: TUoaDesign;
FCurrentUoaDesignAnchor: TWorldItem;
{ Methods } { Methods }
procedure BuildTileList; procedure BuildTileList;
function ConfirmAction: Boolean; function ConfirmAction: Boolean;
@ -381,6 +383,7 @@ type
procedure PlaceUoaDesign(AWorldItem: TWorldItem); procedure PlaceUoaDesign(AWorldItem: TWorldItem);
procedure PrepareMapCell(AMapCell: TMapCell); procedure PrepareMapCell(AMapCell: TMapCell);
procedure PrepareScreenBlock(ABlockInfo: PBlockInfo); procedure PrepareScreenBlock(ABlockInfo: PBlockInfo);
procedure PreviewUoaDesign(AWorldItem: TWorldItem);
procedure ProcessToolState; procedure ProcessToolState;
procedure ProcessAccessLevel; procedure ProcessAccessLevel;
procedure RebuildScreenBuffer; procedure RebuildScreenBuffer;
@ -420,10 +423,12 @@ type
procedure InvalidateFilter; procedure InvalidateFilter;
procedure InvalidateScreenBuffer; procedure InvalidateScreenBuffer;
procedure RegisterAccessChangedListener(AListener: TAccessChangedListener); procedure RegisterAccessChangedListener(AListener: TAccessChangedListener);
procedure RegisterHoverListener(AListener: TSelectionListener);
procedure RegisterSelectionListener(AListener: TSelectionListener); procedure RegisterSelectionListener(AListener: TSelectionListener);
procedure SetPos(AX, AY: Word); procedure SetPos(AX, AY: Word);
procedure SwitchToSelection; procedure SwitchToSelection;
procedure UnregisterAccessChangedListener(AListener: TAccessChangedListener); procedure UnregisterAccessChangedListener(AListener: TAccessChangedListener);
procedure UnregisterHoverListener(AListener: TSelectionListener);
procedure UnregisterSelectionListener(AListener: TSelectionListener); procedure UnregisterSelectionListener(AListener: TSelectionListener);
end; end;
@ -1038,6 +1043,7 @@ begin
pnlBottom.DoubleBuffered := True; pnlBottom.DoubleBuffered := True;
FAccessChangedListeners := TAccessChangedListeners.Create; FAccessChangedListeners := TAccessChangedListeners.Create;
FHoverListeners := TSelectionListeners.Create;
FSelectionListeners := TSelectionListeners.Create; FSelectionListeners := TSelectionListeners.Create;
FLastDraw := Now; FLastDraw := Now;
@ -1408,6 +1414,7 @@ begin
FreeAndNil(FGLFont); FreeAndNil(FGLFont);
FreeAndNil(FRandomPresetsDoc); FreeAndNil(FRandomPresetsDoc);
FreeAndNil(FAccessChangedListeners); FreeAndNil(FAccessChangedListeners);
FreeAndNil(FHoverListeners);
FreeAndNil(FSelectionListeners); FreeAndNil(FSelectionListeners);
FreeAndNil(FUoaDesigns); FreeAndNil(FUoaDesigns);
@ -1989,8 +1996,24 @@ begin
end; end;
procedure TfrmMain.vstUoaDesignsDblClick(Sender: TObject); procedure TfrmMain.vstUoaDesignsDblClick(Sender: TObject);
var
selectedNode: PVirtualNode;
begin 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); RegisterSelectionListener(@PlaceUoaDesign);
RegisterHoverListener(@PreviewUoaDesign);
end; end;
procedure TfrmMain.vstUoaDesignsGetText(Sender: TBaseVirtualTree; procedure TfrmMain.vstUoaDesignsGetText(Sender: TBaseVirtualTree;
@ -2065,6 +2088,12 @@ begin
FAccessChangedListeners.Add(AListener); FAccessChangedListeners.Add(AListener);
end; end;
procedure TfrmMain.RegisterHoverListener(AListener: TSelectionListener);
begin
if FHoverListeners.IndexOf(AListener) = -1 then
FHoverListeners.Add(AListener);
end;
procedure TfrmMain.RegisterSelectionListener(AListener: TSelectionListener); procedure TfrmMain.RegisterSelectionListener(AListener: TSelectionListener);
begin begin
if FSelectionListeners.IndexOf(AListener) = -1 then if FSelectionListeners.IndexOf(AListener) = -1 then
@ -2077,6 +2106,11 @@ begin
FAccessChangedListeners.Remove(AListener); FAccessChangedListeners.Remove(AListener);
end; end;
procedure TfrmMain.UnregisterHoverListener(AListener: TSelectionListener);
begin
FHoverListeners.Remove(Alistener);
end;
procedure TfrmMain.UnregisterSelectionListener(AListener: TSelectionListener); procedure TfrmMain.UnregisterSelectionListener(AListener: TSelectionListener);
begin begin
FSelectionListeners.Remove(AListener); FSelectionListeners.Remove(AListener);
@ -2294,7 +2328,9 @@ begin
if selectedNode = nil then if selectedNode = nil then
Exit; Exit;
header := FUoaDesigns.Headers[selectedNode^.Index]; vstUoaDesigns.ClearSelection;
{header := FUoaDesigns.Headers[selectedNode^.Index];
tiles := FUoaDesigns.LoadTiles(header, AWorldItem.X, AWorldItem.Y, AWorldItem.Z); tiles := FUoaDesigns.LoadTiles(header, AWorldItem.X, AWorldItem.Y, AWorldItem.Z);
try try
FUndoList.Clear; FUndoList.Clear;
@ -2305,7 +2341,7 @@ begin
end; end;
finally finally
tiles.Free; tiles.Free;
end; end;}
end; end;
procedure TfrmMain.PrepareMapCell(AMapCell: TMapCell); procedure TfrmMain.PrepareMapCell(AMapCell: TMapCell);
@ -2568,6 +2604,62 @@ begin
end; end;
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; procedure TfrmMain.Render;
var var
highlight: Boolean; highlight: Boolean;
@ -3060,6 +3152,7 @@ end;
procedure TfrmMain.UpdateCurrentTile(AX, AY: Integer); procedure TfrmMain.UpdateCurrentTile(AX, AY: Integer);
var var
blockInfo: PBlockInfo; blockInfo: PBlockInfo;
listener: TSelectionListener;
begin begin
//Logger.EnterMethod([lcClient, lcDebug], 'UpdateCurrentTile'); //Logger.EnterMethod([lcClient, lcDebug], 'UpdateCurrentTile');
FOverlayUI.ActiveArrow := FOverlayUI.HitTest(AX, AY); FOverlayUI.ActiveArrow := FOverlayUI.HitTest(AX, AY);
@ -3077,6 +3170,9 @@ begin
else else
CurrentTile := nil; CurrentTile := nil;
for listener in FHoverListeners do
listener(CurrentTile);
//Logger.ExitMethod([lcClient, lcDebug], 'UpdateCurrentTile'); //Logger.ExitMethod([lcClient, lcDebug], 'UpdateCurrentTile');
end; end;