1 (* Copyright (C) DooM 2D:Forever Developers
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *)
16 {$INCLUDE a_modes.inc}
20 interface
22 uses
23 Classes,
27 // ////////////////////////////////////////////////////////////////////////// //
28 type
38 // this is base type for all scalars (and arrays)
40 public
41 type
42 TType = (TBool, TChar, TByte, TUByte, TShort, TUShort, TInt, TUInt, TString, TPoint, TSize, TList, TTrigData);
43 // TPoint: pair of Integers
44 // TSize: pair of UShorts
45 // TList: actually, array of records
46 // TTrigData: array of mMaxDim bytes, but internally a record (mRecRef)
47 // arrays of chars are pascal shortstrings (with counter in the first byte)
49 private
50 type
53 private
74 mAsMonsterId: Boolean; // special hack for triggers: monster record number+1 in binary (so 0 means "none")
75 // default value
82 mEBSType: TObject; // either TDynRecord or TDynEBS; nil means "simple type"; nil for `TTrigData` too
84 // for binary parser
87 // for userdata
91 private
96 procedure parseDefaultValue (); // parse `mDefUnparsed` to `mDefSVal`, `mDefIVal`, `mDefIVal2`, `mDefRecRef`
108 protected
109 // returns `true` for duplicate record id
112 public
113 {
114 type
115 TListEnumerator = record
116 private
117 mList: TDynRecList;
118 mCurIdx: Integer;
119 public
120 constructor Create (alist: TDynRecList);
121 function MoveNext (): Boolean; inline;
122 function getCurrent (): TDynRecord; inline;
123 property Current: TDynRecord read getCurrent;
124 end;
125 }
127 public
145 // won't work for lists
152 public
171 property recrefIndex: Integer read getRecRefIndex; // search for this record in header; -1: not found
172 // for lists
175 property items[const aname: AnsiString]: TDynRecord read getListItem; default; // alas, FPC 3+ lost property overloading feature
176 // userdata
182 // "value" header record contains TList fields, with name equal to record type
184 private
191 {$IF DEFINED(XDYNREC_USE_FIELDHASH)}
193 {$ENDIF}
197 mHeaderRec: TDynRecord; // for "value" records this is header record with data, for "type" records this is header type record
199 // for userdata
203 private
218 protected
221 function addRecordByType (const atypename: AnsiString; rc: TDynRecord): Boolean; // `true`: duplicate record id
226 public
244 // find field with `TriggerType` type
247 // number of records of the given instance
253 public
258 //property fields: TDynFieldList read mFields;
269 // userdata
275 private
284 private
293 public
300 // return empty string if not found
303 public
312 public
317 private
325 public
336 // creates new header record
339 // creates new header record
342 public
349 {$IF DEFINED(D2D_DYNREC_PROFILER)}
351 {$ENDIF}
354 implementation
356 uses
357 SysUtils, e_log
361 // ////////////////////////////////////////////////////////////////////////// //
365 // ////////////////////////////////////////////////////////////////////////// //
366 {
367 constructor TDynField.TListEnumerator.Create (alist: TDynRecList);
368 begin
369 mList := alist;
370 mCurIdx := -1;
371 end;
374 function TDynField.TListEnumerator.MoveNext (): Boolean; inline;
375 begin
376 Inc(mCurIdx);
377 result := (mList <> nil) and (mCurIdx < mList.count);
378 end;
381 function TDynField.TListEnumerator.getCurrent (): TDynRecord; inline;
382 begin
383 result := mList[mCurIdx];
384 end;
385 }
389 begin
390 //result := TListEnumerator.Create(mRVal);
391 if (mRVal <> nil) then result := mRVal.GetEnumerator else result := TDynRecList.TEnumerator.Create(nil, 0);
395 // ////////////////////////////////////////////////////////////////////////// //
397 begin
405 begin
413 begin
420 begin
427 begin
464 var
466 begin
477 begin
509 begin
510 //FIXME: check type
516 // won't work for lists
518 begin
536 begin
546 var
548 begin
550 try
552 finally
559 var
565 begin
567 begin
572 end
573 else
574 begin
580 try
587 finally
599 // default value should be parsed
601 begin
604 begin
606 raise Exception.Create(Format('field ''%s'' in record ''%s'' of record type ''%s'' is not set', [mName, mOwner.mId, mOwner.mName]));
616 // default value should be parsed
618 begin
631 begin
637 begin
638 if (mRVal <> nil) and (idx >= 0) and (idx < mRVal.count) then result := mRVal[idx] else result := nil;
643 var
645 begin
651 begin
654 begin
662 begin
683 begin
692 TEBS.TBitSet: begin result += ' bitset '; if mBitSetUnique then result += 'unique '; result += mEBSTypeName; end;
697 begin
698 if (mType = TType.TPoint) then begin if (mAsT) then result += ' as txy' else result += ' as xy'; end
699 else if (mType = TType.TSize) then begin if (mAsT) then result += ' as twh' else result += ' as wh'; end;
707 begin
711 TType.TChar: if (mMaxDim > 0) then result += formatstrf('Char%d;', [mMaxDim]) else result += 'Char;';
735 var
753 begin
784 begin
786 if (lmaxdim < 1) then raise Exception.Create(Format('invalid field ''%s'' array size', [fldname]));
788 end;
791 begin
793 begin
794 if (fldofs >= 0) then raise Exception.Create(Format('duplicate field ''%s'' offset', [fldname]));
797 continue;
801 begin
808 continue;
809 end;
812 begin
814 if (Length(fldrecname) <> 0) then raise Exception.Create(Format('field ''%s'' already typed as ''%s''', [fldname, fldrecname]));
816 continue;
820 begin
822 if (Length(fldrecname) <> 0) then raise Exception.Create(Format('field ''%s'' already typed as ''%s''', [fldname, fldrecname]));
825 continue;
829 begin
830 if hasdefStr or hasdefInt or hasdefId then raise Exception.Create(Format('field ''%s'' has duplicate default', [fldname]));
833 begin
838 begin
843 begin
847 else
850 continue;
854 begin
856 continue;
860 begin
862 continue;
865 if (pr.tokType <> pr.TTId) then raise Exception.Create(Format('field ''%s'' has something unexpected in definition', [fldname]));
867 if (Length(fldrecname) <> 0) then raise Exception.Create(Format('field ''%s'' already typed as ''%s''', [fldname, fldrecname]));
874 // create field
889 else raise Exception.Create(Format('field ''%s'' has invalid type ''%s''', [fldname, fldtype]));
891 if (lmaxdim > 0) and (mType <> TType.TChar) and (mType <> TType.TTrigData) then raise Exception.Create(Format('field ''%s'' of type ''%s'' cannot be array', [fldname, fldtype]));
893 begin
894 if (lmaxdim < 1) then raise Exception.Create(Format('field ''%s'' of type ''%s'' cannot be array', [fldname, fldtype]));
895 if (Length(fldrecname) > 0) then raise Exception.Create(Format('field ''%s'' of type ''%s'' cannot have another type', [fldname, fldtype]));
915 end;
919 begin
926 var
932 begin
936 begin
938 begin
939 // this must be triggerdata
941 begin
942 raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
944 // write triggerdata
946 if (buf = nil) then raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
947 try
950 begin
955 finally
959 exit;
961 // record reference
969 else raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
971 // find record number
973 begin
975 if (f < 0) then raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' not found in record list', [mEBSTypeName, mName]));
977 if (f > maxv) then raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' has too big index', [mEBSTypeName, mName]));
978 end
979 else
980 begin
987 else raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
989 exit;
998 begin
1000 begin
1002 end
1003 else
1004 begin
1007 exit;
1010 begin
1011 if (mMaxDim = 0) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
1013 begin
1014 if (Length(mSVal) <> 1) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
1016 end
1017 else
1018 begin
1019 if (Length(mSVal) > mMaxDim) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
1024 exit;
1028 begin
1029 // triggerdata array was processed earlier
1030 if (mMaxDim >= 0) then Exception.Create(Format('byte array in field ''%s'' cannot be written', [mName]));
1032 exit;
1036 begin
1037 if (mMaxDim >= 0) then raise Exception.Create(Format('short array in field ''%s'' cannot be written', [mName]));
1039 exit;
1043 begin
1044 if (mMaxDim >= 0) then raise Exception.Create(Format('int array in field ''%s'' cannot be written', [mName]));
1046 exit;
1049 begin
1053 begin
1054 if (mMaxDim >= 0) then raise Exception.Create(Format('pos/size array in field ''%s'' cannot be written', [mName]));
1057 exit;
1060 begin
1061 if (mMaxDim >= 0) then raise Exception.Create(Format('pos/size array in field ''%s'' cannot be written', [mName]));
1064 exit;
1067 begin
1069 exit;
1072 begin
1074 exit;
1082 var
1086 begin
1092 begin
1094 begin
1096 end
1098 begin
1100 end
1101 else
1102 begin
1106 exit;
1109 begin
1110 //def := mOwner.mOwner;
1111 //es := def.findEBSType(mEBSTypeName);
1114 if (es = nil) or (not es.mIsEnum) then raise Exception.Create(Format('record enum type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1116 begin
1118 begin
1121 exit;
1124 raise Exception.Create(Format('value %d in record enum type ''%s'' for field ''%s'' not found', [mIVal, mEBSTypeName, mName]));
1127 begin
1128 //def := mOwner.mOwner;
1129 //es := def.findEBSType(mEBSTypeName);
1132 if (es = nil) or es.mIsEnum then raise Exception.Create(Format('record bitset type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1133 // none?
1135 begin
1137 begin
1139 begin
1142 exit;
1145 raise Exception.Create(Format('value %d in record bitset type ''%s'' for field ''%s'' not found', [0, mEBSTypeName, mName]));
1147 // not none
1151 begin
1153 begin
1156 begin
1158 begin
1162 break;
1165 if not found then raise Exception.Create(Format('value %d in record bitset type ''%s'' for field ''%s'' not found', [mask, mEBSTypeName, mName]));
1170 exit;
1177 begin
1179 exit;
1182 begin
1183 if (mMaxDim = 0) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
1186 exit;
1194 begin
1196 exit;
1199 begin
1202 exit;
1206 begin
1208 exit;
1211 begin
1213 exit;
1216 begin
1218 exit;
1227 var
1234 begin
1238 begin
1239 // this must be triggerdata
1241 begin
1244 // find trigger definition
1246 if (tfld = nil) then raise Exception.Create(Format('triggerdata value for field ''%s'' in record ''%s'' without TriggerType field', [mName, rec.mName]));
1248 if (rc = nil) then raise Exception.Create(Format('triggerdata definition for field ''%s'' in record ''%s'' with type ''%s'' not found', [mName, rec.mName, tfld.mSVal]));
1251 try
1255 finally
1259 exit;
1260 end
1261 else
1262 begin
1263 // not a trigger data
1271 else raise Exception.Create(Format('invalid non-numeric type ''%s'' for field ''%s'' of record ''%s''', [getTypeName(mType), mName, mEBSTypeName]));
1277 exit;
1281 begin
1290 else raise Exception.Create(Format('invalid non-numeric type ''%s'' for field ''%s'' of record ''%s''', [getTypeName(mType), mName, mEBSTypeName]));
1294 if (es = nil) or (es.mIsEnum <> (mEBS = TEBS.TEnum)) then raise Exception.Create(Format('record enum type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1296 // build enum/bitfield values
1298 begin
1300 if (Length(mSVal) = 0) then raise Exception.Create(Format('record enum type ''%s'' for field ''%s'' has invalid value %d', [mEBSTypeName, mName, mIVal]));
1301 end
1302 else
1303 begin
1304 // special for 'none'
1306 begin
1308 if (Length(mSVal) = 0) then raise Exception.Create(Format('record bitset type ''%s'' for field ''%s'' has invalid value %d', [mEBSTypeName, mName, mIVal]));
1309 end
1310 else
1311 begin
1315 begin
1317 begin
1319 if (Length(s) = 0) then raise Exception.Create(Format('record bitset type ''%s'' for field ''%s'' has invalid value %d', [mEBSTypeName, mName, mask]));
1327 //writeln('ebs <', es.mName, '>: ', mSVal);
1329 exit;
1336 begin
1342 exit;
1345 begin
1347 begin
1349 end
1350 else
1351 begin
1354 try
1359 begin
1364 finally
1369 exit;
1378 begin
1380 exit;
1383 begin
1387 exit;
1390 begin
1394 exit;
1397 begin
1399 exit;
1402 begin
1404 exit;
1415 begin
1417 if (mIVal < min) or (mIVal > max) then raise Exception.Create(Format('invalid %s value for field ''%s''', [getTypeName(mType), mName]));
1421 var
1427 begin
1428 // if this field should contain struct, convert type and parse struct
1432 begin
1433 // ugly hack. sorry.
1435 begin
1438 begin
1439 // '{}'
1442 end
1443 else
1444 begin
1446 // find trigger definition
1448 if (tfld = nil) then raise Exception.Create(Format('triggerdata value for field ''%s'' in record ''%s'' without ''type'' field', [mName, rec.mName]));
1450 if (rc = nil) then raise Exception.Create(Format('triggerdata definition for field ''%s'' in record ''%s'' with type ''%s'' not found', [mName, rec.mName, tfld.mSVal]));
1453 //writeln(rc.definition);
1454 try
1458 finally
1464 exit;
1466 // other record types
1468 begin
1470 begin
1472 end
1473 else
1474 begin
1476 if (rec = nil) then raise Exception.Create(Format('record ''%s'' (%s) value for field ''%s'' not found', [pr.tokStr, mEBSTypeName, mName]));
1482 exit;
1483 end
1485 begin
1486 //rec := mOwner.mOwner.findRecType(mEBSTypeName); // find in mapdef
1489 if (rec = nil) then raise Exception.Create(Format('record type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1496 begin
1497 //raise Exception.Create(Format('record type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1498 e_LogWritefln('duplicate record with id ''%s'' for field ''%s'' in record ''%s''', [rc.mId, mName, mOwner.mName]);
1501 exit;
1506 begin
1507 //es := mOwner.mOwner.findEBSType(mEBSTypeName); // find in mapdef
1510 if (es = nil) or (not es.mIsEnum) then raise Exception.Create(Format('record enum type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1512 if not es.has[tk] then raise Exception.Create(Format('record enum value ''%s'' of type ''%s'' for field ''%s'' not found', [tk, mEBSTypeName, mName]));
1515 //writeln('ENUM ', mEBSName, '; element <', mSVal, '> with value ', mIVal);
1518 exit;
1521 begin
1522 //es := mOwner.mOwner.findEBSType(mEBSTypeName); // find in mapdef
1525 if (es = nil) or es.mIsEnum then raise Exception.Create(Format('record bitset type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1528 begin
1530 if not es.has[tk] then raise Exception.Create(Format('record bitset value ''%s'' of type ''%s'' for field ''%s'' not found', [tk, mEBSTypeName, mName]));
1534 if mBitSetUnique then raise Exception.Create(Format('record bitset of type ''%s'' for field ''%s'' expects only one value', [tk, mEBSTypeName, mName]));
1535 //pr.expectDelim('|');
1540 exit;
1547 begin
1553 exit;
1556 begin
1557 if (mMaxDim = 0) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
1560 begin
1561 // single char
1562 if (Length(mSVal) <> 1) then raise Exception.Create(Format('invalid string size for field ''%s''', [mName]));
1565 end
1566 else
1567 begin
1568 // string
1569 if (Length(mSVal) > mMaxDim) then raise Exception.Create(Format('invalid string size for field ''%s''', [mName]));
1573 exit;
1576 begin
1579 exit;
1582 begin
1585 exit;
1588 begin
1591 exit;
1594 begin
1597 exit;
1600 begin
1603 exit;
1606 begin
1609 exit;
1612 begin
1616 exit;
1620 begin
1624 begin
1625 if (mIVal < 0) or (mIVal > 32767) then raise Exception.Create(Format('invalid %s value for field ''%s''', [getTypeName(mType), mName]));
1629 begin
1630 if (mIVal2 < 0) or (mIVal2 > 32767) then raise Exception.Create(Format('invalid %s value for field ''%s''', [getTypeName(mType), mName]));
1635 exit;
1638 begin
1640 exit;
1643 begin
1645 exit;
1653 // ////////////////////////////////////////////////////////////////////////// //
1655 begin
1656 if (pr = nil) then raise Exception.Create('cannot create record type without type definition');
1661 {$IF DEFINED(XDYNREC_USE_FIELDHASH)}
1663 {$ENDIF}
1675 begin
1679 {$IF DEFINED(XDYNREC_USE_FIELDHASH)}
1681 {$ENDIF}
1691 begin
1695 {$IF DEFINED(XDYNREC_USE_FIELDHASH)}
1698 {$ENDIF}
1708 begin
1711 {$IF DEFINED(XDYNREC_USE_FIELDHASH)}
1713 {$ENDIF}
1717 function TDynRecord.addFieldChecked (fld: TDynField): Boolean; inline; // `true`: duplicate name
1718 begin
1721 {$IF not DEFINED(XDYNREC_USE_FIELDHASH)}
1723 {$ENDIF}
1725 {$IF DEFINED(XDYNREC_USE_FIELDHASH)}
1727 {$ENDIF}
1732 begin
1733 {$IF DEFINED(XDYNREC_USE_FIELDHASH)}
1735 {$ELSE}
1738 begin
1743 {$ENDIF}
1748 begin
1754 var
1756 begin
1763 begin
1769 begin
1775 begin
1781 var
1783 begin
1791 begin
1797 begin
1803 var
1806 begin
1814 begin
1829 var
1832 begin
1835 // find record data
1838 if (fld.mType <> fld.TType.TList) then raise Exception.Create(Format('cannot get record of type ''%s'' due to name conflict with ordinary field', [atypename]));
1839 // find by id
1841 begin
1844 // alas
1848 function TDynRecord.findRecordNumByType (const atypename: AnsiString; rc: TDynRecord): Integer;
1849 var
1852 begin
1854 // find record data
1857 if (fld.mType <> fld.TType.TList) then raise Exception.Create(Format('cannot get record of type ''%s'' due to name conflict with ordinary field', [atypename]));
1858 // find by ref
1860 begin
1862 begin
1866 // alas
1871 var
1873 begin
1874 // find record data
1877 begin
1878 // first record
1883 if (fld.mType <> fld.TType.TList) then raise Exception.Create(Format('cannot append record of type ''%s'' due to name conflict with ordinary field', [atypename]));
1884 // append
1886 begin
1895 var
1897 begin
1903 begin
1911 var
1914 begin
1916 begin
1927 // number of records of the given instance
1929 var
1931 begin
1939 var
1941 begin
1945 begin
1947 begin
1950 end
1951 else
1952 begin
1964 var
1966 begin
1970 begin
1972 begin
1975 end
1976 else
1977 begin
1989 var
1992 begin
1994 begin
1997 begin
1999 begin
2003 if isForTrig[tdn] then raise Exception.Create(Format('duplicate trigdata ''%s'' trigtype ''%s''', [mName, tdn]));
2007 end
2008 else
2009 begin
2015 end
2016 else
2017 begin
2022 begin
2025 begin
2026 if (mSize > 0) then raise Exception.Create(Format('duplicate `size` in record ''%s''', [mName]));
2028 if (mSize < 1) then raise Exception.Create(Format('invalid record ''%s'' size: %d', [mName, mSize]));
2030 continue;
2033 begin
2034 if (mBinBlock >= 0) then raise Exception.Create(Format('duplicate `binblock` in record ''%s''', [mName]));
2036 if (mBinBlock < 1) then raise Exception.Create(Format('invalid record ''%s'' binblock: %d', [mName, mBinBlock]));
2037 continue;
2043 // load fields
2045 begin
2047 //if hasByName(fld.name) then begin fld.Free(); raise Exception.Create(Format('duplicate field ''%s''', [fld.name])); end;
2048 // append
2051 begin
2055 // done with field
2062 var
2064 begin
2066 begin
2069 end
2070 else
2071 begin
2072 // record
2076 begin
2086 var
2088 begin
2090 begin
2091 // trigger data
2094 begin
2097 begin
2102 end
2103 else
2104 begin
2107 end
2108 else
2109 begin
2110 // record
2117 begin
2127 var
2139 var
2142 begin
2143 //writeln('*** rec: ', rec.mName, '.', rec.mId, ' (', rec.mFields.count, ')');
2145 begin
2147 begin
2149 continue;
2155 begin
2156 e_LogWritefln('record of type ''%s'' with id ''%s'' links to inexistant record of type ''%s'' with id ''%s''', [rec.mName, rec.mId, fld.mEBSTypeName, fld.mRecRefId], MSG_WARNING);
2157 //raise Exception.Create(Format('record of type ''%s'' with id ''%s'' links to inexistant record of type ''%s'' with id ''%s''', [rec.mName, rec.mId, fld.mEBSTypeName, fld.mRecRefId]));
2159 //writeln(' ', rec.mName, '.', rec.mId, ':', fld.mName, ' -> ', rt.mName, '.', rt.mId, ' (', fld.mEBSTypeName, '.', fld.mRecRefId, ')');
2165 begin
2166 //writeln(' ', fld.mName);
2171 begin
2174 try
2176 begin
2177 // parse map file as sequence of blocks
2181 // parse blocks
2183 begin
2189 if (bsize < 0) or (bsize > $1fffffff) then raise Exception.Create(Format('block of type %d has invalid size %d', [btype, bsize]));
2190 if loaded[btype] then raise Exception.Create(Format('block of type %d already loaded', [btype]));
2192 // find record type for this block
2195 if (rect = nil) then raise Exception.Create(Format('block of type %d has no corresponding record', [btype]));
2196 //writeln('found type ''', rec.mName, ''' for block type ', btype);
2197 if (rec.mSize = 0) or ((bsize mod rec.mSize) <> 0) then raise Exception.Create(Format('block of type %d has invalid number of records', [btype]));
2198 // header?
2200 begin
2201 if (bsize <> mSize) then raise Exception.Create(Format('header block of type %d has invalid number of records', [btype]));
2206 end
2207 else
2208 begin
2209 // create list for this type
2214 begin
2218 begin
2225 //writeln('parsed ''', rec.mId, '''...');
2231 //st.position := st.position+bsize;
2233 // link fields
2235 begin
2239 exit;
2242 // read fields
2244 if (mSize < 1) then raise Exception.Create(Format('cannot read record of type ''%s'' with unknown size', [mName]));
2248 begin
2251 if (fld.mBinOfs >= st.size) then raise Exception.Create(Format('record of type ''%s'' has invalid field ''%s''', [fld.mName]));
2253 //writeln('parsing ''', mName, '.', fld.mName, '''...');
2256 finally
2263 procedure TDynRecord.writeBinTo (st: TStream; trigbufsz: Integer=-1; onlyFields: Boolean=false);
2264 var
2270 //f, c: Integer;
2273 begin
2275 begin
2276 if (mBinBlock < 1) then raise Exception.Create('cannot write binary record without block number');
2279 end
2280 else
2281 begin
2284 try
2289 // write normal fields
2291 begin
2292 // record list?
2296 if (fld.mBinOfs >= bufsz) then raise Exception.Create('binary value offset is outside of the buffer');
2298 //writeln('writing field <', fld.mName, '>');
2302 // write block with normal fields
2304 begin
2305 //writeln('writing header...');
2306 // signature and version
2317 // write other blocks, if any
2319 begin
2320 // calculate blkmax
2323 begin
2324 // record list?
2326 begin
2334 // write blocks
2336 begin
2340 begin
2341 // record list?
2343 begin
2352 // flush block
2354 begin
2365 // write end marker
2370 finally
2378 var
2381 begin
2383 begin
2390 try
2392 begin
2393 // record list?
2395 begin
2398 begin
2400 begin
2406 continue;
2413 finally
2421 {$IF DEFINED(D2D_DYNREC_PROFILER)}
2422 var
2433 begin
2435 writeln('record cloning: ', profCloneRec div 1000, '.', profCloneRec mod 1000, ' milliseconds');
2436 writeln('findRecType : ', profFindRecType div 1000, '.', profFindRecType mod 1000, ' milliseconds');
2437 writeln('field[] : ', profFieldSearching div 1000, '.', profFieldSearching mod 1000, ' milliseconds');
2438 writeln('list dup check: ', profListDupChecking div 1000, '.', profListDupChecking mod 1000, ' milliseconds');
2439 writeln('addRecByType : ', profAddRecByType div 1000, '.', profAddRecByType mod 1000, ' milliseconds');
2440 writeln('field valparse: ', profFieldValParsing div 1000, '.', profFieldValParsing mod 1000, ' milliseconds');
2441 writeln('fix defaults : ', profFixDefaults div 1000, '.', profFixDefaults mod 1000, ' milliseconds');
2442 writeln('recvalparse : ', profRecValParse div 1000, '.', profRecValParse mod 1000, ' milliseconds');
2444 {$ENDIF}
2448 var
2452 {$IF DEFINED(D2D_DYNREC_PROFILER)}
2454 {$ENDIF}
2455 begin
2456 if (mOwner = nil) then raise Exception.Create(Format('can''t parse record ''%s'' value without owner', [mName]));
2460 // not a header?
2462 begin
2463 // id?
2465 end
2466 else
2467 begin
2471 //writeln('parsing record <', mName, '>');
2474 begin
2476 //writeln('<', mName, '.', pr.tokStr, '>');
2478 // records
2480 begin
2481 // add records with this type (if any)
2486 begin
2491 try
2494 (*
2495 if (Length(rec.mId) > 0) then
2496 begin
2497 {$IF DEFINED(D2D_DYNREC_PROFILER)}stt := curTimeMicro();{$ENDIF}
2498 fld := field[pr.tokStr];
2499 {$IF DEFINED(D2D_DYNREC_PROFILER)}profFieldSearching := curTimeMicro()-stt;{$ENDIF}
2500 (*
2501 if (fld <> nil) and (fld.mRVal <> nil) then
2502 begin
2503 {$IF DEFINED(D2D_DYNREC_PROFILER)}stt := curTimeMicro();{$ENDIF}
2504 //idtmp := trc.mName+':'+rec.mId;
2505 //if ids.put(idtmp, 1) then raise Exception.Create(Format('duplicate thing ''%s'' in record ''%s''', [fld.mName, mName]));
2506 if fld.mRHash.has(rec.mId) then raise Exception.Create(Format('duplicate thing ''%s'' in record ''%s''', [fld.mName, mName]));
2507 {$IF DEFINED(D2D_DYNREC_PROFILER)}profListDupChecking := curTimeMicro()-stt;{$ENDIF}
2508 end;
2509 end;
2510 *)
2515 finally
2518 continue;
2522 // fields
2527 begin
2528 if fld.defined then raise Exception.Create(Format('duplicate field ''%s'' in record ''%s''', [fld.mName, mName]));
2529 if fld.internal then raise Exception.Create(Format('internal field ''%s'' in record ''%s''', [fld.mName, mName]));
2534 continue;
2537 // something is wrong
2541 // fix field defaults
2545 //writeln('done parsing record <', mName, '>');
2546 //{$IF DEFINED(D2D_DYNREC_PROFILER)}writeln('stall: ', curTimeMicro()-stall);{$ENDIF}
2551 // ////////////////////////////////////////////////////////////////////////// //
2553 begin
2560 begin
2567 begin
2578 begin
2581 begin
2590 begin
2596 var
2598 begin
2605 var
2607 begin
2611 // fields
2614 begin
2618 begin
2622 end
2623 else
2624 begin
2629 // max field
2636 var
2638 begin
2640 // fields
2642 begin
2649 var
2651 begin
2653 begin
2661 var
2667 begin
2676 begin
2679 begin
2680 if StrEqu(mIds[f], idname) then raise Exception.Create(Format('duplicate field ''%s'' in enum/bitset ''%s''', [idname, mName]));
2682 if StrEqu(mMaxName, idname) then raise Exception.Create(Format('duplicate field ''%s'' in enum/bitset ''%s''', [idname, mName]));
2686 // has value?
2688 begin
2690 begin
2691 if (Length(mMaxName) > 0) then raise Exception.Create(Format('duplicate max field ''%s'' in enum/bitset ''%s''', [idname, mName]));
2694 end
2695 else
2696 begin
2702 // append it?
2704 begin
2705 // fix maxvalue
2707 begin
2714 // next cv
2716 begin
2725 // add max field
2727 begin
2736 // ////////////////////////////////////////////////////////////////////////// //
2738 begin
2747 var
2750 begin
2765 begin
2772 var
2774 begin
2776 begin
2784 var
2786 begin
2788 begin
2796 var
2798 begin
2800 begin
2808 var
2813 // setup header links and type links
2815 var
2817 begin
2820 begin
2825 begin
2827 if (fld.mEBSType = nil) then raise Exception.Create(Format('field ''%s'' of type ''%s'' has no correcponding record definition', [fld.mName, fld.mEBSTypeName]));
2831 begin
2833 if (fld.mEBSType = nil) then raise Exception.Create(Format('field ''%s'' of type ''%s'' has no correcponding enum/bitset', [fld.mName, fld.mEBSTypeName]));
2834 if ((fld.mEBS = TDynField.TEBS.TEnum) <> (fld.mEBSType as TDynEBS).mIsEnum) then raise Exception.Create(Format('field ''%s'' of type ''%s'' enum/bitset type conflict', [fld.mName, fld.mEBSTypeName]));
2840 // setup default values
2842 var
2844 begin
2848 begin
2851 begin
2856 begin
2859 begin
2865 //writeln(eb.definition); writeln;
2866 continue;
2870 begin
2873 begin
2875 begin
2882 //writeln(dr.definition); writeln;
2883 continue;
2887 //writeln(dr.definition); writeln;
2888 if (findRecType(rec.name) <> nil) then begin rec.Free(); raise Exception.Create(Format('duplicate record ''%s''', [rec.name])); end;
2889 if (hdr <> nil) and StrEqu(rec.name, hdr.name) then begin rec.Free(); raise Exception.Create(Format('duplicate record ''%s''', [rec.name])); end;
2892 begin
2893 if (hdr <> nil) then begin rec.Free(); raise Exception.Create(Format('duplicate header record ''%s'' (previous is ''%s'')', [rec.name, hdr.name])); end;
2895 end
2896 else
2897 begin
2902 // put header record to top
2908 // setup header links and type links
2912 // setup default values
2918 // ////////////////////////////////////////////////////////////////////////// //
2920 var
2922 begin
2924 try
2931 finally
2938 var
2940 begin
2942 try
2948 finally
2955 var
2961 begin
2963 result += '// ////////////////////////////////////////////////////////////////////////// //'#10;
2966 result += #10#10'// ////////////////////////////////////////////////////////////////////////// //'#10;
2969 begin
2974 result += #10#10'// ////////////////////////////////////////////////////////////////////////// //'#10;
2980 begin
2984 begin
2990 begin
3002 var
3004 begin
3006 result += '// ////////////////////////////////////////////////////////////////////////// //'#10;
3012 function TDynMapDef.getTrigTypeCount (): Integer; inline; begin result := trigTypes.count; end;
3013 function TDynMapDef.getTrigTypeAt (idx: Integer): TDynRecord; inline; begin if (idx >= 0) and (idx < trigTypes.count) then result := trigTypes[idx] else result := nil; end;