/// <summary> /// Prefetches planetary voxel physics along a ray /// </summary> /// <param name="ray">ray to prefetch</param> /// <param name="force">force a new prefetch task</param> public static void PrefetchRay(ref LineD ray, bool force = false) { // Force is second so we still update the cache for forced if (!_raycastPrefetchCache.IsItemPresent(ray.GetHash(), (int)MyAPIGateway.Session.ElapsedPlayTime.TotalSeconds) || force) { var voxelHits = _voxelCache.Get(); try { MyGamePruningStructure.GetVoxelMapsOverlappingRay(ref ray, voxelHits); foreach (var e in voxelHits) { var planet = (e.Element?.RootVoxel ?? e.Element) as MyPlanet; // This needs to be done for all voxel maps. To bad we can't. planet?.PrefetchShapeOnRay(ref ray); } } finally { voxelHits.Clear(); if (_voxelCache.Count <= 1) { _voxelCache.Return(voxelHits); } } } }
public void Update() { if (_targetHit) { Kill(); return; } // Update velocity due to gravity Vector3D totalGravity = MyParticlesManager.CalculateGravityInPoint(_position); // Does this get affected by artificial grav? If so... cooooool Vector3D naturalGravity = RailgunCore.GetNaturalGravityAtPoint(_position); Vector3D artificialGravity = totalGravity - naturalGravity; _velocity += (naturalGravity * RailgunCore.MyConfig.NaturalGravityMultiplier + artificialGravity * RailgunCore.MyConfig.ArtificialGravityMultiplier) * _tick; // Update direction if velocity has changed if (!_velocity.Equals(_lastVelocity, 1e-3)) { _direction = Vector3D.Normalize(_velocity); } _lastVelocity = _velocity; // Update position _position += _velocity * _tick; var _toOrigin = _position - _origin; //draw tracer line if (_drawTrail && _currentTracerFadeTicks < _maxTracerFadeTicks) { _lineColor *= _trailColorDecayRatio; _currentTracerFadeTicks++; } if (_toOrigin.LengthSquared() > _maxTrajectory * _maxTrajectory) { MyLog.Default.WriteLine(">> Max range hit"); _targetHit = true; _hitPosition = _position; Kill(); if (_shouldExplode) { CreateExplosion(_position, _direction, _explosionRadius, _explosionDamage); } return; } _checkIntersectionIndex = ++_checkIntersectionIndex % 5; if (_checkIntersectionIndex != 0 && _positionChecked) { return; } // Add current position to trajectory list _trajectoryPoints.Add(_position); var to = _position; //_position + 5.0 * _velocity * _tick; var from = _lastPositionChecked; _positionChecked = true; _lastPositionChecked = _position; IHitInfo hitInfo; bool hit = false; if (Vector3D.DistanceSquared(to, from) > 50 * 50) { // Use faster raycast if ray is long enough hit = MyAPIGateway.Physics.CastLongRay(from, to, out hitInfo, true); } else { hit = MyAPIGateway.Physics.CastRay(from, to, out hitInfo, 0); } if (hit) { MyLog.Default.WriteLine(">> Raycast hit"); _hitPosition = hitInfo.Position + -0.5 * _direction; if ((_hitPosition - _origin).LengthSquared() > _minimumArmDistance * _minimumArmDistance) //only explode if beyond arm distance { if (_shouldExplode) { CreateExplosion(_hitPosition, _direction, _explosionRadius, _explosionDamage); } if (_shouldPenetrate) { GetObjectsToPenetrate(_hitPosition, _hitPosition + _direction * _penetrationRange); } _targetHit = true; Kill(); } else { _targetHit = true; _hitPosition = _position; Kill(); } return; } // implied else var line = new LineD(from, to); MyGamePruningStructure.GetVoxelMapsOverlappingRay(ref line, _voxelOverlap); foreach (var result in _voxelOverlap) { MatrixD matrix; MatrixD matrixInv; Vector3 sizeInMetersHalf; MyPlanet planet = result.Element as MyPlanet; IMyVoxelMap voxelMap = result.Element as IMyVoxelMap; if (planet == null && voxelMap == null) { continue; } if (planet != null) { matrix = planet.WorldMatrix; matrixInv = planet.PositionComp.WorldMatrixInvScaled; sizeInMetersHalf = planet.SizeInMetresHalf; } else { matrix = voxelMap.WorldMatrix; matrixInv = voxelMap.PositionComp.WorldMatrixInvScaled; sizeInMetersHalf = new Vector3(voxelMap.Storage.Size) * 0.5f; } Vector3 localTo; Vector3 localFrom; MyVoxelCoordSystems.WorldPositionToLocalPosition(from, matrix, matrixInv, sizeInMetersHalf, out localFrom); MyVoxelCoordSystems.WorldPositionToLocalPosition(to, matrix, matrixInv, sizeInMetersHalf, out localTo); var localLine = new LineD(localFrom, localTo); if (planet != null && ((IMyStorage)(planet.Storage)).Intersect(ref localLine)) { MyLog.Default.WriteLine(">> Railgun projectile hit planet"); _hitPosition = _position; _targetHit = true; Kill(); return; } // This is very broken //if (voxelMap != null && ((IMyStorage)(voxelMap.Storage)).Intersect(ref localLine)) //{ // MyLog.Default.WriteLine(">> Railgun projectile hit voxel"); // _hitPosition = _position; // _targetHit = true; // Kill(); // return; //} } }