public static SaveGameHeader?CreateFromHeaderInfo(SourceSave?saveRef, ParsedDataMap dataHeader) { CharArray name = dataHeader.GetField <CharArray>("szName"); switch (name) { case "Entities": return(new ETableHeader(saveRef, dataHeader)); case "Physics": return(new PhysicsInfoHeader(saveRef, dataHeader)); case "AI": case "Templates": case "ResponseSystem": case "Commentary": case "EventQueue": case "Achievement": return(new VersionableSaveGameHeader(saveRef, dataHeader)); default: saveRef !.SaveInfo.AddError($"unknown header name: {name}"); return(null); // todo VScriptServer and maybe PaintDatabase (will have to ree) } }
public PhysicsConstraint( TypeDesc desc, int oldObj, ConstraintType physicsConstraintType, ParsedDataMap header, ParsedDataMap?constraint) : base(desc, oldObj) { PhysicsConstraintType = physicsConstraintType; Header = header; Constraint = constraint; }
public ParsedDataMap ReadDataMapRecursive(DataMap map, SaveInfo info) { if (map.BaseMap == null) { return(ReadDataMap(map, info)); } ParsedDataMap baseMap = ReadDataMapRecursive(map.BaseMap, info); ParsedDataMap thisMap = ReadDataMap(map, info); thisMap.AddBaseParsedMap(baseMap, info); return(thisMap); }
public ParsedDataMap ReadDataMap(DataMap map, SaveInfo info) { if (ReadSShort() != 4) { throw new ConstraintException($"bad first value while parsing datamap \"{map.ClassName}\", expected 4"); } string sym = ReadSymbol(info) !; if (sym != map.DataMapName) { info.SDataMapLookup.TryGetValue(sym, out DataMap? cmpMap); if (!ReferenceEquals(cmpMap, map)) { DetermineDataMapHierarchy(info, $"\"{sym}\" does not match \"{map.DataMapName}\"", AbsoluteByteIndex - 4); throw new ArgumentException($"bad symbol, expected \"{map.DataMapName}\" but read \"{sym}\""); } } int fieldsSaved = ReadSInt(); ParsedDataMap ret = new ParsedDataMap(map, fieldsSaved); for (int i = 0; i < fieldsSaved; i++) { StartBlock(info, out short byteSize, out string?s); map.FieldDict.TryGetValue(s !, out TypeDesc? curFieldDesc); if (curFieldDesc != null) { if (!curFieldDesc.Placeholder) { try { int index = AbsoluteByteIndex; ParsedSaveField?f = ReadSaveField(curFieldDesc !, info, byteSize); f?.SetIndex(index); // I allow returning null here for the vphys read EndBlock(info); // try ending the block to see if we read this correctly ret.AddSaveField(f); } catch (Exception e) { info.AddError($"exception while reading field {s} from datamap \"{map.ClassName}\": {e.Message}"); SkipCurrentBlock(info); } } else { DetermineDataMapHierarchy(info, $"placeholder field \"{curFieldDesc.Name}\"", AbsoluteByteIndex); SkipCurrentBlock(info); } } else { info.AddError($"skipping field \"{s}\" from datamap \"{map.ClassName}\" ({byteSize} bytes), no appropriate field found"); SkipCurrentBlock(info); } } return(ret); }
protected override void Parse(ref ByteStreamReader bsr) { SourceFileHeader = new SourceFileHeader(this); SourceFileHeader.ParseStream(ref bsr); SaveInfo.ParseContext.CurrentSymbolTable = bsr.ReadSymbolTable(SourceFileHeader.TokenCount, SourceFileHeader.TokenTableSize) !; GameHeader = bsr.ReadDataMap("GameHeader", SaveInfo); Globals = bsr.ReadDataMap("GLOBAL", SaveInfo); StateFiles = new EmbeddedStateFile[bsr.ReadSInt()]; for (int i = 0; i < StateFiles.Length; i++) { StateFiles[i] = EmbeddedStateFile.CreateFromName(this, bsr.ReadCharArray(260)); int fileLength = bsr.ReadSInt(); StateFiles[i].ParseStream(bsr.SplitAndSkip(fileLength)); } SaveInfo.Cleanup(); Debug.Assert(bsr.BytesRemaining == 0); SaveInfo.PrintDeterminedDatamaps(); }
public static ParsedEntData CreateFromName(SourceSave saveRef, ParsedDataMap headerInfo, DataMap entMap) { // order of these checks matters if (entMap.InheritsFrom("CBasePlayer")) { return(new CBasePlayerEntData(saveRef, headerInfo, entMap)); } else if (entMap.InheritsFrom("CAI_BaseNPC")) { return(new CAI_BaseNpcEntData(saveRef, headerInfo, entMap)); } else if (entMap.InheritsFrom("CBaseEntity")) { return(new CBaseEntityParsedEntData(saveRef, headerInfo, entMap)); } else { return(new ParsedEntData(saveRef, headerInfo, entMap)); } }
/* 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)); }
/* This pretty much exactly what the game does. A datamap is created dynamically which contains only a single * description for each element of this vector. This solution means I only have to do a single cast. * Custom params: * [0] - the field type of each element * [1] - the custom read function of each element (if applicable) * [2] - the embedded map of each element (if applicable) * */ public static UtilVector <T> Restore(TypeDesc vecDesc, SaveInfo info, ref ByteStreamReader bsr) { object[] @params = vecDesc.CustomParams !; DataMap?embMap = @params[2] is string s ? info.SDataMapLookup[s] : null; int count = bsr.ReadSInt(); TypeDesc elemDesc = new TypeDesc( name: "elems", flags: DescFlags.FTYPEDESC_SAVE, fieldType: (FieldType)@params[0], customReadFunc: (CustomReadFunc?)@params[1], numElements: (ushort)(embMap == null ? count : 1)) { EmbeddedMap = embMap }; // Sometimes the count is one but the read result does not have an element. I'm not sure if this is // intended or not but by default that will cause an exception. DataMap vecMap = new DataMap(embMap == null ? "elems" : "uv", new[] { elemDesc }); T[] res; if (embMap == null && count > 1) { ParsedDataMap mapReadResult = bsr.ReadDataMap(vecMap, info); res = (ParsedSaveField <T[]>)mapReadResult.ParsedFields.Single().Value; } else // if the field type is embedded then the elements are read one by one { res = new T[count]; for (int i = 0; i < count; i++) { ParsedDataMap mapReadResult = bsr.ReadDataMap(vecMap, info); res[i] = (ParsedSaveField <T>)mapReadResult.ParsedFields.Single().Value; } } return(new UtilVector <T>(res, elemDesc, vecDesc)); }
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); }
protected override void Parse(ref ByteStreamReader bsr) { base.Parse(ref bsr); Version = bsr.ReadSInt(); int nBytesSymbols = bsr.ReadSInt(); int nSymbols = bsr.ReadSInt(); int nBytesDataHeaders = bsr.ReadSInt(); int nBytesData = bsr.ReadSInt(); SaveInfo.ParseContext.CurrentSymbolTable = bsr.ReadSymbolTable(nSymbols, nBytesSymbols) !; int @base = bsr.CurrentByteIndex; int sizeHeaders = bsr.ReadSInt(); int sizeBodies = bsr.ReadSInt(); // info about the header block BlockHeadersInfo = UtilVector <ParsedDataMap> .RestoreEmbedded("BlockHeadersInfo", "SaveRestoreBlockHeader_t", SaveInfo, ref bsr); SaveGameHeaders = new List <SaveGameHeader>(BlockHeadersInfo.Count); // read the headers one by one foreach (ParsedDataMap headerInfo in BlockHeadersInfo) { int loc = headerInfo.GetField <int>("locHeader"); if (loc == -1) { continue; } bsr.CurrentByteIndex = @base + loc; SaveGameHeader?sgh = SaveGameHeader.CreateFromHeaderInfo(SaveRef, headerInfo); if (sgh == null) { continue; } sgh.ParseStream(ref bsr); SaveGameHeaders.Add(sgh); } //@base = bsr.CurrentByteIndex = @base + sizeHeaders; ByteStreamReader bodyBase = bsr.Split(); // block data is offset from this location SaveHeader = bsr.ReadDataMap("Save Header", SaveInfo); SaveInfo.BaseTime = SaveHeader.GetFieldOrDefault <Time>("time__USE_VCR_MODE"); //SaveInfo.LandmarkPos // todo gotten from adjacency list? @base = bsr.CurrentByteIndex; int connections = SaveHeader.GetFieldOrDefault <int>("connectionCount"); // to other maps? int lightStyles = SaveHeader.GetFieldOrDefault <int>("lightStyleCount"); if (connections > 0) { AdjacencyList = new ParsedDataMap[connections]; for (int i = 0; i < connections; i++) { AdjacencyList[i] = bsr.ReadDataMap("ADJACENCY", SaveInfo); } } if (lightStyles > 0) { LightStyleList = new ParsedDataMap[lightStyles]; for (int i = 0; i < lightStyles; i++) { LightStyleList[i] = bsr.ReadDataMap("LIGHTSTYLE", SaveInfo); } } @base = bsr.CurrentByteIndex; Blocks = new List <SaveStateBlock>(SaveGameHeaders.Count); // now read the actual blocks of data based off of information from the headers foreach (SaveGameHeader header in SaveGameHeaders) { int loc = header.DataHeader.GetFieldOrDefault <int>("locBody"); if (loc == -1) { continue; } //bodyBase.CurrentByteIndex = loc; //bsr.CurrentByteIndex = @base; if (!SaveStateBlock.CreateFromHeader(SaveRef !, header, out SaveStateBlock blockHandler)) { SaveInfo.AddError($"{nameof(SaveStateBlock)} not created from header: \"{header.Name}\""); continue; } blockHandler.ParseStream(ref bodyBase); Blocks.Add(blockHandler); } //bsr.CurrentByteIndex = @base + sizeBodies; }
public CAI_BaseNpcEntData(SourceSave saveRef, ParsedDataMap headerInfo, DataMap classMap) : base(saveRef, headerInfo, classMap) { }
public VersionableSaveGameHeader(SourceSave?saveRef, ParsedDataMap dataHeader) : base(saveRef, dataHeader) { }
public PhysicsVehicleController(TypeDesc desc, int oldObj, ParsedDataMap controller) : base(desc, oldObj) { Controller = controller; }
public class CBasePlayerEntData : CBaseEntityParsedEntData { // todo any other classes along the way that do stuff? public CBasePlayerEntData(SourceSave saveRef, ParsedDataMap headerInfo, DataMap classMap) : base(saveRef, headerInfo, classMap) { }
protected override void Parse(ref ByteStreamReader bsr) { base.Parse(ref bsr); PhysHeader = bsr.ReadDataMap("PhysBlockHeader_t", SaveInfo); }
// all of these generic types must* stay consistent with TypeDesc.GetNetTypeFromFieldType private ParsedSaveField?ReadSaveField(TypeDesc desc, SaveInfo info, int bytesAvail) { switch (desc.FieldType) { case EMBEDDED: if (desc.NumElements == 1) { return(new ParsedSaveField <ParsedDataMap>(ReadDataMapRecursive(desc.EmbeddedMap !, info), desc)); } else { ParsedDataMap[] parsedMaps = new ParsedDataMap[desc.NumElements]; for (int i = 0; i < desc.NumElements; i++) { parsedMaps[i] = ReadDataMapRecursive(desc.EmbeddedMap !, info); } return(new ParsedSaveField <ParsedDataMap[]>(parsedMaps, desc, parsedMaps.Length)); } case CUSTOM: return(desc.InvokeCustomReadFunc(ref this, info)); // this can return null case MODELNAME: return(ReadSimpleString(desc, bytesAvail, s => (ModelName)s)); case SOUNDNAME: return(ReadSimpleString(desc, bytesAvail, s => (SoundName)s)); case FUNCTION: return(ReadSimpleString(desc, bytesAvail, s => (Func)s)); case STRING: return(ReadSimpleString(desc, bytesAvail)); case MODELINDEX: return(ReadSimpleString(desc, bytesAvail, s => (ModelIndex)s)); case MATERIALINDEX: return(ReadSimple <int, MaterialIndex>(desc, bytesAvail, i => (MaterialIndex)i)); case FLOAT: return(ReadSimple <float>(desc, bytesAvail)); case VECTOR2D: return(ReadSimple <Vector2>(desc, bytesAvail)); case VECTOR: return(ReadSimple <Vector3>(desc, bytesAvail)); case POSITION_VECTOR: return(ReadSimple <Vector3>(desc, bytesAvail, vec => vec + info.LandmarkPos)); case QUATERNION: return(ReadSimple <Vector4>(desc, bytesAvail)); case EHANDLE: return(ReadSimple <int, Ehandle>(desc, bytesAvail, i => (Ehandle)i)); case CLASSPTR: return(ReadSimple <int, ClassPtr>(desc, bytesAvail, i => (ClassPtr)i)); case EDICT: return(ReadSimple <int, Edict>(desc, bytesAvail, i => (Edict)i)); case INTEGER: return(ReadSimple <int>(desc, bytesAvail)); case BOOLEAN: return(ReadSimple <byte, bool>(desc, bytesAvail, b => b != 0)); case SHORT: return(ReadSimple <short>(desc, bytesAvail)); case BYTE: return(ReadSimple <byte>(desc, bytesAvail)); case INTERVAL: return(ReadSimple <Interval>(desc, bytesAvail)); case CHARACTER: return(desc.NumElements == 1 ? ReadSimple <byte, char>(desc, bytesAvail, b => (char)b) : new ParsedSaveField <CharArray>(ReadCharArray(bytesAvail), desc, bytesAvail)); case COLOR32: return(ReadSimple <int, Color32>(desc, bytesAvail, i => (Color32)i)); case TIME: return(ReadSimple <float, Time>(desc, bytesAvail, f => { if (f == ZERO_TIME) { return (Time)0; } if (f != INVALID_TIME && f != FLT_MAX) { return (Time)(f + info.BaseTime); } return (Time)f; })); case TICK: int baseTick = info.TimeToTicks(info.BaseTime + 0.1f); return(ReadSimple <int, Tick>(desc, bytesAvail, i => (Tick)(i == TICK_NEVER_THINK_ENCODE ? TICK_NEVER_THINK : i + baseTick))); case VMATRIX: return(ReadSimple <VMatrix>(desc, bytesAvail)); case VMATRIX_WORLDSPACE: return(ReadSimple <VMatrix>(desc, bytesAvail, mat => { mat.ApplyTranslation(in info.LandmarkPos); return mat; }));
protected SaveGameHeader(SourceSave?saveRef, ParsedDataMap dataHeader) : base(saveRef) { DataHeader = dataHeader; }
public PhysicsConstraintGroup(TypeDesc desc, int oldObj, ParsedDataMap groupTemplate) : base(desc, oldObj) { GroupTemplate = groupTemplate; }
public PhysicsObject(TypeDesc desc, int oldObj, ParsedDataMap objTemplate, ParsedDataMap?controllerTemplate) : base(desc, oldObj) { ObjectTemplate = objTemplate; ControllerTemplate = controllerTemplate; }
// same name as in game code - CPhysicsEnvironment::Restore public static ParsedSaveField?Restore( SaveInfo saveInfo, ParsedDataMap physHeader, (ParsedEntData ent, TypeDesc typeDesc) physRestoreInfo,
public ParsedEntData(SourceSave saveRef, ParsedDataMap headerInfo, DataMap classMap) : base(saveRef) { HeaderInfo = headerInfo; ClassMap = classMap; }
public PhysicsMotionController(TypeDesc desc, int oldObj, ParsedDataMap motionController) : base(desc, oldObj) { MotionController = motionController; }
public ETableHeader(SourceSave?saveRef, ParsedDataMap dataHeader) : base(saveRef, dataHeader) { }
public PhysicsInfoHeader(SourceSave?saveRef, ParsedDataMap dataHeader) : base(saveRef, dataHeader) { }
public PhysicsSpring(TypeDesc desc, int oldObj, ParsedDataMap spring) : base(desc, oldObj) { Spring = spring; }