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
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`
111 protected
112 // returns `true` for duplicate record id
115 public
134 // won't work for lists
141 public
160 property recrefIndex: Integer read getRecRefIndex; // search for this record in header; -1: not found
161 // for lists
164 property items[const aname: AnsiString]: TDynRecord read getListItem; default; // alas, FPC 3+ lost property overloading feature
165 // userdata
168 //
173 // "value" header record contains TList fields, with name equal to record type
175 private
182 {$IF DEFINED(XDYNREC_USE_FIELDHASH)}
184 {$ENDIF}
188 mHeaderRec: TDynRecord; // for "value" records this is header record with data, for "type" records this is header type record
190 // for userdata
194 private
209 protected
212 function addRecordByType (const atypename: AnsiString; rc: TDynRecord): Boolean; // `true`: duplicate record id
217 public
235 // find field with `TriggerType` type
238 // number of records of the given instance
241 //procedure setUserField (const fldname: AnsiString; v: LongInt);
242 //procedure setUserField (const fldname: AnsiString; v: AnsiString);
243 //procedure setUserField (const fldname: AnsiString; v: Boolean);
248 public
253 //property fields: TDynFieldList read mFields;
264 // userdata
267 // userfields
272 private
281 private
290 public
297 // return empty string if not found
300 public
309 public
314 private
322 public
333 // creates new header record
336 // creates new header record
339 public
346 {$IF DEFINED(D2D_DYNREC_PROFILER)}
348 {$ENDIF}
351 implementation
353 uses
354 SysUtils, e_log
358 // ////////////////////////////////////////////////////////////////////////// //
362 // ////////////////////////////////////////////////////////////////////////// //
364 begin
365 //result := TListEnumerator.Create(mRVal);
366 if (mRVal <> nil) then result := mRVal.GetEnumerator else result := TDynRecList.TEnumerator.Create(nil, 0);
370 // ////////////////////////////////////////////////////////////////////////// //
372 begin
380 begin
388 begin
396 begin
420 else
424 begin
461 begin
468 begin
505 var
507 begin
518 begin
550 begin
551 //FIXME: check type
558 begin
581 begin
605 else
609 begin
620 varString:
622 begin
624 end
625 else
626 begin
630 varBoolean:
642 else
647 varByte,
648 varWord,
649 varShortInt,
650 varSmallint,
651 varInteger:
653 varInt64:
656 else
658 varLongWord:
659 if (val > LongWord($7FFFFFFF)) then raise Exception.Create('cannot convert longword variant to field value')
669 // won't work for lists
671 begin
689 begin
699 var
701 begin
703 try
705 finally
712 var
718 begin
720 begin
725 end
726 else
727 begin
733 try
740 finally
752 // default value should be parsed
754 begin
757 begin
759 raise Exception.Create(Format('field ''%s'' in record ''%s'' of record type ''%s'' is not set', [mName, mOwner.mId, mOwner.mName]));
769 // default value should be parsed
771 begin
784 begin
790 begin
791 if (mRVal <> nil) and (idx >= 0) and (idx < mRVal.count) then result := mRVal[idx] else result := nil;
796 var
798 begin
804 begin
807 begin
815 begin
836 begin
845 TEBS.TBitSet: begin result += ' bitset '; if mBitSetUnique then result += 'unique '; result += mEBSTypeName; end;
850 begin
851 if (mType = TType.TPoint) then begin if (mAsT) then result += ' as txy' else result += ' as xy'; end
852 else if (mType = TType.TSize) then begin if (mAsT) then result += ' as twh' else result += ' as wh'; end;
860 begin
864 TType.TChar: if (mMaxDim > 0) then result += formatstrf('Char%d;', [mMaxDim]) else result += 'Char;';
888 var
906 begin
937 begin
939 if (lmaxdim < 1) then raise Exception.Create(Format('invalid field ''%s'' array size', [fldname]));
941 end;
944 begin
946 begin
947 if (fldofs >= 0) then raise Exception.Create(Format('duplicate field ''%s'' offset', [fldname]));
950 continue;
954 begin
961 continue;
962 end;
965 begin
967 if (Length(fldrecname) <> 0) then raise Exception.Create(Format('field ''%s'' already typed as ''%s''', [fldname, fldrecname]));
969 continue;
973 begin
975 if (Length(fldrecname) <> 0) then raise Exception.Create(Format('field ''%s'' already typed as ''%s''', [fldname, fldrecname]));
978 continue;
982 begin
983 if hasdefStr or hasdefInt or hasdefId then raise Exception.Create(Format('field ''%s'' has duplicate default', [fldname]));
986 begin
991 begin
996 begin
1000 else
1003 continue;
1007 begin
1009 continue;
1013 begin
1015 continue;
1018 if (pr.tokType <> pr.TTId) then raise Exception.Create(Format('field ''%s'' has something unexpected in definition', [fldname]));
1020 if (Length(fldrecname) <> 0) then raise Exception.Create(Format('field ''%s'' already typed as ''%s''', [fldname, fldrecname]));
1027 // create field
1042 else raise Exception.Create(Format('field ''%s'' has invalid type ''%s''', [fldname, fldtype]));
1044 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]));
1046 begin
1047 if (lmaxdim < 1) then raise Exception.Create(Format('field ''%s'' of type ''%s'' cannot be array', [fldname, fldtype]));
1048 if (Length(fldrecname) > 0) then raise Exception.Create(Format('field ''%s'' of type ''%s'' cannot have another type', [fldname, fldtype]));
1068 end;
1072 begin
1079 var
1085 begin
1089 begin
1091 begin
1092 // this must be triggerdata
1094 begin
1095 raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
1097 // write triggerdata
1099 if (buf = nil) then raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
1100 try
1103 begin
1108 finally
1112 exit;
1114 // record reference
1122 else raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
1124 // find record number
1126 begin
1128 if (f < 0) then raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' not found in record list', [mEBSTypeName, mName]));
1130 if (f > maxv) then raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' has too big index', [mEBSTypeName, mName]));
1131 end
1132 else
1133 begin
1140 else raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
1142 exit;
1151 begin
1153 begin
1155 end
1156 else
1157 begin
1160 exit;
1163 begin
1164 if (mMaxDim = 0) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
1166 begin
1167 if (Length(mSVal) <> 1) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
1169 end
1170 else
1171 begin
1172 if (Length(mSVal) > mMaxDim) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
1177 exit;
1181 begin
1182 // triggerdata array was processed earlier
1183 if (mMaxDim >= 0) then Exception.Create(Format('byte array in field ''%s'' cannot be written', [mName]));
1185 exit;
1189 begin
1190 if (mMaxDim >= 0) then raise Exception.Create(Format('short array in field ''%s'' cannot be written', [mName]));
1192 exit;
1196 begin
1197 if (mMaxDim >= 0) then raise Exception.Create(Format('int array in field ''%s'' cannot be written', [mName]));
1199 exit;
1202 begin
1206 begin
1207 if (mMaxDim >= 0) then raise Exception.Create(Format('pos/size array in field ''%s'' cannot be written', [mName]));
1210 exit;
1213 begin
1214 if (mMaxDim >= 0) then raise Exception.Create(Format('pos/size array in field ''%s'' cannot be written', [mName]));
1217 exit;
1220 begin
1222 exit;
1225 begin
1227 exit;
1235 var
1239 begin
1245 begin
1247 begin
1249 end
1251 begin
1253 end
1254 else
1255 begin
1259 exit;
1262 begin
1263 //def := mOwner.mOwner;
1264 //es := def.findEBSType(mEBSTypeName);
1267 if (es = nil) or (not es.mIsEnum) then raise Exception.Create(Format('record enum type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1269 begin
1271 begin
1274 exit;
1277 raise Exception.Create(Format('value %d in record enum type ''%s'' for field ''%s'' not found', [mIVal, mEBSTypeName, mName]));
1280 begin
1281 //def := mOwner.mOwner;
1282 //es := def.findEBSType(mEBSTypeName);
1285 if (es = nil) or es.mIsEnum then raise Exception.Create(Format('record bitset type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1286 // none?
1288 begin
1290 begin
1292 begin
1295 exit;
1298 raise Exception.Create(Format('value %d in record bitset type ''%s'' for field ''%s'' not found', [0, mEBSTypeName, mName]));
1300 // not none
1304 begin
1306 begin
1309 begin
1311 begin
1315 break;
1318 if not found then raise Exception.Create(Format('value %d in record bitset type ''%s'' for field ''%s'' not found', [mask, mEBSTypeName, mName]));
1323 exit;
1330 begin
1332 exit;
1335 begin
1336 if (mMaxDim = 0) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
1339 exit;
1347 begin
1349 exit;
1352 begin
1355 exit;
1359 begin
1361 exit;
1364 begin
1366 exit;
1369 begin
1371 exit;
1380 var
1387 begin
1391 begin
1392 // this must be triggerdata
1394 begin
1397 // find trigger definition
1399 if (tfld = nil) then raise Exception.Create(Format('triggerdata value for field ''%s'' in record ''%s'' without TriggerType field', [mName, rec.mName]));
1401 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]));
1404 try
1408 finally
1412 exit;
1413 end
1414 else
1415 begin
1416 // not a trigger data
1424 else raise Exception.Create(Format('invalid non-numeric type ''%s'' for field ''%s'' of record ''%s''', [getTypeName(mType), mName, mEBSTypeName]));
1430 exit;
1434 begin
1443 else raise Exception.Create(Format('invalid non-numeric type ''%s'' for field ''%s'' of record ''%s''', [getTypeName(mType), mName, mEBSTypeName]));
1447 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]));
1449 // build enum/bitfield values
1451 begin
1453 if (Length(mSVal) = 0) then raise Exception.Create(Format('record enum type ''%s'' for field ''%s'' has invalid value %d', [mEBSTypeName, mName, mIVal]));
1454 end
1455 else
1456 begin
1457 // special for 'none'
1459 begin
1461 if (Length(mSVal) = 0) then raise Exception.Create(Format('record bitset type ''%s'' for field ''%s'' has invalid value %d', [mEBSTypeName, mName, mIVal]));
1462 end
1463 else
1464 begin
1468 begin
1470 begin
1472 if (Length(s) = 0) then raise Exception.Create(Format('record bitset type ''%s'' for field ''%s'' has invalid value %d', [mEBSTypeName, mName, mask]));
1480 //writeln('ebs <', es.mName, '>: ', mSVal);
1482 exit;
1489 begin
1495 exit;
1498 begin
1500 begin
1502 end
1503 else
1504 begin
1507 try
1512 begin
1517 finally
1522 exit;
1531 begin
1533 exit;
1536 begin
1540 exit;
1543 begin
1547 exit;
1550 begin
1552 exit;
1555 begin
1557 exit;
1568 begin
1570 if (mIVal < min) or (mIVal > max) then raise Exception.Create(Format('invalid %s value for field ''%s''', [getTypeName(mType), mName]));
1574 var
1580 begin
1581 // if this field should contain struct, convert type and parse struct
1585 begin
1586 // ugly hack. sorry.
1588 begin
1591 begin
1592 // '{}'
1595 end
1596 else
1597 begin
1599 // find trigger definition
1601 if (tfld = nil) then raise Exception.Create(Format('triggerdata value for field ''%s'' in record ''%s'' without ''type'' field', [mName, rec.mName]));
1603 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]));
1606 //writeln(rc.definition);
1607 try
1611 finally
1617 exit;
1619 // other record types
1621 begin
1623 begin
1625 end
1626 else
1627 begin
1629 if (rec = nil) then raise Exception.Create(Format('record ''%s'' (%s) value for field ''%s'' not found', [pr.tokStr, mEBSTypeName, mName]));
1635 exit;
1636 end
1638 begin
1639 //rec := mOwner.mOwner.findRecType(mEBSTypeName); // find in mapdef
1642 if (rec = nil) then raise Exception.Create(Format('record type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1649 begin
1650 //raise Exception.Create(Format('record type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1651 e_LogWritefln('duplicate record with id ''%s'' for field ''%s'' in record ''%s''', [rc.mId, mName, mOwner.mName]);
1654 exit;
1659 begin
1660 //es := mOwner.mOwner.findEBSType(mEBSTypeName); // find in mapdef
1663 if (es = nil) or (not es.mIsEnum) then raise Exception.Create(Format('record enum type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1665 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]));
1668 //writeln('ENUM ', mEBSName, '; element <', mSVal, '> with value ', mIVal);
1671 exit;
1674 begin
1675 //es := mOwner.mOwner.findEBSType(mEBSTypeName); // find in mapdef
1678 if (es = nil) or es.mIsEnum then raise Exception.Create(Format('record bitset type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1681 begin
1683 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]));
1687 if mBitSetUnique then raise Exception.Create(Format('record bitset of type ''%s'' for field ''%s'' expects only one value', [tk, mEBSTypeName, mName]));
1688 //pr.expectDelim('|');
1693 exit;
1700 begin
1706 exit;
1709 begin
1710 if (mMaxDim = 0) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
1713 begin
1714 // single char
1715 if (Length(mSVal) <> 1) then raise Exception.Create(Format('invalid string size for field ''%s''', [mName]));
1718 end
1719 else
1720 begin
1721 // string
1722 if (Length(mSVal) > mMaxDim) then raise Exception.Create(Format('invalid string size for field ''%s''', [mName]));
1726 exit;
1729 begin
1732 exit;
1735 begin
1738 exit;
1741 begin
1744 exit;
1747 begin
1750 exit;
1753 begin
1756 exit;
1759 begin
1762 exit;
1765 begin
1769 exit;
1773 begin
1777 begin
1778 if (mIVal < 0) or (mIVal > 32767) then raise Exception.Create(Format('invalid %s value for field ''%s''', [getTypeName(mType), mName]));
1782 begin
1783 if (mIVal2 < 0) or (mIVal2 > 32767) then raise Exception.Create(Format('invalid %s value for field ''%s''', [getTypeName(mType), mName]));
1788 exit;
1791 begin
1793 exit;
1796 begin
1798 exit;
1806 // ////////////////////////////////////////////////////////////////////////// //
1808 begin
1809 if (pr = nil) then raise Exception.Create('cannot create record type without type definition');
1814 {$IF DEFINED(XDYNREC_USE_FIELDHASH)}
1816 {$ENDIF}
1828 begin
1832 {$IF DEFINED(XDYNREC_USE_FIELDHASH)}
1834 {$ENDIF}
1844 begin
1848 {$IF DEFINED(XDYNREC_USE_FIELDHASH)}
1851 {$ENDIF}
1861 begin
1864 {$IF DEFINED(XDYNREC_USE_FIELDHASH)}
1866 {$ENDIF}
1870 function TDynRecord.addFieldChecked (fld: TDynField): Boolean; inline; // `true`: duplicate name
1871 begin
1874 {$IF not DEFINED(XDYNREC_USE_FIELDHASH)}
1876 {$ENDIF}
1878 {$IF DEFINED(XDYNREC_USE_FIELDHASH)}
1880 {$ENDIF}
1885 begin
1886 {$IF DEFINED(XDYNREC_USE_FIELDHASH)}
1888 {$ELSE}
1891 begin
1896 {$ENDIF}
1901 begin
1907 var
1909 begin
1916 begin
1922 begin
1928 begin
1934 var
1936 begin
1944 begin
1950 begin
1956 var
1959 begin
1967 begin
1982 var
1985 begin
1988 // find record data
1991 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]));
1992 // find by id
1994 begin
1997 // alas
2001 function TDynRecord.findRecordNumByType (const atypename: AnsiString; rc: TDynRecord): Integer;
2002 var
2005 begin
2007 // find record data
2010 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]));
2011 // find by ref
2013 begin
2015 begin
2019 // alas
2024 var
2026 begin
2027 // find record data
2030 begin
2031 // first record
2036 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]));
2037 // append
2039 begin
2048 var
2050 begin
2056 begin
2064 var
2067 begin
2069 begin
2080 // number of records of the given instance
2082 var
2084 begin
2092 var
2094 begin
2101 var
2103 begin
2106 begin
2112 end
2113 else
2114 begin
2120 {
2121 procedure TDynRecord.setUserField (const fldname: AnsiString; v: LongInt);
2122 var
2123 fld: TDynField;
2124 begin
2125 if (Length(fldname) = 0) then exit;
2126 fld := field[fldname];
2127 if (fld <> nil) then
2128 begin
2129 if (fld.mType <> fld.TType.TInt) or (fld.mEBS <> fld.TEBS.TNone) then
2130 begin
2131 raise Exception.Create(Format('invalid user field ''%s'' type', [fld.name]));
2132 end;
2133 end
2134 else
2135 begin
2136 fld := TDynField.Create(fldname, fld.TType.TInt);
2137 fld.mOwner := self;
2138 fld.mIVal := v;
2139 fld.mInternal := true;
2140 fld.mDefined := true;
2141 addField(fld);
2142 end;
2143 end;
2146 procedure TDynRecord.setUserField (const fldname: AnsiString; v: AnsiString);
2147 var
2148 fld: TDynField;
2149 begin
2150 if (Length(fldname) = 0) then exit;
2151 fld := field[fldname];
2152 if (fld <> nil) then
2153 begin
2154 if (fld.mType <> fld.TType.TString) or (fld.mEBS <> fld.TEBS.TNone) then
2155 begin
2156 raise Exception.Create(Format('invalid user field ''%s'' type', [fld.name]));
2157 end;
2158 end
2159 else
2160 begin
2161 fld := TDynField.Create(fldname, fld.TType.TString);
2162 fld.mOwner := self;
2163 fld.mSVal := v;
2164 fld.mInternal := true;
2165 fld.mDefined := true;
2166 addField(fld);
2167 end;
2168 end;
2171 procedure TDynRecord.setUserField (const fldname: AnsiString; v: Boolean);
2172 var
2173 fld: TDynField;
2174 begin
2175 if (Length(fldname) = 0) then exit;
2176 fld := field[fldname];
2177 if (fld <> nil) then
2178 begin
2179 if (fld.mType <> fld.TType.TBool) or (fld.mEBS <> fld.TEBS.TNone) then
2180 begin
2181 raise Exception.Create(Format('invalid user field ''%s'' type', [fld.name]));
2182 end;
2183 end
2184 else
2185 begin
2186 fld := TDynField.Create(fldname, fld.TType.TBool);
2187 fld.mOwner := self;
2188 fld.mIVal := Integer(v);
2189 fld.mInternal := true;
2190 fld.mDefined := true;
2191 addField(fld);
2192 end;
2193 end;
2194 }
2198 var
2201 begin
2203 begin
2206 begin
2208 begin
2212 if isForTrig[tdn] then raise Exception.Create(Format('duplicate trigdata ''%s'' trigtype ''%s''', [mName, tdn]));
2216 end
2217 else
2218 begin
2224 end
2225 else
2226 begin
2231 begin
2234 begin
2235 if (mSize > 0) then raise Exception.Create(Format('duplicate `size` in record ''%s''', [mName]));
2237 if (mSize < 1) then raise Exception.Create(Format('invalid record ''%s'' size: %d', [mName, mSize]));
2239 continue;
2242 begin
2243 if (mBinBlock >= 0) then raise Exception.Create(Format('duplicate `binblock` in record ''%s''', [mName]));
2245 if (mBinBlock < 1) then raise Exception.Create(Format('invalid record ''%s'' binblock: %d', [mName, mBinBlock]));
2246 continue;
2252 // load fields
2254 begin
2256 //if hasByName(fld.name) then begin fld.Free(); raise Exception.Create(Format('duplicate field ''%s''', [fld.name])); end;
2257 // append
2260 begin
2264 // done with field
2271 var
2273 begin
2275 begin
2278 end
2279 else
2280 begin
2281 // record
2285 begin
2295 var
2297 begin
2299 begin
2300 // trigger data
2303 begin
2306 begin
2311 end
2312 else
2313 begin
2316 end
2317 else
2318 begin
2319 // record
2326 begin
2336 var
2348 var
2351 begin
2352 //writeln('*** rec: ', rec.mName, '.', rec.mId, ' (', rec.mFields.count, ')');
2354 begin
2356 begin
2358 continue;
2364 begin
2365 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);
2366 //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]));
2368 //writeln(' ', rec.mName, '.', rec.mId, ':', fld.mName, ' -> ', rt.mName, '.', rt.mId, ' (', fld.mEBSTypeName, '.', fld.mRecRefId, ')');
2374 begin
2375 //writeln(' ', fld.mName);
2380 begin
2383 try
2385 begin
2386 // parse map file as sequence of blocks
2390 // parse blocks
2392 begin
2398 if (bsize < 0) or (bsize > $1fffffff) then raise Exception.Create(Format('block of type %d has invalid size %d', [btype, bsize]));
2399 if loaded[btype] then raise Exception.Create(Format('block of type %d already loaded', [btype]));
2401 // find record type for this block
2404 if (rect = nil) then raise Exception.Create(Format('block of type %d has no corresponding record', [btype]));
2405 //writeln('found type ''', rec.mName, ''' for block type ', btype);
2406 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]));
2407 // header?
2409 begin
2410 if (bsize <> mSize) then raise Exception.Create(Format('header block of type %d has invalid number of records', [btype]));
2415 end
2416 else
2417 begin
2418 // create list for this type
2423 begin
2427 begin
2434 //writeln('parsed ''', rec.mId, '''...');
2440 //st.position := st.position+bsize;
2442 // link fields
2444 begin
2448 exit;
2451 // read fields
2453 if (mSize < 1) then raise Exception.Create(Format('cannot read record of type ''%s'' with unknown size', [mName]));
2457 begin
2460 if (fld.mBinOfs >= st.size) then raise Exception.Create(Format('record of type ''%s'' has invalid field ''%s''', [fld.mName]));
2462 //writeln('parsing ''', mName, '.', fld.mName, '''...');
2465 finally
2472 procedure TDynRecord.writeBinTo (st: TStream; trigbufsz: Integer=-1; onlyFields: Boolean=false);
2473 var
2479 //f, c: Integer;
2482 begin
2484 begin
2485 if (mBinBlock < 1) then raise Exception.Create('cannot write binary record without block number');
2488 end
2489 else
2490 begin
2493 try
2498 // write normal fields
2500 begin
2501 // record list?
2505 if (fld.mBinOfs >= bufsz) then raise Exception.Create('binary value offset is outside of the buffer');
2507 //writeln('writing field <', fld.mName, '>');
2511 // write block with normal fields
2513 begin
2514 //writeln('writing header...');
2515 // signature and version
2526 // write other blocks, if any
2528 begin
2529 // calculate blkmax
2532 begin
2533 // record list?
2535 begin
2543 // write blocks
2545 begin
2549 begin
2550 // record list?
2552 begin
2561 // flush block
2563 begin
2574 // write end marker
2579 finally
2587 var
2590 begin
2592 begin
2599 try
2601 begin
2602 // record list?
2604 begin
2607 begin
2609 begin
2615 continue;
2622 finally
2630 {$IF DEFINED(D2D_DYNREC_PROFILER)}
2631 var
2642 begin
2644 writeln('record cloning: ', profCloneRec div 1000, '.', profCloneRec mod 1000, ' milliseconds');
2645 writeln('findRecType : ', profFindRecType div 1000, '.', profFindRecType mod 1000, ' milliseconds');
2646 writeln('field[] : ', profFieldSearching div 1000, '.', profFieldSearching mod 1000, ' milliseconds');
2647 writeln('list dup check: ', profListDupChecking div 1000, '.', profListDupChecking mod 1000, ' milliseconds');
2648 writeln('addRecByType : ', profAddRecByType div 1000, '.', profAddRecByType mod 1000, ' milliseconds');
2649 writeln('field valparse: ', profFieldValParsing div 1000, '.', profFieldValParsing mod 1000, ' milliseconds');
2650 writeln('fix defaults : ', profFixDefaults div 1000, '.', profFixDefaults mod 1000, ' milliseconds');
2651 writeln('recvalparse : ', profRecValParse div 1000, '.', profRecValParse mod 1000, ' milliseconds');
2653 {$ENDIF}
2657 var
2661 {$IF DEFINED(D2D_DYNREC_PROFILER)}
2663 {$ENDIF}
2664 begin
2665 if (mOwner = nil) then raise Exception.Create(Format('can''t parse record ''%s'' value without owner', [mName]));
2669 // not a header?
2671 begin
2672 // id?
2674 end
2675 else
2676 begin
2680 //writeln('parsing record <', mName, '>');
2683 begin
2685 //writeln('<', mName, '.', pr.tokStr, '>');
2687 // records
2689 begin
2690 // add records with this type (if any)
2695 begin
2700 try
2703 (*
2704 if (Length(rec.mId) > 0) then
2705 begin
2706 {$IF DEFINED(D2D_DYNREC_PROFILER)}stt := curTimeMicro();{$ENDIF}
2707 fld := field[pr.tokStr];
2708 {$IF DEFINED(D2D_DYNREC_PROFILER)}profFieldSearching := curTimeMicro()-stt;{$ENDIF}
2709 (*
2710 if (fld <> nil) and (fld.mRVal <> nil) then
2711 begin
2712 {$IF DEFINED(D2D_DYNREC_PROFILER)}stt := curTimeMicro();{$ENDIF}
2713 //idtmp := trc.mName+':'+rec.mId;
2714 //if ids.put(idtmp, 1) then raise Exception.Create(Format('duplicate thing ''%s'' in record ''%s''', [fld.mName, mName]));
2715 if fld.mRHash.has(rec.mId) then raise Exception.Create(Format('duplicate thing ''%s'' in record ''%s''', [fld.mName, mName]));
2716 {$IF DEFINED(D2D_DYNREC_PROFILER)}profListDupChecking := curTimeMicro()-stt;{$ENDIF}
2717 end;
2718 end;
2719 *)
2724 finally
2727 continue;
2731 // fields
2736 begin
2737 if fld.defined then raise Exception.Create(Format('duplicate field ''%s'' in record ''%s''', [fld.mName, mName]));
2738 if fld.internal then raise Exception.Create(Format('internal field ''%s'' in record ''%s''', [fld.mName, mName]));
2743 continue;
2746 // something is wrong
2750 // fix field defaults
2754 //writeln('done parsing record <', mName, '>');
2755 //{$IF DEFINED(D2D_DYNREC_PROFILER)}writeln('stall: ', curTimeMicro()-stall);{$ENDIF}
2760 // ////////////////////////////////////////////////////////////////////////// //
2762 begin
2769 begin
2776 begin
2787 begin
2790 begin
2799 begin
2805 var
2807 begin
2814 var
2816 begin
2820 // fields
2823 begin
2827 begin
2831 end
2832 else
2833 begin
2838 // max field
2845 var
2847 begin
2849 // fields
2851 begin
2858 var
2860 begin
2862 begin
2870 var
2876 begin
2885 begin
2888 begin
2889 if StrEqu(mIds[f], idname) then raise Exception.Create(Format('duplicate field ''%s'' in enum/bitset ''%s''', [idname, mName]));
2891 if StrEqu(mMaxName, idname) then raise Exception.Create(Format('duplicate field ''%s'' in enum/bitset ''%s''', [idname, mName]));
2895 // has value?
2897 begin
2899 begin
2900 if (Length(mMaxName) > 0) then raise Exception.Create(Format('duplicate max field ''%s'' in enum/bitset ''%s''', [idname, mName]));
2903 end
2904 else
2905 begin
2911 // append it?
2913 begin
2914 // fix maxvalue
2916 begin
2923 // next cv
2925 begin
2934 // add max field
2936 begin
2945 // ////////////////////////////////////////////////////////////////////////// //
2947 begin
2956 var
2959 begin
2974 begin
2981 var
2983 begin
2985 begin
2993 var
2995 begin
2997 begin
3005 var
3007 begin
3009 begin
3017 var
3022 // setup header links and type links
3024 var
3026 begin
3029 begin
3034 begin
3036 if (fld.mEBSType = nil) then raise Exception.Create(Format('field ''%s'' of type ''%s'' has no correcponding record definition', [fld.mName, fld.mEBSTypeName]));
3040 begin
3042 if (fld.mEBSType = nil) then raise Exception.Create(Format('field ''%s'' of type ''%s'' has no correcponding enum/bitset', [fld.mName, fld.mEBSTypeName]));
3043 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]));
3049 // setup default values
3051 var
3053 begin
3057 begin
3060 begin
3065 begin
3068 begin
3074 //writeln(eb.definition); writeln;
3075 continue;
3079 begin
3082 begin
3084 begin
3091 //writeln(dr.definition); writeln;
3092 continue;
3096 //writeln(dr.definition); writeln;
3097 if (findRecType(rec.name) <> nil) then begin rec.Free(); raise Exception.Create(Format('duplicate record ''%s''', [rec.name])); end;
3098 if (hdr <> nil) and StrEqu(rec.name, hdr.name) then begin rec.Free(); raise Exception.Create(Format('duplicate record ''%s''', [rec.name])); end;
3101 begin
3102 if (hdr <> nil) then begin rec.Free(); raise Exception.Create(Format('duplicate header record ''%s'' (previous is ''%s'')', [rec.name, hdr.name])); end;
3104 end
3105 else
3106 begin
3111 // put header record to top
3117 // setup header links and type links
3121 // setup default values
3127 // ////////////////////////////////////////////////////////////////////////// //
3129 var
3131 begin
3133 try
3140 finally
3147 var
3149 begin
3151 try
3157 finally
3164 var
3170 begin
3172 result += '// ////////////////////////////////////////////////////////////////////////// //'#10;
3175 result += #10#10'// ////////////////////////////////////////////////////////////////////////// //'#10;
3178 begin
3183 result += #10#10'// ////////////////////////////////////////////////////////////////////////// //'#10;
3189 begin
3193 begin
3199 begin
3211 var
3213 begin
3215 result += '// ////////////////////////////////////////////////////////////////////////// //'#10;
3221 function TDynMapDef.getTrigTypeCount (): Integer; inline; begin result := trigTypes.count; end;
3222 function TDynMapDef.getTrigTypeAt (idx: Integer): TDynRecord; inline; begin if (idx >= 0) and (idx < trigTypes.count) then result := trigTypes[idx] else result := nil; end;