8ebac36188754ef6349bbb7bbc5147a1a0ccfe7a
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 type
115 private
118 public
125 public
143 // won't work for lists
150 public
169 property recrefIndex: Integer read getRecRefIndex; // search for this record in header; -1: not found
170 // for lists
173 property items[const aname: AnsiString]: TDynRecord read getListItem; default; // alas, FPC 3+ lost property overloading feature
174 // userdata
180 // "value" header record contains TList fields, with name equal to record type
182 private
189 {$IF DEFINED(XDYNREC_USE_FIELDHASH)}
191 {$ENDIF}
195 mHeaderRec: TDynRecord; // for "value" records this is header record with data, for "type" records this is header type record
197 // for userdata
201 private
216 protected
219 function addRecordByType (const atypename: AnsiString; rc: TDynRecord): Boolean; // `true`: duplicate record id
224 public
242 // find field with `TriggerType` type
245 // number of records of the given instance
248 public
253 //property fields: TDynFieldList read mFields;
264 // userdata
270 private
279 private
288 public
295 // return empty string if not found
298 public
307 public
312 private
320 public
331 // creates new header record
334 // creates new header record
337 public
344 {$IF DEFINED(D2D_DYNREC_PROFILER)}
346 {$ENDIF}
349 implementation
351 uses
352 SysUtils, e_log
356 // ////////////////////////////////////////////////////////////////////////// //
360 // ////////////////////////////////////////////////////////////////////////// //
362 begin
369 begin
376 begin
382 begin
387 // ////////////////////////////////////////////////////////////////////////// //
389 begin
397 begin
405 begin
412 begin
419 begin
456 var
458 begin
469 begin
501 begin
502 //FIXME: check type
508 // won't work for lists
510 begin
528 begin
538 var
540 begin
542 try
544 finally
551 var
557 begin
559 begin
564 end
565 else
566 begin
572 try
579 finally
591 // default value should be parsed
593 begin
596 begin
598 raise Exception.Create(Format('field ''%s'' in record ''%s'' of record type ''%s'' is not set', [mName, mOwner.mId, mOwner.mName]));
608 // default value should be parsed
610 begin
623 begin
629 begin
630 if (mRVal <> nil) and (idx >= 0) and (idx < mRVal.count) then result := mRVal[idx] else result := nil;
635 var
637 begin
643 begin
646 begin
654 begin
675 begin
684 TEBS.TBitSet: begin result += ' bitset '; if mBitSetUnique then result += 'unique '; result += mEBSTypeName; end;
689 begin
690 if (mType = TType.TPoint) then begin if (mAsT) then result += ' as txy' else result += ' as xy'; end
691 else if (mType = TType.TSize) then begin if (mAsT) then result += ' as twh' else result += ' as wh'; end;
699 begin
703 TType.TChar: if (mMaxDim > 0) then result += formatstrf('Char%d;', [mMaxDim]) else result += 'Char;';
727 var
745 begin
776 begin
778 if (lmaxdim < 1) then raise Exception.Create(Format('invalid field ''%s'' array size', [fldname]));
780 end;
783 begin
785 begin
786 if (fldofs >= 0) then raise Exception.Create(Format('duplicate field ''%s'' offset', [fldname]));
789 continue;
793 begin
800 continue;
801 end;
804 begin
806 if (Length(fldrecname) <> 0) then raise Exception.Create(Format('field ''%s'' already typed as ''%s''', [fldname, fldrecname]));
808 continue;
812 begin
814 if (Length(fldrecname) <> 0) then raise Exception.Create(Format('field ''%s'' already typed as ''%s''', [fldname, fldrecname]));
817 continue;
821 begin
822 if hasdefStr or hasdefInt or hasdefId then raise Exception.Create(Format('field ''%s'' has duplicate default', [fldname]));
825 begin
830 begin
835 begin
839 else
842 continue;
846 begin
848 continue;
852 begin
854 continue;
857 if (pr.tokType <> pr.TTId) then raise Exception.Create(Format('field ''%s'' has something unexpected in definition', [fldname]));
859 if (Length(fldrecname) <> 0) then raise Exception.Create(Format('field ''%s'' already typed as ''%s''', [fldname, fldrecname]));
866 // create field
881 else raise Exception.Create(Format('field ''%s'' has invalid type ''%s''', [fldname, fldtype]));
883 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]));
885 begin
886 if (lmaxdim < 1) then raise Exception.Create(Format('field ''%s'' of type ''%s'' cannot be array', [fldname, fldtype]));
887 if (Length(fldrecname) > 0) then raise Exception.Create(Format('field ''%s'' of type ''%s'' cannot have another type', [fldname, fldtype]));
907 end;
911 begin
918 var
924 begin
928 begin
930 begin
931 // this must be triggerdata
933 begin
934 raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
936 // write triggerdata
938 if (buf = nil) then raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
939 try
942 begin
947 finally
951 exit;
953 // record reference
961 else raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
963 // find record number
965 begin
967 if (f < 0) then raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' not found in record list', [mEBSTypeName, mName]));
969 if (f > maxv) then raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' has too big index', [mEBSTypeName, mName]));
970 end
971 else
972 begin
979 else raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
981 exit;
990 begin
992 begin
994 end
995 else
996 begin
999 exit;
1002 begin
1003 if (mMaxDim = 0) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
1005 begin
1006 if (Length(mSVal) <> 1) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
1008 end
1009 else
1010 begin
1011 if (Length(mSVal) > mMaxDim) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
1016 exit;
1020 begin
1021 // triggerdata array was processed earlier
1022 if (mMaxDim >= 0) then Exception.Create(Format('byte array in field ''%s'' cannot be written', [mName]));
1024 exit;
1028 begin
1029 if (mMaxDim >= 0) then raise Exception.Create(Format('short array in field ''%s'' cannot be written', [mName]));
1031 exit;
1035 begin
1036 if (mMaxDim >= 0) then raise Exception.Create(Format('int array in field ''%s'' cannot be written', [mName]));
1038 exit;
1041 begin
1045 begin
1046 if (mMaxDim >= 0) then raise Exception.Create(Format('pos/size array in field ''%s'' cannot be written', [mName]));
1049 exit;
1052 begin
1053 if (mMaxDim >= 0) then raise Exception.Create(Format('pos/size array in field ''%s'' cannot be written', [mName]));
1056 exit;
1059 begin
1061 exit;
1064 begin
1066 exit;
1074 var
1078 begin
1084 begin
1086 begin
1088 end
1090 begin
1092 end
1093 else
1094 begin
1098 exit;
1101 begin
1102 //def := mOwner.mOwner;
1103 //es := def.findEBSType(mEBSTypeName);
1106 if (es = nil) or (not es.mIsEnum) then raise Exception.Create(Format('record enum type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1108 begin
1110 begin
1113 exit;
1116 raise Exception.Create(Format('value %d in record enum type ''%s'' for field ''%s'' not found', [mIVal, mEBSTypeName, mName]));
1119 begin
1120 //def := mOwner.mOwner;
1121 //es := def.findEBSType(mEBSTypeName);
1124 if (es = nil) or es.mIsEnum then raise Exception.Create(Format('record bitset type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1125 // none?
1127 begin
1129 begin
1131 begin
1134 exit;
1137 raise Exception.Create(Format('value %d in record bitset type ''%s'' for field ''%s'' not found', [0, mEBSTypeName, mName]));
1139 // not none
1143 begin
1145 begin
1148 begin
1150 begin
1154 break;
1157 if not found then raise Exception.Create(Format('value %d in record bitset type ''%s'' for field ''%s'' not found', [mask, mEBSTypeName, mName]));
1162 exit;
1169 begin
1171 exit;
1174 begin
1175 if (mMaxDim = 0) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
1178 exit;
1186 begin
1188 exit;
1191 begin
1194 exit;
1198 begin
1200 exit;
1203 begin
1205 exit;
1208 begin
1210 exit;
1219 var
1226 begin
1230 begin
1231 // this must be triggerdata
1233 begin
1236 // find trigger definition
1238 if (tfld = nil) then raise Exception.Create(Format('triggerdata value for field ''%s'' in record ''%s'' without TriggerType field', [mName, rec.mName]));
1240 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]));
1243 try
1247 finally
1251 exit;
1252 end
1253 else
1254 begin
1255 // not a trigger data
1263 else raise Exception.Create(Format('invalid non-numeric type ''%s'' for field ''%s'' of record ''%s''', [getTypeName(mType), mName, mEBSTypeName]));
1269 exit;
1273 begin
1282 else raise Exception.Create(Format('invalid non-numeric type ''%s'' for field ''%s'' of record ''%s''', [getTypeName(mType), mName, mEBSTypeName]));
1286 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]));
1288 // build enum/bitfield values
1290 begin
1292 if (Length(mSVal) = 0) then raise Exception.Create(Format('record enum type ''%s'' for field ''%s'' has invalid value %d', [mEBSTypeName, mName, mIVal]));
1293 end
1294 else
1295 begin
1296 // special for 'none'
1298 begin
1300 if (Length(mSVal) = 0) then raise Exception.Create(Format('record bitset type ''%s'' for field ''%s'' has invalid value %d', [mEBSTypeName, mName, mIVal]));
1301 end
1302 else
1303 begin
1307 begin
1309 begin
1311 if (Length(s) = 0) then raise Exception.Create(Format('record bitset type ''%s'' for field ''%s'' has invalid value %d', [mEBSTypeName, mName, mask]));
1319 //writeln('ebs <', es.mName, '>: ', mSVal);
1321 exit;
1328 begin
1334 exit;
1337 begin
1339 begin
1341 end
1342 else
1343 begin
1346 try
1351 begin
1356 finally
1361 exit;
1370 begin
1372 exit;
1375 begin
1379 exit;
1382 begin
1386 exit;
1389 begin
1391 exit;
1394 begin
1396 exit;
1407 begin
1409 if (mIVal < min) or (mIVal > max) then raise Exception.Create(Format('invalid %s value for field ''%s''', [getTypeName(mType), mName]));
1413 var
1419 begin
1420 // if this field should contain struct, convert type and parse struct
1424 begin
1425 // ugly hack. sorry.
1427 begin
1430 begin
1431 // '{}'
1434 end
1435 else
1436 begin
1438 // find trigger definition
1440 if (tfld = nil) then raise Exception.Create(Format('triggerdata value for field ''%s'' in record ''%s'' without ''type'' field', [mName, rec.mName]));
1442 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]));
1445 //writeln(rc.definition);
1446 try
1450 finally
1456 exit;
1458 // other record types
1460 begin
1462 begin
1464 end
1465 else
1466 begin
1468 if (rec = nil) then raise Exception.Create(Format('record ''%s'' (%s) value for field ''%s'' not found', [pr.tokStr, mEBSTypeName, mName]));
1474 exit;
1475 end
1477 begin
1478 //rec := mOwner.mOwner.findRecType(mEBSTypeName); // find in mapdef
1481 if (rec = nil) then raise Exception.Create(Format('record type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1488 begin
1489 //raise Exception.Create(Format('record type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1490 e_LogWritefln('duplicate record with id ''%s'' for field ''%s'' in record ''%s''', [rc.mId, mName, mOwner.mName]);
1493 exit;
1498 begin
1499 //es := mOwner.mOwner.findEBSType(mEBSTypeName); // find in mapdef
1502 if (es = nil) or (not es.mIsEnum) then raise Exception.Create(Format('record enum type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1504 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]));
1507 //writeln('ENUM ', mEBSName, '; element <', mSVal, '> with value ', mIVal);
1510 exit;
1513 begin
1514 //es := mOwner.mOwner.findEBSType(mEBSTypeName); // find in mapdef
1517 if (es = nil) or es.mIsEnum then raise Exception.Create(Format('record bitset type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1520 begin
1522 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]));
1526 if mBitSetUnique then raise Exception.Create(Format('record bitset of type ''%s'' for field ''%s'' expects only one value', [tk, mEBSTypeName, mName]));
1527 //pr.expectDelim('|');
1532 exit;
1539 begin
1545 exit;
1548 begin
1549 if (mMaxDim = 0) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
1552 begin
1553 // single char
1554 if (Length(mSVal) <> 1) then raise Exception.Create(Format('invalid string size for field ''%s''', [mName]));
1557 end
1558 else
1559 begin
1560 // string
1561 if (Length(mSVal) > mMaxDim) then raise Exception.Create(Format('invalid string size for field ''%s''', [mName]));
1565 exit;
1568 begin
1571 exit;
1574 begin
1577 exit;
1580 begin
1583 exit;
1586 begin
1589 exit;
1592 begin
1595 exit;
1598 begin
1601 exit;
1604 begin
1608 exit;
1612 begin
1616 begin
1617 if (mIVal < 0) or (mIVal > 32767) then raise Exception.Create(Format('invalid %s value for field ''%s''', [getTypeName(mType), mName]));
1621 begin
1622 if (mIVal2 < 0) or (mIVal2 > 32767) then raise Exception.Create(Format('invalid %s value for field ''%s''', [getTypeName(mType), mName]));
1627 exit;
1630 begin
1632 exit;
1635 begin
1637 exit;
1645 // ////////////////////////////////////////////////////////////////////////// //
1647 begin
1648 if (pr = nil) then raise Exception.Create('cannot create record type without type definition');
1653 {$IF DEFINED(XDYNREC_USE_FIELDHASH)}
1655 {$ENDIF}
1667 begin
1671 {$IF DEFINED(XDYNREC_USE_FIELDHASH)}
1673 {$ENDIF}
1683 begin
1687 {$IF DEFINED(XDYNREC_USE_FIELDHASH)}
1690 {$ENDIF}
1700 begin
1703 {$IF DEFINED(XDYNREC_USE_FIELDHASH)}
1705 {$ENDIF}
1709 function TDynRecord.addFieldChecked (fld: TDynField): Boolean; inline; // `true`: duplicate name
1710 begin
1713 {$IF not DEFINED(XDYNREC_USE_FIELDHASH)}
1715 {$ENDIF}
1717 {$IF DEFINED(XDYNREC_USE_FIELDHASH)}
1719 {$ENDIF}
1724 begin
1725 {$IF DEFINED(XDYNREC_USE_FIELDHASH)}
1727 {$ELSE}
1730 begin
1735 {$ENDIF}
1740 begin
1746 var
1748 begin
1755 begin
1761 begin
1767 begin
1773 var
1775 begin
1783 begin
1789 begin
1795 var
1798 begin
1806 begin
1821 var
1824 begin
1827 // find record data
1830 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]));
1831 // find by id
1833 begin
1836 // alas
1840 function TDynRecord.findRecordNumByType (const atypename: AnsiString; rc: TDynRecord): Integer;
1841 var
1844 begin
1846 // find record data
1849 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]));
1850 // find by ref
1852 begin
1854 begin
1858 // alas
1863 var
1865 begin
1866 // find record data
1869 begin
1870 // first record
1875 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]));
1876 // append
1878 begin
1887 var
1889 begin
1895 begin
1903 var
1906 begin
1908 begin
1919 // number of records of the given instance
1921 var
1923 begin
1931 var
1934 begin
1936 begin
1939 begin
1941 begin
1945 if isForTrig[tdn] then raise Exception.Create(Format('duplicate trigdata ''%s'' trigtype ''%s''', [mName, tdn]));
1949 end
1950 else
1951 begin
1957 end
1958 else
1959 begin
1964 begin
1967 begin
1968 if (mSize > 0) then raise Exception.Create(Format('duplicate `size` in record ''%s''', [mName]));
1970 if (mSize < 1) then raise Exception.Create(Format('invalid record ''%s'' size: %d', [mName, mSize]));
1972 continue;
1975 begin
1976 if (mBinBlock >= 0) then raise Exception.Create(Format('duplicate `binblock` in record ''%s''', [mName]));
1978 if (mBinBlock < 1) then raise Exception.Create(Format('invalid record ''%s'' binblock: %d', [mName, mBinBlock]));
1979 continue;
1985 // load fields
1987 begin
1989 //if hasByName(fld.name) then begin fld.Free(); raise Exception.Create(Format('duplicate field ''%s''', [fld.name])); end;
1990 // append
1993 begin
1997 // done with field
2004 var
2006 begin
2008 begin
2011 end
2012 else
2013 begin
2014 // record
2018 begin
2028 var
2030 begin
2032 begin
2033 // trigger data
2036 begin
2039 begin
2044 end
2045 else
2046 begin
2049 end
2050 else
2051 begin
2052 // record
2059 begin
2069 var
2081 var
2084 begin
2085 //writeln('*** rec: ', rec.mName, '.', rec.mId, ' (', rec.mFields.count, ')');
2087 begin
2089 begin
2091 continue;
2097 begin
2098 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);
2099 //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]));
2101 //writeln(' ', rec.mName, '.', rec.mId, ':', fld.mName, ' -> ', rt.mName, '.', rt.mId, ' (', fld.mEBSTypeName, '.', fld.mRecRefId, ')');
2107 begin
2108 //writeln(' ', fld.mName);
2113 begin
2116 try
2118 begin
2119 // parse map file as sequence of blocks
2123 // parse blocks
2125 begin
2131 if (bsize < 0) or (bsize > $1fffffff) then raise Exception.Create(Format('block of type %d has invalid size %d', [btype, bsize]));
2132 if loaded[btype] then raise Exception.Create(Format('block of type %d already loaded', [btype]));
2134 // find record type for this block
2137 if (rect = nil) then raise Exception.Create(Format('block of type %d has no corresponding record', [btype]));
2138 //writeln('found type ''', rec.mName, ''' for block type ', btype);
2139 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]));
2140 // header?
2142 begin
2143 if (bsize <> mSize) then raise Exception.Create(Format('header block of type %d has invalid number of records', [btype]));
2148 end
2149 else
2150 begin
2151 // create list for this type
2156 begin
2160 begin
2167 //writeln('parsed ''', rec.mId, '''...');
2173 //st.position := st.position+bsize;
2175 // link fields
2177 begin
2181 exit;
2184 // read fields
2186 if (mSize < 1) then raise Exception.Create(Format('cannot read record of type ''%s'' with unknown size', [mName]));
2190 begin
2193 if (fld.mBinOfs >= st.size) then raise Exception.Create(Format('record of type ''%s'' has invalid field ''%s''', [fld.mName]));
2195 //writeln('parsing ''', mName, '.', fld.mName, '''...');
2198 finally
2205 procedure TDynRecord.writeBinTo (st: TStream; trigbufsz: Integer=-1; onlyFields: Boolean=false);
2206 var
2212 //f, c: Integer;
2215 begin
2217 begin
2218 if (mBinBlock < 1) then raise Exception.Create('cannot write binary record without block number');
2221 end
2222 else
2223 begin
2226 try
2231 // write normal fields
2233 begin
2234 // record list?
2238 if (fld.mBinOfs >= bufsz) then raise Exception.Create('binary value offset is outside of the buffer');
2240 //writeln('writing field <', fld.mName, '>');
2244 // write block with normal fields
2246 begin
2247 //writeln('writing header...');
2248 // signature and version
2259 // write other blocks, if any
2261 begin
2262 // calculate blkmax
2265 begin
2266 // record list?
2268 begin
2276 // write blocks
2278 begin
2282 begin
2283 // record list?
2285 begin
2294 // flush block
2296 begin
2307 // write end marker
2312 finally
2320 var
2323 begin
2325 begin
2332 try
2334 begin
2335 // record list?
2337 begin
2340 begin
2342 begin
2348 continue;
2355 finally
2363 {$IF DEFINED(D2D_DYNREC_PROFILER)}
2364 var
2375 begin
2377 writeln('record cloning: ', profCloneRec div 1000, '.', profCloneRec mod 1000, ' milliseconds');
2378 writeln('findRecType : ', profFindRecType div 1000, '.', profFindRecType mod 1000, ' milliseconds');
2379 writeln('field[] : ', profFieldSearching div 1000, '.', profFieldSearching mod 1000, ' milliseconds');
2380 writeln('list dup check: ', profListDupChecking div 1000, '.', profListDupChecking mod 1000, ' milliseconds');
2381 writeln('addRecByType : ', profAddRecByType div 1000, '.', profAddRecByType mod 1000, ' milliseconds');
2382 writeln('field valparse: ', profFieldValParsing div 1000, '.', profFieldValParsing mod 1000, ' milliseconds');
2383 writeln('fix defaults : ', profFixDefaults div 1000, '.', profFixDefaults mod 1000, ' milliseconds');
2384 writeln('recvalparse : ', profRecValParse div 1000, '.', profRecValParse mod 1000, ' milliseconds');
2386 {$ENDIF}
2390 var
2394 {$IF DEFINED(D2D_DYNREC_PROFILER)}
2396 {$ENDIF}
2397 begin
2398 if (mOwner = nil) then raise Exception.Create(Format('can''t parse record ''%s'' value without owner', [mName]));
2402 // not a header?
2404 begin
2405 // id?
2407 end
2408 else
2409 begin
2413 //writeln('parsing record <', mName, '>');
2416 begin
2418 //writeln('<', mName, '.', pr.tokStr, '>');
2420 // records
2422 begin
2423 // add records with this type (if any)
2428 begin
2433 try
2436 (*
2437 if (Length(rec.mId) > 0) then
2438 begin
2439 {$IF DEFINED(D2D_DYNREC_PROFILER)}stt := curTimeMicro();{$ENDIF}
2440 fld := field[pr.tokStr];
2441 {$IF DEFINED(D2D_DYNREC_PROFILER)}profFieldSearching := curTimeMicro()-stt;{$ENDIF}
2442 (*
2443 if (fld <> nil) and (fld.mRVal <> nil) then
2444 begin
2445 {$IF DEFINED(D2D_DYNREC_PROFILER)}stt := curTimeMicro();{$ENDIF}
2446 //idtmp := trc.mName+':'+rec.mId;
2447 //if ids.put(idtmp, 1) then raise Exception.Create(Format('duplicate thing ''%s'' in record ''%s''', [fld.mName, mName]));
2448 if fld.mRHash.has(rec.mId) then raise Exception.Create(Format('duplicate thing ''%s'' in record ''%s''', [fld.mName, mName]));
2449 {$IF DEFINED(D2D_DYNREC_PROFILER)}profListDupChecking := curTimeMicro()-stt;{$ENDIF}
2450 end;
2451 end;
2452 *)
2457 finally
2460 continue;
2464 // fields
2469 begin
2470 if fld.defined then raise Exception.Create(Format('duplicate field ''%s'' in record ''%s''', [fld.mName, mName]));
2471 if fld.internal then raise Exception.Create(Format('internal field ''%s'' in record ''%s''', [fld.mName, mName]));
2476 continue;
2479 // something is wrong
2483 // fix field defaults
2487 //writeln('done parsing record <', mName, '>');
2488 //{$IF DEFINED(D2D_DYNREC_PROFILER)}writeln('stall: ', curTimeMicro()-stall);{$ENDIF}
2493 // ////////////////////////////////////////////////////////////////////////// //
2495 begin
2502 begin
2509 begin
2520 begin
2523 begin
2532 begin
2538 var
2540 begin
2547 var
2549 begin
2553 // fields
2556 begin
2560 begin
2564 end
2565 else
2566 begin
2571 // max field
2578 var
2580 begin
2582 // fields
2584 begin
2591 var
2593 begin
2595 begin
2603 var
2609 begin
2618 begin
2621 begin
2622 if StrEqu(mIds[f], idname) then raise Exception.Create(Format('duplicate field ''%s'' in enum/bitset ''%s''', [idname, mName]));
2624 if StrEqu(mMaxName, idname) then raise Exception.Create(Format('duplicate field ''%s'' in enum/bitset ''%s''', [idname, mName]));
2628 // has value?
2630 begin
2632 begin
2633 if (Length(mMaxName) > 0) then raise Exception.Create(Format('duplicate max field ''%s'' in enum/bitset ''%s''', [idname, mName]));
2636 end
2637 else
2638 begin
2644 // append it?
2646 begin
2647 // fix maxvalue
2649 begin
2656 // next cv
2658 begin
2667 // add max field
2669 begin
2678 // ////////////////////////////////////////////////////////////////////////// //
2680 begin
2689 var
2692 begin
2707 begin
2714 var
2716 begin
2718 begin
2726 var
2728 begin
2730 begin
2738 var
2740 begin
2742 begin
2750 var
2755 // setup header links and type links
2757 var
2759 begin
2762 begin
2767 begin
2769 if (fld.mEBSType = nil) then raise Exception.Create(Format('field ''%s'' of type ''%s'' has no correcponding record definition', [fld.mName, fld.mEBSTypeName]));
2773 begin
2775 if (fld.mEBSType = nil) then raise Exception.Create(Format('field ''%s'' of type ''%s'' has no correcponding enum/bitset', [fld.mName, fld.mEBSTypeName]));
2776 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]));
2782 // setup default values
2784 var
2786 begin
2790 begin
2793 begin
2798 begin
2801 begin
2807 //writeln(eb.definition); writeln;
2808 continue;
2812 begin
2815 begin
2817 begin
2824 //writeln(dr.definition); writeln;
2825 continue;
2829 //writeln(dr.definition); writeln;
2830 if (findRecType(rec.name) <> nil) then begin rec.Free(); raise Exception.Create(Format('duplicate record ''%s''', [rec.name])); end;
2831 if (hdr <> nil) and StrEqu(rec.name, hdr.name) then begin rec.Free(); raise Exception.Create(Format('duplicate record ''%s''', [rec.name])); end;
2834 begin
2835 if (hdr <> nil) then begin rec.Free(); raise Exception.Create(Format('duplicate header record ''%s'' (previous is ''%s'')', [rec.name, hdr.name])); end;
2837 end
2838 else
2839 begin
2844 // put header record to top
2850 // setup header links and type links
2854 // setup default values
2860 // ////////////////////////////////////////////////////////////////////////// //
2862 var
2864 begin
2866 try
2873 finally
2880 var
2882 begin
2884 try
2890 finally
2897 var
2903 begin
2905 result += '// ////////////////////////////////////////////////////////////////////////// //'#10;
2908 result += #10#10'// ////////////////////////////////////////////////////////////////////////// //'#10;
2911 begin
2916 result += #10#10'// ////////////////////////////////////////////////////////////////////////// //'#10;
2922 begin
2926 begin
2932 begin
2944 var
2946 begin
2948 result += '// ////////////////////////////////////////////////////////////////////////// //'#10;
2954 function TDynMapDef.getTrigTypeCount (): Integer; inline; begin result := trigTypes.count; end;
2955 function TDynMapDef.getTrigTypeAt (idx: Integer): TDynRecord; inline; begin if (idx >= 0) and (idx < trigTypes.count) then result := trigTypes[idx] else result := nil; end;