Skip to content

Improve the behavior of death planes #257

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 33 commits into from
Oct 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
99aa6e7
Add ObjectScript for death planes
Frozenreflex Jul 19, 2021
28ef53a
Fix size of death barrier objects
Frozenreflex Jul 20, 2021
4e451f8
Switch death plane to use SmashAsync
Frozenreflex Jul 20, 2021
fc22164
Merge branch 'dev' of https://github.com/UchuServer/Uchu into enhance…
Frozenreflex Aug 1, 2021
78bd598
Add initial water death plane script
Frozenreflex Aug 3, 2021
b63934d
Switch smasher for death planes to death plane
Frozenreflex Aug 3, 2021
172a31a
Remove comment in DeathPlane
Frozenreflex Aug 3, 2021
4142353
Merge branch 'dev' of github.com:UchuServer/Uchu into enhancement/dea…
TheNexusAvenger Aug 31, 2021
62d1b41
Merge and improve object script loading for LuaScriptComponent and cu…
TheNexusAvenger Aug 31, 2021
58a9671
Add player fall death script.
TheNexusAvenger Aug 31, 2021
831709b
Move death plane scripts.
TheNexusAvenger Aug 31, 2021
2970ac0
Add death (teleport) plane for properties.
TheNexusAvenger Aug 31, 2021
c3a4370
Correct player sphere physics to be at center instead of bottom. (Fix…
TheNexusAvenger Aug 31, 2021
d5c43d5
Disable check for hasCustomClientScript
Frozenreflex Sep 1, 2021
bed88fe
Disable fallback, replace FV death plane objectscript with nativescript
Frozenreflex Sep 2, 2021
3bef1b2
Reformatting
Frozenreflex Sep 2, 2021
4366f2d
Add CapsuleBody (for cylinders)
enteryournamehere Sep 11, 2021
b8dc90e
Capsule-sphere collision test
enteryournamehere Sep 11, 2021
a85a3e4
Clean up some code
enteryournamehere Sep 11, 2021
bd96217
Replace client script names with server ones
enteryournamehere Sep 11, 2021
73c1174
Run native DeathPlane script in multiple worlds
Frozenreflex Sep 13, 2021
234c322
Move PrimitiveModel cube origins from center to bottom
Frozenreflex Sep 17, 2021
5a43b05
Fix scripts linked to client script names
enteryournamehere Sep 17, 2021
9478fe9
Merge branch 'enhancement/death-planes' of github.com:UchuServer/Uchu…
enteryournamehere Sep 17, 2021
28ca057
Merge branch 'dev' of github.com:UchuServer/Uchu into enhancement/dea…
enteryournamehere Sep 17, 2021
fd0aeaf
Correctly split PATH env variable on *nix systems
enteryournamehere Sep 18, 2021
a1ac3fe
Apply binoculars script to all binoculars
enteryournamehere Sep 18, 2021
254d67b
Always give all rewards for achievements
enteryournamehere Sep 19, 2021
7de8b6d
Fix for ghost players after dying to death plane
Frozenreflex Sep 20, 2021
12226ae
Merge branch 'enhancement/death-planes' of https://github.com/UchuSer…
Frozenreflex Sep 20, 2021
66449bb
Fix Instantiate when item is not in Objects table
enteryournamehere Sep 24, 2021
6cd4f5d
Fix not dying after falling near Tortoise Terrace
Frozenreflex Sep 25, 2021
fb70e80
Add LOT-specific scripts.
TheNexusAvenger Sep 29, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Uchu.Master/ServerInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public void Start(string location, string dotnet)
var useDotNet = !string.IsNullOrWhiteSpace(dotnet);
if (useDotNet && dotnet?.ToLower() == "dotnet" && !File.Exists(dotnet))
{
var pathDirectories = (Environment.GetEnvironmentVariable("PATH") ?? "").Split(";");
var pathDirectories = (Environment.GetEnvironmentVariable("PATH") ?? "").Split(new[] { ';', ':' });
var dotNetInPath = pathDirectories.Any(pathDirectory => File.Exists(Path.Combine(pathDirectory, dotnet)));
if (!dotNetInPath)
{
Expand Down
34 changes: 34 additions & 0 deletions Uchu.Physics.Test/CollisionTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,5 +129,39 @@ public void BoxBoxCollision()
Assert.IsFalse(PhysicsSimulation.BoxBoxCollision(smallBox5, box7));
Assert.IsTrue(PhysicsSimulation.BoxBoxCollision(box9, box8Rotated));
}

[Test]
public void CapsuleSphereCollision()
{
// r=1.5 at (0,8,0)
var sphere = SphereBody.Create(_simulation,
new Vector3(0, 8, 0),
1.5f);

// pointing straight up, should hit sphere
var capsule1 = CapsuleBody.Create(this._simulation,
new Vector3(0, 0, 0),
Quaternion.Identity,
1f,
6f);

// rotated 45deg, should miss sphere
var capsule2 = CapsuleBody.Create(this._simulation,
new Vector3(0, 0, 0),
Quaternion.CreateFromAxisAngle(Vector3.UnitX, (float) (0.125 * Math.Tau)),
1f,
6f);

// floating, rotated 90deg, should hit sphere
var capsule3 = CapsuleBody.Create(this._simulation,
new Vector3(8, 8, 0),
Quaternion.CreateFromAxisAngle(Vector3.UnitZ, (float) (0.25 * Math.Tau)),
1f,
6f);

Assert.IsTrue(PhysicsSimulation.CapsuleSphereCollision(capsule1, sphere));
Assert.IsFalse(PhysicsSimulation.CapsuleSphereCollision(capsule2, sphere));
Assert.IsTrue(PhysicsSimulation.CapsuleSphereCollision(capsule3, sphere));
}
}
}
51 changes: 51 additions & 0 deletions Uchu.Physics/Objects/CapsuleBody.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System.Numerics;

namespace Uchu.Physics
{
public class CapsuleBody : PhysicsObject
{
/// <summary>
/// Value used to determine the order in which objects are passed to the collision detection functions.
/// </summary>
public override int CollisionPrecedence { get; } = 2;

/// <summary>
/// Creates a capsule body.
/// </summary>
/// <param name="simulation">The simulation to use.</param>
public CapsuleBody(PhysicsSimulation simulation) : base(simulation)
{
}

/// <summary>
/// Creates a capsule body.
/// </summary>
/// <param name="simulation">The simulation to use.</param>
/// <param name="position">The position of the body.</param>
/// <param name="rotation">The rotation of the body.</param>
/// <param name="radius">The radius of the capsule.</param>
/// <param name="height">The height of the cylinder part of the capsule.</param>
/// <returns>The capsule body that was created.</returns>
public static CapsuleBody Create(PhysicsSimulation simulation, Vector3 position, Quaternion rotation,
float radius, float height)
{
var obj = new CapsuleBody(simulation);
obj.Position = position;
obj.Rotation = rotation;
obj.Radius = radius;
obj.Height = height;
simulation.Register(obj);
return obj;
}

/// <summary>
/// Radius of the capsule.
/// </summary>
public float Radius;

/// <summary>
/// Height of the cylinder part of the capsule.
/// </summary>
public float Height;
}
}
70 changes: 62 additions & 8 deletions Uchu.Physics/PhysicsSimulation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,20 @@ public static bool Collides(PhysicsObject firstObject, PhysicsObject secondObjec
}

// First precedence value >= second precedence value
// Cube = 1, sphere = 0

if (first is BoxBody box && second is SphereBody sphere)
return BoxSphereCollision(box, sphere);
if (first is SphereBody sphere1 && second is SphereBody sphere2)
return SphereSphereCollision(sphere1, sphere2);
if (first is BoxBody box1 && second is BoxBody box2)
return BoxBoxCollision(box1, box2);
// Capsule = 2, cube = 1, sphere = 0

if (first is BoxBody boxSphereFirst && second is SphereBody boxSphereSecond)
return BoxSphereCollision(boxSphereFirst, boxSphereSecond);
if (first is SphereBody sphereSphereFirst && second is SphereBody sphereSphereSecond)
return SphereSphereCollision(sphereSphereFirst, sphereSphereSecond);
if (first is BoxBody boxBoxFirst && second is BoxBody boxBoxSecond)
return BoxBoxCollision(boxBoxFirst, boxBoxSecond);
if (first is CapsuleBody capsuleSphereFirst && second is SphereBody capsuleSphereSecond)
return CapsuleSphereCollision(capsuleSphereFirst, capsuleSphereSecond);
if (first is CapsuleBody capsuleBoxFirst && second is BoxBody capsuleBoxSecond)
return CapsuleBoxCollision(capsuleBoxFirst, capsuleBoxSecond);
if (first is CapsuleBody capsuleCapsuleFirst && second is CapsuleBody capsuleCapsuleSecond)
return CapsuleCapsuleCollision(capsuleCapsuleFirst, capsuleCapsuleSecond);

throw new NotSupportedException();
}
Expand Down Expand Up @@ -144,6 +150,54 @@ public static bool SphereSphereCollision(SphereBody firstSphere, SphereBody seco
return distanceSquared < maxDistanceSquared;
}

/// <summary>
/// Determine whether a capsule and a sphere intersect.
/// </summary>
/// <param name="capsule">Capsule physics object</param>
/// <param name="sphere">Sphere physics object</param>
public static bool CapsuleSphereCollision(CapsuleBody capsule, SphereBody sphere)
{
// reference frame: capsule at (0, 0, 0), pointing in positive y direction
var sphereCoordsRelative = sphere.Position - capsule.Position;

// to transform coordinate system to have capsule be axis-aligned, we apply
// the reverse of the rotation to the sphere coordinates
var inverse = new Quaternion(capsule.Rotation.X, capsule.Rotation.Y, capsule.Rotation.Z, -capsule.Rotation.W);
var sphereCoordsTransformed = Vector3.Transform(sphereCoordsRelative, inverse);

// coordinates of the line in the centre of the cylinder part
const int capsuleMinY = 0;
var capsuleMaxY = capsule.Height;

const int closestPointToSphereX = 0;
var closestPointToSphereY = Math.Clamp(sphereCoordsTransformed.Y, capsuleMinY, capsuleMaxY);
const int closestPointToSphereZ = 0;

return Vector3.DistanceSquared(sphereCoordsTransformed,
new Vector3(closestPointToSphereX, closestPointToSphereY, closestPointToSphereZ))
< Math.Pow(capsule.Radius + sphere.Radius, 2);
}

/// <summary>
/// Determine whether two capsules intersect.
/// </summary>
/// <param name="firstCapsule">The first capsule</param>
/// <param name="secondCapsule">The second capsule</param>
public static bool CapsuleCapsuleCollision(CapsuleBody firstCapsule, CapsuleBody secondCapsule)
{
throw new NotImplementedException("Capsule-capsule collision checks are not implemented.");
}

/// <summary>
/// Determine whether a capsule and a box intersect.
/// </summary>
/// <param name="capsule">The capsule</param>
/// <param name="box">The box</param>
public static bool CapsuleBoxCollision(CapsuleBody capsule, BoxBody box)
{
throw new NotImplementedException("Capsule-box collision checks are not implemented.");
}

/// <summary>
/// Registers a physics object.
/// </summary>
Expand Down
6 changes: 3 additions & 3 deletions Uchu.StandardScripts/AvantGardens/MaelstromSample.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
namespace Uchu.StandardScripts.AvantGardens
{
/// <summary>
/// Native implementation of scripts/02_client/map/ag/l_ag_maelstrom_sample.lua
/// Script to show/hide maelstrom samples based on whether the player has the relevant mission
/// </summary>
[ScriptName("l_ag_maelstrom_sample.lua")]
[LotSpecific(14718)]
public class MaelstromSample : ObjectScript
{
/// <summary>
Expand All @@ -21,4 +21,4 @@ public MaelstromSample(GameObject gameObject) : base(gameObject)
missionFilter.AddMissionIdToFilter(MissionId.SampleforScience);
}
}
}
}
6 changes: 3 additions & 3 deletions Uchu.StandardScripts/AvantGardens/MaelstromVacuum.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
namespace Uchu.StandardScripts.AvantGardens
{
/// <summary>
/// Native implementation of scripts/02_client/Equipment/l_maelstrom_extracticator_client.lua
/// Script for spawned maelstrom vacuum (https://lu.lcdruniverse.org/explorer/objects/14596)
/// </summary>
[ScriptName("l_maelstrom_extracticator_client.lua")]
[ScriptName("ScriptComponent_1582_script_name__removed")]
public class MaelstromVacuum : ObjectScript
{
/// <summary>
Expand Down Expand Up @@ -57,4 +57,4 @@ public MaelstromVacuum(GameObject gameObject) : base(gameObject)
});
}
}
}
}
6 changes: 3 additions & 3 deletions Uchu.StandardScripts/AvantGardens/TargetFilter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
namespace Uchu.StandardScripts.AvantGardens
{
/// <summary>
/// Native implementation of scripts/02_client/map/ag/l_ag_plunger_target.lua
/// Script to show/hide targets based on whether the player has the relevant mission
/// </summary>
[ScriptName("l_ag_plunger_target.lua")]
[LotSpecific(14380)]
public class TargetFilter : ObjectScript
{
/// <summary>
Expand All @@ -20,4 +20,4 @@ public TargetFilter(GameObject gameObject) : base(gameObject)
missionFilter.AddMissionIdToFilter(MissionId.SixShooter);
}
}
}
}
11 changes: 8 additions & 3 deletions Uchu.StandardScripts/General/Binoculars.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@
namespace Uchu.StandardScripts.General
{
/// <summary>
/// Native implementation of scripts/02_client/map/general/l_binoculars_client.lua
/// Script to set flags for binoculars (e.g. https://lu.lcdruniverse.org/explorer/objects/6700) the player uses
/// </summary>
[ScriptName("l_binoculars_client.lua")]
[ScriptName("ScriptComponent_1002_script_name__removed")] // Binoculars, id 6700
[ScriptName("ScriptComponent_952_script_name__removed")] // AG - Spaceship Binoculars, id 6842
[ScriptName("ScriptComponent_975_script_name__removed")] // GF - Binoculars, id 6958
[ScriptName("ScriptComponent_1020_script_name__removed")] // PR - Binoculars, id 7607
[ScriptName("ScriptComponent_1021_script_name__removed")] // NS - Binoculars, id 7608
[ScriptName("ScriptComponent_1335_script_name__removed")] // FB - Binoculars, id 12306
public class Binoculars : ObjectScript
{
/// <summary>
Expand Down Expand Up @@ -40,4 +45,4 @@ public Binoculars(GameObject gameObject) : base(gameObject)
});
}
}
}
}
31 changes: 31 additions & 0 deletions Uchu.StandardScripts/General/DeathPlane/DeathPlane.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Threading.Tasks;
using Uchu.World;
using Uchu.World.Scripting.Native;

namespace Uchu.StandardScripts.General.DeathPlane
{
/// <summary>
/// Native implementation of scripts/ai/act/l_act_player_death_trigger.lua
/// </summary>
[ScriptName("l_act_player_death_trigger.lua")]
public class DeathPlane : ObjectScript
{
/// <summary>
/// Creates the object script.
/// </summary>
/// <param name="gameObject">Game object to control with the script.</param>
public DeathPlane(GameObject gameObject) : base(gameObject)
{
var physics = gameObject.GetComponent<PhysicsComponent>();
if (physics == default) return;
Listen(physics.OnEnter, other =>
{
if (!(other.GameObject is Player player)) return;
Task.Run(async () =>
{
await player.GetComponent<DestructibleComponent>().SmashAsync(gameObject);
});
});
}
}
}
32 changes: 32 additions & 0 deletions Uchu.StandardScripts/General/DeathPlane/PlayerFallDeath.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System.Threading.Tasks;
using Uchu.World;
using Uchu.World.Scripting.Native;

namespace Uchu.StandardScripts.General.DeathPlane
{
/// <summary>
/// Native implementation of scripts/ai/gf/l_player_fall_death.lua
/// </summary>
[ScriptName("l_player_fall_death.lua")]
public class PlayerFallDeath : ObjectScript
{
/// <summary>
/// Creates the object script.
/// </summary>
/// <param name="gameObject">Game object to control with the script.</param>
public PlayerFallDeath(GameObject gameObject) : base(gameObject)
{
var physics = gameObject.GetComponent<PhysicsComponent>();
if (physics == default) return;
Listen(physics.OnEnter, other =>
{
if (!(other.GameObject is Player player)) return;
Task.Run(async () =>
{
await Task.Delay(2000);
await player.GetComponent<DestructibleComponent>().SmashAsync(gameObject);
});
});
}
}
}
28 changes: 28 additions & 0 deletions Uchu.StandardScripts/General/DeathPlane/PropertyDeathPlane.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using Uchu.World;
using Uchu.World.Scripting.Native;

namespace Uchu.StandardScripts.General.DeathPlane
{
/// <summary>
/// Native implementation of scripts/ai/ns/ns_pp_01/l_ns_pp_01_teleport.lua
/// </summary>
[ScriptName("l_ns_pp_01_teleport.lua")]
public class PropertyDeathPlane : ObjectScript
{
/// <summary>
/// Creates the object script.
/// </summary>
/// <param name="gameObject">Game object to control with the script.</param>
public PropertyDeathPlane(GameObject gameObject) : base(gameObject)
{
var physics = gameObject.GetComponent<PhysicsComponent>();
if (physics == default) return;
Listen(physics.OnEnter, other =>
{
if (!(other.GameObject is Player player)) return;
var teleportObject = this.GetGroup("Teleport")[0];
player.Teleport(teleportObject.Transform.Position, ignore: false);
});
}
}
}
Loading