mirror of
https://github.com/celisej567/gm_construct_port.git
synced 2026-01-08 22:10:36 +03:00
281 lines
6.1 KiB
C#
281 lines
6.1 KiB
C#
using Sandbox;
|
|
using Sandbox.Joints;
|
|
using System;
|
|
using System.Linq;
|
|
|
|
[Library( "gravgun" )]
|
|
public partial class GravGun : Carriable
|
|
{
|
|
public override string ViewModelPath => "weapons/rust_pistol/v_rust_pistol.vmdl";
|
|
|
|
private PhysicsBody holdBody;
|
|
private WeldJoint holdJoint;
|
|
|
|
public PhysicsBody HeldBody { get; private set; }
|
|
public Rotation HeldRot { get; private set; }
|
|
public ModelEntity HeldEntity { get; private set; }
|
|
|
|
protected virtual float MaxPullDistance => 2000.0f;
|
|
protected virtual float MaxPushDistance => 500.0f;
|
|
protected virtual float LinearFrequency => 10.0f;
|
|
protected virtual float LinearDampingRatio => 1.0f;
|
|
protected virtual float AngularFrequency => 10.0f;
|
|
protected virtual float AngularDampingRatio => 1.0f;
|
|
protected virtual float PullForce => 20.0f;
|
|
protected virtual float PushForce => 1000.0f;
|
|
protected virtual float ThrowForce => 2000.0f;
|
|
protected virtual float HoldDistance => 100.0f;
|
|
protected virtual float AttachDistance => 150.0f;
|
|
protected virtual float DropCooldown => 0.5f;
|
|
protected virtual float BreakLinearForce => 2000.0f;
|
|
|
|
private TimeSince timeSinceDrop;
|
|
|
|
public override void Spawn()
|
|
{
|
|
base.Spawn();
|
|
|
|
SetModel( "weapons/rust_pistol/rust_pistol.vmdl" );
|
|
|
|
CollisionGroup = CollisionGroup.Weapon;
|
|
SetInteractsAs( CollisionLayer.Debris );
|
|
}
|
|
|
|
public override void Simulate( Client client )
|
|
{
|
|
if ( Owner is not Player owner ) return;
|
|
|
|
if ( !IsServer )
|
|
return;
|
|
|
|
using ( Prediction.Off() )
|
|
{
|
|
var eyePos = owner.EyePos;
|
|
var eyeRot = owner.EyeRot;
|
|
var eyeDir = owner.EyeRot.Forward;
|
|
|
|
if ( HeldBody.IsValid() && HeldBody.PhysicsGroup != null )
|
|
{
|
|
if ( holdJoint.IsValid && !holdJoint.IsActive )
|
|
{
|
|
GrabEnd();
|
|
}
|
|
else if ( Input.Pressed( InputButton.Attack1 ) )
|
|
{
|
|
if ( HeldBody.PhysicsGroup.BodyCount > 1 )
|
|
{
|
|
// Don't throw ragdolls as hard
|
|
HeldBody.PhysicsGroup.ApplyImpulse( eyeDir * (ThrowForce * 0.5f), true );
|
|
HeldBody.PhysicsGroup.ApplyAngularImpulse( Vector3.Random * ThrowForce, true );
|
|
}
|
|
else
|
|
{
|
|
HeldBody.ApplyImpulse( eyeDir * (HeldBody.Mass * ThrowForce) );
|
|
HeldBody.ApplyAngularImpulse( Vector3.Random * (HeldBody.Mass * ThrowForce) );
|
|
}
|
|
|
|
GrabEnd();
|
|
}
|
|
else if ( Input.Pressed( InputButton.Attack2 ) )
|
|
{
|
|
timeSinceDrop = 0;
|
|
|
|
GrabEnd();
|
|
}
|
|
else
|
|
{
|
|
GrabMove( eyePos, eyeDir, eyeRot );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if ( timeSinceDrop < DropCooldown )
|
|
return;
|
|
|
|
var tr = Trace.Ray( eyePos, eyePos + eyeDir * MaxPullDistance )
|
|
.UseHitboxes()
|
|
.Ignore( owner, false )
|
|
.Radius( 2.0f )
|
|
.HitLayer( CollisionLayer.Debris )
|
|
.Run();
|
|
|
|
if ( !tr.Hit || !tr.Body.IsValid() || !tr.Entity.IsValid() || tr.Entity.IsWorld )
|
|
return;
|
|
|
|
if ( tr.Entity.PhysicsGroup == null )
|
|
return;
|
|
|
|
var modelEnt = tr.Entity as ModelEntity;
|
|
if ( !modelEnt.IsValid() )
|
|
return;
|
|
|
|
var body = tr.Body;
|
|
|
|
if ( Input.Pressed( InputButton.Attack1 ) )
|
|
{
|
|
if ( tr.Distance < MaxPushDistance && !IsBodyGrabbed( body ) )
|
|
{
|
|
var pushScale = 1.0f - Math.Clamp( tr.Distance / MaxPushDistance, 0.0f, 1.0f );
|
|
body.ApplyImpulseAt( tr.EndPos, eyeDir * (body.Mass * (PushForce * pushScale)) );
|
|
}
|
|
}
|
|
else if ( Input.Down( InputButton.Attack2 ) )
|
|
{
|
|
var physicsGroup = tr.Entity.PhysicsGroup;
|
|
|
|
if ( physicsGroup.BodyCount > 1 )
|
|
{
|
|
body = modelEnt.PhysicsBody;
|
|
if ( !body.IsValid() )
|
|
return;
|
|
}
|
|
|
|
if ( eyePos.Distance( body.Position ) <= AttachDistance )
|
|
{
|
|
GrabStart( modelEnt, body, eyePos + eyeDir * HoldDistance, eyeRot );
|
|
}
|
|
else if ( !IsBodyGrabbed( body ) )
|
|
{
|
|
physicsGroup.ApplyImpulse( eyeDir * -PullForce, true );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void Activate()
|
|
{
|
|
if ( !holdBody.IsValid() )
|
|
{
|
|
holdBody = new PhysicsBody
|
|
{
|
|
BodyType = PhysicsBodyType.Keyframed
|
|
};
|
|
}
|
|
}
|
|
|
|
private void Deactivate()
|
|
{
|
|
GrabEnd();
|
|
|
|
holdBody?.Remove();
|
|
holdBody = null;
|
|
}
|
|
|
|
public override void ActiveStart( Entity ent )
|
|
{
|
|
base.ActiveStart( ent );
|
|
|
|
if ( IsServer )
|
|
{
|
|
Activate();
|
|
}
|
|
}
|
|
|
|
public override void ActiveEnd( Entity ent, bool dropped )
|
|
{
|
|
base.ActiveEnd( ent, dropped );
|
|
|
|
if ( IsServer )
|
|
{
|
|
Deactivate();
|
|
}
|
|
}
|
|
|
|
protected override void OnDestroy()
|
|
{
|
|
base.OnDestroy();
|
|
|
|
if ( IsServer )
|
|
{
|
|
Deactivate();
|
|
}
|
|
}
|
|
|
|
public override void OnCarryDrop( Entity dropper )
|
|
{
|
|
}
|
|
|
|
private static bool IsBodyGrabbed( PhysicsBody body )
|
|
{
|
|
// There for sure is a better way to deal with this
|
|
if ( All.OfType<PhysGun>().Any( x => x?.HeldBody?.PhysicsGroup == body?.PhysicsGroup ) ) return true;
|
|
if ( All.OfType<GravGun>().Any( x => x?.HeldBody?.PhysicsGroup == body?.PhysicsGroup ) ) return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
private void GrabStart( ModelEntity entity, PhysicsBody body, Vector3 grabPos, Rotation grabRot )
|
|
{
|
|
if ( !body.IsValid() )
|
|
return;
|
|
|
|
if ( body.PhysicsGroup == null )
|
|
return;
|
|
|
|
if ( IsBodyGrabbed( body ) )
|
|
return;
|
|
|
|
GrabEnd();
|
|
|
|
HeldBody = body;
|
|
HeldRot = grabRot.Inverse * HeldBody.Rotation;
|
|
|
|
holdBody.Position = grabPos;
|
|
holdBody.Rotation = HeldBody.Rotation;
|
|
|
|
HeldBody.Wake();
|
|
HeldBody.EnableAutoSleeping = false;
|
|
|
|
holdJoint = PhysicsJoint.Weld
|
|
.From( holdBody )
|
|
.To( HeldBody, HeldBody.LocalMassCenter )
|
|
.WithLinearSpring( LinearFrequency, LinearDampingRatio, 0.0f )
|
|
.WithAngularSpring( AngularFrequency, AngularDampingRatio, 0.0f )
|
|
.Breakable( HeldBody.Mass * BreakLinearForce, 0 )
|
|
.Create();
|
|
|
|
HeldEntity = entity;
|
|
|
|
var client = GetClientOwner();
|
|
client?.Pvs.Add( HeldEntity );
|
|
}
|
|
|
|
private void GrabEnd()
|
|
{
|
|
if ( holdJoint.IsValid )
|
|
{
|
|
holdJoint.Remove();
|
|
}
|
|
|
|
if ( HeldBody.IsValid() )
|
|
{
|
|
HeldBody.EnableAutoSleeping = true;
|
|
}
|
|
|
|
if ( HeldEntity.IsValid() )
|
|
{
|
|
var client = GetClientOwner();
|
|
client?.Pvs.Remove( HeldEntity );
|
|
}
|
|
|
|
HeldBody = null;
|
|
HeldRot = Rotation.Identity;
|
|
HeldEntity = null;
|
|
}
|
|
|
|
private void GrabMove( Vector3 startPos, Vector3 dir, Rotation rot )
|
|
{
|
|
if ( !HeldBody.IsValid() )
|
|
return;
|
|
|
|
holdBody.Position = startPos + dir * HoldDistance;
|
|
holdBody.Rotation = rot * HeldRot;
|
|
}
|
|
|
|
public override bool IsUsable( Entity user )
|
|
{
|
|
return Owner == null || HeldBody.IsValid();
|
|
}
|
|
}
|