public int Spawn(Edict pent) { var pEntity = pent.Entity(); if (pEntity != null) { // Initialize these or entities who don't link to the world won't have anything in here pEntity.AbsMin = pEntity.Origin - new Vector(1, 1, 1); pEntity.AbsMax = pEntity.Origin + new Vector(1, 1, 1); pEntity.Spawn(); // Try to get the pointer again, in case the spawn function deleted the entity. // UNDONE: Spawn() should really return a code to ask that the entity be deleted, but // that would touch too much code for me to do that right now. pEntity = pent.Entity(); if (pEntity != null) { if (!Engine.GameRules.IsAllowedToSpawn(pEntity)) { return(-1); // return that this entity should be deleted } if (0 != (pEntity.Flags & EntFlags.KillMe)) { return(-1); } } // Handle global stuff here if (pEntity != null && !string.IsNullOrEmpty(pEntity.GlobalName)) { var pGlobal = Globals.GlobalState.EntityFromTable(pEntity.GlobalName); if (pGlobal != null) { // Already dead? delete if (pGlobal.State == GlobalEState.Dead) { return(-1); } else if (Engine.Globals.MapName != pGlobal.LevelName) { pEntity.MakeDormant(); // Hasn't been moved to this level yet, wait but stay alive } // In this level & not dead, continue on as normal } else { // Spawned entities default to 'On' Globals.GlobalState.EntityAdd(pEntity.GlobalName, Engine.Globals.MapName, GlobalEState.On); // Log.Alert(AlertType.Console, $"Added global entity {pEntity.ClassName} ({pEntity.GlobalName})\n"); } } } return(0); //TODO: define return codes }
public void Blocked(Edict pentBlocked, Edict pentOther) { var blocked = pentBlocked.Entity(); var other = pentOther.Entity(); blocked?.Blocked(other); }
public void OnFreeEntPrivateData(Edict pEnt) { if (pEnt.PrivateData != null) { //Inform of destruction pEnt.Entity().OnDestroy(); //Mark the private data as freed, and set the managed instance to be garbage collected pEnt.PrivateData = null; } }
public void Use(Edict pentUsed, Edict pentOther) { var used = pentUsed.Entity(); var other = pentOther.Entity(); if (used != null && (used.Flags & EntFlags.KillMe) == 0) { used.Use(other, other, UseType.Toggle, 0); } }
public void Think(Edict pent) { var thinker = pent.Entity(); if (thinker != null) { if ((thinker.Flags & EntFlags.Dormant) != 0) { Log.Alert(AlertType.Error, $"Dormant entity {thinker.ClassName} is thinking!!"); } thinker.Think(); } }
public void Touch(Edict pentTouched, Edict pentOther) { if (TouchDisabled) { return; } var touched = pentTouched.Entity(); var other = pentOther.Entity(); if (touched != null && other != null && ((touched.Flags | other.Flags) & EntFlags.KillMe) == 0) { touched.Touch(other); } }
public void SetupVisibility(Edict pViewEntity, Edict pClient, out IntPtr pvs, out IntPtr pas) { var client = pClient.Entity(); // Find the client's PVS var view = pViewEntity?.TryGetEntity() ?? client; if ((client.Flags & EntFlags.Proxy) != 0) { pvs = IntPtr.Zero; // the spectator proxy sees pas = IntPtr.Zero; // and hears everything return; } var org = view.Origin + view.ViewOffset; if ((view.Flags & EntFlags.Ducking) != 0) { org += (WorldConstants.HULL_MIN - WorldConstants.DUCK_HULL_MIN); } pvs = EngineServer.SetFatPVS(org); pas = EngineServer.SetFatPAS(org); }
public bool AddToFullPack(EntityState state, int e, Edict ent, Edict host, HostFlags hostFlags, bool isPlayer, IntPtr pSet) { //Never add entities that aren't in use if (ent.Free) { return(false); } var entity = ent.Entity(); var hostEntity = host.Entity(); // don't send if flagged for NODRAW and it's not the host getting the message if ((entity.Effects & EntityEffects.NoDraw) != 0 && (entity != hostEntity)) { return(false); } // Ignore ents without valid / visible models if (entity.ModelIndex == 0 || string.IsNullOrEmpty(entity.ModelName)) { return(false); } // Don't send spectators to other players if ((entity.Flags & EntFlags.Spectator) != 0 && (entity != hostEntity)) { return(false); } // Ignore if not the host and not touching a PVS/PAS leaf // If pSet is NULL, then the test will always succeed and the entity will be added to the update if (entity != hostEntity) { if (!EngineServer.CheckVisibility(ent, pSet)) { return(false); } } // Don't send entity to local client if the client says it's predicting the entity itself. if ((entity.Flags & EntFlags.SkipLocalHost) != 0) { if ((hostFlags & HostFlags.SkipLocalEnts) != 0 && (entity.Owner == hostEntity)) { return(false); } } if (hostEntity.GroupInfo != 0) { Trace.PushGroupTrace(hostEntity.GroupInfo, GroupOp.And); try { Trace.GetGroupTrace(out var currentMask, out var currentOp); // Should always be set, of course if (entity.GroupInfo != 0) { if (currentOp == GroupOp.And) { if ((entity.GroupInfo & hostEntity.GroupInfo) == 0) { return(false); } } else if (currentOp == GroupOp.NAnd) { if ((entity.GroupInfo & hostEntity.GroupInfo) != 0) { return(false); } } } } finally { //There is a bug in the SDK that can cause the last group trace to remain if it failed the tests above Trace.PopGroupTrace(); } } //This is done by the wrapper since there's no memset in managed code //memset(state, 0, sizeof( * state) ); // Assign index so we can track this entity from frame to frame and // delta from it. state.Number = e; state.EntityType = EntityType.Normal; // Flag custom entities. if ((entity.Flags & EntFlags.CustomEntity) != 0) { state.EntityType = EntityType.Beam; } // // Copy state data // // Round animtime to nearest millisecond state.AnimTime = (float)((int)(1000.0 * entity.AnimationTime) / 1000.0); state.Origin = entity.Origin; state.Angles = entity.Angles; state.Mins = entity.Mins; state.Maxs = entity.Maxs; state.EndPos = entity.EndPosition; state.StartPos = entity.StartPosition; state.ImpactTime = entity.ImpactTime; state.StartTime = entity.StartTime; state.ModelIndex = entity.ModelIndex; state.Frame = entity.Frame; state.Skin = (short)entity.Skin; state.Effects = entity.Effects; // This non-player entity is being moved by the game .dll and not the physics simulation system // make sure that we interpolate it's position on the client if it moves if (!isPlayer && entity.AnimationTime != 0 && entity.Velocity[0] == 0 && entity.Velocity[1] == 0 && entity.Velocity[2] == 0) { state.EFlags |= EntityStateFlags.SLerp; } state.Scale = entity.Scale; state.Solid = entity.Solid; state.ColorMap = entity.ColorMap; state.MoveType = entity.MoveType; state.Sequence = entity.Sequence; state.FrameRate = entity.FrameRate; state.Body = entity.Body; for (var i = 0; i < 4; ++i) { state.SetController(i, entity.GetController(i)); } for (var i = 0; i < 2; ++i) { state.SetBlending(i, entity.GetBlending(i)); } state.RenderMode = entity.RenderMode; state.RenderAmount = (int)entity.RenderAmount; state.RenderEffect = entity.RenderEffect; state.RenderColor = new Color24 { r = (byte)entity.RenderColor.x, g = (byte)entity.RenderColor.y, b = (byte)entity.RenderColor.z }; state.AimEnt = 0; if (entity.AimEntity != null) { state.AimEnt = entity.AimEntity.EntIndex(); } state.Owner = 0; if (entity.Owner != null) { var owner = entity.Owner.EntIndex(); // Only care if owned by a player if (owner >= 1 && owner <= Globals.MaxClients) { state.Owner = owner; } } // HACK: Somewhat... // Class is overridden for non-players to signify a breakable glass object ( sort of a class? ) if (!isPlayer) { state.PlayerClass = entity.PlayerClass; } // Special stuff for players only if (isPlayer) { state.BaseVelocity = entity.BaseVelocity; state.WeaponModel = EngineModel.IndexOf(entity.WeaponModelName); state.GaitSequence = entity.GaitSequence; state.Spectator = (entity.Flags & EntFlags.Spectator) != 0; state.Friction = entity.Friction; state.Gravity = entity.Gravity; // state.Team = entity.Team; // state.UseHull = (entity.Flags & EntFlags.Ducking) != 0 ? 1 : 0; state.Health = (int)entity.Health; } return(true); }