294 lines
7.3 KiB
Plaintext
294 lines
7.3 KiB
Plaintext
(*
|
|
* CDDL HEADER START
|
|
*
|
|
* The contents of this file are subject to the terms of the
|
|
* Common Development and Distribution License, Version 1.0 only
|
|
* (the "License"). You may not use this file except in compliance
|
|
* with the License.
|
|
*
|
|
* You can obtain a copy of the license at
|
|
* http://www.opensource.org/licenses/cddl1.php.
|
|
* See the License for the specific language governing permissions
|
|
* and limitations under the License.
|
|
*
|
|
* When distributing Covered Code, include this CDDL HEADER in each
|
|
* file and include the License file at
|
|
* http://www.opensource.org/licenses/cddl1.php. If applicable,
|
|
* add the following below this CDDL HEADER, with the fields enclosed
|
|
* by brackets "[]" replaced with your own identifying * information:
|
|
* Portions Copyright [yyyy] [name of copyright owner]
|
|
*
|
|
* CDDL HEADER END
|
|
*
|
|
*
|
|
* Portions Copyright 2007 Andreas Schneider
|
|
*)
|
|
unit URadarMap;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, UConfig, UNetState, UEnhancedMemoryStream, UEnums;
|
|
|
|
type
|
|
|
|
TRadarColorArray = array of Word;
|
|
|
|
{ TRadarMap }
|
|
|
|
TRadarMap = class(TObject)
|
|
constructor Create(AMap, AStatics, AStaIdx: TStream; AWidth, AHeight: Word;
|
|
ARadarCol: string);
|
|
destructor Destroy; override;
|
|
protected
|
|
FWidth: Word;
|
|
FHeight: Word;
|
|
FRadarColors: TRadarColorArray;
|
|
FRadarMap: TRadarColorArray;
|
|
FPackets: TList;
|
|
FPacketSize: Cardinal;
|
|
procedure OnRadarHandlingPacket(ABuffer: TEnhancedMemoryStream;
|
|
ANetState: TNetState);
|
|
public
|
|
procedure Update(AX, AY, ATileID: Word);
|
|
procedure BeginUpdate;
|
|
procedure EndUpdate;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
UPacket, UPackets, UPacketHandlers, UCEDServer, crc, UStatics;
|
|
|
|
type
|
|
TMulIndex = packed record
|
|
Position: Cardinal;
|
|
Size: Cardinal;
|
|
Userdata: Cardinal;
|
|
end;
|
|
TMapCell = packed record
|
|
TileID: Word;
|
|
Altitude: ShortInt;
|
|
end;
|
|
TOldStaticItem = packed record
|
|
Unknown: Cardinal;
|
|
TileID: Word;
|
|
X, Y: Byte;
|
|
Z: ShortInt;
|
|
Hue: Word;
|
|
end;
|
|
TStaticItem = packed record
|
|
TileID: Word;
|
|
X, Y: Byte;
|
|
Z: ShortInt;
|
|
Hue: Word;
|
|
end;
|
|
|
|
{ TRadarChecksumPacket }
|
|
|
|
TRadarChecksumPacket = class(TPacket)
|
|
constructor Create(ARadarMap: TRadarColorArray);
|
|
end;
|
|
|
|
{ TRadarMapPacket }
|
|
|
|
TRadarMapPacket = class(TPacket)
|
|
constructor Create(ARadarMap: TRadarColorArray);
|
|
end;
|
|
|
|
{ TUpdateRadarPacket }
|
|
|
|
TUpdateRadarPacket = class(TPacket)
|
|
constructor Create(AX, AY, AColor: Word);
|
|
end;
|
|
|
|
{ TRadarChecksumPacket }
|
|
|
|
constructor TRadarChecksumPacket.Create(ARadarMap: TRadarColorArray);
|
|
var
|
|
checksum: Cardinal;
|
|
begin
|
|
inherited Create($0D, 0);
|
|
FStream.WriteByte($01);
|
|
checksum := crc32(0, nil, 0);
|
|
checksum := crc32(checksum, @ARadarMap[0], Length(ARadarMap) * SizeOf(Word));
|
|
FStream.WriteCardinal(checksum);
|
|
end;
|
|
|
|
{ TRadarMapPacket }
|
|
|
|
constructor TRadarMapPacket.Create(ARadarMap: TRadarColorArray);
|
|
begin
|
|
inherited Create($0D, 0);
|
|
FStream.WriteByte($02);
|
|
FStream.Write(ARadarMap[0], Length(ARadarMap) * SizeOf(Word));
|
|
end;
|
|
|
|
{ TUpdateRadarPacket }
|
|
|
|
constructor TUpdateRadarPacket.Create(AX, AY, AColor: Word);
|
|
begin
|
|
inherited Create($0D, 0);
|
|
FStream.WriteByte($03);
|
|
FStream.WriteWord(AX);
|
|
FStream.WriteWord(AY);
|
|
FStream.WriteWord(AColor);
|
|
end;
|
|
|
|
{ TRadarMap }
|
|
|
|
constructor TRadarMap.Create(AMap, AStatics, AStaIdx: TStream; AWidth,
|
|
AHeight: Word; ARadarCol: string);
|
|
var
|
|
radarcol: TFileStream;
|
|
count, i, item, highestZ: Integer;
|
|
staticsItems: array of TStaticItem;
|
|
oldStaticsItems: array of TOldStaticItem;
|
|
mapCell: TMapCell;
|
|
index: TMulIndex;
|
|
begin
|
|
radarcol := TFileStream.Create(ARadarCol, fmOpenRead);
|
|
SetLength(FRadarColors, radarcol.Size div SizeOf(Word));
|
|
radarcol.Read(FRadarColors[0], radarcol.Size);
|
|
radarcol.Free;
|
|
|
|
FWidth := AWidth;
|
|
FHeight := AHeight;
|
|
|
|
count := AWidth * AHeight;
|
|
SetLength(FRadarMap, count);
|
|
|
|
AMap.Position := 4;
|
|
AStaIdx.Position := 0;
|
|
|
|
for i := 0 to count - 1 do
|
|
begin
|
|
AMap.Read(mapCell, SizeOf(TMapCell));
|
|
AMap.Seek(193, soFromCurrent);
|
|
FRadarMap[i] := FRadarColors[mapCell.TileID];
|
|
AStaIdx.Read(index, SizeOf(TMulIndex));
|
|
if (index.Position < $FFFFFFFF) and (index.Size > 0)
|
|
and (index.Position + index.Size < AStatics.Size) then
|
|
begin
|
|
AStatics.Position := index.Position;
|
|
if not UseStaticsOldFormat then
|
|
begin
|
|
SetLength(staticsItems, index.Size div 7);
|
|
AStatics.Read(staticsItems[0], index.Size);
|
|
highestZ := mapCell.Altitude;
|
|
for item := Low(staticsItems) to High(staticsItems) do
|
|
begin
|
|
if (staticsItems[item].X = 0) and (staticsItems[item].Y = 0) and
|
|
(staticsItems[item].Z >= highestZ) then
|
|
begin
|
|
highestZ := staticsItems[item].Z;
|
|
FRadarMap[i] := FRadarColors[staticsItems[item].TileID + $4000];
|
|
end;
|
|
end;
|
|
end else begin
|
|
SetLength(oldStaticsItems, index.Size div 11);
|
|
AStatics.Read(oldStaticsItems[0], index.Size);
|
|
highestZ := mapCell.Altitude;
|
|
for item := Low(oldStaticsItems) to High(oldStaticsItems) do
|
|
begin
|
|
if (oldStaticsItems[item].X = 0) and (oldStaticsItems[item].Y = 0) and
|
|
(oldStaticsItems[item].Z >= highestZ) then
|
|
begin
|
|
highestZ := oldStaticsItems[item].Z;
|
|
FRadarMap[i] := FRadarColors[oldStaticsItems[item].TileID + $4000];
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
FPackets := nil;
|
|
|
|
RegisterPacketHandler($0D, TPacketHandler.Create(2, @OnRadarHandlingPacket));
|
|
|
|
inherited Create;
|
|
end;
|
|
|
|
destructor TRadarMap.Destroy;
|
|
begin
|
|
RegisterPacketHandler($0D, nil);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TRadarMap.OnRadarHandlingPacket(ABuffer: TEnhancedMemoryStream;
|
|
ANetState: TNetState);
|
|
var
|
|
subID: Byte;
|
|
begin
|
|
if not ValidateAccess(ANetState, alView) then Exit;
|
|
|
|
subID := ABuffer.ReadByte;
|
|
case subID of
|
|
$01: //request checksum
|
|
begin
|
|
CEDServerInstance.SendPacket(ANetState, TRadarChecksumPacket.Create(
|
|
FRadarMap));
|
|
end;
|
|
$02: //request radarmap
|
|
begin
|
|
CEDServerInstance.SendPacket(ANetState, TCompressedPacket.Create(
|
|
TRadarMapPacket.Create(FRadarMap)));
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TRadarMap.Update(AX, AY, ATileID: Word);
|
|
var
|
|
color: Word;
|
|
block: Cardinal;
|
|
packet: TPacket;
|
|
begin
|
|
block := AX * FHeight + AY;
|
|
color := FRadarColors[ATileID];
|
|
if FRadarMap[block] <> color then
|
|
begin
|
|
FRadarMap[block] := color;
|
|
packet := TUpdateRadarPacket.Create(AX, AY, color);
|
|
if FPackets <> nil then
|
|
begin
|
|
FPackets.Add(packet);
|
|
Inc(FPacketSize, packet.Stream.Size);
|
|
end else
|
|
CEDServerInstance.SendPacket(nil, packet);
|
|
end;
|
|
end;
|
|
|
|
procedure TRadarMap.BeginUpdate;
|
|
begin
|
|
if FPackets <> nil then Exit;
|
|
FPackets := TList.Create;
|
|
FPacketSize := 0;
|
|
end;
|
|
|
|
procedure TRadarMap.EndUpdate;
|
|
var
|
|
completePacket: TPacket;
|
|
i: Integer;
|
|
begin
|
|
if FPackets = nil then Exit;
|
|
completePacket := TCompressedPacket.Create(TRadarMapPacket.Create(FRadarMap));
|
|
if completePacket.Stream.Size <= (FPacketSize div 4) * 5 then
|
|
begin
|
|
CEDServerInstance.SendPacket(nil, completePacket);
|
|
for i := 0 to FPackets.Count - 1 do
|
|
TPacket(FPackets.Items[i]).Free;
|
|
end else
|
|
begin
|
|
for i := 0 to FPackets.Count - 1 do
|
|
CEDServerInstance.SendPacket(nil, TPacket(FPackets.Items[i]));
|
|
completePacket.Free;
|
|
end;
|
|
FreeAndNil(FPackets);
|
|
end;
|
|
|
|
end.
|
|
|