source: tags/1.2.0/CmdList.pas

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