Skip to content
This repository was archived by the owner on Sep 22, 2021. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
0f423c9
Molotov have ThrownBy players
econoraptor Dec 15, 2017
94e6c11
Made FireWithOwnerStart a separate event
econoraptor Dec 16, 2017
2d17741
Cell positions to standard coordinates, vector distance function
econoraptor Dec 16, 2017
bdca4b9
merge with InfernoThrownBy2
econoraptor Dec 16, 2017
5ead2bf
molotov and smoke detonate interpolation
econoraptor Dec 17, 2017
5050196
ProjectileEntityID added to BlindEventArgs
econoraptor Dec 17, 2017
51d0ac8
DetonateEntity now implements Owner so that it updates NadeArgs.ThrownBy
econoraptor Dec 17, 2017
a22db0e
Added nade event args copy constructors and interpolated detonate end…
econoraptor Dec 18, 2017
0a48dc7
Raise detonate end for grenades that aren't destroyed at end of round.
econoraptor Dec 20, 2017
adebdae
decoys added
econoraptor Dec 21, 2017
39b8cc8
Use IngameTick instead of CurrentTick, check that m_fFlags didn't hap…
econoraptor Dec 29, 2017
53e35b8
Correct check on DetonateStarts for interpolated, not containskey
econoraptor Dec 29, 2017
861486e
construct DetonateEntity with NadeArgs so that molotov detonates can …
econoraptor Dec 30, 2017
479f318
Big refactor to isolate more in DetonateEntity.
econoraptor Dec 30, 2017
67878a7
Change way replaced entities are handled
econoraptor Jan 1, 2018
1dac4fa
Match serverclasses with DetonateEntity type when checking replacement.
econoraptor Jan 1, 2018
ac7628f
Check whether DetonateEntity NadeArgs is interpolated before updating…
econoraptor Jan 2, 2018
6d67c64
Merge branch 'HelixMaster' into DetonateInterpolate
econoraptor Jan 11, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 31 additions & 9 deletions DemoInfo/DP/Handler/GameEventHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public static void Apply(GameEvent rawEvent, DemoParser parser)
}

if (eventDescriptor.Name == "round_officially_ended")
parser.RaiseRoundOfficiallyEnd ();
parser.RaiseRoundOfficiallyEnd();

if (eventDescriptor.Name == "round_mvp") {
data = MapData (eventDescriptor, rawEvent);
Expand Down Expand Up @@ -204,6 +204,9 @@ public static void Apply(GameEvent rawEvent, DemoParser parser)
else
blind.FlashDuration = null;

if (data.ContainsKey("entityid"))
blind.ProjectileEntityID = (int?)data["entityid"];

parser.RaiseBlind(blind);
}

Expand All @@ -222,30 +225,47 @@ public static void Apply(GameEvent rawEvent, DemoParser parser)
parser.RaiseGrenadeExploded(FillNadeEvent<GrenadeEventArgs>(MapData(eventDescriptor, rawEvent), parser));
break;
case "decoy_started":
parser.RaiseDecoyStart(FillNadeEvent<DecoyEventArgs>(MapData(eventDescriptor, rawEvent), parser));
var decoyData = MapData(eventDescriptor, rawEvent);
var decoyArgs = FillNadeEvent<DecoyEventArgs>(decoyData, parser);
parser.RaiseDecoyStart(decoyArgs);
var decoyEnt = parser.DetonateEntities[(int)decoyData["entityid"]];
decoyEnt.DetonateState = DetonateState.Detonating;
decoyEnt.NadeArgs = decoyArgs;
break;
case "decoy_detonate":
parser.RaiseDecoyEnd(FillNadeEvent<DecoyEventArgs>(MapData(eventDescriptor, rawEvent), parser));
var decoyEndData = MapData(eventDescriptor, rawEvent);
parser.RaiseDecoyEnd(FillNadeEvent<DecoyEventArgs>(decoyEndData, parser));
parser.DetonateEntities.Remove((int)decoyEndData["entityid"]);
break;
case "smokegrenade_detonate":
parser.RaiseSmokeStart(FillNadeEvent<SmokeEventArgs>(MapData(eventDescriptor, rawEvent), parser));
var smokeData = MapData(eventDescriptor, rawEvent);
var smokeArgs = FillNadeEvent<SmokeEventArgs>(smokeData, parser);
parser.RaiseSmokeStart(smokeArgs);
var smokeEnt = parser.DetonateEntities[(int)smokeData["entityid"]];
smokeEnt.DetonateState = DetonateState.Detonating;
smokeEnt.NadeArgs = smokeArgs;
break;
case "smokegrenade_expired":
parser.RaiseSmokeEnd(FillNadeEvent<SmokeEventArgs>(MapData(eventDescriptor, rawEvent), parser));
var smokeEndData = MapData(eventDescriptor, rawEvent);
parser.RaiseSmokeEnd(FillNadeEvent<SmokeEventArgs>(smokeEndData, parser));
parser.DetonateEntities.Remove((int)smokeEndData["entityid"]);
break;
case "inferno_startburn":
var fireData = MapData(eventDescriptor, rawEvent);
var fireArgs = FillNadeEvent<FireEventArgs>(fireData, parser);
var fireStarted = new Tuple<int, FireEventArgs>((int)fireData["entityid"], fireArgs);
parser.GEH_StartBurns.Enqueue(fireStarted);
var fireEnt = new FireDetonateEntity(parser);
parser.DetonateEntities[(int)fireData["entityid"]] = fireEnt;
fireEnt.NadeArgs = fireArgs;
fireEnt.DetonateState = DetonateState.Detonating;
parser.RaiseFireStart(fireArgs);
break;
case "inferno_expire":
var fireEndData = MapData(eventDescriptor, rawEvent);
var fireEndArgs = FillNadeEvent<FireEventArgs>(fireEndData, parser);
int entityID = (int)fireEndData["entityid"];
fireEndArgs.ThrownBy = parser.InfernoOwners[entityID];
int endEntityID = (int)fireEndData["entityid"];
fireEndArgs.ThrownBy = parser.DetonateEntities[endEntityID].NadeArgs.ThrownBy;
parser.RaiseFireEnd(fireEndArgs);
parser.DetonateEntities.Remove(endEntityID);
break;
#endregion

Expand Down Expand Up @@ -390,6 +410,8 @@ public static void Apply(GameEvent rawEvent, DemoParser parser)
{
var nade = new T();

nade.EntityID = (int)data["entityid"];

if (data.ContainsKey("userid") && parser.Players.ContainsKey((int)data["userid"]))
nade.ThrownBy = parser.Players[(int)data["userid"]];

Expand Down
2 changes: 2 additions & 0 deletions DemoInfo/DT/ServerClass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ internal void AnnounceNewEntity(Entity e)
OnNewEntity(this, new EntityCreatedEventArgs(this, e));
}

// On rare occasions entities are replaced rather than destroyed,
// in which case this event won't be raised
public event EventHandler<EntityDestroyedEventArgs> OnDestroyEntity;

internal void AnnounceDestroyedEntity(Entity e)
Expand Down
194 changes: 172 additions & 22 deletions DemoInfo/DemoParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public class DemoParser : IDisposable
const int MAXPLAYERS = 64;
const int MAXWEAPONS = 64;

private const int MAX_COORD_INTEGER = 16384;
private int cellWidth;

#region Events
/// <summary>
Expand Down Expand Up @@ -421,12 +423,6 @@ public string TFlag
/// </summary>
internal List<Player> GEH_BlindPlayers = new List<Player>();

/// <summary>
/// Holds inferno_startburn event args so they can be matched with player
/// </summary>
internal Queue<Tuple<int, FireEventArgs>> GEH_StartBurns = new Queue<Tuple<int, FireEventArgs>>();


// These could be Dictionary<int, RecordedPropertyUpdate[]>, but I was too lazy to
// define that class. Also: It doesn't matter anyways, we always have to cast.

Expand Down Expand Up @@ -596,10 +592,54 @@ public bool ParseNextTick()
}
}

while (GEH_StartBurns.Count > 0) {
var fireTup = GEH_StartBurns.Dequeue();
fireTup.Item2.ThrownBy = InfernoOwners[fireTup.Item1];
RaiseFireWithOwnerStart(fireTup.Item2);
while (InterpDetonates.Count > 0) {
var detonate = InterpDetonates.Dequeue();
detonate.RaiseNadeStart();
detonate.DetonateState = DetonateState.Detonating;
}

// It's possible for entities to be replaced without being destroyed
// It might be possible for an entity to be replaced by the same type of entity,
// but that hasn't been seen so far. If such a case arises, I think the only way to differentiate
// two entities with the same id and same class would be to look at the seriesid,
// but that's not currently coded.
if (DetonateEntities.Count > 0)
{
List<int> badEntities = new List<int>();
foreach (var detEnt in DetonateEntities)
{
var ent = Entities[detEnt.Key];
if (ent != null)
{
string detClsName = "";
if (detEnt.Value is FireDetonateEntity)
detClsName = "CInferno";
else if (detEnt.Value is SmokeDetonateEntity)
detClsName = "CSmokeGrenadeProjectile";
else if (detEnt.Value is DecoyDetonateEntity)
detClsName = "CDecoyProjectile";

if (ent.ServerClass.Name != detClsName)
badEntities.Add(detEnt.Key);
}
}

foreach (int k in badEntities)
PopDetonateEntity(k);
}

const int preStartThresh = 2;
if (CurrentTick % 10 == 0)
{
foreach (var det in DetonateEntities.Values)
{
if (det is DecoyDetonateEntity &&
det.DetonateState == DetonateState.PreDetonate &&
CurrentTime - ((DecoyDetonateEntity)det).FlagTime > preStartThresh)
{
InterpDetonates.Enqueue(det);
}
}
}

if (b) {
Expand Down Expand Up @@ -697,7 +737,9 @@ private void BindEntites()

HandleWeapons ();

HandleInfernos();
HandleDetonates();

SetCellWidth();
}

private void HandleTeamScores()
Expand Down Expand Up @@ -1116,23 +1158,131 @@ private void HandleBombSites()

}

internal Dictionary<int, Player> InfernoOwners = new Dictionary<int, Player>();
private void HandleInfernos()
internal Queue<DetonateEntity> InterpDetonates = new Queue<DetonateEntity>();
internal Dictionary<int, DetonateEntity> DetonateEntities = new Dictionary<int, DetonateEntity>();
private void HandleDetonates()
{
var inferno = SendTableParser.FindByName("CInferno");
var infernoClass = SendTableParser.FindByName("CInferno"); // fire-making entity, not projectile
var smokeClass = SendTableParser.FindByName("CSmokeGrenadeProjectile");
var decoyClass = SendTableParser.FindByName("CDecoyProjectile");
ServerClass[] projClasses = new ServerClass[3] {infernoClass, smokeClass, decoyClass};
foreach (var projClass in projClasses)
{
projClass.OnNewEntity += (s, ent) =>
{
DetonateEntity det;

inferno.OnNewEntity += (s, infEntity) => {
infEntity.Entity.FindProperty("m_hOwnerEntity").IntRecived += (s2, handleID) => {
int playerEntityID = handleID.Value & INDEX_MASK;
if (playerEntityID < PlayerInformations.Length && PlayerInformations[playerEntityID - 1] != null)
InfernoOwners[infEntity.Entity.ID] = PlayerInformations[playerEntityID - 1];
if (projClass == infernoClass)
{
if (DetonateEntities.ContainsKey(ent.Entity.ID))
{
// inferno_startburn successfully triggered, but we still want to add owner
det = DetonateEntities[ent.Entity.ID];
InterpDetonates.Enqueue(det);
}
else
det = new FireDetonateEntity(this);
}
else if (projClass == smokeClass)
{
det = new SmokeDetonateEntity(this);
ent.Entity.FindProperty("m_bDidSmokeEffect").IntRecived += (s2, smokeEffect) =>
{
//m_bDidSmokeEffect happens on the same tick as smokegrenade_detonate
if (smokeEffect.Value == 1 && det.DetonateState == DetonateState.PreDetonate)
InterpDetonates.Enqueue(det);
};
}
else
{
det = new DecoyDetonateEntity(this);
ent.Entity.FindProperty("m_fFlags").IntRecived += (s2, flag) =>
{
// There doesn't seem to be any property that is tightly coupled with
// decoy_started events, but m_fFlags always occurs some time beforehand.
if (flag.Value == 1)
{
if (det.DetonateState == DetonateState.PreDetonate)
{
// It's possible, but rare, for m_fFlags to be set on the same tick as decoy_started
((DecoyDetonateEntity)det).FlagTime = CurrentTime;
}
}
};
}

ent.Entity.FindProperty("m_hOwnerEntity").IntRecived += (s2, handleID) =>
{
int playerEntityID = handleID.Value & INDEX_MASK;
if (playerEntityID < PlayerInformations.Length && PlayerInformations[playerEntityID - 1] != null)
DetonateEntities[ent.Entity.ID].NadeArgs.ThrownBy = PlayerInformations[playerEntityID - 1];
};

if (det.DetonateState == DetonateState.PreDetonate)
{
//DT_Inferno entity is created on the same tick as inferno_startburn, but parsed after
if (projClass == infernoClass)
InterpDetonates.Enqueue(det);

DetonateEntities[ent.Entity.ID] = det;
det.EntityID = ent.Entity.ID;

ent.Entity.FindProperty("m_cellX").IntRecived += (s2, cell) => det.CellX = cell.Value;
ent.Entity.FindProperty("m_cellY").IntRecived += (s2, cell) => det.CellY = cell.Value;
ent.Entity.FindProperty("m_cellZ").IntRecived += (s2, cell) => det.CellZ = cell.Value;
ent.Entity.FindProperty("m_vecOrigin").VectorRecived += (s2, vector) => det.Origin = vector.Value;
}
};
};

inferno.OnDestroyEntity += (s, infEntity) => {
InfernoOwners.Remove(infEntity.Entity.ID);
projClass.OnDestroyEntity += (s, ent) =>
{
// DetonateEntities get removed on detonate_end events,
// so the only ones left at this point are those that had no end triggered
if (DetonateEntities.ContainsKey(ent.Entity.ID))
PopDetonateEntity(ent.Entity.ID);
};
}
}

private void PopDetonateEntity(int entID)
{
var detEntity = DetonateEntities[entID];

if (detEntity.DetonateState == DetonateState.PreDetonate)
{
// This happens when a player throws a grenade, but it never detonates.
// Either the round ended before detonation, or if it's a molotov it detonated in the sky.
DetonateEntities.Remove(entID);
return;
}

detEntity.CopyAndReplaceNadeArgs();
detEntity.NadeArgs.Interpolated = true;

detEntity.RaiseNadeEnd();

DetonateEntities.Remove(entID);
}

private void SetCellWidth()
{
SendTableParser.FindByName("CBaseEntity").OnNewEntity += (s, baseEnt) =>
{
baseEnt.Entity.FindProperty("m_cellbits").IntRecived += (s2, bitnum) =>
{
cellWidth = 1 << bitnum.Value;
};
};
}

internal Vector CellsToCoords(int cellX, int cellY, int cellZ)
{
return new Vector(
cellX * cellWidth - MAX_COORD_INTEGER,
cellY * cellWidth - MAX_COORD_INTEGER,
cellZ * cellWidth - MAX_COORD_INTEGER);
}

#if SAVE_PROP_VALUES
[Obsolete("This method is only for debugging-purposes and shuld never be used in production, so you need to live with this warning.")]
public string DumpAllEntities()
Expand Down
Loading