public static EventsSave Restore(TypeDesc typeDesc, SaveInfo info, ref ByteStreamReader bsr) { int count = bsr.ReadSInt(); // inline version of reading embedded field of type CBaseEntityOutput (it only contains 1 field) if (bsr.ReadSShort() != 4) { throw new ConstraintException("first entry in data map should be 4"); } string?mapSym = bsr.ReadSymbol(info); if (mapSym != "Value") { throw new ConstraintException($"bad symbol, expected \"Value\" but read \"{mapSym}\""); } int fieldsSaved = bsr.ReadSInt(); ParsedSaveField?psf = null; if (fieldsSaved == 1) { bsr.StartBlock(info, out string?sym); if (sym != "m_Value") { throw new ConstraintException($"bad symbol, expected \"m_Value\" but read \"{sym}\""); } FieldType type = (FieldType)bsr.ReadSInt(); string? s = FieldNameFromType(type); if (s != null) { TypeDesc t = new TypeDesc(s, type); DataMap m = new DataMap("m_Value", new [] { t }); var pm = bsr.ReadDataMap(m, info); if (pm.ParsedFields.Any()) { psf = pm.ParsedFields.Single().Value; } } bsr.EndBlock(info); } else if (fieldsSaved != 0) { throw new ConstraintException($"expected 0 fields, got {fieldsSaved}"); } ParsedDataMap[] events = new ParsedDataMap[count]; for (int i = 0; i < count; i++) { events[i] = bsr.ReadDataMap("EntityOutput", info); } return(new EventsSave(typeDesc, psf, events)); }
protected override void Parse(ref ByteStreamReader bsr) { ExtendedHeader = bsr.ReadDataMap("AIExtendedSaveHeader_t", SaveInfo); if (ExtendedHeader.GetFieldOrDefault <short>("version") >= AI_EXTENDED_SAVE_HEADER_FIRST_VERSION_WITH_CONDITIONS) { bsr.StartBlock(SaveInfo); Conditions = new ConditionStrings(SaveRef); Conditions.ParseStream(ref bsr); bsr.EndBlock(SaveInfo); } if (ExtendedHeader.GetFieldOrDefault <short>("version") >= AI_EXTENDED_SAVE_HEADER_FIRST_VERSION_WITH_NAVIGATOR_SAVE) { bsr.StartBlock(SaveInfo); Navigator = new CAI_NavigatorEntData(SaveRef !); Navigator.ParseStream(ref bsr); bsr.EndBlock(SaveInfo); } base.Parse(ref bsr); }
/* This pretty much exactly what the game does. A datamap is created dynamically which contains a description * for each key/value of the map. * Custom params: * [0] - the field type of each key * [1] - the custom read function of each key (if applicable) * [2] - the embedded map of each key (if applicable) * [3] - the field type of each value * [4] - the custom read function of each value (if applicable) * [5] - the embedded map of each value (if applicable) * */ public static UtilMap <TK, TV> Restore(TypeDesc mapDesc, SaveInfo info, ref ByteStreamReader bsr) { object[] @params = mapDesc.CustomParams !; DataMap? embKeyMap = @params[2] is string sk ? info.SDataMapLookup[sk] : null; DataMap? embValMap = @params[5] is string sv ? info.SDataMapLookup[sv] : null; TypeDesc keyDesc = new TypeDesc( name: "K", flags: DescFlags.FTYPEDESC_SAVE, fieldType: (FieldType)@params[0], customReadFunc: (CustomReadFunc?)@params[1], numElements: 1) { EmbeddedMap = embKeyMap }; TypeDesc valDesc = new TypeDesc( name: "T", // std::map<Key, T> flags: DescFlags.FTYPEDESC_SAVE, fieldType: (FieldType)@params[3], customReadFunc: (CustomReadFunc?)@params[4], numElements: 1) { EmbeddedMap = embValMap }; DataMap vecMap = new DataMap("um", new[] { keyDesc, valDesc }); bsr.StartBlock(info); int count = bsr.ReadSInt(); var res = new KeyValuePair <ParsedSaveField <TK>, ParsedSaveField <TV> > [count]; for (int i = 0; i < count; i++) { ParsedDataMap readResult = bsr.ReadDataMap(vecMap, info); var k = (ParsedSaveField <TK>)readResult.ParsedFields["K"]; var v = (ParsedSaveField <TV>)readResult.ParsedFields["T"]; res[i] = new KeyValuePair <ParsedSaveField <TK>, ParsedSaveField <TV> >(k, v); } bsr.EndBlock(info); return(new UtilMap <TK, TV>(mapDesc, res, keyDesc, valDesc)); }