protected override void Update(Entity entity, HitCollisionOwner hitCollisionOwner, DestructibleProp prop, DestructablePropReplicatedState replicatedState) { if (prop.health <= 0) { return; } if (hitCollisionOwner.damageEvents.Count == 0) { return; } var instigator = Entity.Null; foreach (var damageEvent in hitCollisionOwner.damageEvents) { prop.health -= damageEvent.damage; if (damageEvent.instigator != Entity.Null) { instigator = damageEvent.instigator; } if (prop.health < 0) { break; } } hitCollisionOwner.damageEvents.Clear(); if (prop.health <= 0) { hitCollisionOwner.collisionEnabled = false; foreach (var gameObject in prop.collision) { gameObject.SetActive(false); } replicatedState.destroyedTick = m_world.worldTime.tick; // Create splash damage if (prop.splashDamage.radius > 0) { var collisionMask = ~0; if (instigator != Entity.Null && EntityManager.HasComponent <Character>(instigator)) { var character = EntityManager.GetComponentObject <Character>(instigator); collisionMask = ~(1 << character.teamId); } var splashCenter = prop.transform.position + prop.splashDamageOffset; SplashDamageRequest.Create(PostUpdateCommands, m_world.worldTime.tick, instigator, splashCenter, collisionMask, prop.splashDamage); } } }
protected override void OnUpdate() { var time = ServerGameLoop.Instance.GameWorld.worldTime; var queryReciever = ServerGameLoop.Instance.ECSWorld.GetExistingSystem <RaySphereQueryReciever>(); var grenadeEntityArray = grenadeQuery.GetEntityArraySt(); var settingsArray = grenadeQuery.GetComponentDataArraySt <GrenadeSimSettings>(); var internalStateArray = grenadeQuery.GetComponentDataArraySt <GrenadeInternalState>(); for (var i = 0; i < internalStateArray.Length; i++) { var internalState = internalStateArray[i]; var entity = grenadeEntityArray[i]; if (internalState.active == 0) { // Keep grenades around for a short duration so shortlived grenades gets a chance to get replicated // and explode effect played if (time.DurationSinceTick(internalState.explodeTick) > 1.0f) { // TODO: LZ: // World.RequestDespawn(PostUpdateCommands, entity); Debug.Log(string.Format("LZ: Grenade {0} should be destroyed!", entity.ToString())); var tr = EntityManager.GetComponentObject <Transform>(entity); if (tr != null) { Object.Destroy(tr.gameObject); } else { EntityManager.DestroyEntity(entity); } } continue; } var settings = settingsArray[i]; var hitCollisionOwner = Entity.Null; if (internalState.rayQueryId != -1) { RaySphereQueryReciever.Query query; RaySphereQueryReciever.QueryResult queryResult; queryReciever.GetResult(internalState.rayQueryId, out query, out queryResult); internalState.rayQueryId = -1; // If grenade hit something that was no hitCollision it is environment and grenade should bounce if (queryResult.hit == 1 && queryResult.hitCollisionOwner == Entity.Null) { var moveDir = math.normalize(internalState.velocity); var moveVel = math.length(internalState.velocity); internalState.position = queryResult.hitPoint + queryResult.hitNormal * settings.collisionRadius; moveDir = Vector3.Reflect(moveDir, queryResult.hitNormal); internalState.velocity = moveDir * moveVel * settings.bounciness; // TODO: LZ: // Figure out a nice way to send the bounce event to the client // so the client can play the bounce sound at the correct time #if false if (moveVel > 1.0f) { interpolatedState.bouncetick = m_world.worldTime.tick; } #endif } if (queryResult.hitCollisionOwner != Entity.Null) { internalState.position = queryResult.hitPoint; } hitCollisionOwner = queryResult.hitCollisionOwner; } // Should we explode ? var timeout = time.DurationSinceTick(internalState.startTick) > settings.maxLifetime; if (timeout || hitCollisionOwner != Entity.Null) { internalState.active = 0; internalState.explodeTick = time.tick; Debug.Log(string.Format("LZ: Grenade {0} explode!", entity.ToString())); if (settings.splashDamage.radius > 0) { var collisionMask = ~(1 << internalState.teamId); // TODO: LZ: // calculate damage #if false SplashDamageRequest.Create(PostUpdateCommands, time.tick, internalState.owner, internalState.position, collisionMask, settings.splashDamage); #endif } } EntityManager.SetComponentData(entity, internalState); // internal state ==> ghost component Translation translation = new Translation { Value = internalState.position }; EntityManager.SetComponentData(entity, translation); // represent it on the server Transform representationTransform = EntityManager.GetComponentObject <Transform>(entity); representationTransform.position = internalState.position; } }
protected override void OnUpdate() { var entityArray = Group.GetEntityArraySt(); var hitCollArray = Group.GetComponentDataArraySt <HitCollisionOwnerData>(); var propArray = Group.ToComponentArray <DestructibleProp>(); var replicatedDataArray = Group.GetComponentDataArraySt <DestructablePropReplicatedData>(); for (int i = 0; i < entityArray.Length; i++) { var prop = propArray[i]; if (prop.health <= 0) { continue; } var entity = entityArray[i]; var damageBuffer = EntityManager.GetBuffer <DamageEvent>(entity); if (damageBuffer.Length == 0) { continue; } var instigator = Entity.Null; for (int j = 0; j < damageBuffer.Length; j++) { var damageEvent = damageBuffer[j]; prop.health -= damageEvent.damage; if (damageEvent.instigator != Entity.Null) { instigator = damageEvent.instigator; } if (prop.health < 0) { break; } } damageBuffer.Clear(); if (prop.health <= 0) { var replicatedState = replicatedDataArray[i]; var hitCollOwner = hitCollArray[i]; hitCollOwner.collisionEnabled = 0; EntityManager.SetComponentData(entity, hitCollOwner); foreach (var gameObject in prop.collision) { gameObject.SetActive(false); } replicatedState.destroyedTick = m_world.worldTime.tick; // Create splash damage if (prop.splashDamage.radius > 0) { var collisionMask = ~0; if (instigator != Entity.Null && EntityManager.HasComponent <Character>(instigator)) { var character = EntityManager.GetComponentObject <Character>(instigator); collisionMask = ~(1 << character.teamId); } var splashCenter = prop.transform.position + prop.splashDamageOffset; SplashDamageRequest.Create(PostUpdateCommands, m_world.worldTime.tick, instigator, splashCenter, collisionMask, prop.splashDamage); } EntityManager.SetComponentData(entity, replicatedState); } } }
protected override void OnUpdate() { Profiler.BeginSample("FinalizeGrenadeMovement"); var time = m_world.worldTime; var queryReciever = World.GetExistingManager <RaySphereQueryReciever>(); var grenadeEntityArray = Group.GetEntityArray(); var settingsArray = Group.GetComponentDataArray <Grenade.Settings>(); var internalStateArray = Group.GetComponentDataArray <Grenade.InternalState>(); var interpolatedStateArray = Group.GetComponentDataArray <Grenade.InterpolatedState>(); for (var i = 0; i < internalStateArray.Length; i++) { var internalState = internalStateArray[i]; var entity = grenadeEntityArray[i]; if (internalState.active == 0) { // Keep grenades around for a short duration so shortlived grenades gets a chance to get replicated // and explode effect played if (m_world.worldTime.DurationSinceTick(internalState.explodeTick) > 1.0f) { m_world.RequestDespawn(PostUpdateCommands, entity); } continue; } var settings = settingsArray[i]; var interpolatedState = interpolatedStateArray[i]; var hitCollisionOwner = Entity.Null; if (internalState.rayQueryId != -1) { RaySphereQueryReciever.Query query; RaySphereQueryReciever.QueryResult queryResult; queryReciever.GetResult(internalState.rayQueryId, out query, out queryResult); internalState.rayQueryId = -1; // If grenade hit something that was no hitCollision it is environment and grenade should bounce if (queryResult.hit == 1 && queryResult.hitCollisionOwner == Entity.Null) { var moveDir = math.normalize(internalState.velocity); var moveVel = math.length(internalState.velocity); internalState.position = queryResult.hitPoint + queryResult.hitNormal * settings.collisionRadius; moveDir = Vector3.Reflect(moveDir, queryResult.hitNormal); internalState.velocity = moveDir * moveVel * settings.bounciness; if (moveVel > 1.0f) { interpolatedState.bouncetick = m_world.worldTime.tick; } } if (queryResult.hitCollisionOwner != Entity.Null) { internalState.position = queryResult.hitPoint; } hitCollisionOwner = queryResult.hitCollisionOwner; } // Should we explode ? var timeout = time.DurationSinceTick(internalState.startTick) > settings.maxLifetime; if (timeout || hitCollisionOwner != Entity.Null) { internalState.active = 0; internalState.explodeTick = time.tick; interpolatedState.exploded = 1; if (settings.splashDamage.radius > 0) { var collisionMask = ~(1 << internalState.teamId); SplashDamageRequest.Create(PostUpdateCommands, time.tick, internalState.owner, internalState.position, collisionMask, settings.splashDamage); } } interpolatedState.position = internalState.position; DebugDraw.Sphere(interpolatedState.position, settings.collisionRadius, Color.red); EntityManager.SetComponentData(entity, internalState); EntityManager.SetComponentData(entity, interpolatedState); } Profiler.EndSample(); }
protected override void OnUpdate() { var entityArray = ProjectileGroup.GetEntityArray(); var projectileDataArray = ProjectileGroup.GetComponentDataArray <ProjectileData>(); var queryReciever = World.GetExistingManager <RaySphereQueryReciever>(); for (var i = 0; i < projectileDataArray.Length; i++) { var projectileData = projectileDataArray[i]; if (projectileData.impactTick > 0) { continue; } RaySphereQueryReciever.Query query; RaySphereQueryReciever.Result result; queryReciever.GetResult(projectileData.rayQueryId, out query, out result); var projectileVec = projectileData.endPos - projectileData.startPos; var projectileDir = Vector3.Normalize(projectileVec); var newPosition = (Vector3)projectileData.position + projectileDir * query.distance; var impact = result.hit == 1; if (impact) { projectileData.impacted = 1; projectileData.impactPos = result.hitPoint; projectileData.impactNormal = result.hitNormal; projectileData.impactTick = m_world.worldTime.tick; var damageInstigator = projectileData.projectileOwner; // GameDebug.Assert(damageInstigator == Entity.Null || !EntityManager.Exists(damageInstigator) || EntityManager.HasComponent<Character>(damageInstigator),"Damage instigator is not a character"); var collisionHit = result.hitCollisionOwner != Entity.Null; if (collisionHit) { if (damageInstigator != Entity.Null) { if (EntityManager.HasComponent <HitCollisionOwner>(result.hitCollisionOwner)) { var hitCollisionOwner = EntityManager.GetComponentObject <HitCollisionOwner>(result.hitCollisionOwner); hitCollisionOwner.damageEvents.Add(new DamageEvent(damageInstigator, projectileData.settings.impactDamage, projectileDir, projectileData.settings.impactImpulse)); } } } if (projectileData.settings.splashDamage.radius > 0) { if (damageInstigator != Entity.Null) { var collisionMask = ~(1 << projectileData.teamId); SplashDamageRequest.Create(PostUpdateCommands, query.hitCollisionTestTick, damageInstigator, result.hitPoint, collisionMask, projectileData.settings.splashDamage); } } newPosition = result.hitPoint; } if (ProjectileModuleServer.drawDebug.IntValue == 1) { var color = impact ? Color.red : Color.green; Debug.DrawLine(projectileData.position, newPosition, color, 2); DebugDraw.Sphere(newPosition, 0.1f, color, impact ? 2 : 0); } projectileData.position = newPosition; PostUpdateCommands.SetComponent(entityArray[i], projectileData); } }
protected override void OnUpdate() { var entityArray = ProjectileGroup.GetEntityArray(); var projectileDataArray = ProjectileGroup.GetComponentDataArray <ProjectileData>(); var queryReciever = World.GetExistingManager <RaySphereQueryReciever>(); for (var i = 0; i < projectileDataArray.Length; i++) { var projectileData = projectileDataArray[i]; if (projectileData.impactTick > 0) { continue; } RaySphereQueryReciever.Query query; RaySphereQueryReciever.QueryResult queryResult; queryReciever.GetResult(projectileData.rayQueryId, out query, out queryResult); var projectileVec = projectileData.endPos - projectileData.startPos; var projectileDir = Vector3.Normalize(projectileVec); var newPosition = (Vector3)projectileData.position + projectileDir * query.distance; var impact = queryResult.hit == 1; if (impact) { projectileData.impacted = 1; projectileData.impactPos = queryResult.hitPoint; projectileData.impactNormal = queryResult.hitNormal; projectileData.impactTick = m_world.worldTime.tick; // Owner can despawn while projectile is in flight, so we need to make sure we dont send non existing instigator var damageInstigator = EntityManager.Exists(projectileData.projectileOwner) ? projectileData.projectileOwner : Entity.Null; var collisionHit = queryResult.hitCollisionOwner != Entity.Null; if (collisionHit) { if (damageInstigator != Entity.Null) { if (EntityManager.HasComponent <DamageEvent>(queryResult.hitCollisionOwner)) { var damageEventBuffer = EntityManager.GetBuffer <DamageEvent>(queryResult.hitCollisionOwner); DamageEvent.AddEvent(damageEventBuffer, damageInstigator, projectileData.settings.impactDamage, projectileDir, projectileData.settings.impactImpulse); } } } if (projectileData.settings.splashDamage.radius > 0) { if (damageInstigator != Entity.Null) { var collisionMask = ~(1 << projectileData.teamId); SplashDamageRequest.Create(PostUpdateCommands, query.hitCollisionTestTick, damageInstigator, queryResult.hitPoint, collisionMask, projectileData.settings.splashDamage); } } newPosition = queryResult.hitPoint; } if (ProjectileModuleServer.drawDebug.IntValue == 1) { var color = impact ? Color.red : Color.green; Debug.DrawLine(projectileData.position, newPosition, color, 2); DebugDraw.Sphere(newPosition, 0.1f, color, impact ? 2 : 0); } projectileData.position = newPosition; PostUpdateCommands.SetComponent(entityArray[i], projectileData); } }
protected override void OnUpdate() { Profiler.BeginSample("FinalizeGrenadeMovement"); var time = m_world.worldTime; var queryReciever = World.GetExistingManager <RaySphereQueryReciever>(); var grenadeArray = Group.GetComponentArray <Grenade>(); var grenadePresentArray = Group.GetComponentArray <GrenadePresentation>(); for (var i = 0; i < grenadeArray.Length; i++) { var grenade = grenadeArray[i]; if (!grenade.active) { // Keep grenades around for a short duration so shortlived grenades gets a chance to get replicated // and explode effect played if (m_world.worldTime.DurationSinceTick(grenade.explodeTick) > 1.0f) { m_world.RequestDespawn(grenade.gameObject, PostUpdateCommands); } continue; } var presentation = grenadePresentArray[i]; var hitCollisionOwner = Entity.Null; if (grenade.rayQueryId != -1) { RaySphereQueryReciever.Query query; RaySphereQueryReciever.Result result; queryReciever.GetResult(grenade.rayQueryId, out query, out result); grenade.rayQueryId = -1; // If grenade hit something that was no hitCollision it is environment and grenade should bounce if (result.hit == 1 && result.hitCollisionOwner == Entity.Null) { float3 moveDir = grenade.velocity.normalized; var moveVel = grenade.velocity.magnitude; grenade.position = result.hitPoint + result.hitNormal * grenade.collisionRadius; moveDir = Vector3.Reflect(moveDir, result.hitNormal); grenade.velocity = moveDir * moveVel * grenade.bounciness; if (grenade.velocity.magnitude > 1.0f) { presentation.state.bouncetick = m_world.worldTime.tick; } } if (result.hitCollisionOwner != Entity.Null) { grenade.position = result.hitPoint; } hitCollisionOwner = result.hitCollisionOwner; } // Should we explode ? var timeout = time.DurationSinceTick(grenade.startTick) > grenade.maxLifetime; if (timeout || hitCollisionOwner != Entity.Null) { grenade.active = false; grenade.explodeTick = time.tick; presentation.state.exploded = true; if (grenade.splashDamage.radius > 0) { var collisionMask = ~(1 << grenade.teamId); SplashDamageRequest.Create(PostUpdateCommands, time.tick, grenade.owner, grenade.position, collisionMask, grenade.splashDamage); } } // Update presentation presentation.state.position = grenade.position; } Profiler.EndSample(); }