Skip to content

Commit 3f2ef0d

Browse files
committed
feat: webgraph saving and loading
much faster than the original but does take way more space. Hopefully compressing bytes gets fixed in the future
1 parent 2ef2347 commit 3f2ef0d

File tree

5 files changed

+244
-47
lines changed

5 files changed

+244
-47
lines changed

osrs/map/maploader.simba

Lines changed: 49 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -391,57 +391,63 @@ This is an internal method. Don't use it if you don't know what you are doing.
391391
*)
392392
function TRSMapLoader.GetGraph(name: String; plane: Integer; map: TImage): TWebGraph;
393393
var
394-
path, filename: String;
395-
t: UInt64;
394+
path: String;
396395
begin
397-
path := Self.CacheDir + 'graphs' + PATH_SEP + ToStr(plane) + PATH_SEP;
398-
filename := name + '-' + GENERATED_GRAPH.Hash();
399-
400-
if not FileExists(filename + '.txt') then
396+
path := Self.CacheDir + 'graphs' + PATH_SEP + ToStr(plane) + PATH_SEP + name + '-' + GENERATED_GRAPH.Hash() + PATH_SEP;
397+
398+
if
399+
not FileExists(path + 'nodes.txt') or
400+
not FileExists(path + 'paths.txt') or
401+
not FileExists(path + 'names.txt') or
402+
not FileExists(path + 'doors.txt') or
403+
not FileExists(path + 'walkablespace.txt') or
404+
not FileExists(path + 'walkableclusters.txt') or
405+
not FileExists(path + 'objectclusters.txt') then
401406
begin
402-
WriteLn GetDebugLn('MapLoader', 'Caching ' + name + ' webgraph, this will take a minute.', EErrorLevel.WARN);
403-
404-
if not DirCreate(path + ToStr(plane) + PATH_SEP) then
407+
if not DirCreate(path) then
405408
raise GetDebugLn('MapLoader', 'Failed to create cache directory: ' + path);
406409

407-
t := GetTickCount();
408410
Result := TWebGraph.BuildGraph(name, map);
409-
WriteLn GetDebugLn('MapLoader', 'Took ' + ToStr((GetTickCount()-t) div 1000) + ' seconds to generate webgraph.', EErrorLevel.SUCCESS);
410-
411-
(* TODO
412-
try
413-
json.Init();
414-
415-
json.Put('nodes', Result.NodesToString());
416-
json.Put('paths', Result.PathsToString());
417-
json.Put('names', Result.NamesToString());
418-
json.Put('doors', Result.DoorsToString());
419-
420-
if not WriteFileContents(cachename + '.json', json.ToString(2), False) then
421-
Self.Fatal('Failed to save ' + name + ' webgraph.');
422-
except
423-
Self.Fatal('Something went wrong saving ' + name + ' webraph: ' + GetExceptionMessage());
424-
finally
425-
json.Free();
426-
end;
427-
*)
411+
412+
if (Result.Nodes <> []) and not FileWriteBytes(path + 'nodes.txt', Result.Nodes.ToBytes()) then
413+
raise GetDebugLn('MapLoader', 'Failed to create cache for graph nodes: ' + path);
414+
if (Result.Paths <> []) and not FileWriteBytes(path + 'paths.txt', Result.Paths.ToBytes()) then
415+
raise GetDebugLn('MapLoader', 'Failed to create cache for graph paths: ' + path);
416+
if (Result.Names <> []) and not FileWriteBytes(path + 'names.txt', Result.Names.ToBytes()) then
417+
raise GetDebugLn('MapLoader', 'Failed to create cache for graph names: ' + path);
418+
419+
if (Result.Doors <> []) and not FileWriteBytes(path + 'doors.txt', Result.Doors.ToBytes()) then
420+
raise GetDebugLn('MapLoader', 'Failed to create cache for graph doors: ' + path);
421+
422+
if (Result.WalkableSpace <> []) and not FileWriteBytes(path + 'walkablespace.txt', Result.WalkableSpace.ToBytes()) then
423+
raise GetDebugLn('MapLoader', 'Failed to create cache for graph WalkableSpace: ' + path);
424+
if (Result.WalkableClusters <> []) and not FileWriteBytes(path + 'walkableclusters.txt', Result.WalkableClusters.ToBytes()) then
425+
raise GetDebugLn('MapLoader', 'Failed to create cache for graph WalkableClusters: ' + path);
426+
if (Result.ObjectClusters <> []) and not FileWriteBytes(path + 'objectclusters.txt', Result.ObjectClusters.ToBytes()) then
427+
raise GetDebugLn('MapLoader', 'Failed to create cache for graph ObjectClusters: ' + path);
428+
428429
Exit;
429430
end;
430431

431-
(* TODO
432-
try
433-
json.Init(ReadFileContents(cachename + '.json'));
434-
435-
Result.LoadNodesFromString(json.getString('nodes'));
436-
Result.LoadPathsFromString(json.getString('paths'));
437-
Result.LoadNamesFromString(json.getString('names'));
438-
Result.LoadDoorsFromString(json.getString('doors'));
439-
except
440-
TerminateScript('Something went wrong loading the webraph: ' + GetExceptionMessage());
441-
finally
442-
json.Free();
443-
end;
444-
*)
432+
if FileExists(path + 'nodes.txt') then
433+
Result.Nodes := TPointArray.CreateFromBytes(FileReadBytes(path + 'nodes.txt'));
434+
if FileExists(path + 'paths.txt') then
435+
Result.Paths := T2DIntegerArray.CreateFromBytes(FileReadBytes(path + 'paths.txt'));
436+
if FileExists(path + 'names.txt') then
437+
Result.Names := TStringArray.CreateFromBytes(FileReadBytes(path + 'names.txt'));
438+
439+
if FileExists(path + 'doors.txt') then
440+
Result.Doors := TRSDoorArray.CreateFromBytes(FileReadBytes(path + 'doors.txt'));
441+
442+
if FileExists(path + 'walkablespace.txt') then
443+
Result.WalkableSpace := TPointArray.CreateFromBytes(FileReadBytes(path + 'walkablespace.txt'));
444+
if FileExists(path + 'walkableclusters.txt') then
445+
Result.WalkableClusters := T2DPointArray.CreateFromBytes(FileReadBytes(path + 'walkableclusters.txt'));
446+
if FileExists(path + 'objectclusters.txt') then
447+
Result.ObjectClusters := T2DPointArray.CreateFromBytes(FileReadBytes(path + 'objectclusters.txt'));
448+
449+
SetLength(Result.Paths, Length(Result.Nodes));
450+
SetLength(Result.Names, Length(Result.Nodes));
445451
end;
446452

447453

utils.simba

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
{$IFNDEF SRLT_SRLTENV_INCLUDED} {$I utils/srltenv.simba}
44
{$IFNDEF SRLT_RANDOM_INCLUDED} {$I utils/math/random.simba}
5+
{$IFNDEF SRLT_CONVERSIONS_INCLUDED} {$I utils/math/conversions.simba}
56
{$IFNDEF SRLT_VECTOR_INCLUDED} {$I utils/math/vector.simba}
67
{$IFNDEF SRLT_GEOMETRY_INCLUDED} {$I utils/math/geometry.simba}
78
{$IFNDEF SRLT_TIME_INCLUDED} {$I utils/time.simba}
@@ -34,3 +35,4 @@
3435
{$ELSE}{$ENDIF}
3536
{$ELSE}{$ENDIF}
3637
{$ELSE}{$ENDIF}
38+
{$ELSE}{$ENDIF}

utils/math/conversions.simba

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
{$DEFINE SRLT_CONVERSIONS_INCLUDED}
2+
{$IFNDEF SRLT_UTILS}
3+
{$I SRLT/utils.simba}
4+
{$ENDIF}
5+
6+
7+
function TStringArray.ToBytes(): TByteArray;
8+
begin
9+
Result := Self.Join(#0).ToBytes();
10+
end;
11+
12+
function TStringArray.CreateFromBytes(bytes: TByteArray): TStringArray; static;
13+
var
14+
str: String;
15+
len: Integer;
16+
begin
17+
if Length(bytes) = 0 then Exit;
18+
len := Length(bytes);
19+
20+
SetLength(str, len);
21+
Move(bytes[0], str[1], len);
22+
23+
Result := str.Split(#0, False);
24+
if str.EndsWith(#0) then Result += '';
25+
end;
26+
27+
28+
function T2DIntegerArray.ToBytes(): TByteArray;
29+
var
30+
size, i, len, offset: Integer;
31+
begin
32+
size := SizeOf(Int32);
33+
len := size;
34+
35+
for i := 0 to High(Self) do
36+
Inc(len, size + Length(Self[i]) * size);
37+
38+
SetLength(Result, len);
39+
Move(Length(Self), Result[0], size);
40+
offset := size;
41+
42+
for i := 0 to High(Self) do
43+
begin
44+
len := Length(Self[i]);
45+
Move(len, Result[offset], size);
46+
Inc(offset, size);
47+
48+
if len > 0 then
49+
begin
50+
Move(Self[i][0], Result[offset], len * size);
51+
Inc(offset, len * size);
52+
end;
53+
end;
54+
end;
55+
56+
function T2DIntegerArray.CreateFromBytes(bytes: TByteArray): T2DIntegerArray; static;
57+
var
58+
size, i, len, row, offset: Integer;
59+
begin
60+
len := Length(bytes);
61+
if len = 0 then Exit;
62+
size := SizeOf(Integer);
63+
Move(bytes[0], len, size);
64+
SetLength(Result, len);
65+
offset := size;
66+
67+
for i := 0 to High(Result) do
68+
begin
69+
Move(bytes[offset], row, size);
70+
SetLength(Result[i], row);
71+
Inc(offset, size);
72+
73+
if row > 0 then
74+
begin
75+
Move(bytes[offset], Result[i][0], row * size);
76+
Inc(offset, row * size);
77+
end;
78+
end;
79+
end;
80+
81+
82+
83+
function TPointArray.ToBytes(): TByteArray;
84+
var
85+
len: Integer;
86+
begin
87+
len := Length(Self) * SizeOf(TPoint);
88+
if len = 0 then Exit;
89+
SetLength(Result, len);
90+
Move(Self[0], Result[0], len);
91+
end;
92+
93+
function TPointArray.CreateFromBytes(bytes: TByteArray): TPointArray; static;
94+
var
95+
len: Integer;
96+
begin
97+
len := Length(bytes);
98+
if len = 0 then Exit;
99+
SetLength(Result, len div SizeOf(TPoint));
100+
Move(bytes[0], Result[0], len);
101+
end;
102+
103+
104+
function T2DPointArray.ToBytes(): TByteArray;
105+
var
106+
size, i, len, offset: Int32;
107+
bytes: TByteArray;
108+
begin
109+
size := SizeOf(TPoint);
110+
len := SizeOf(Int32); // Start with the length of the outer array
111+
112+
// Calculate the total size required for the byte array
113+
for i := 0 to High(Self) do
114+
Inc(len, SizeOf(Int32) + Length(Self[i]) * size);
115+
116+
// Allocate the byte array
117+
SetLength(bytes, len);
118+
119+
// Write the length of the outer array
120+
Move(Length(Self), bytes[0], SizeOf(Int32));
121+
offset := SizeOf(Int32);
122+
123+
// Write each inner array
124+
for i := 0 to High(Self) do
125+
begin
126+
len := Length(Self[i]);
127+
Move(len, bytes[offset], SizeOf(Int32)); // Write the length of the inner array
128+
Inc(offset, SizeOf(Int32));
129+
130+
if len > 0 then
131+
begin
132+
Move(Self[i][0], bytes[offset], len * size); // Write the inner array data
133+
Inc(offset, len * size);
134+
end;
135+
end;
136+
137+
Result := bytes;
138+
end;
139+
140+
141+
function T2DPointArray.CreateFromBytes(bytes: TByteArray): T2DPointArray; static;
142+
var
143+
size, i, len, row, offset: Int32;
144+
begin
145+
size := SizeOf(TPoint);
146+
147+
// Read the length of the outer array
148+
Move(bytes[0], len, SizeOf(Int32));
149+
SetLength(Result, len);
150+
offset := SizeOf(Int32);
151+
152+
// Read each inner array
153+
for i := 0 to High(Result) do
154+
begin
155+
Move(bytes[offset], row, SizeOf(Int32)); // Read the length of the inner array
156+
SetLength(Result[i], row);
157+
Inc(offset, SizeOf(Int32));
158+
159+
if row > 0 then
160+
begin
161+
Move(bytes[offset], Result[i][0], row * size); // Read the inner array data
162+
Inc(offset, row * size);
163+
end;
164+
end;
165+
end;

utils/webgraph.simba

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,6 @@ begin
603603
end;
604604

605605

606-
607606
procedure TWebGraph.Merge(graph: TWebGraph);
608607
var
609608
i, j, len: Integer;
@@ -663,3 +662,28 @@ begin
663662
canvas.DrawBox(TBox.Create(Self.Nodes[i], 1, 1), $FF7F00);
664663
end;
665664
end;
665+
666+
667+
668+
function TRSDoorArray.ToBytes(): TByteArray;
669+
var
670+
len: Integer;
671+
begin
672+
len := Length(Self) * SizeOf(TRSDoor);
673+
if len = 0 then Exit;
674+
SetLength(Result, len);
675+
Move(Self[0], Result[0], len);
676+
end;
677+
678+
function TRSDoorArray.CreateFromBytes(bytes: TByteArray): TRSDoorArray; static;
679+
var
680+
len: Integer;
681+
begin
682+
len := Length(bytes);
683+
if len = 0 then Exit;
684+
len := Length(bytes);
685+
SetLength(Result, len div SizeOf(TRSDoor));
686+
Move(bytes[0], Result[0], len);
687+
end;
688+
689+

utils/webgraphgen.simba

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -299,14 +299,14 @@ var
299299
white, red, gray, merged, graySubset: TPointArray;
300300
whiteClusters, grayClusters, mergedClusters: T2DPointArray;
301301
i, j: Integer;
302-
t: Double;
302+
t: UInt64;
303303
begin
304304
white := map.FindColor($FFFFFF, 0);
305305
red := map.FindColor($0000FF, 0);
306306

307307
WriteLn GetDebugLn('Generating webgraph for region: ' + name);
308308

309-
t := PerformanceTimer();
309+
t := GetTickCount();
310310
Result := Self._BuildGraph(map, white, red);
311311

312312
gray := map.FindColor($333333, 0);
@@ -333,5 +333,5 @@ begin
333333
Result.WalkableSpace := white + gray;
334334
Result.ObjectClusters := grayClusters;
335335

336-
WriteLn GetDebugLn('WebGraph', 'Generating webgraph took ' + ToStr(Round((PerformanceTimer()-t/1000), 3)) + 'ms.', EErrorLevel.SUCCESS);
336+
WriteLn GetDebugLn('WebGraph', 'Generating webgraph took ' + ToStr(Round((GetTickCount()-t/1000), 3)) + 'seconds.', EErrorLevel.SUCCESS);
337337
end;

0 commit comments

Comments
 (0)