source: tags/1.3.0/CmdList.pas

Last change on this file was 355, checked in by chronos, 3 years ago
  • Modified: Code cleanup.
File size: 10.1 KB
Line 
1{$INCLUDE Switches.inc}
2unit CmdList;
3
4interface
5
6uses
7 Classes;
8
9const
10 MaxDataSize = 1024;
11
12type
13 TLogData = array [0 .. 999999999] of Byte;
14
15 TCmdListState = record
16 nLog: Integer; { used size of LogData in bytes }
17 LoadPos: Integer; { position in LogData when loading a game }
18 LastMovingUnit: Integer;
19 MoveCode: Cardinal;
20 LoadMoveCode: Cardinal;
21 end;
22
23 TCmdList = class
24 constructor Create;
25 destructor Destroy; override;
26 procedure Get(var Command, Player, Subject: integer; var Data: pointer);
27 procedure GetDataChanges(Data: pointer; DataSize: integer);
28 procedure Put(Command, Player, Subject: integer; Data: pointer);
29 procedure PutDataChanges(Command, Player: integer;
30 OldData, NewData: pointer; DataSize: integer);
31 procedure LoadFromFile(const f: TFileStream);
32 procedure SaveToFile(const f: TFileStream);
33 procedure AppendToFile(const f: TFileStream; const OldState: TCmdListState);
34 procedure Cut;
35 function Progress: integer;
36 private
37 LogAlloc: integer; { allocated size of LogData in bytes }
38 LogData: ^TLogData;
39 FState: TCmdListState;
40 procedure PutData(Data: pointer; Length: integer);
41 procedure CompleteMoveCode;
42 public
43 property State: TCmdListState read FState write FState;
44 end;
45
46implementation
47
48uses
49 Protocol;
50
51const
52 LogGrow = 1 shl 18;
53
54type
55 TData = array [0 .. MaxDataSize - 1] of Cardinal;
56 PData = ^TData;
57
58constructor TCmdList.Create;
59begin
60 inherited;
61 FState.nLog := 0;
62 LogAlloc := 0;
63 LogData := nil;
64 FState.LastMovingUnit := -1;
65 FState.MoveCode := 0;
66 FState.LoadMoveCode := 0;
67end;
68
69destructor TCmdList.Destroy;
70begin
71 ReallocMem(LogData, 0);
72 inherited;
73end;
74
75procedure TCmdList.Get(var Command, Player, Subject: integer; var Data: pointer);
76var
77 DirCode: Cardinal;
78 Code: Cardinal;
79begin
80 if FState.LoadMoveCode > 0 then
81 begin
82 Player := -1;
83 if FState.LoadMoveCode and 1 = 1 then
84 begin // FM
85 DirCode := FState.LoadMoveCode shr 1 and 7;
86 Subject := FState.LastMovingUnit;
87 FState.LoadMoveCode := FState.LoadMoveCode shr 4;
88 end
89 else
90 begin // M
91 DirCode := FState.LoadMoveCode shr 3 and 7;
92 Subject := FState.LoadMoveCode shr 6 and $FFF;
93 FState.LoadMoveCode := FState.LoadMoveCode shr 18;
94 FState.LastMovingUnit := Subject
95 end;
96 case DirCode of
97 0: Command := sMoveUnit + $090;
98 1: Command := sMoveUnit + $0F0;
99 2: Command := sMoveUnit + $390;
100 3: Command := sMoveUnit + $3F0;
101 4: Command := sMoveUnit + $020;
102 5: Command := sMoveUnit + $060;
103 6: Command := sMoveUnit + $100;
104 7: Command := sMoveUnit + $300;
105 end;
106 Data := nil;
107 end
108 else
109 begin
110 code := Cardinal((@LogData[FState.LoadPos])^);
111 if code and 3 = 0 then
112 begin // non-clientex command
113 Command := code shr 2 and $3FFF + sExecute;
114 Player := code shr 16 and $F;
115 Subject := code shr 20 and $FFF;
116 inc(FState.LoadPos, 4);
117 end
118 else if code and 7 = 2 then
119 begin // clientex command
120 Command := code shr 3 and $FFFF;
121 Player := code shr 19 and $F;
122 Subject := 0;
123 inc(FState.LoadPos, 3);
124 end
125 else
126 begin // move command shortcut
127 if (code and 1 = 1) and (code and (7 shl 4) <> 6 shl 4) then
128 begin
129 FState.LoadMoveCode := code and $FF;
130 inc(FState.LoadPos);
131 end
132 else
133 begin
134 FState.LoadMoveCode := code and $FFFFFF;
135 inc(FState.LoadPos, 3);
136 end;
137 Get(Command, Player, Subject, Data);
138 Exit;
139 end;
140
141 if Command and $F = 0 then
142 Data := nil
143 else
144 begin
145 Data := @LogData[FState.LoadPos];
146 inc(FState.LoadPos, Command and $F * 4);
147 end;
148 end;
149end;
150
151procedure TCmdList.GetDataChanges(Data: pointer; DataSize: integer);
152var
153 b0, b1: integer;
154 Map0, Map1: Cardinal;
155begin
156 Map0 := Cardinal((@LogData[FState.LoadPos])^);
157 inc(FState.LoadPos, 4);
158 b0 := 0;
159 while Map0 > 0 do begin
160 if Map0 and 1 <> 0 then begin
161 Map1 := Cardinal((@LogData[FState.LoadPos])^);
162 inc(FState.LoadPos, 4);
163 for b1 := 0 to 31 do
164 if 1 shl b1 and Map1 <> 0 then begin
165 if b0 * 32 + b1 < DataSize then
166 PData(Data)[b0 * 32 + b1] := Cardinal((@LogData[FState.LoadPos])^);
167 inc(FState.LoadPos, 4);
168 end;
169 end;
170 inc(b0);
171 Map0 := Map0 shr 1;
172 end;
173end;
174
175procedure TCmdList.Put(Command, Player, Subject: integer; Data: pointer);
176var
177 DirCode, code: Cardinal;
178begin
179 if Command and $FC00 = sMoveUnit then
180 begin // move command shortcut
181 case Command of
182 sMoveUnit + $090: DirCode := 0;
183 sMoveUnit + $0F0: DirCode := 1;
184 sMoveUnit + $390: DirCode := 2;
185 sMoveUnit + $3F0: DirCode := 3;
186 sMoveUnit + $020: DirCode := 4;
187 sMoveUnit + $060: DirCode := 5;
188 sMoveUnit + $100: DirCode := 6;
189 sMoveUnit + $300: DirCode := 7;
190 end;
191 if Subject = FState.LastMovingUnit then
192 code := 1 + DirCode shl 1
193 else
194 code := 6 + DirCode shl 3 + Cardinal(Subject) shl 6;
195 if FState.MoveCode = 0 then
196 FState.MoveCode := code
197 else if FState.MoveCode and 1 = 1 then
198 begin // FM + this
199 FState.MoveCode := FState.MoveCode + code shl 4;
200 if code and 1 = 1 then
201 PutData(@FState.MoveCode, 1) // FM + FM
202 else
203 PutData(@FState.MoveCode, 3); // FM + M
204 FState.MoveCode := 0;
205 end
206 else if code and 1 = 1 then
207 begin // M + FM
208 FState.MoveCode := FState.MoveCode + code shl 18;
209 PutData(@FState.MoveCode, 3);
210 FState.MoveCode := 0;
211 end
212 else // M + M
213 begin
214 PutData(@FState.MoveCode, 3);
215 FState.MoveCode := code;
216 end;
217 FState.LastMovingUnit := Subject;
218 end
219 else
220 begin
221 CompleteMoveCode;
222 if Command >= cClientEx then
223 begin
224 code := 2 + Command shl 3 + Player shl 19;
225 PutData(@code, 3);
226 end
227 else
228 begin
229 code := Cardinal(Command - sExecute) shl 2 + Cardinal(Player) shl 16 +
230 Cardinal(Subject) shl 20;
231 PutData(@code, 4);
232 end;
233 end;
234 if Command and $F <> 0 then
235 PutData(Data, Command and $F * 4);
236end;
237
238procedure TCmdList.PutDataChanges(Command, Player: integer;
239 OldData, NewData: pointer; DataSize: integer);
240var
241 MapPos, LogPos, b0, b1, RowEnd: integer;
242 Map0, Map1, code: Cardinal;
243begin
244 if DataSize <= 0 then
245 exit;
246 if DataSize > MaxDataSize then
247 DataSize := MaxDataSize;
248 CompleteMoveCode;
249 MapPos := FState.nLog + 8;
250 LogPos := MapPos + 4;
251 Map0 := 0;
252 for b0 := 0 to (DataSize - 1) div 32 do
253 begin
254 if LogPos + 4 * 32 > LogAlloc then
255 begin
256 inc(LogAlloc, LogGrow);
257 ReallocMem(LogData, LogAlloc);
258 end;
259 Map0 := Map0 shr 1;
260 Map1 := 0;
261 RowEnd := DataSize - 1;
262 if RowEnd > b0 * 32 + 31 then
263 RowEnd := b0 * 32 + 31;
264 for b1 := b0 * 32 to RowEnd do
265 begin
266 Map1 := Map1 shr 1;
267 if PData(NewData)[b1] <> PData(OldData)[b1] then
268 begin
269 Cardinal((@LogData[LogPos])^) := PData(NewData)[b1];
270 inc(LogPos, 4);
271 inc(Map1, $80000000);
272 end;
273 end;
274 if Map1 > 0 then
275 begin
276 Map1 := Map1 shr (b0 * 32 + 31 - RowEnd);
277 Cardinal((@LogData[MapPos])^) := Map1;
278 MapPos := LogPos;
279 inc(LogPos, 4);
280 inc(Map0, $80000000);
281 end;
282 end;
283 if Map0 = 0 then
284 exit; // no changes
285
286 Map0 := Map0 shr (31 - (DataSize - 1) div 32);
287 Cardinal((@LogData[FState.nLog + 4])^) := Map0;
288 code := Cardinal(Command - sExecute) shl 2 + Cardinal(Player) shl 16;
289 Cardinal((@LogData[FState.nLog])^) := code;
290 FState.nLog := MapPos;
291end;
292
293procedure TCmdList.PutData(Data: pointer; Length: integer);
294begin
295 if FState.nLog + Length > LogAlloc then
296 begin
297 inc(LogAlloc, LogGrow);
298 ReallocMem(LogData, LogAlloc);
299 end;
300 move(Data^, LogData[FState.nLog], Length);
301 inc(FState.nLog, Length);
302end;
303
304procedure TCmdList.CompleteMoveCode;
305begin
306 if FState.MoveCode > 0 then
307 begin
308 if FState.MoveCode and 1 = 1 then
309 PutData(@FState.MoveCode, 1) // Single FM
310 else
311 PutData(@FState.MoveCode, 3); // Single M
312 FState.MoveCode := 0;
313 end;
314end;
315
316procedure TCmdList.LoadFromFile(const f: TFileStream);
317begin
318 f.read(FState.nLog, 4);
319 LogData := nil;
320 LogAlloc := ((FState.nLog + 2) div LogGrow + 1) * LogGrow;
321 ReallocMem(LogData, LogAlloc);
322 f.read(LogData^, FState.nLog);
323 FState.LoadPos := 0;
324end;
325
326procedure TCmdList.SaveToFile(const f: TFileStream);
327begin
328 CompleteMoveCode;
329 f.write(FState.nLog, 4);
330 f.write(LogData^, FState.nLog);
331end;
332
333procedure TCmdList.AppendToFile(const f: TFileStream;
334 const OldState: TCmdListState);
335begin
336 CompleteMoveCode;
337 f.write(FState.nLog, 4);
338 f.Position := f.Position + OldState.nLog;
339 f.write(LogData[OldState.nLog], FState.nLog - OldState.nLog);
340end;
341
342procedure TCmdList.Cut;
343begin
344 FState.nLog := FState.LoadPos;
345end;
346
347function TCmdList.Progress: integer;
348begin
349 if (FState.LoadPos = FState.nLog) and (FState.LoadMoveCode = 0) then
350 result := 1000 // loading complete
351 else if FState.nLog > 1 shl 20 then
352 result := (FState.LoadPos shr 8) * 999 div (FState.nLog shr 8)
353 else
354 result := FState.LoadPos * 999 div FState.nLog;
355end;
356
357{ Format Specification:
358
359 Non-ClientEx-Command:
360 Byte3 Byte2 Byte1 Byte0
361 ssssssss sssspppp cccccccc cccccc00
362 (c = Command-sExecute, p = Player, s = Subject)
363
364 ClientEx-Command:
365 Byte2 Byte1 Byte0
366 0ppppccc cccccccc ccccc010
367 (c = Command, p = Player)
368
369 Single Move:
370 Byte2 Byte1 Byte0
371 000000ss ssssssss ssaaa110
372 (a = Direction, s = Subject)
373
374 Move + Follow Move:
375 Byte2 Byte1 Byte0
376 00bbb1ss ssssssss ssaaa110
377 (a = Direction 1, s = Subject 1, b = Direction 2)
378
379 Follow Move + Move:
380 Byte2 Byte1 Byte0
381 00ssssss ssssssbb b110aaa1
382 (a = Direction 1, b = Direction 2, s = Subject 2)
383
384 Single Follow Move:
385 Byte0
386 0000aaa1
387 (a = Direction)
388
389 Double Follow Move:
390 Byte0
391 bbb1aaa1
392 (a = Direction 1, b = Direction 2)
393}
394
395end.
Note: See TracBrowser for help on using the repository browser.