public void FlattenClasses(bool allowModifyDemo) { var tableLookup = _dtRef.Tables.ToImmutableDictionary(table => table.Name, table => table); FlattenedProps = new PropLookup(_dtRef.ServerClasses.Count); foreach (ServerClass serverClass in _dtRef.ServerClasses) { SendTable table = _dtRef.Tables[serverClass.DataTableId]; GatherProps(tableLookup, GatherExcludes(tableLookup, table), table, serverClass, ""); SortProps(FlattenedProps[serverClass.DataTableId].flattenedProps); } // Now that I know the order of the props, I will parse the baselines of any SvcCreateMessages that // appeared BEFORE the datatables (valve really do be like that). In game, the baselines are stored as an // array and reparsed every time they're updated during demo playback. I just parse them once and store // them in a more accessible format. if (allowModifyDemo && _demoRef.StringTablesManager.TableReadable.GetValueOrDefault(TableNames.InstanceBaseLine)) { _demoRef.StringTablesManager.Tables[TableNames.InstanceBaseLine] .Entries .Select(entry => entry.EntryData) .Cast <InstanceBaseline>() .ToList() .ForEach(baseline => baseline.ParseStream(baseline.Reader)); } }
private Event?Process(CSVCMsg_SendTable message) { client.SendTables.Add(SendTable.CreateWith(message)); log.Debug(String.Format("CSVCMsg_SendTable: {0} with {1} props", message.net_table_name, message.props.Count)); return(null); }
public Entity(WorldState ws, ServerClass sClass, SendTable table, uint index, uint serialNumber) { m_World = ws; m_Class = sClass; m_NetworkTable = table; m_Index = index; m_SerialNumber = serialNumber; Team = new EntityPropertyMonitor <Team?>("DT_BaseEntity.m_iTeamNum", this, o => (Team)(int)o); Owner = new EntityPropertyMonitor <EHandle>("DT_BaseEntity.m_hOwnerEntity", this, o => new EHandle(ws, (uint)o)); }
private void BuildHierarchy( List <PropertyInfo> properties, SendTable send, Dictionary <string, SendTable> all, HashSet <string> excluding) { var nonDtProps = new List <PropertyInfo>(); GatherProperties(properties, send, all, nonDtProps, excluding); properties.AddRange(nonDtProps); }
private void GatherExcludes( SendTable table, Dictionary <string, SendTable> all, HashSet <string> excluding) { foreach (var property in table.Properties) { if (property.Flags.HasFlag(PropertyInfo.MultiFlag.Exclude)) { excluding.Add(QualifyProperty(property.DtName, property)); } else if (property.Type == PropertyInfo.PropertyType.DataTable) { GatherExcludes(all[property.DtName], all, excluding); } } }
public void ApplyWorldState(WorldState ws) { List <IBaseEntity> tempents = new List <IBaseEntity>(); { BitStream local = Data.Clone(); local.Cursor = 0; TempEntity e = null; for (int i = 0; i < EntryCount; i++) { double delay = 0; if (local.ReadBool()) { delay = local.ReadInt(8) / 100.0; } if (local.ReadBool()) { uint classID = local.ReadUInt(ws.ClassBits); ServerClass serverClass = ws.ServerClasses[(int)classID - 1]; SendTable sendTable = ws.SendTables.Single(st => st.NetTableName == serverClass.DatatableName); var flattened = sendTable.FlattenedProps; e = new TempEntity(ws, serverClass, sendTable); EntityCoder.ApplyEntityUpdate(e, local); tempents.Add(e); } else { Debug.Assert(e != null); EntityCoder.ApplyEntityUpdate(e, local); } } } foreach (IBaseEntity te in tempents) { ws.Listeners.TempEntityCreated.Invoke(te); } }
Entity ReadEnterPVS(WorldState ws, BitStream stream, uint entityIndex) { ServerClass serverClass = ws.ServerClasses[(int)stream.ReadUInt(ws.ClassBits)]; SendTable networkTable = ws.SendTables.Single(st => st.NetTableName == serverClass.DatatableName); uint serialNumber = stream.ReadUInt(SourceConstants.NUM_NETWORKED_EHANDLE_SERIAL_NUMBER_BITS); Entity e; { Entity existing = ws.Entities[entityIndex]; e = (existing == null || existing.SerialNumber != serialNumber) ? new Entity(ws, serverClass, networkTable, entityIndex, serialNumber) : existing; } var decodedBaseline = ws.InstanceBaselines[(int)Baseline.Value][entityIndex]; if (decodedBaseline != null) { var propertiesToAdd = decodedBaseline .Except(e.Properties, SendPropDefinitionComparer.Instance) .Select(sp => sp.Clone(e)); foreach (var p2a in propertiesToAdd) { e.AddProperty(p2a); } } else { BitStream baseline = ws.StaticBaselines.SingleOrDefault(bl => bl.Key == e.Class).Value; if (baseline != null) { baseline.Cursor = 0; EntityCoder.ApplyEntityUpdate(e, baseline); Debug.Assert((baseline.Length - baseline.Cursor) < 8); } } return(e); }
public void ParsePacket(IBitStream bitstream) { while (true) { var type = (SVC_Messages)bitstream.ReadProtobufVarInt(); if (type != SVC_Messages.svc_SendTable) throw new Exception("Expected SendTable, got " + type); var size = bitstream.ReadProtobufVarInt(); bitstream.BeginChunk(size * 8); var sendTable = new SendTable(bitstream); bitstream.EndChunk(); if (sendTable.IsEnd) break; DataTables.Add(sendTable); } int serverClassCount = checked((int)bitstream.ReadInt(16)); for (int i = 0; i < serverClassCount; i++) { ServerClass entry = new ServerClass(); entry.ClassID = checked((int)bitstream.ReadInt(16)); if (entry.ClassID > serverClassCount) throw new Exception("Invalid class index"); entry.Name = bitstream.ReadDataTableString(); entry.DTName = bitstream.ReadDataTableString(); entry.DataTableID = DataTables.FindIndex(a => a.Name == entry.DTName); ServerClasses.Add(entry); } for (int i = 0; i < serverClassCount; i++) FlattenDataTable(i); }
private void GatherProperties( List <PropertyInfo> properties, SendTable send, Dictionary <string, SendTable> all, List <PropertyInfo> nonDtProps, HashSet <string> excluding) { var skipOn = PropertyInfo.MultiFlag.Exclude | PropertyInfo.MultiFlag.InsideArray; foreach (var property in send.Properties) { if ((uint)(property.Flags & skipOn) > 0) { continue; } if (excluding.Contains(QualifyProperty(property.Origin.NetTableName, property))) { continue; } if (property.Type == PropertyInfo.PropertyType.DataTable) { var pointsAt = all[property.DtName]; if (property.Flags.HasFlag(PropertyInfo.MultiFlag.Collapsible)) { GatherProperties(properties, pointsAt, all, nonDtProps, excluding); } else { BuildHierarchy(properties, pointsAt, all, excluding); } } else { nonDtProps.Add(property); } } }
public TempEntity(WorldState ws, ServerClass sClass, SendTable table) { World = ws; Class = sClass; NetworkTable = table; }
public static Task Read(this SourceDemo demo, DataTables frame) { var buf = frame.Buffer; while (buf.ReadBoolean()) { bool needsdecoder = buf.ReadBoolean(); var table = new SendTable() { NetTableName = buf.ReadString(), NeedsDecoder = needsdecoder }; var props = buf.ReadUBits(DataTable.PROPINFOBITS_NUMPROPS); for (int j = 0; j < props; j++) { int fbits = (demo.Protocol == 2) ? 11 : DataTable.PROPINFOBITS_FLAGS; var prop = new SendProp { Type = (SendPropType)buf.ReadUBits(DataTable.PROPINFOBITS_TYPE), VarName = buf.ReadString(), Flags = (SendPropFlags)buf.ReadUBits(fbits) }; if ((prop.Type == SendPropType.DataTable) || (prop.IsExcludeProp())) { prop.ExcludeDtName = buf.ReadString(); //if ((prop.Flags & SendPropFlags.Collapsible) != 0) //{ //} } else if (prop.Type == SendPropType.Array) { prop.Elements = (int)buf.ReadUBits(DataTable.PROPINFOBITS_NUMELEMENTS); } else { prop.LowValue = buf.ReadSingle(); prop.HighValue = buf.ReadSingle(); prop.Bits = (int)buf.ReadUBits(DataTable.PROPINFOBITS_NUMBITS + 1); } table.Props.Add(prop); } frame.Tables.Add(table); } var classes = buf.ReadInt16(); for (var i = 0; i < classes; i++) { frame.Classes.Add(new ServerClassInfo { ClassId = buf.ReadInt16(), ClassName = buf.ReadString(), DataTableName = buf.ReadString() }); } return(Task.CompletedTask); }
private Events?Handle(CSVCMsg_SendTable message) { state.SendTables.Add(SendTable.CreateWith(message)); return(null); }
void GatherProps_IterateProps(SendTable table, int ServerClassIndex, List<FlattenedPropEntry> flattenedProps, string prefix) { for (int i = 0; i < table.Properties.Count; i++) { SendTableProperty property = table.Properties[i]; if (property.Flags.HasFlagFast(SendPropertyFlags.InsideArray) || property.Flags.HasFlagFast(SendPropertyFlags.Exclude) || IsPropExcluded(table, property)) continue; if (property.Type == SendPropertyType.DataTable) { SendTable subTable = GetTableByName(property.DataTableName); if (property.Flags.HasFlagFast(SendPropertyFlags.Collapsible)) { //we don't prefix Collapsible stuff, since it is just derived mostly GatherProps_IterateProps(subTable, ServerClassIndex, flattenedProps, prefix); } else { //We do however prefix everything else string nfix = prefix + ((property.Name.Length > 0) ? property.Name + "." : ""); GatherProps(subTable, ServerClassIndex, nfix); } } else { if (property.Type == SendPropertyType.Array) { flattenedProps.Add(new FlattenedPropEntry(prefix + property.Name, property, table.Properties[i - 1])); } else { flattenedProps.Add(new FlattenedPropEntry(prefix + property.Name, property, null)); } } } }
bool IsPropExcluded(SendTable table, SendTableProperty prop) { return CurrentExcludes.Exists(a => table.Name == a.DTName && prop.Name == a.VarName); }
void GatherProps(SendTable table, int serverClassIndex, string prefix) { List<FlattenedPropEntry> tmpFlattenedProps = new List<FlattenedPropEntry>(); GatherProps_IterateProps(table, serverClassIndex, tmpFlattenedProps, prefix); List<FlattenedPropEntry> flattenedProps = ServerClasses[serverClassIndex].FlattenedProps; flattenedProps.AddRange(tmpFlattenedProps); }
private ISet <(string propName, string tableName)> GatherExcludes(IReadOnlyDictionary <string, SendTable> tableLookup, SendTable table) { var excludes = new HashSet <(string, string)>(); foreach (SendTableProp sendProp in table.SendProps) { if (sendProp.SendPropType == SendPropType.DataTable) { excludes.UnionWith(GatherExcludes(tableLookup, tableLookup[sendProp.ExcludeDtName !]));
static SendTable ParseSendTable(BitStream stream) { SendTable table = new SendTable(); table.Unknown1 = stream.ReadBool(); table.NetTableName = stream.ReadCString(); int propertyCount = (int)stream.ReadULong(PROPINFOBITS_NUMPROPS); SendPropDefinition arrayElementProp = null; for (int i = 0; i < propertyCount; i++) { SendPropDefinition prop = new SendPropDefinition(table); prop.Type = (SendPropType)stream.ReadULong(PROPINFOBITS_TYPE); Debug.Assert(Enum.GetValues(typeof(SendPropType)).Cast <SendPropType>().Contains(prop.Type)); Debug.Assert(prop.Type == SendPropType.Datatable ? prop.Flags == 0 : true); prop.Name = stream.ReadCString(); prop.Flags = (SendPropFlags)stream.ReadULong(PROPINFOBITS_FLAGS); if (prop.Type == SendPropType.Datatable) { prop.ExcludeName = stream.ReadCString(); } else { if ((prop.Flags & SendPropFlags.Exclude) != 0) { prop.ExcludeName = stream.ReadCString(); } else if (prop.Type == SendPropType.Array) { prop.ArrayElements = (int)stream.ReadULong(PROPINFOBITS_NUMELEMENTS); } else { prop.LowValue = stream.ReadSingle(); prop.HighValue = stream.ReadSingle(); prop.BitCount = stream.ReadULong(PROPINFOBITS_NUMBITS); } } if (prop.Flags.HasFlag(SendPropFlags.NoScale)) { if (prop.Type == SendPropType.Float) { prop.BitCount = 32; } else if (prop.Type == SendPropType.Vector) { if (!prop.Flags.HasFlag(SendPropFlags.Normal)) { prop.BitCount = 32 * 3; } } } if (arrayElementProp != null) { Debug.Assert(prop.Type == SendPropType.Array); prop.ArrayProperty = arrayElementProp; arrayElementProp = null; } if (prop.Flags.HasFlag(SendPropFlags.InsideArray)) { Debug.Assert(arrayElementProp == null); Debug.Assert(!prop.Flags.HasFlag(SendPropFlags.ChangesOften)); arrayElementProp = prop; } else { table.Properties.Add(prop); } } return(table); }
public SendTableProp(SourceDemo?demoRef, SendTable tableRef) : base(demoRef) { TableRef = tableRef; }
void GatherExcludesAndBaseclasses(SendTable sendTable, bool collectBaseClasses) { CurrentExcludes.AddRange( sendTable.Properties .Where(a => a.Flags.HasFlagFast(SendPropertyFlags.Exclude)) .Select(a => new ExcludeEntry(a.Name, a.DataTableName, sendTable.Name)) ); foreach (var prop in sendTable.Properties.Where(a => a.Type == SendPropertyType.DataTable)) { if (collectBaseClasses && prop.Name == "baseclass") { GatherExcludesAndBaseclasses (GetTableByName (prop.DataTableName), true); CurrentBaseclasses.Add (FindByDTName (prop.DataTableName)); } else { GatherExcludesAndBaseclasses (GetTableByName (prop.DataTableName), false); } } }