private float[] GetCollisionPointFromCamera(NiNode cameraNode, TESObjectCELL cell, NiAVObject[] ignore) { float[] source = new float[3]; float[] target = new float[3]; var nodePos = cameraNode.WorldTransform.Position; source[0] = nodePos.X; source[1] = nodePos.Y; source[2] = nodePos.Z; cameraNode.WorldTransform.Translate(this.AimVectorPointDoubled, this.TargetTeleportPoint); target[0] = this.TargetTeleportPoint.X; target[1] = this.TargetTeleportPoint.Y; target[2] = this.TargetTeleportPoint.Z; var ray = this.DoRayCast(cell, source, target); var best = this.GetBestResult(source, ray, ignore, false); if (best == null) { return(target); } return(best.Position); }
private List <RayCastResult> DoRayCast(TESObjectCELL cell, float[] source, float[] target) { return(cell.RayCast(new RayCastParameters() { Begin = source, End = target })); }
private float QuickRay(float[] source, float[] target, NiAVObject[] ignore, TESObjectCELL cell) { var ray = this.DoRayCast(cell, source, target); var best = this.GetBestResult(source, ray, ignore, false); if (best == null) { return(-1.0f); } return(Distance(best.Position, source)); }
internal bool CanPlaceGrass(TESObjectCELL cell, TESObjectLAND land, float x, float y, float z) { if (cell == null) { return(true); } // Currently not dealing with this. if (cell.IsInterior || !cell.IsAttached) { return(true); } var rp = new RayCastParameters(); rp.Begin = new float[] { x, y, z + this.RayHeight }; rp.End = new float[] { x, y, z - this.RayDepth }; rp.Cell = cell; var rs = TESObjectCELL.RayCast(rp); foreach (var r in rs) { if (r.Fraction >= 1.0f || r.HavokObject == IntPtr.Zero) { continue; } uint flags = Memory.ReadUInt32(r.HavokObject + 0x2C) & 0x7F; ulong mask = (ulong)1 << (int)flags; if ((this.RaycastMask & mask) == 0) { continue; } if (this.Ignore != null && this.IsIgnoredObject(r)) { continue; } return(false); } return(true); }
private bool CheckRay(float[] source, float[] target, NiAVObject[] ignore, TESObjectCELL cell) { var ray = this.DoRayCast(cell, source, target); return(this.GetBestResult(source, ray, ignore, true) == null); }
private bool CalculatePositionFromCollision(float[] colPos, float[] colNormal, ref float[] teleportPos, ref float[] markerPos, NiAVObject[] ignore, TESObjectCELL cell, bool allowWallClimb) { // Calculate the position. var ntype = CalculateNormalType(colNormal); float tpush = 1.0f; bool canMoveDown = true; switch (ntype) { case NormalTypes.Up: canMoveDown = false; break; case NormalTypes.Down: //tpush = this.Plugin.Settings.PlayerRadius * 2.0f; break; case NormalTypes.Sideways: { tpush = this.Plugin.Settings.PlayerRadius; var pushed = PushAway(colPos, colNormal, this.Plugin.Settings.PlayerRadius * 2.0f + 2.0f); var pushedSource = PushAway(colPos, colNormal, 0.5f); if (!this.CheckRay(pushedSource, pushed, ignore, cell)) { return(false); } } break; case NormalTypes.Diagonal: /*if (colNormal[2] >= 0.0f) * tpush = this.Plugin.Settings.PlayerRadius * 0.66f; * else * tpush = this.Plugin.Settings.PlayerRadius * 1.33f;*/ break; } var tpos = PushAway(colPos, colNormal, tpush); // Try to climb a wall. bool skipSnap = false; bool skipHeight = false; if (allowWallClimb) { float wallClimb = this.Plugin.Settings.MaxWallClimbHeight; if (ntype == NormalTypes.Sideways && wallClimb > 0.0f /* && tpos[2] > (this.SourceMovePoint.X - 40.0f)*/) { var srcPos = tpos.ToArray(); var dstPos = srcPos.ToArray(); dstPos[2] += wallClimb; float dist = QuickRay(srcPos, dstPos, ignore, cell); float pheight = this.Plugin.Settings.PlayerRadius * 3.0f; if (dist < 0.0f || dist > pheight) { var colNormalRev = colNormal.ToArray(); for (int i = 0; i < colNormalRev.Length; i++) { colNormalRev[i] *= -1.0f; } if (dist < 0.0f) { srcPos[2] += wallClimb; } else { srcPos[2] += (dist - 5.0f); } float width = this.Plugin.Settings.WallClimbWidth; dstPos = PushAway(srcPos, colNormalRev, width); if (CheckRay(srcPos, dstPos, ignore, cell)) { srcPos = PushAway(srcPos, colNormalRev, width - this.Plugin.Settings.PlayerRadius); dstPos = srcPos.ToArray(); dstPos[2] -= wallClimb; float dist2 = QuickRay(srcPos, dstPos, ignore, cell); if (dist2 >= 0.0f && (srcPos[2] - dist2) > (tpos[2] - 40.0f)) { srcPos[2] -= (dist2 - 1.0f); // Make sure there's enough height for player to exist there. bool climb = true; { dstPos = srcPos.ToArray(); dstPos[2] += pheight; float dist3 = QuickRay(srcPos, dstPos, ignore, cell); if (dist3 >= 0.0f) { float moveDown = pheight - dist3; dstPos[2] = srcPos[2] - moveDown; if (!CheckRay(srcPos, dstPos, ignore, cell)) { climb = false; } else { srcPos[2] -= moveDown; } } } if (climb) { tpos = srcPos.ToArray(); skipSnap = true; skipHeight = true; } } } } } } // Make sure there's enough height for player to exist there. if (!skipHeight) { float pheight = this.Plugin.Settings.PlayerRadius * 3.0f; var srcPos = tpos.ToArray(); var dstPos = srcPos.ToArray(); dstPos[2] += pheight; float dist = QuickRay(srcPos, dstPos, ignore, cell); if (dist >= 0.0f) { if (!canMoveDown) { return(false); } float moveDown = pheight - dist; dstPos[2] = srcPos[2] - moveDown; if (!CheckRay(srcPos, dstPos, ignore, cell)) { return(false); } tpos[2] -= moveDown; } } // Try to snap to ground. float maxSnap = this.Plugin.Settings.MaxSnapToGroundDistance; if (!skipSnap && maxSnap > 0.0f && canMoveDown) { var srcPos = tpos.ToArray(); var dstPos = srcPos.ToArray(); dstPos[2] -= maxSnap; float dist = QuickRay(srcPos, dstPos, ignore, cell); if (dist >= 0.0f) { float reduce = dist - 1.0f; tpos[2] -= reduce; } } teleportPos = tpos; float[] mpos = tpos.ToArray(); mpos[2] += this.Plugin.Settings.PlayerRadius; markerPos = mpos; return(true); }
private void UpdateAiming(float diff, float totalTime, PlayerCharacter plr, TESObjectCELL cell) { if (!this.IsMarkerInWorld) { return; } var camera = PlayerCamera.Instance; if (camera == null) { return; } var cameraNode = camera.Node; if (cameraNode == null) { return; } NiNode[] playerNode = new NiNode[2] { plr.GetSkeletonNode(false), plr.GetSkeletonNode(true) }; for (int i = 0; i < playerNode.Length; i++) { if (playerNode[i] == null) { return; } } { var plrPos = plr.Position; this.SourceMovePoint.X = plrPos.X; this.SourceMovePoint.Y = plrPos.Y; this.SourceMovePoint.Z = plrPos.Z; } if (camera.State != null && camera.State.Id == TESCameraStates.FirstPerson) { var plrPos = cameraNode.WorldTransform.Position; this.SourceTeleportPoint.X = plrPos.X; this.SourceTeleportPoint.Y = plrPos.Y; this.SourceTeleportPoint.Z = plrPos.Z; cameraNode.WorldTransform.Translate(this.AimVectorPoint, this.TargetTeleportPoint); } else { var headNode = playerNode[0].LookupNodeByName("NPC Head [Head]"); if (headNode != null) { var plrPos = headNode.WorldTransform.Position; this.SourceTeleportPoint.X = plrPos.X; this.SourceTeleportPoint.Y = plrPos.Y; this.SourceTeleportPoint.Z = plrPos.Z; } else { var plrPos = plr.Position; this.SourceTeleportPoint.X = plrPos.X; this.SourceTeleportPoint.Y = plrPos.Y; this.SourceTeleportPoint.Z = plrPos.Z + this.Plugin.Settings.PlayerRadius; } var cameraCol = this.GetCollisionPointFromCamera(cameraNode, cell, playerNode); byte[] data = Memory.ReadBytes(cameraNode.WorldTransform.Address, MemoryObject.SizeOf <NiTransform>()); Memory.WriteBytes(this.ThirdPersonTempTransform.Address, data); this.TargetTeleportPoint.X = cameraCol[0]; this.TargetTeleportPoint.Y = cameraCol[1]; this.TargetTeleportPoint.Z = cameraCol[2]; this.ThirdPersonTempTransform.LookAt(this.TargetTeleportPoint); this.ThirdPersonTempTransform.Translate(this.AimVectorPoint, this.TargetTeleportPoint); } bool allowWallClimb = true; { var source = new[] { this.SourceTeleportPoint.X, this.SourceTeleportPoint.Y, this.SourceTeleportPoint.Z }; var target = new[] { this.TargetTeleportPoint.X, this.TargetTeleportPoint.Y, this.TargetTeleportPoint.Z }; var ray = this.DoRayCast(cell, source, target); float[] collisionPosition = null; float[] collisionNormal = null; var best = this.GetBestResult(source, ray, playerNode, false); if (best == null) { collisionPosition = target; float[] revNormal = new float[3]; float rx = target[0] - source[0]; float ry = target[1] - source[1]; float rz = target[2] - source[2]; float rd = (float)Math.Sqrt(rx * rx + ry * ry + rz * rz); if (rd > 0.0f) { rx /= rd; ry /= rd; rz /= rd; } revNormal[0] = rx * -1.0f; revNormal[1] = ry * -1.0f; revNormal[2] = rz * -1.0f; collisionNormal = revNormal; allowWallClimb = false; } else { collisionPosition = best.Position; collisionNormal = best.Normal; float nlen = Length(collisionNormal); if (nlen > 0.0f) { collisionNormal[0] /= nlen; collisionNormal[1] /= nlen; collisionNormal[2] /= nlen; } if (!this.Plugin.Settings.AllowLedgeClimbNPC) { var hkObj = best.HavokObject; if (hkObj != IntPtr.Zero) { var layer = (CollisionLayers)(Memory.ReadUInt32(hkObj + 0x2C) & 0x7F); switch (layer) { case CollisionLayers.LivingAndDeadActors: case CollisionLayers.BipedNoCC: case CollisionLayers.CharController: allowWallClimb = false; break; } } } } float fullDist = Distance(collisionPosition, source); float ratioInc = 1.0f; if (fullDist > 0.0f) { ratioInc = Math.Max(10.0f, this.Plugin.Settings.TeleportIncrementalCheck) / fullDist; } ratioInc = Math.Max(0.02f, ratioInc); float ratioNow = 1.0f; float[] checkPos = new float[3]; bool ok = false; while (ratioNow > 0.0f) { for (int i = 0; i < 3; i++) { checkPos[i] = (collisionPosition[i] - source[i]) * ratioNow + source[i]; } float[] tpPos = null; float[] mrPos = null; if (this.CalculatePositionFromCollision(checkPos, collisionNormal, ref tpPos, ref mrPos, playerNode, cell, allowWallClimb)) { this.TargetTeleportPoint.X = tpPos[0]; this.TargetTeleportPoint.Y = tpPos[1]; this.TargetTeleportPoint.Z = tpPos[2]; this.TargetMarkerPoint.X = mrPos[0]; this.TargetMarkerPoint.Y = mrPos[1]; this.TargetMarkerPoint.Z = mrPos[2]; ok = true; break; } ratioNow -= ratioInc; } if (!ok) { this.TargetTeleportPoint.X = this.SourceMovePoint.X; this.TargetTeleportPoint.Y = this.SourceMovePoint.Y; this.TargetTeleportPoint.Z = this.SourceMovePoint.Z; this.TargetMarkerPoint.X = this.SourceMovePoint.X; this.TargetMarkerPoint.Y = this.SourceMovePoint.Y; this.TargetMarkerPoint.Z = this.SourceMovePoint.Z + this.Plugin.Settings.PlayerRadius; } } var mpos = this.Marker.LocalTransform.Position; mpos.X = this.TargetMarkerPoint.X; mpos.Y = this.TargetMarkerPoint.Y; mpos.Z = this.TargetMarkerPoint.Z; this.Marker.Update(totalTime); }
internal void Update(float diff, float totalTime) { NetScriptFramework.SkyrimSE.Main main = NetScriptFramework.SkyrimSE.Main.Instance; PlayerCharacter plr = null; TESObjectCELL cell = null; SpellItem spell = this.Plugin.Settings.SpellForm; if (main == null || main.IsGamePaused || (plr = PlayerCharacter.Instance) == null || (cell = plr.ParentCell) == null) { this.Reset(); return; } this.UpdateHotkey(); if (this.CurrentDistortionTime < DistortionDurationAfter) { this.CurrentDistortionTime += diff; } if (this.Plugin.Settings.AutoLearnSpell && spell != null && !plr.HasSpell(spell)) { plr.AddSpell(spell, true); } switch (this.State) { case InternalStates.None: { var castState = this.GetCurrentCastingState(plr, spell); if (castState == MagicCastingStates.Charged) { if (!this.CheckCosts(plr, true, false)) { if (spell != null) { this.InterruptCast(plr, spell); } if (this.HotkeyState != 0) { this.HotkeyState = -1; } return; } this.State = InternalStates.Aiming; this.AddMarkerToWorld(); this.UpdateAiming(diff, totalTime, plr, cell); } } break; case InternalStates.Aiming: { var castState = this.GetCurrentCastingState(plr, spell); if (castState != MagicCastingStates.Charged && castState != MagicCastingStates.Released) { this.State = InternalStates.None; this.RemoveMarkerFromWorld(); } else { if (!this.CheckCosts(plr, true, false)) { this.State = InternalStates.None; this.RemoveMarkerFromWorld(); if (spell != null) { this.InterruptCast(plr, spell); } if (this.HotkeyState != 0) { this.HotkeyState = -1; } return; } this.UpdateAiming(diff, totalTime, plr, cell); } } break; case InternalStates.Fire: { this.RemoveMarkerFromWorld(); if (!this.CheckCosts(plr, true, true)) { this.State = InternalStates.None; if (this.HotkeyState != 0) { this.HotkeyState = -1; } return; } this.ApplyIMod(plr); this.PlaySound(plr); float distance = this.TargetTeleportPoint.GetDistance(this.SourceTeleportPoint); float speed = this.Plugin.Settings.TeleportSpeed; this.CurrentDistortionTime = 0.0f; this.CurrentTeleportTime = 0.0f; float maxDistance = Math.Max(100.0f, this.Plugin.Settings.MaxDistance); this.CurrentMaxDistort = MaxTargetDistort * (distance / maxDistance); if (speed > 0.0f) { if (speed < 1.0f) { speed = 1.0f; } float time = distance / speed; if (time > 0.0f) { this.TimedValues[(int)TimedValueTypes.TeleportDoneRatio] = new List <TimedValue>() { new TimedValue(time, 0, 1) }; this.CurrentDistortionTime = -time; this.CurrentTeleportTime = maxDistance / speed; // time; } } this.State = InternalStates.Teleporting; } break; case InternalStates.Teleporting: { var tm = this.TimedValues[(int)TimedValueTypes.TeleportDoneRatio]; float ratio = 1.0f; if (tm != null && tm.Count != 0) { tm[0].Update(diff); ratio = tm[0].CurrentValue; if (tm[0].IsFinished) { this.TimedValues[(int)TimedValueTypes.TeleportDoneRatio] = null; } } this.CurrentTeleportPoint.X = (this.TargetTeleportPoint.X - this.SourceTeleportPoint.X) * ratio + this.SourceTeleportPoint.X; this.CurrentTeleportPoint.Y = (this.TargetTeleportPoint.Y - this.SourceTeleportPoint.Y) * ratio + this.SourceTeleportPoint.Y; this.CurrentTeleportPoint.Z = (this.TargetTeleportPoint.Z - this.SourceTeleportPoint.Z) * ratio + this.SourceTeleportPoint.Z; Memory.InvokeCdecl(this.fn_Actor_SetPosition, plr.Address, this.CurrentTeleportPoint.Address, 1); if (ratio >= 1.0f) { this.State = InternalStates.None; } } break; } }
internal static bool Apply(CameraUpdate update, NiTransform transform, NiPoint3 result) { init(); if (update == null || transform == null || result == null) { return(false); } if (update.Values.CollisionEnabled.CurrentValue < 0.5) { return(false); } var actor = update.Target.Actor; if (actor == null) { return(false); } var cell = actor.ParentCell; if (cell == null) { return(false); } float safety = (float)(update.Values.NearClip.CurrentValue + 1.0); if (safety < 1.0f) { safety = 1.0f; } float safety2 = Math.Max(0.0f, Settings.Instance.CameraCollisionSafety); var tpos = transform.Position; TempPoint1.CopyFrom(actor.Position); TempPoint1.Z = tpos.Z; if (safety2 > 0.0f) { TempSafety.Y = -safety2 * 0.5f; TempTransform.CopyFrom(transform); TempTransform.Position.CopyFrom(TempPoint1); TempTransform.Translate(TempSafety, TempPoint1); } TempNormal.X = tpos.X - TempPoint1.X; TempNormal.Y = tpos.Y - TempPoint1.Y; TempNormal.Z = tpos.Z - TempPoint1.Z; float len = TempNormal.Length; if (len <= 0.0f) { return(false); } TempNormal.Normalize(TempNormal); TempNormal.Multiply(len + safety + safety2, TempNormal); TempPoint2.X = TempPoint1.X + TempNormal.X; TempPoint2.Y = TempPoint1.Y + TempNormal.Y; TempPoint2.Z = TempPoint1.Z + TempNormal.Z; var ls = TESObjectCELL.RayCast(new RayCastParameters() { Cell = cell, Begin = new float[] { TempPoint1.X, TempPoint1.Y, TempPoint1.Z }, End = new float[] { TempPoint2.X, TempPoint2.Y, TempPoint2.Z } }); if (ls == null || ls.Count == 0) { return(false); } RayCastResult best = null; float bestDist = 0.0f; List <NiAVObject> ignore = new List <NiAVObject>(3); { var sk = actor.GetSkeletonNode(true); if (sk != null) { ignore.Add(sk); } } { var sk = actor.GetSkeletonNode(false); if (sk != null) { ignore.Add(sk); } } if (update.CachedMounted) { var mount = actor.GetMount(); if (mount != null) { var sk = mount.GetSkeletonNode(false); if (sk != null) { ignore.Add(sk); } } } foreach (var r in ls) { if (!IsValid(r, ignore)) { continue; } float dist = r.Fraction; if (best == null) { best = r; bestDist = dist; } else if (dist < bestDist) { best = r; bestDist = dist; } } if (best == null) { return(false); } bestDist *= len + safety + safety2; bestDist -= safety + safety2; bestDist /= len + safety + safety2; // Negative is ok! result.X = (TempPoint2.X - TempPoint1.X) * bestDist + TempPoint1.X; result.Y = (TempPoint2.Y - TempPoint1.Y) * bestDist + TempPoint1.Y; result.Z = (TempPoint2.Z - TempPoint1.Z) * bestDist + TempPoint1.Z; return(true); }
private TESEffectShader ShouldGlow(TESObjectREFR obj, NiPoint3 pos) { if (obj == null) { return(null); } var form = obj.BaseForm; TESObjectBOOK book = null; if (form == null || (book = form as TESObjectBOOK) == null || book.IsRead) { return(null); } TESObjectCELL cell = null; if (obj.Node == null || (cell = obj.ParentCell) == null) { return(null); } var tes = TES.Instance; if (tes == null) { return(null); } if (!Memory.InvokeCdecl(_is_cell_loaded, tes.Cast <TES>(), cell.Cast <TESObjectCELL>(), 0).ToBool()) { return(null); } var tracker = Tools.BookTracker.Instance; var type = tracker.GetBookType(book); if (!type.HasValue) { #if DEBUG_MSG NetScriptFramework.Main.WriteDebugMessage("Warning: " + book.ToString() + " does not have a type in tracker!"); #endif return(null); } int mask = 1 << (int)type.Value; if ((this._care_mask & mask) == 0) { return(null); } if (obj.Position.GetDistance(pos) > 8000.0f) { return(null); } var ls = this._shaders[(int)type.Value]; if (ls.Count == 0) { return(null); } if (ls.Count == 1) { return(ls[0]); } return(ls[rnd.Next(0, ls.Count)]); }