Skip to content

Commit e18ceea

Browse files
committed
Fix prop_physics Spawn and CreateVPhysics ignoring map settings
1 parent 41e18ea commit e18ceea

4 files changed

Lines changed: 217 additions & 6 deletions

File tree

‎Game.Server/BaseAnimating.cs‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -879,6 +879,11 @@ public virtual void HandleAnimEvent(ref AnimEvent animEvent) {
879879
public TimeUnit_t LastEventCheck;
880880
public TimeUnit_t GetCycle() => Cycle;
881881
public void SetCycle(TimeUnit_t cycle) => Cycle = cycle;
882+
883+
public void SetFadeDistance(float minFadeDist, float maxFadeDist) {
884+
FadeMinDist = minFadeDist;
885+
FadeMaxDist = maxFadeDist;
886+
}
882887
public float GetSequenceMoveDist(StudioHdr? studioHdr, int sequence) {
883888
Animation.GetSequenceLinearMotion(studioHdr, sequence, GetPoseParameterArray(), out Vector3 ret);
884889

‎Game.Server/Physics.cs‎

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,79 @@ public static float PhysGetEntityMass(BaseEntity entity) {
4747
return otherMass;
4848
}
4949

50+
class SkipKeys : IVPhysicsKeyHandler
51+
{
52+
public void ParseKeyValue<T>(T data, ReadOnlySpan<char> key, ReadOnlySpan<char> value) { }
53+
public void SetDefaults<T>(T data) { }
54+
}
55+
56+
public static void PhysSolidOverride(ref Solid solid, string? overrideScript) {
57+
if (overrideScript != null) {
58+
bool collisions = solid.Params.EnableCollisions;
59+
60+
StringBuilder tmpString = new("solid { ");
61+
62+
nexttoken(out ReadOnlySpan<char> token, overrideScript, ',', out ReadOnlySpan<char> str);
63+
while (!token.IsEmpty) {
64+
tmpString.Append('"');
65+
tmpString.Append(token);
66+
tmpString.Append("\" ");
67+
nexttoken(out token, str, ',', out str);
68+
}
69+
tmpString.Append('}');
70+
71+
IVPhysicsKeyParser parse = physcollision.VPhysicsKeyParserCreate(Encoding.ASCII.GetBytes(tmpString.ToString()));
72+
parse.ParseSolid(ref solid, new SkipKeys());
73+
physcollision.VPhysicsKeyParserDestroy(parse);
74+
75+
solid.Params.EnableCollisions = collisions;
76+
}
77+
}
78+
79+
public static void PhysSetMassCenterOverride(in MassCenterOverride massOverride) {
80+
if (massOverride.EntityName != null)
81+
g_PhysicsHook.MassCenterOverrides.Add(massOverride);
82+
}
83+
84+
public static int PhysGetMassCenterOverrideIndex(string? name) {
85+
if (name != null && g_PhysicsHook.MassCenterOverrides.Count != 0) {
86+
for (int i = 0; i < g_PhysicsHook.MassCenterOverrides.Count; i++) {
87+
if (g_PhysicsHook.MassCenterOverrides[i].EntityName == name)
88+
return i;
89+
}
90+
}
91+
return -1;
92+
}
93+
94+
public static void PhysGetMassCenterOverride(BaseEntity entity, VCollide? collide, ref Solid solidOut) {
95+
int index = PhysGetMassCenterOverrideIndex(entity.GetEntityName());
96+
97+
if (index >= 0) {
98+
MassCenterOverride massOverride = g_PhysicsHook.MassCenterOverrides[index];
99+
Vector3 massCenterWS = massOverride.Center;
100+
switch (massOverride.AlignType) {
101+
case MassCenterOverride.Align.Point:
102+
MathLib.VectorITransform(massCenterWS, entity.EntityToWorldTransform(), out solidOut.MassCenterOverride);
103+
break;
104+
case MassCenterOverride.Align.Axis: {
105+
physcollision.CollideGetMassCenter(collide!.Solids![solidOut.Index], out Vector3 massCenterLocal);
106+
MathLib.VectorTransform(massCenterLocal, entity.EntityToWorldTransform(), out Vector3 defaultMassCenterWS);
107+
massCenterWS += massOverride.Axis *
108+
(Vector3.Dot(defaultMassCenterWS, massOverride.Axis) - Vector3.Dot(massOverride.Axis, massOverride.Center));
109+
MathLib.VectorITransform(massCenterWS, entity.EntityToWorldTransform(), out solidOut.MassCenterOverride);
110+
}
111+
break;
112+
}
113+
g_PhysicsHook.MassCenterOverrides[index] = g_PhysicsHook.MassCenterOverrides[^1];
114+
g_PhysicsHook.MassCenterOverrides.RemoveAt(g_PhysicsHook.MassCenterOverrides.Count - 1);
115+
116+
if (solidOut.MassCenterOverride.Length() > DIST_EPSILON) {
117+
Vector3[] massCenter = [solidOut.MassCenterOverride];
118+
solidOut.Params.MassCenterOverrideFn = () => ref massCenter[0];
119+
}
120+
}
121+
}
122+
50123
public static void PhysicsImpactSound(BaseEntity entity, IPhysicsObject physObject, SoundEntityChannel channel, int surfaceProps, int surfacePropsHit, float volume, float impactSpeed) {
51124
PhysicsSound.AddImpactSound(g_PhysicsHook.ImpactSounds, entity, entity.EntIndex(), channel, physObject, surfaceProps, surfacePropsHit, volume, impactSpeed);
52125
}
@@ -202,6 +275,38 @@ public static void PhysCallbackDamage(BaseEntity entity, in TakeDamageInfo info)
202275
}
203276
}
204277

278+
public struct MassCenterOverride
279+
{
280+
public enum Align
281+
{
282+
Point = 0,
283+
Axis = 1,
284+
}
285+
286+
public void Defaults() {
287+
EntityName = null;
288+
}
289+
290+
public void SnapToPoint(string? name, in Vector3 pointWS) {
291+
EntityName = name;
292+
Center = pointWS;
293+
Axis = default;
294+
AlignType = Align.Point;
295+
}
296+
297+
public void SnapToAxis(string? name, in Vector3 axisStartWS, in Vector3 unitAxisDirWS) {
298+
EntityName = name;
299+
Center = axisStartWS;
300+
Axis = unitAxisDirWS;
301+
AlignType = Align.Axis;
302+
}
303+
304+
public Vector3 Center;
305+
public Vector3 Axis;
306+
public Align AlignType;
307+
public string? EntityName;
308+
}
309+
205310
public class PhysicsHook : BaseGameSystemPerFrame
206311
{
207312
public static TimeUnit_t g_PhysAverageSimTime;
@@ -341,6 +446,7 @@ public override void LevelShutdownPreEntity() {
341446
}
342447
public override void LevelShutdownPostEntity() {
343448
base.LevelShutdownPostEntity();
449+
MassCenterOverrides.Clear();
344450
}
345451
public override void FrameUpdatePostEntityThink() {
346452
base.FrameUpdatePostEntityThink();
@@ -358,4 +464,5 @@ public override void PreClientUpdate() {
358464
TimeUnit_t ImpactSoundTime;
359465
public readonly List<ImpactSound> ImpactSounds = [];
360466
public readonly List<BreakSound> BreakSounds = [];
467+
public readonly List<MassCenterOverride> MassCenterOverrides = [];
361468
}

‎Game.Server/Props.cs‎

Lines changed: 93 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ namespace Game.Server;
1616
using System.Diagnostics;
1717
using System.Numerics;
1818

19+
using DEFINE = Source.DEFINE<Game.Server.PhysicsProp>;
1920
using FIELD_BPD = Source.FIELD<BasePropDoor>;
2021
using FIELD_DP = Source.FIELD<DynamicProp>;
2122
using FIELD_PBM = Source.FIELD<PhysBoxMultiplayer>;
@@ -62,6 +63,13 @@ public class BreakableProp : BaseProp, IBreakableWithPropData
6263
public static readonly SendTable DT_BreakableProp = new(DT_BaseAnimating, []);
6364
public static readonly new ServerClass ServerClass = new ServerClass(DT_BreakableProp);
6465

66+
public bool PropDataOverrodeBlockLOS() => BlockLOSSetByPropData;
67+
68+
public void DisableAutoFade() {
69+
FadeScale = 0;
70+
DefaultFadeScale = 0;
71+
}
72+
6573
public void SetDmgModBullet(float dmgMod) => DmgModBullet = dmgMod;
6674
public void SetDmgModClub(float dmgMod) => DmgModClub = dmgMod;
6775
public void SetDmgModExplosive(float dmgMod) => DmgModExplosive = dmgMod;
@@ -82,7 +90,7 @@ public class BreakableProp : BaseProp, IBreakableWithPropData
8290
public int GetBreakableCount() => BreakableCount;
8391
public void SetMaxBreakableSize(int size) => MaxBreakableSize = size;
8492
public int GetMaxBreakableSize() => MaxBreakableSize;
85-
public void SetPropDataBlocksLOS(bool blocksLOS) => SetBlocksLOS(blocksLOS);
93+
public void SetPropDataBlocksLOS(bool blocksLOS) { BlockLOSSetByPropData = true; SetBlocksLOS(blocksLOS); }
8694
public void SetPropDataIsAIWalkable(bool blocksLOS) => SetAIWalkable(blocksLOS);
8795
public void SetBasePropData(ReadOnlySpan<char> propdata) => BasePropData = propdata.IsEmpty ? null : new(propdata);
8896
public ReadOnlySpan<char> GetBasePropData() => BasePropData;
@@ -107,6 +115,8 @@ public class BreakableProp : BaseProp, IBreakableWithPropData
107115
protected float ExplodeRadius;
108116
protected PhysicsMultiplayerMode m_iPhysicsMode;
109117
protected MultiplayerBreak MpBreakMode;
118+
bool BlockLOSSetByPropData;
119+
float DefaultFadeScale;
110120
}
111121

112122
[LinkEntityToClass("func_physbox_multiplayer")]
@@ -146,7 +156,36 @@ public class PhysicsProp : BreakableProp
146156
[NetworkName("m_bAwake")]
147157
public bool Awake;
148158

159+
public static readonly new DataMap DataDesc = new(typeof(PhysicsProp), BaseEntity.DataDesc, [
160+
DEFINE.KEYFIELD(nameof(MassScale), FieldType.Float, "massscale"),
161+
DEFINE.KEYFIELD(nameof(InertiaScale), FieldType.Float, "inertiascale"),
162+
DEFINE.KEYFIELD(nameof(DamageType), FieldType.Integer, "Damagetype"),
163+
DEFINE.KEYFIELD(nameof(OverrideScript), FieldType.String, "overridescript"),
164+
DEFINE.KEYFIELD(nameof(DamageToEnableMotion), FieldType.Integer, "damagetoenablemotion"),
165+
DEFINE.KEYFIELD(nameof(ForceToEnableMotion), FieldType.Float, "forcetoenablemotion"),
166+
]);
167+
public override DataMap? GetDataDescMap() => DataDesc;
168+
169+
public static int g_ActiveGibCount = 0;
170+
171+
float MassScale;
172+
float InertiaScale;
173+
int DamageType;
174+
string? OverrideScript;
175+
int DamageToEnableMotion;
176+
float ForceToEnableMotion;
177+
178+
public override void Term() {
179+
if (HasSpawnFlags(SF_PHYSPROP_IS_GIB))
180+
g_ActiveGibCount--;
181+
182+
base.Term();
183+
}
184+
149185
public override void Spawn() {
186+
if (HasSpawnFlags(SF_PHYSPROP_IS_GIB))
187+
g_ActiveGibCount++;
188+
150189
// Condense classnames to one, except for "prop_physics_override"
151190
if (FClassnameIs(this, "physics_prop"))
152191
SetClassname("prop_physics");
@@ -160,7 +199,21 @@ public override void Spawn() {
160199
if (FClassnameIs(this, "prop_physics_override"))
161200
SetClassname("prop_physics");
162201

202+
if (HasSpawnFlags(SF_PHYSPROP_DEBRIS) || HasInteraction(PropDataInteractions.PhysgunCreateFlare))
203+
SetCollisionGroup(HasSpawnFlags(SF_PHYSPROP_FORCE_TOUCH_TRIGGERS) ? Source.CollisionGroup.DebrisTrigger : Source.CollisionGroup.Debris);
204+
205+
if (HasSpawnFlags(SF_PHYSPROP_NO_ROTORWASH_PUSH))
206+
AddEFlags(EFL.NoRotorWashPush);
207+
163208
CreateVPhysics();
209+
210+
if (!PropDataOverrodeBlockLOS())
211+
CalculateBlockLOS();
212+
213+
if (((ReadOnlySpan<char>)GetModelName()).Equals("models/props_c17/door01_left.mdl", StringComparison.Ordinal)) {
214+
SetFadeDistance(-1, 0);
215+
DisableAutoFade();
216+
}
164217
}
165218

166219
public static bool PropIsGib(BaseEntity entity) {
@@ -174,18 +227,52 @@ public static bool PropIsGib(BaseEntity entity) {
174227
public bool IsGib() => (SpawnFlags & SF_PHYSPROP_IS_GIB) != 0;
175228

176229
public virtual bool CreateVPhysics() {
177-
SetSolid(SolidType.VPhysics);
230+
bool asleep = HasSpawnFlags(SF_PHYSPROP_START_ASLEEP);
178231

179-
if (m_takedamage == (byte)Damage.No)
180-
SetMoveType(Source.MoveType.None);
232+
Solid tmpSolid = default;
233+
PhysModelParseSolid(ref tmpSolid, this, GetModelIndex());
234+
235+
if (MassScale > 0)
236+
tmpSolid.Params.Mass *= MassScale;
237+
238+
if (InertiaScale > 0) {
239+
tmpSolid.Params.Inertia *= InertiaScale;
240+
if (tmpSolid.Params.Inertia < 0.5)
241+
tmpSolid.Params.Inertia = 0.5f;
242+
}
243+
244+
PhysGetMassCenterOverride(this, modelinfo.GetVCollide(GetModelIndex()), ref tmpSolid);
245+
if (HasSpawnFlags(SF_PHYSPROP_NO_COLLISIONS))
246+
tmpSolid.Params.EnableCollisions = false;
247+
248+
PhysSolidOverride(ref tmpSolid, OverrideScript);
181249

182-
IPhysicsObject? physObj = VPhysicsInitNormal(SolidType.VPhysics, GetSolidFlags(), false);
183-
if (physObj == null) {
250+
IPhysicsObject? physicsObject = VPhysicsInitNormal(SolidType.VPhysics, 0, asleep, ref tmpSolid);
251+
252+
if (physicsObject == null) {
184253
SetSolid(SolidType.None);
185254
SetMoveType(Source.MoveType.None);
186255
Warning($"ERROR!: Can't create physics object for {GetModelName()}\n");
187256
return false;
188257
}
258+
else {
259+
if (DamageType == 1)
260+
PhysSetGameFlags(physicsObject, PhysicsFlags.DamageSlice);
261+
262+
if (HasSpawnFlags(SF_PHYSPROP_MOTIONDISABLED) || DamageToEnableMotion > 0 || ForceToEnableMotion > 0)
263+
physicsObject.EnableMotion(false);
264+
}
265+
266+
if (HasInteraction(PropDataInteractions.PhysgunLaunchSpinZ)) {
267+
if ((VPhysicsGetObject()!.GetGameFlags() & PhysicsFlags.DamageSlice) == 0)
268+
PhysSetGameFlags(physicsObject, PhysicsFlags.DamageSlice);
269+
}
270+
271+
if (HasInteraction(PropDataInteractions.PhysgunDamageNone))
272+
PhysSetGameFlags(physicsObject, PhysicsFlags.NoImpactDamage);
273+
274+
if (HasSpawnFlags(SF_PHYSPROP_PREVENT_PICKUP))
275+
PhysSetGameFlags(physicsObject, PhysicsFlags.NoPlayerPickup);
189276

190277
return true;
191278
}

‎Game.Shared/PhysicsShared.cs‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,18 @@ public static void PhysFrictionEffect(in Vector3 pos, Vector3 vel, float energy,
339339
}
340340
#endif
341341

342+
public static bool PhysModelParseSolidByIndex(ref Solid solid, BaseEntity entity, int modelIndex, int solidIndex) {
343+
VCollide? collide = modelinfo.GetVCollide(modelIndex);
344+
if (collide == null)
345+
return false;
346+
347+
return PhysModelParseSolidByIndex(ref solid, entity, collide, solidIndex);
348+
}
349+
350+
public static bool PhysModelParseSolid(ref Solid solid, BaseEntity entity, int modelIndex) {
351+
return PhysModelParseSolidByIndex(ref solid, entity, modelIndex, -1);
352+
}
353+
342354
public static bool PhysModelParseSolidByIndex(ref Solid solid, BaseEntity entity, VCollide? collide, int solidIndex) {
343355
if (collide == null || collide.KeyValues == null)
344356
return false;

0 commit comments

Comments
 (0)