From 9adec4a0c61dcb161185237f0aaf179280412a5b Mon Sep 17 00:00:00 2001 From: Craig McKay Date: Sat, 4 Jan 2025 15:46:39 +1300 Subject: [PATCH 01/16] Stop an error that happens when a player is physgunning and dies --- Code/Components/Base/BaseWeapon.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Code/Components/Base/BaseWeapon.cs b/Code/Components/Base/BaseWeapon.cs index 546faf6..75c4bfe 100644 --- a/Code/Components/Base/BaseWeapon.cs +++ b/Code/Components/Base/BaseWeapon.cs @@ -114,7 +114,8 @@ protected override void OnUpdate() if ( IsProxy ) return; - Scene.Camera.Tags.Set( "viewer", Owner.Controller.ThirdPerson ); + if (Owner.IsValid()) + Scene.Camera.Tags.Set( "viewer", Owner.Controller.ThirdPerson ); OnControl(); } From dc54d404fcdae70cef77e75eb0786083e8c9b446 Mon Sep 17 00:00:00 2001 From: Craig McKay Date: Sat, 4 Jan 2025 15:47:26 +1300 Subject: [PATCH 02/16] Add minimum delay between undos to avoid accidentally undoing too many things - my keyboard is doubling keypresses sometimes, so this was painful beforehand. --- Code/Components/Player/Player.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Code/Components/Player/Player.cs b/Code/Components/Player/Player.cs index 95a800f..10516cf 100644 --- a/Code/Components/Player/Player.cs +++ b/Code/Components/Player/Player.cs @@ -38,6 +38,8 @@ public PlayerSettings Settings public Ray AimRay => new( EyeTransform.Position, EyeTransform.Rotation.Forward ); public bool SuppressScrollWheelInventory { get; set; } = false; + private RealTimeSince TimeSinceLastUndo = 0f; + public bool isInParty() { return PartyId != 0UL; @@ -48,8 +50,9 @@ protected override void OnUpdate() base.OnUpdate(); if ( !IsProxy ) { - if ( Input.Pressed( "undo" ) ) + if ( Input.Pressed( "undo" ) && TimeSinceLastUndo > 0.1f ) { + TimeSinceLastUndo = 0; UndoSystem.PlayerUndo(); } if ( Input.Pressed( "attack3" ) ) From 5aea9ae4f27faeee32b6cec6d3ed8d63a25d71aa Mon Sep 17 00:00:00 2001 From: Craig McKay Date: Sat, 4 Jan 2025 15:52:31 +1300 Subject: [PATCH 03/16] Add Parenting tool. Can't "bulk-add" constrained props until #57 is sorted. --- Code/Components/Tools/Parent.cs | 197 ++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 Code/Components/Tools/Parent.cs diff --git a/Code/Components/Tools/Parent.cs b/Code/Components/Tools/Parent.cs new file mode 100644 index 0000000..3ec0786 --- /dev/null +++ b/Code/Components/Tools/Parent.cs @@ -0,0 +1,197 @@ +[Library( "tool_parent", Title = "Parent", Description = """ + Parent one or more objects to a singular object. + NOTE: Parenting something *does not* weld them together. + + Primary Attack: Select one or more objects that + Reload: Clear all selected targets. + Secondary Attack: Parent all selected objects to the target object. + + WIP - not yet. Sprint + Primary Attack: Find all objects that are constrained to the target, and target them all + """, Group = "constraints" )] +public class Parent : BaseTool +{ + List targeted = new(); + + public override bool Primary( SceneTraceResult trace ) + { + if ( !trace.Hit ) + return false; + + var go = trace.GameObject; + + if ( Input.Pressed( "attack1" ) && go.Components.TryGet( out var propHelper ) ) + { + + if ( targeted.Contains(go) ) + { + RemoveTarget( go ); + return true; + } + + // If we're holding Sprint, we want to find all constrained objects + if ( Input.Down( "run" ) ) + { + AddAllRecursively( go, propHelper ); + + return true; + } + + AddTarget( go ); + + return true; + } + + return false; + } + + public override bool Secondary( SceneTraceResult trace ) + { + if ( !trace.Hit ) + return false; + + var go = trace.GameObject; + + if ( Input.Pressed( "attack2" ) && go.Components.TryGet( out var propHelper ) ) + { + if ( targeted.Contains( go ) ) + RemoveTarget( go ); + + foreach( var target in targeted ) + { + target.SetParent( go ); + } + + UndoSystem.Add( Owner, PrepareUndo(targeted), go ); + + ClearTargets(); + + return true; + } + + return false; + } + + private Func PrepareUndo(List objects) + { + List undoList = new(); + foreach(var obj in objects) + { + undoList.Add( obj ); + } + + + return () => + { + foreach(var obj in undoList) + { + Log.Info( obj.Root ); + obj.SetParent( null ); + } + + return "Undone Parenting " + undoList.Count + " objects together"; + }; + } + + private bool AddAllRecursively(GameObject target, PropHelper propHelper) + { + Log.Info( "Parent all!" ); + + AddTarget( target ); + + Log.Info( propHelper.Welds.Count ); + + // TODO: Wait for https://github.com/Nebual/sandbox-plus/issues/57 and finish this afterwards. + foreach ( var obj in propHelper.Welds ) + { + Log.Info( obj.Body + " " + targeted.Contains( obj.Body ) ); + if ( !targeted.Contains( obj.Body ) && obj.Body.Components.TryGet( out var objPH ) ) AddAllRecursively( obj.Body, objPH ); + } + + return true; + } + + public override bool Reload( SceneTraceResult trace ) + { + if (targeted.Count > 0) + ClearTargets(); + + return false; + } + + //private Func ReadyUndo( PropHelper propHelper, GameObject from) + //{ + // return () => + // { + // propHelper.Unweld( from ); + + // return "Un-welded two objects"; + // }; + //} + + private void AddTarget(GameObject obj) + { + targeted.Add( obj ); + AddGlow( obj ); + } + + private void RemoveTarget(GameObject obj) + { + targeted.Remove( obj ); + RemoveGlow( obj ); + } + + private void ClearTargets() + { + while(targeted.Count > 0) + RemoveTarget( targeted.First() ); + } + + private void AddGlow(GameObject obj) + { + if ( obj.GetComponent().IsValid() ) + { + var glow = obj.GetOrAddComponent(); + glow.Width = 0.25f; + glow.Color = new Color( 100f, 100.0f, 100.0f, 1.0f ); + + foreach ( var child in obj.Children ) + { + if ( !child.GetComponent().IsValid() ) + continue; + + glow = child.GetOrAddComponent(); + glow.Color = new Color( 0.1f, 1.0f, 1.0f, 1.0f ); + } + } + } + + private void RemoveGlow( GameObject obj ) + { + if ( obj.IsValid() ) + { + foreach ( var child in obj.Children ) + { + if ( !child.Components.Get().IsValid() ) + continue; + + if ( child.Components.TryGet( out var childglow ) ) + { + childglow.Destroy(); + } + } + + if ( obj.Components.TryGet( out var glow ) ) + { + glow.Destroy(); + } + } + } + + private void RemoveAllGlows() + { + foreach (var obj in targeted) + { + RemoveGlow( obj ); + } + } +} From ec0f61ec87379134eab656fd31706f865426354a Mon Sep 17 00:00:00 2001 From: Nebual Date: Sat, 4 Jan 2025 01:53:48 -0800 Subject: [PATCH 04/16] Fix some null references --- Code/Components/Base/BaseTool.cs | 7 +++---- Code/Components/Player/PlayerDresser.cs | 2 +- .../PlayerController/PlayerController.Snapping.cs | 2 +- Code/Components/Tools/Stacker.cs | 1 + Code/Components/Tools/WhatIsThat.cs | 2 ++ Code/Components/Weapons/PhysGun.cs | 8 ++++---- Code/GameObjectSystems/SandboxGameManager.cs | 4 +++- 7 files changed, 15 insertions(+), 11 deletions(-) diff --git a/Code/Components/Base/BaseTool.cs b/Code/Components/Base/BaseTool.cs index 588a35b..a52b98b 100644 --- a/Code/Components/Base/BaseTool.cs +++ b/Code/Components/Base/BaseTool.cs @@ -135,14 +135,13 @@ protected virtual void OnUpdatePreviewModel( Model model ) public void DoAxisOverlay( SceneTraceResult trace, CameraComponent camera, bool DrawLabels = true ) { - Prop prop = trace.GameObject.GetComponent(); - - if ( !trace.Hit || !trace.Body.IsValid() || !prop.IsValid() ) + if ( !trace.Hit || !trace.Body.IsValid() ) return; + Prop prop = trace.GameObject.GetComponent(); Rigidbody rigidbody = trace.GameObject.GetComponent(); - if ( !rigidbody.IsValid() ) return; + if ( !prop.IsValid() || !rigidbody.IsValid() ) return; //Vector3 GOCenter = prop.WorldPosition + prop.Model.Bounds.Center; BBox bounds = rigidbody.PhysicsBody.GetBounds(); diff --git a/Code/Components/Player/PlayerDresser.cs b/Code/Components/Player/PlayerDresser.cs index def04bc..33417af 100644 --- a/Code/Components/Player/PlayerDresser.cs +++ b/Code/Components/Player/PlayerDresser.cs @@ -49,6 +49,6 @@ private void changePlayerModelType( bool UseHumanModel ) { BodyRenderer.Model = Model.Load( "models/citizen/citizen.vmdl" ); } - clothing.Apply( BodyRenderer ); + clothing?.Apply( BodyRenderer ); } } diff --git a/Code/Components/PlayerController/PlayerController.Snapping.cs b/Code/Components/PlayerController/PlayerController.Snapping.cs index 80c219a..730b6e9 100644 --- a/Code/Components/PlayerController/PlayerController.Snapping.cs +++ b/Code/Components/PlayerController/PlayerController.Snapping.cs @@ -112,7 +112,7 @@ void OnRenderSnapHUD() return; // Check if our active weapon wants to override this too - if (GetComponent() is {} inventory) + if (GetComponent() is {} inventory && inventory.ActiveWeapon.IsValid()) { IEvents.PostToGameObject(inventory.ActiveWeapon.GameObject, x => x.OnEnableSnapping(ref enabled)); if (!enabled) diff --git a/Code/Components/Tools/Stacker.cs b/Code/Components/Tools/Stacker.cs index 8f2fc58..f78d6e0 100644 --- a/Code/Components/Tools/Stacker.cs +++ b/Code/Components/Tools/Stacker.cs @@ -122,6 +122,7 @@ public override bool Secondary( SceneTraceResult trace ) protected override void OnUpdate() { base.OnUpdate(); + if ( !Parent.IsValid() ) return; var trace = Parent.BasicTraceTool(); diff --git a/Code/Components/Tools/WhatIsThat.cs b/Code/Components/Tools/WhatIsThat.cs index e03aa68..b26ed05 100644 --- a/Code/Components/Tools/WhatIsThat.cs +++ b/Code/Components/Tools/WhatIsThat.cs @@ -41,6 +41,8 @@ protected override void OnUpdate() { base.OnUpdate(); + if ( !Parent.IsValid() ) return; + var trace = Parent.BasicTraceTool(); DoAxisOverlay( trace, Scene.Camera ); diff --git a/Code/Components/Weapons/PhysGun.cs b/Code/Components/Weapons/PhysGun.cs index fdcada9..b35b690 100644 --- a/Code/Components/Weapons/PhysGun.cs +++ b/Code/Components/Weapons/PhysGun.cs @@ -251,11 +251,11 @@ public static List GetAllConnectedProps( GameObject gameObject ) foreach ( Joint joint in result ) { - GameObject object1 = joint.Body1.GetGameObject(); - GameObject object2 = joint.Body2.GetGameObject(); + GameObject object1 = joint?.Body1?.GetGameObject(); + GameObject object2 = joint?.Body2?.GetGameObject(); - if ( !returned.Contains( object1 ) ) returned.Add( object1 ); - if ( !returned.Contains( object2 ) ) returned.Add( object2 ); + if ( object1.IsValid() && !returned.Contains( object1 ) ) returned.Add( object1 ); + if ( object2.IsValid() && !returned.Contains( object2 ) ) returned.Add( object2 ); } return returned; diff --git a/Code/GameObjectSystems/SandboxGameManager.cs b/Code/GameObjectSystems/SandboxGameManager.cs index 2284291..8f66487 100644 --- a/Code/GameObjectSystems/SandboxGameManager.cs +++ b/Code/GameObjectSystems/SandboxGameManager.cs @@ -83,7 +83,9 @@ public void SpawnPlayerForConnection( Connection channel ) if ( inventory.IsValid() ) player.Inventory = inventory; - channel.CanRefreshObjects = true; + if (Networking.IsHost) { + channel.CanRefreshObjects = true; + } playerGo.NetworkSpawn( channel ); From 83ed1107de6261e67f447c280d9afa22cbcbec74 Mon Sep 17 00:00:00 2001 From: Nebual Date: Sat, 4 Jan 2025 01:59:47 -0800 Subject: [PATCH 05/16] Smartsnap: allow holding a point through leaving range --- .../PlayerController/PlayerController.Snapping.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Code/Components/PlayerController/PlayerController.Snapping.cs b/Code/Components/PlayerController/PlayerController.Snapping.cs index 730b6e9..7e9609d 100644 --- a/Code/Components/PlayerController/PlayerController.Snapping.cs +++ b/Code/Components/PlayerController/PlayerController.Snapping.cs @@ -141,21 +141,19 @@ void OnRenderSnapHUD() void UpdateSnapInput() { IsSnapping = false; - - if ( !IsShowingSnapHUD ) - return; if ( !SnapLocation.HasValue ) return; - if ( !Hovered.IsValid() ) - return; - if ( Input.Down( UseButton ) ) { EyeAngles = Vector3.Direction( Scene.Camera.WorldPosition, SnapLocation.Value ).EulerAngles; IsSnapping = true; } + else if ( !Hovered.IsValid() ) + { + SnapLocation = null; + } } void UpdateCachedSnapData(BBox bounds, Transform worldTransform) From feec99af883fae67e62c99072879f2e39a28ec0e Mon Sep 17 00:00:00 2001 From: Nebual Date: Sat, 4 Jan 2025 02:00:09 -0800 Subject: [PATCH 06/16] Resizer: shift/ctrl for faster/slower --- Code/Components/Tools/Resizer.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Code/Components/Tools/Resizer.cs b/Code/Components/Tools/Resizer.cs index a23afcc..008708d 100644 --- a/Code/Components/Tools/Resizer.cs +++ b/Code/Components/Tools/Resizer.cs @@ -15,17 +15,21 @@ protected bool IncrementScale( SceneTraceResult trace, int resizeDir ) if ( !trace.Hit || !trace.GameObject.IsValid() ) return false; + var speed = Input.Down( "run" ) ? 2f + : Input.Down( "duck" ) ? 0.125f + : 0.5f; + var skinnedModelRenderer = trace.GameObject.GetComponent(); if ( skinnedModelRenderer.IsValid() && skinnedModelRenderer.GetBoneObject( trace.Bone ) is GameObject boneGo && boneGo.IsValid() ) { - var size = boneGo.WorldScale + (resizeDir * 0.5f * Time.Delta); + var size = boneGo.WorldScale + (resizeDir * speed * Time.Delta); SetRagSize( trace.GameObject, size, trace.Bone ); } else { var go = trace.GameObject; - var size = go.WorldScale + (resizeDir * 0.5f * Time.Delta); + var size = go.WorldScale + (resizeDir * speed * Time.Delta); SetPropSize( trace.GameObject, size ); } From 6b71a70e2a4dec72300db1a97578441714329206 Mon Sep 17 00:00:00 2001 From: Nebual Date: Sat, 4 Jan 2025 02:01:28 -0800 Subject: [PATCH 07/16] Weight Tool: use MassOverride, more stable? --- Code/Components/Tools/Weight.cs | 27 ++++++++++++++++++++++++--- Code/Components/Tools/WhatIsThat.cs | 7 ++++++- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/Code/Components/Tools/Weight.cs b/Code/Components/Tools/Weight.cs index 840e324..43e39b5 100644 --- a/Code/Components/Tools/Weight.cs +++ b/Code/Components/Tools/Weight.cs @@ -20,7 +20,15 @@ public override bool Primary( SceneTraceResult trace ) { ModelWeights.Add( prop.Model.Name, trace.Body.Mass ); } - trace.Body.Mass = TargetWeight; + var rigidBody = trace.GameObject.GetComponent(); + if ( rigidBody.IsValid() ) + { + rigidBody.MassOverride = TargetWeight; + } + else + { + trace.Body.Mass = TargetWeight; + } return true; } @@ -34,7 +42,15 @@ public override bool Secondary( SceneTraceResult trace ) if ( Input.Pressed( "attack2" ) ) { - SetWeightConvar( trace.Body.Mass ); + var rigidBody = trace.GameObject.GetComponent(); + if ( rigidBody.IsValid() && rigidBody.MassOverride > 0 ) + { + SetWeightConvar( rigidBody.MassOverride ); + } + else + { + SetWeightConvar( trace.Body.Mass ); + } return true; } @@ -49,7 +65,12 @@ public override bool Reload( SceneTraceResult trace ) if ( Input.Pressed( "reload" ) ) { var prop = trace.GameObject.GetComponent(); - if ( ModelWeights.ContainsKey( prop.Model.Name ) ) + var rigidBody = trace.GameObject.GetComponent(); + if ( rigidBody.IsValid() && rigidBody.MassOverride > 0 ) + { + rigidBody.MassOverride = 0; + } + else if ( ModelWeights.ContainsKey( prop.Model.Name ) ) { trace.Body.Mass = ModelWeights[prop.Model.Name]; } diff --git a/Code/Components/Tools/WhatIsThat.cs b/Code/Components/Tools/WhatIsThat.cs index b26ed05..3f137ac 100644 --- a/Code/Components/Tools/WhatIsThat.cs +++ b/Code/Components/Tools/WhatIsThat.cs @@ -18,7 +18,12 @@ public override bool Primary( SceneTraceResult tr ) { Clipboard.SetText(prop.Prop.Model.Name); message += $" {prop.Prop.Model.Name},\n"; - if ( tr.Body.IsValid() ) + var rigidBody = tr.GameObject.GetComponent(); + if ( rigidBody.IsValid() && rigidBody.MassOverride > 0 ) + { + message += $" weighing {rigidBody.MassOverride:F2} (overridden),"; + } + else if ( tr.Body.IsValid() ) { message += $" weighing {tr.Body.Mass:F2},"; } From a4a481a3316d60a91371995164accbc769d02356 Mon Sep 17 00:00:00 2001 From: Nebual Date: Sat, 4 Jan 2025 02:03:24 -0800 Subject: [PATCH 08/16] Physgun: Double tap R (or shift-r) to unfreeze all connected --- Code/Components/Weapons/PhysGun.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Code/Components/Weapons/PhysGun.cs b/Code/Components/Weapons/PhysGun.cs index b35b690..62794d1 100644 --- a/Code/Components/Weapons/PhysGun.cs +++ b/Code/Components/Weapons/PhysGun.cs @@ -7,7 +7,7 @@ public partial class PhysGun : BaseWeapon, Component.INetworkListener [Property] public float AngularFrequency { get; set; } = 20.0f; [Property] public float AngularDampingRatio { get; set; } = 1.0f; [Property] public float TargetDistanceSpeed { get; set; } = 25.0f; - [Property] public float RotateSpeed { get; set; } = 0.2f; + [Property] public float RotateSpeed { get; set; } = 0.4f; [Property] public float RotateSnapAt { get; set; } = 45.0f; [Sync] public bool Beaming { get; set; } @@ -20,7 +20,8 @@ public partial class PhysGun : BaseWeapon, Component.INetworkListener private SoundHandle BeamSound; private bool BeamSoundPlaying; GameObject lastGrabbed = null; - private Model _model = Cloud.Model("katka/gravitygun"); // in the prefab, but this ensures its downloaded + private Model _model = Cloud.Model( "katka/gravitygun" ); // in the prefab, but this ensures its downloaded + private RealTimeSince LastReloadPressed; PhysicsBody _heldBody; PhysicsBody HeldBody @@ -134,11 +135,15 @@ public override void OnControl() grabbed = false; } - if ( Input.Pressed( "reload" ) && Input.Down( "run" ) ) + if ( Input.Pressed( "reload" ) && (Input.Down( "run" ) || LastReloadPressed < 0.5f) ) { TryUnfreezeAll(); SetRendererAnimParam( "fire", true ); } + if ( Input.Pressed( "reload" ) ) + { + LastReloadPressed = 0; + } if ( Beaming ) { From 1497d2a6dfdfedb621989061a770d9582624c841 Mon Sep 17 00:00:00 2001 From: Nebual Date: Sat, 4 Jan 2025 02:08:35 -0800 Subject: [PATCH 09/16] CreateGameModal: default to > 1 player, its funnier --- Code/UI/MainMenu/Components/Modals/CreateGameModal.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/UI/MainMenu/Components/Modals/CreateGameModal.razor b/Code/UI/MainMenu/Components/Modals/CreateGameModal.razor index 2de72a8..6096109 100644 --- a/Code/UI/MainMenu/Components/Modals/CreateGameModal.razor +++ b/Code/UI/MainMenu/Components/Modals/CreateGameModal.razor @@ -61,7 +61,7 @@ CurrentConfig = new LobbyConfig() { - MaxPlayers = 1, + MaxPlayers = 8, Name = $"{Package.GetCachedTitle(Game.Ident)} Server" }; From 4fa3a4b03a806e4bb3d89415cd1864a02b85e6fe Mon Sep 17 00:00:00 2001 From: Nebual Date: Sat, 4 Jan 2025 02:09:01 -0800 Subject: [PATCH 10/16] BaseTool: Sync PreviewModel rotation with default spawn logic --- Code/Utils/PreviewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Utils/PreviewModel.cs b/Code/Utils/PreviewModel.cs index 87a74ed..8d7b94d 100644 --- a/Code/Utils/PreviewModel.cs +++ b/Code/Utils/PreviewModel.cs @@ -22,7 +22,7 @@ public void Update( SceneTraceResult trace ) } previewObject.WorldPosition = trace.HitPosition + PositionOffset + trace.Normal * NormalOffset; - previewObject.WorldRotation = (FaceNormal ? Rotation.LookAt( trace.Normal ) : Rotation.Identity) * RotationOffset; + previewObject.WorldRotation = (FaceNormal ? Rotation.LookAt( trace.Normal, trace.Direction ) : Rotation.Identity) * RotationOffset; SetEnabled( true ); } From 2e0b9ced3c4707d0339e49bbb452603247a75fa3 Mon Sep 17 00:00:00 2001 From: Nebual Date: Sat, 4 Jan 2025 02:10:04 -0800 Subject: [PATCH 11/16] Remove vpcf_c files, they get recompiled differently on each machine --- Assets/particles/impact.flesh.vpcf_c | 3 --- Assets/particles/impact.wood.smokepuff.vpcf_c | 3 --- Assets/particles/physgun_beam.vpcf_c | 3 --- Assets/particles/physgun_end_nohit.vpcf_c | 3 --- Assets/particles/physgun_freeze.vpcf_c | 3 --- Assets/particles/physgun_hitsmoke.vpcf_c | 3 --- Assets/particles/physgun_light.vpcf_c | 3 --- Assets/particles/physgun_start.vpcf_c | 3 --- Assets/particles/rope.vpcf_c | 3 --- Assets/particles/tool_hit.vpcf_c | 3 --- Assets/particles/tool_select_hit.vpcf_c | 3 --- Assets/particles/tool_select_indicator.vpcf_c | 3 --- Assets/particles/tool_select_ring.vpcf_c | 3 --- Assets/particles/tool_tracer.vpcf_c | 3 --- Assets/particles/water_squirt.vpcf_c | 3 --- 15 files changed, 45 deletions(-) delete mode 100644 Assets/particles/impact.flesh.vpcf_c delete mode 100644 Assets/particles/impact.wood.smokepuff.vpcf_c delete mode 100644 Assets/particles/physgun_beam.vpcf_c delete mode 100644 Assets/particles/physgun_end_nohit.vpcf_c delete mode 100644 Assets/particles/physgun_freeze.vpcf_c delete mode 100644 Assets/particles/physgun_hitsmoke.vpcf_c delete mode 100644 Assets/particles/physgun_light.vpcf_c delete mode 100644 Assets/particles/physgun_start.vpcf_c delete mode 100644 Assets/particles/rope.vpcf_c delete mode 100644 Assets/particles/tool_hit.vpcf_c delete mode 100644 Assets/particles/tool_select_hit.vpcf_c delete mode 100644 Assets/particles/tool_select_indicator.vpcf_c delete mode 100644 Assets/particles/tool_select_ring.vpcf_c delete mode 100644 Assets/particles/tool_tracer.vpcf_c delete mode 100644 Assets/particles/water_squirt.vpcf_c diff --git a/Assets/particles/impact.flesh.vpcf_c b/Assets/particles/impact.flesh.vpcf_c deleted file mode 100644 index 58f00a6..0000000 --- a/Assets/particles/impact.flesh.vpcf_c +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:59e899d04f63ca18d7385316e1242f64cf6e0c587c32644807584931b713aa0f -size 3382 diff --git a/Assets/particles/impact.wood.smokepuff.vpcf_c b/Assets/particles/impact.wood.smokepuff.vpcf_c deleted file mode 100644 index bb32403..0000000 --- a/Assets/particles/impact.wood.smokepuff.vpcf_c +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:709573b800649319603a45753801973e742f6896b9606671d8e92254b800e418 -size 2957 diff --git a/Assets/particles/physgun_beam.vpcf_c b/Assets/particles/physgun_beam.vpcf_c deleted file mode 100644 index e06fcd5..0000000 --- a/Assets/particles/physgun_beam.vpcf_c +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:df7936a826de0a9843e8783a0571eae14f355709f771d7f0254de4c1d53d1fd2 -size 3011 diff --git a/Assets/particles/physgun_end_nohit.vpcf_c b/Assets/particles/physgun_end_nohit.vpcf_c deleted file mode 100644 index 00b8947..0000000 --- a/Assets/particles/physgun_end_nohit.vpcf_c +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e1e9797f7c8bad0b91775af4564c961e7861ccacd1a482f09706ee6de355f5ca -size 3785 diff --git a/Assets/particles/physgun_freeze.vpcf_c b/Assets/particles/physgun_freeze.vpcf_c deleted file mode 100644 index 3381155..0000000 --- a/Assets/particles/physgun_freeze.vpcf_c +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d12b4961aedb6ad2771c707d796ffbe6a80f44ff2405f115cd62140f395e887a -size 3192 diff --git a/Assets/particles/physgun_hitsmoke.vpcf_c b/Assets/particles/physgun_hitsmoke.vpcf_c deleted file mode 100644 index 9a294e9..0000000 --- a/Assets/particles/physgun_hitsmoke.vpcf_c +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6b8e486a5d40c48a17361ed3408cb3edb16f0bc5cdeadaba6a94b9ece5fdc321 -size 3149 diff --git a/Assets/particles/physgun_light.vpcf_c b/Assets/particles/physgun_light.vpcf_c deleted file mode 100644 index 5e10480..0000000 --- a/Assets/particles/physgun_light.vpcf_c +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1c597edbcf0da7f2b5e3d79b94dcfc3fe1ab3963b7705fd478bfc5ed585f1cb0 -size 1989 diff --git a/Assets/particles/physgun_start.vpcf_c b/Assets/particles/physgun_start.vpcf_c deleted file mode 100644 index 1def791..0000000 --- a/Assets/particles/physgun_start.vpcf_c +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bf6bfa8e04aa186960df660050ad149995f1f183eda012a9d1dccfe32cebcf34 -size 3289 diff --git a/Assets/particles/rope.vpcf_c b/Assets/particles/rope.vpcf_c deleted file mode 100644 index adb4e2c..0000000 --- a/Assets/particles/rope.vpcf_c +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ecd633f97dc43f3a1dc2b51ee7106a6c03f5d988e4f13d7e3b8ad342f83a1952 -size 2367 diff --git a/Assets/particles/tool_hit.vpcf_c b/Assets/particles/tool_hit.vpcf_c deleted file mode 100644 index c8befe8..0000000 --- a/Assets/particles/tool_hit.vpcf_c +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:691046875bfaed1dfa213f6792654af98eee791b60db936d6c65a3647ebe8ee3 -size 3032 diff --git a/Assets/particles/tool_select_hit.vpcf_c b/Assets/particles/tool_select_hit.vpcf_c deleted file mode 100644 index d13624e..0000000 --- a/Assets/particles/tool_select_hit.vpcf_c +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d2bf9b83943eb666da862c263078f9e00ed6ec14e7444ca2a2ed1778496fb26d -size 1726 diff --git a/Assets/particles/tool_select_indicator.vpcf_c b/Assets/particles/tool_select_indicator.vpcf_c deleted file mode 100644 index 3ab54c9..0000000 --- a/Assets/particles/tool_select_indicator.vpcf_c +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8c34faf126a57fa0e7902c06d031dce12a6b4d7c2472fe3b303789fae8e62729 -size 1947 diff --git a/Assets/particles/tool_select_ring.vpcf_c b/Assets/particles/tool_select_ring.vpcf_c deleted file mode 100644 index 7f57d3e..0000000 --- a/Assets/particles/tool_select_ring.vpcf_c +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:65fb76bf39ce4bb12931a6555d33faf2ac4b12892f462437d3f1713dae663ac8 -size 2349 diff --git a/Assets/particles/tool_tracer.vpcf_c b/Assets/particles/tool_tracer.vpcf_c deleted file mode 100644 index 4e4d72d..0000000 --- a/Assets/particles/tool_tracer.vpcf_c +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:13841ff6490747b80c5ab92b3c1754dffe30fafa02180ee968e3a6675107e2d7 -size 2846 diff --git a/Assets/particles/water_squirt.vpcf_c b/Assets/particles/water_squirt.vpcf_c deleted file mode 100644 index 9a4bb54..0000000 --- a/Assets/particles/water_squirt.vpcf_c +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:499fd872403f80ca66ca8c63b0c871322be7480ee83b7e5f7ed2d2b511d18bb4 -size 2792 From 419271f9f1421b0cc2941d7d68cb56cb9614854e Mon Sep 17 00:00:00 2001 From: Craig McKay Date: Sat, 4 Jan 2025 23:15:44 +1300 Subject: [PATCH 12/16] Fix the placement of Dynshapes (#74) --- Code/Components/Player/Player.cs | 25 ++++++++++++++++--- .../VertexMeshBuilder.Cylinder.cs | 6 ++--- Code/MeshBuilders/VertexMeshBuilder.Gear.cs | 5 ++-- Code/MeshBuilders/VertexMeshBuilder.Sphere.cs | 7 +++--- Code/MeshBuilders/VertexMeshBuilder.cs | 5 ++-- 5 files changed, 31 insertions(+), 17 deletions(-) diff --git a/Code/Components/Player/Player.cs b/Code/Components/Player/Player.cs index 10516cf..d76051b 100644 --- a/Code/Components/Player/Player.cs +++ b/Code/Components/Player/Player.cs @@ -161,19 +161,36 @@ void SandboxPlus.PlayerController.IEvents.OnLanded( float distance, Vector3 impa IPlayerEvent.PostToGameObject( GameObject, x => x.OnLand( distance, impactVelocity ) ); } - public static SceneTraceResult DoBasicTrace() + /// + /// Function that runs a trace from the Player's eye forwards. + /// + /// Use this is you already have a copy of the Player. + /// + /// + public SceneTraceResult BasicTrace() { - var player = Player.FindLocalPlayer(); - var trace = player.Scene.Trace.Ray( player.AimRay.Position, player.AimRay.Position + player.AimRay.Forward * 5000 ) + var trace = Scene.Trace.Ray( AimRay.Position, AimRay.Position + AimRay.Forward * 5000 ) .UseHitboxes() .WithAnyTags( "solid", "npc", "glass" ) .WithoutTags( "debris", "player" ) - .IgnoreGameObjectHierarchy( player.GameObject ) + .IgnoreGameObjectHierarchy( GameObject ) .Size( 2 ); return trace.Run(); } + /// + /// Static function that gets the Local Player, and runs a trace from it's eye forwards. + /// + /// Use this if you don't have a copy of the Player + /// + /// SceneTraceResult of a straight trace from the player's eye forwards + public static SceneTraceResult DoBasicTrace() + { + var player = Player.FindLocalPlayer(); + return player.BasicTrace(); + } + public static Player FindPlayerByConnection( Connection connection ) { return Game.ActiveScene.GetAllComponents().FirstOrDefault( x => x.Network.Owner == connection ); diff --git a/Code/MeshBuilders/VertexMeshBuilder.Cylinder.cs b/Code/MeshBuilders/VertexMeshBuilder.Cylinder.cs index 58f034d..d255d16 100644 --- a/Code/MeshBuilders/VertexMeshBuilder.Cylinder.cs +++ b/Code/MeshBuilders/VertexMeshBuilder.Cylinder.cs @@ -139,10 +139,10 @@ public static void SpawnCylinder( float radius, float depth, int numFaces = 16, var modelId = CreateCylinder(radius, depth, numFaces, texScale); var entity = SpawnEntity( modelId ); + Player player = Player.FindLocalPlayer(); - GameObject pawn = player.Controller.GameObject; - Transform eye = player.EyeTransform; - SceneTraceResult trace = pawn.Scene.Trace.Ray(eye.Position, eye.Position + eye.Forward * 5000.0f ).UseHitboxes().IgnoreGameObject(pawn).Run(); + SceneTraceResult trace = player.BasicTrace(); + entity.WorldPosition = trace.EndPosition + trace.Normal; UndoSystem.Add( creator: player, callback: ReadyUndo( entity, "Cylinder" ), prop: entity ); diff --git a/Code/MeshBuilders/VertexMeshBuilder.Gear.cs b/Code/MeshBuilders/VertexMeshBuilder.Gear.cs index 604200e..58e68e5 100644 --- a/Code/MeshBuilders/VertexMeshBuilder.Gear.cs +++ b/Code/MeshBuilders/VertexMeshBuilder.Gear.cs @@ -234,10 +234,9 @@ public static void SpawnGear( float radius, float depth, int numTeeth = 16, floa { var modelId = CreateGear( radius, depth, numTeeth, cutDepth, cutAngle, texScale ); var entity = SpawnEntity( modelId ); + Player player = Player.FindLocalPlayer(); - GameObject pawn = player.Controller.GameObject; - Transform eye = player.EyeTransform; - SceneTraceResult trace = pawn.Scene.Trace.Ray(eye.Position, eye.Position + eye.Forward * 5000.0f ).UseHitboxes().IgnoreGameObject(pawn).Run(); + SceneTraceResult trace = player.BasicTrace(); entity.WorldPosition = trace.EndPosition + trace.Normal; diff --git a/Code/MeshBuilders/VertexMeshBuilder.Sphere.cs b/Code/MeshBuilders/VertexMeshBuilder.Sphere.cs index 833c416..b156ce2 100644 --- a/Code/MeshBuilders/VertexMeshBuilder.Sphere.cs +++ b/Code/MeshBuilders/VertexMeshBuilder.Sphere.cs @@ -105,12 +105,11 @@ public static void SpawnSphere( float radius, int numSegments = 16, int texSize var modelId = CreateSphere(radius, numSegments, texSize); var entity = SpawnEntity( modelId ); + Player player = Player.FindLocalPlayer(); - GameObject pawn = player.Controller.GameObject; - Transform eye = player.EyeTransform; - SceneTraceResult trace = pawn.Scene.Trace.Ray(eye.Position, eye.Position + eye.Forward * 5000.0f ).UseHitboxes().IgnoreGameObject(pawn).Run(); + SceneTraceResult trace = player.BasicTrace(); - entity.WorldPosition = trace.EndPosition + trace.Normal; + entity.WorldPosition = trace.EndPosition + trace.Normal + new Vector3(0, 0, radius); UndoSystem.Add( creator: player, callback: ReadyUndo( entity, "Sphere" ), prop: entity ); } diff --git a/Code/MeshBuilders/VertexMeshBuilder.cs b/Code/MeshBuilders/VertexMeshBuilder.cs index 0997a55..e090c30 100644 --- a/Code/MeshBuilders/VertexMeshBuilder.cs +++ b/Code/MeshBuilders/VertexMeshBuilder.cs @@ -54,10 +54,9 @@ public static void SpawnPlate( float length, float width, float height, int texS { var modelId = CreateRectangle( length, width, height, texSize ); var entity = SpawnEntity( modelId ); + Player player = Player.FindLocalPlayer(); - GameObject pawn = player.Controller.GameObject; - Transform eye = player.EyeTransform; - SceneTraceResult trace = pawn.Scene.Trace.Ray(eye.Position, eye.Position + eye.Forward * 5000.0f ).UseHitboxes().IgnoreGameObject(pawn).Run(); + SceneTraceResult trace = player.BasicTrace(); entity.WorldPosition = trace.EndPosition + trace.Normal; From 0e7f818cad52bd64fd59a2d4af88956c5cc08803 Mon Sep 17 00:00:00 2001 From: Nebual Date: Sun, 5 Jan 2025 03:19:01 -0800 Subject: [PATCH 13/16] Toolgun Previews: fixed doubling in multiplayer --- Code/Components/Base/BaseTool.cs | 15 +++++++-------- Code/Components/Tools/Thruster.cs | 2 +- Code/UI/Hud/Components/ColorSelector.cs | 2 +- Code/UI/Hud/Components/MaterialSelector.cs | 2 +- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Code/Components/Base/BaseTool.cs b/Code/Components/Base/BaseTool.cs index a52b98b..66dd237 100644 --- a/Code/Components/Base/BaseTool.cs +++ b/Code/Components/Base/BaseTool.cs @@ -33,27 +33,25 @@ public virtual bool Reload( SceneTraceResult trace ) public virtual void Activate() { - if ( previewModel != null ) - { - previewModel.Destroy(); - } - CreatePreview(); if ( !IsProxy ) { + previewModel?.Destroy(); + CreatePreview(); Sandbox.UI.ToolMenu.Instance?.UpdateInspector(); } } public virtual void Disabled() { - previewModel?.Destroy(); + if ( !IsProxy ) + previewModel?.Destroy(); } protected override void OnUpdate() { base.OnUpdate(); - if ( previewModel != null ) + if ( !IsProxy && previewModel != null ) { var trace = Parent.BasicTraceTool(); if ( IsPreviewTraceValid( trace ) ) @@ -76,7 +74,8 @@ protected override void OnUpdate() protected override void OnDestroy() { base.OnDestroy(); - previewModel?.Destroy(); + if ( !IsProxy ) + previewModel?.Destroy(); } protected string GetConvarValue( string name, string defaultValue = null ) { diff --git a/Code/Components/Tools/Thruster.cs b/Code/Components/Tools/Thruster.cs index c816135..904adc8 100644 --- a/Code/Components/Tools/Thruster.cs +++ b/Code/Components/Tools/Thruster.cs @@ -4,7 +4,7 @@ public class Thruster : BaseTool { [Property, Title( "Model" ), ModelProperty( SpawnLists = ["thruster"] )] public override string SpawnModel { get; set; } = "models/thruster/thrusterprojector.vmdl"; - [Property, Range( 0, 10000, 10 ), Title("Force Multiplier"), Description("The amount of force the thruster will apply to the attached object.")] + [Property, Range( 1, 10000, 10 ), Title("Force Multiplier"), Description("The amount of force the thruster will apply to the attached object.")] public float ForceMultiplier { get; set; } = 1000f; [Property] public bool Massless { get; set; } = true; diff --git a/Code/UI/Hud/Components/ColorSelector.cs b/Code/UI/Hud/Components/ColorSelector.cs index a0e27db..899b94e 100644 --- a/Code/UI/Hud/Components/ColorSelector.cs +++ b/Code/UI/Hud/Components/ColorSelector.cs @@ -44,7 +44,7 @@ protected override void OnParametersSet() return; } var sceneWorld = new SceneWorld(); - var mod = new SceneObject( sceneWorld, Cloud.Model( "https://asset.party/drakefruit.cube32" ), Transform.Zero ); + var mod = new SceneObject( sceneWorld, Cloud.Model( "drakefruit.cube32" ), Transform.Zero ); var color = colors[index]; mod.ColorTint = color; diff --git a/Code/UI/Hud/Components/MaterialSelector.cs b/Code/UI/Hud/Components/MaterialSelector.cs index e5d830c..7014e9e 100644 --- a/Code/UI/Hud/Components/MaterialSelector.cs +++ b/Code/UI/Hud/Components/MaterialSelector.cs @@ -88,7 +88,7 @@ private Panel AddLocalMaterialIcon( Panel cell, string file ) var material = Material.Load( file ); var sceneWorld = new SceneWorld(); - var mod = new SceneObject( sceneWorld, Cloud.Model( "https://asset.party/drakefruit/cube32" ), Transform.Zero ); + var mod = new SceneObject( sceneWorld, Cloud.Model( "drakefruit/cube32" ), Transform.Zero ); mod.SetMaterialOverride( material ); var sceneLight = new SceneLight( sceneWorld, Vector3.Up * 45.0f, 300.0f, Color.White * 30.0f ); From 047098bc0f98569a90b2a9c5af29874df4695953 Mon Sep 17 00:00:00 2001 From: Nebual Date: Thu, 26 Dec 2024 18:13:03 -0800 Subject: [PATCH 14/16] WIP Porting the Toolgun Screen --- Code/Components/Weapons/ToolGun.Screen.cs | 67 ++++ Code/Components/Weapons/ToolGun.cs | 3 + .../UI/Hud/Components}/ToolgunPanel.razor | 0 CodeOld/Tool.Preview.cs | 97 ------ CodeOld/Tool.cs | 293 ------------------ 5 files changed, 70 insertions(+), 390 deletions(-) create mode 100644 Code/Components/Weapons/ToolGun.Screen.cs rename {CodeOld/ui => Code/UI/Hud/Components}/ToolgunPanel.razor (100%) delete mode 100644 CodeOld/Tool.Preview.cs delete mode 100644 CodeOld/Tool.cs diff --git a/Code/Components/Weapons/ToolGun.Screen.cs b/Code/Components/Weapons/ToolGun.Screen.cs new file mode 100644 index 0000000..a757ea7 --- /dev/null +++ b/Code/Components/Weapons/ToolGun.Screen.cs @@ -0,0 +1,67 @@ +partial class ToolGun +{ + private Texture screenTexture; + private ToolgunPanel screenPanel; + private SceneCustomObject screenRenderObject; + + private void SetupToolgunPanel() + { + screenRenderObject = new SceneCustomObject( Scene.SceneWorld ) + { + RenderOverride = ToolgunScreenRender + }; + + screenPanel = new() + { + RenderedManually = true, + PanelBounds = new Rect( 0, 0, 1024, 1024 ), + }; + + UpdateToolgunPanel(); + + screenTexture = Texture.CreateRenderTarget().WithSize( screenPanel.PanelBounds.Size ).Create(); + } + private void DestroyToolgunPanel() + { + screenRenderObject?.Delete(); + screenRenderObject = null; + + screenPanel?.Delete(); + screenPanel = null; + // screenTexture.Dispose(); + } + private void UpdateToolgunPanel() + { + if ( !screenPanel.IsValid() ) return; + + var toolName = DisplayInfo.For( CurrentTool ).Name; + screenPanel.CurrentToolName = toolName; + if ( CurrentTool is Sandbox.Tools.ConstraintTool ctool ) + { + screenPanel.CurrentToolName = $"{toolName} | {ctool.Type.ToString()}"; + } + + if ( WorldModel.SceneObject.IsValid() ) + { + WorldModel.SceneObject.Batchable = false; + WorldModel.SceneObject.Attributes.Set( "screenTexture", screenTexture ); + } + + if ( ViewModel.Renderer.SceneObject.IsValid() ) + { + ViewModel.Renderer.SceneObject.Batchable = false; + ViewModel.Renderer.SceneObject.Attributes.Set( "screenTexture", screenTexture ); + } + } + private void ToolgunScreenRender( SceneObject sceneObject ) + { + Graphics.RenderTarget = RenderTarget.From( screenTexture ); + Graphics.Attributes.SetCombo( "D_WORLDPANEL", 0 ); + Graphics.Viewport = new Rect( 0, screenPanel.PanelBounds.Size ); + Graphics.Clear(); + + screenPanel.RenderManual(); + + Graphics.RenderTarget = null; + } +} diff --git a/Code/Components/Weapons/ToolGun.cs b/Code/Components/Weapons/ToolGun.cs index abe5645..008ca02 100644 --- a/Code/Components/Weapons/ToolGun.cs +++ b/Code/Components/Weapons/ToolGun.cs @@ -9,12 +9,14 @@ protected override void OnEnabled() { base.OnEnabled(); UpdateTool(); + SetupToolgunPanel(); } protected override void OnDisabled() { base.OnDisabled(); CurrentTool?.Disabled(); + DestroyToolgunPanel(); } public override bool WantsSnapGrid() @@ -42,6 +44,7 @@ protected override void OnUpdate() { base.OnUpdate(); UpdateEffects(); + UpdateToolgunPanel(); } public override void AttackPrimary() diff --git a/CodeOld/ui/ToolgunPanel.razor b/Code/UI/Hud/Components/ToolgunPanel.razor similarity index 100% rename from CodeOld/ui/ToolgunPanel.razor rename to Code/UI/Hud/Components/ToolgunPanel.razor diff --git a/CodeOld/Tool.Preview.cs b/CodeOld/Tool.Preview.cs deleted file mode 100644 index 8501555..0000000 --- a/CodeOld/Tool.Preview.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System.Collections.Generic; - -namespace Sandbox.Tools -{ - public partial class BaseTool - { - [Net] - public IList Previews { get; set; } - - protected virtual bool IsPreviewTraceValid( TraceResult tr ) - { - if ( !tr.Hit ) - return false; - - if ( !tr.Entity.IsValid() ) - return false; - - return true; - } - - public virtual void CreatePreviews() - { - // Nothing - } - - public virtual void DeletePreviews() - { - if ( !Game.IsServer ) - return; - - if ( Previews == null || Previews.Count == 0 ) - return; - - foreach ( var preview in Previews ) - { - preview.Delete(); - } - - Previews.Clear(); - } - - public virtual bool TryCreatePreview( ref PreviewEntity ent, string model ) - { - if ( !ent.IsValid() ) - { - ent = new PreviewEntity - { - Predictable = true, - Owner = Owner - }; - - ent.SetModel( model ); - } - - if ( Previews == null ) - { - Previews = new List(); - } - - if ( !Previews.Contains( ent ) ) - { - Previews.Add( ent ); - } - - return ent.IsValid(); - } - - public virtual void UpdatePreviews() - { - if ( Previews == null || Previews.Count == 0 ) - return; - - if ( !Owner.IsValid() ) - return; - - if ( !Owner.IsAuthority ) - return; - - var tr = DoTrace(); - - foreach ( var preview in Previews ) - { - if ( !preview.IsValid() ) - continue; - - if ( IsPreviewTraceValid( tr ) && preview.UpdateFromTrace( tr ) ) - { - preview.RenderColor = preview.RenderColor.WithAlpha( 0.5f ); - } - else - { - preview.RenderColor = preview.RenderColor.WithAlpha( 0.0f ); - } - } - } - } -} diff --git a/CodeOld/Tool.cs b/CodeOld/Tool.cs deleted file mode 100644 index b9f1181..0000000 --- a/CodeOld/Tool.cs +++ /dev/null @@ -1,293 +0,0 @@ -using Sandbox; -using Sandbox.Tools; -using Sandbox.UI; - -[Library( "weapon_tool", Title = "Toolgun" )] -partial class Tool : Carriable -{ - [ConVar.ClientData( "tool_current" )] - public static string UserToolCurrent { get; set; } = "tool_boxgun"; - - public AnimatedEntity ViewModelArms { get; set; } - - [Net, Change] - public BaseTool CurrentTool { get; set; } - - private Texture Texture; - private ToolgunPanel Panel; - private SceneCustomObject RenderObject; - - public override void Spawn() - { - base.Spawn(); - - SetModel( "models/weapons/toolgun.vmdl" ); - } - - public override void CreateViewModel() - { - base.CreateViewModel(); - - ViewModelEntity = new ViewModel(); - ViewModelEntity.Position = Position; - ViewModelEntity.Owner = Owner; - ViewModelEntity.EnableViewmodelRendering = true; - ViewModelEntity.Model = Model.Load( "models/weapons/v_toolgun.vmdl" ); - - ViewModelArms = new AnimatedEntity( "models/first_person/first_person_arms.vmdl" ); - ViewModelArms.SetParent( ViewModelEntity, true ); - ViewModelArms.EnableViewmodelRendering = true; - } - - public override void Simulate( IClient owner ) - { - if ( Game.IsServer ) - { - UpdateCurrentTool( owner ); - } - - CurrentTool?.Simulate(); - - if ( Game.IsServer ) - { - CurrentTool?.UpdatePreviews(); - } - } - - private void UpdateCurrentTool( IClient owner ) - { - var toolName = owner.GetClientData( "tool_current", "tool_balloon" ); - if ( toolName == null ) - return; - - // Already the right tool - if ( CurrentTool != null && CurrentTool.ClassName == toolName ) - return; - - if ( CurrentTool != null ) - { - CurrentTool?.Deactivate(); - CurrentTool = null; - } - - CurrentTool = TypeLibrary.Create( toolName ); - - if ( CurrentTool != null ) - { - CurrentTool.Parent = this; - CurrentTool.Owner = owner.Pawn as Player; - CurrentTool.Activate(); - } - } - - // Note: called clientside only - private void OnCurrentToolChanged( BaseTool oldTool, BaseTool newTool ) - { - oldTool?.Deactivate(); - newTool?.Activate(); - } - - private void UpdateToolgunPanel() - { - var toolName = DisplayInfo.For( CurrentTool ).Name; - Panel.CurrentToolName = toolName; - - //var type = DisplayInfo.For( CurrentTool ). - - if (CurrentTool is ConstraintTool ctool) - { - Panel.CurrentToolName = $"{toolName} | {ctool.Type.ToString()}"; - } - } - - public override void ActiveStart( Entity ent ) - { - base.ActiveStart( ent ); - - CurrentTool?.Activate(); - - if (Game.IsClient) - { - RenderObject = new SceneCustomObject( Game.SceneWorld ) - { - RenderOverride = ToolgunScreenRender - }; - - Panel = new() - { - RenderedManually = true, - PanelBounds = new Rect( 0, 0, 1024, 1024 ), - }; - - UpdateToolgunPanel(); - - Texture = Texture.CreateRenderTarget().WithSize( Panel.PanelBounds.Size ).Create(); - } - } - - private void ToolgunScreenRender( SceneObject sceneObject ) - { - Graphics.RenderTarget = RenderTarget.From( Texture ); - Graphics.Attributes.SetCombo( "D_WORLDPANEL", 0 ); - Graphics.Viewport = new Rect( 0, Panel.PanelBounds.Size ); - Graphics.Clear(); - - Panel.RenderManual(); - - Graphics.RenderTarget = null; - } - - public override void ActiveEnd( Entity ent, bool dropped ) - { - base.ActiveEnd( ent, dropped ); - - CurrentTool?.Deactivate(); - - if (Game.IsClient) - { - RenderObject?.Delete(); - RenderObject = null; - - Panel?.Delete(); - Panel = null; - } - } - - protected override void OnDestroy() - { - base.OnDestroy(); - - CurrentTool?.Deactivate(); - CurrentTool = null; - } - - public override void BuildInput() - { - CurrentTool?.BuildInput(); - } - - public override void OnCarryDrop( Entity dropper ) - { - } - - [Event.Client.Frame] - public void OnFrame() - { - if ( Owner is Player player && player.ActiveChild != this ) - return; - - CurrentTool?.OnFrame(); - - UpdateToolgunPanel(); - - // world model screen - if ( SceneObject.IsValid() ) - { - SceneObject.Batchable = false; - SceneObject.Attributes.Set( "screenTexture", Texture ); - } - - // view model screen - if ( ViewModelEntity.SceneObject.IsValid() ) - { - ViewModelEntity.SceneObject.Batchable = false; - ViewModelEntity.SceneObject.Attributes.Set( "screenTexture", Texture ); - } - } - - public override void SimulateAnimator( CitizenAnimationHelper anim ) - { - anim.HoldType = CitizenAnimationHelper.HoldTypes.Pistol; - anim.Handedness = CitizenAnimationHelper.Hand.Right; - anim.AimBodyWeight = 1.0f; - } - - public static void SetActiveTool( string toolId ) - { - ConsoleSystem.Run( "tool_current", toolId ); - InventoryBar.SetActiveSlot( "weapon_tool" ); - } -} - -namespace Sandbox.Tools -{ - public partial class BaseTool : BaseNetworkable - { - [Net] - public Tool Parent { get; set; } - - [Net] - public Player Owner { get; set; } - - protected virtual float MaxTraceDistance => 10000.0f; - - // Set this to override the [Library]'s class default - public string Description { get; set; } = null; - - public virtual void Activate() - { - if ( Game.IsServer ) - { - CreatePreviews(); - CurrentTool.CreateToolPanel(); - } - } - - public virtual void CreateToolPanel() - { - - } - - public virtual void Deactivate() - { - DeletePreviews(); - SpawnMenu.Instance?.ToolPanel?.DeleteChildren( true ); - } - - public virtual void Simulate() - { - - } - - public virtual void BuildInput() - { - - } - - public virtual void OnFrame() - { - UpdatePreviews(); - } - - public virtual void CreateHitEffects( Vector3 pos, Vector3 normal = new Vector3(), bool continuous = false ) - { - Parent?.CreateHitEffects( pos, normal, continuous ); - } - - public virtual TraceResult DoTrace( bool checkCanTool = true ) - { - var startPos = Owner.EyePosition; - var dir = Owner.EyeRotation.Forward; - - var tr = Trace.Ray( startPos, startPos + (dir * MaxTraceDistance) ) - .WithAnyTags( "solid", "nocollide" ) - .Ignore( Owner ) - .Run(); - - if ( checkCanTool && tr.Entity.IsValid() && !tr.Entity.IsWorld ) - { - return CanToolParams.RunCanTool( Owner, ClassName, tr ); - } - - return tr; - } - - protected string GetConvarValue( string name, string defaultValue = null ) - { - return Game.IsServer - ? Owner.Client.GetClientData( name, defaultValue ) - : ConsoleSystem.GetValue( name, default ); - } - } - -} From 3e8d4b2d05edf1ec54ccfef31c5443fd871c930f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrik=20=C5=A0imansk=C3=BD?= Date: Sun, 5 Jan 2025 15:09:51 +0100 Subject: [PATCH 15/16] Edit toolgun prefab to use proper model, fixes screen text --- Assets/models/weapons/v_toolgun.vmdl | 241 +---- .../weapons/toolgun/v_toolgun-gmod.prefab | 843 ++++-------------- Code/Components/Weapons/ToolGun.Effects.cs | 2 +- 3 files changed, 170 insertions(+), 916 deletions(-) diff --git a/Assets/models/weapons/v_toolgun.vmdl b/Assets/models/weapons/v_toolgun.vmdl index b156b79..c3e3eba 100644 --- a/Assets/models/weapons/v_toolgun.vmdl +++ b/Assets/models/weapons/v_toolgun.vmdl @@ -29,231 +29,6 @@ }, ] }, - { - _class = "Skeleton" - children = - [ - { - _class = "Bone" - name = "base" - children = - [ - { - _class = "Bone" - name = "bip01_l_upperarm" - children = - [ - { - _class = "Bone" - name = "bip01_l_forearm" - children = - [ - { - _class = "Bone" - name = "bip01_l_hand" - children = - [ - { - _class = "Bone" - name = "bip01_l_finger4" - children = - [ - { - _class = "Bone" - name = "bip01_l_finger41" - children = - [ - { - _class = "Bone" - name = "bip01_l_finger42" - origin = [ 0.729362, 0.000005, -0.000004 ] - angles = [ -0.0, -13.76284, 0.000005 ] - do_not_discard = true - }, - ] - origin = [ 1.312565, 0.000004, -0.000008 ] - angles = [ -0.000004, -24.951517, 0.000012 ] - do_not_discard = true - }, - ] - origin = [ 3.859673, -0.142406, -1.191969 ] - angles = [ 3.145481, -62.421795, -28.150337 ] - do_not_discard = true - }, - { - _class = "Bone" - name = "bip01_l_finger3" - children = - [ - { - _class = "Bone" - name = "bip01_l_finger31" - children = - [ - { - _class = "Bone" - name = "bip01_l_finger32" - origin = [ 1.196316, 0.000003, -0.000011 ] - angles = [ 0.000001, -33.315498, -0.0 ] - do_not_discard = true - }, - ] - origin = [ 1.539101, 0.000008, -0.000006 ] - angles = [ 0.0, -23.468119, 0.000001 ] - do_not_discard = true - }, - ] - origin = [ 3.942301, 0.046772, -0.431437 ] - angles = [ 4.411375, -44.499905, -8.601761 ] - do_not_discard = true - }, - { - _class = "Bone" - name = "bip01_l_finger2" - children = - [ - { - _class = "Bone" - name = "bip01_l_finger21" - children = - [ - { - _class = "Bone" - name = "bip01_l_finger22" - origin = [ 1.20919, 0.00001, -0.000002 ] - angles = [ -0.000006, -14.698598, -0.0 ] - do_not_discard = true - }, - ] - origin = [ 1.719585, -0.00001, -0.00001 ] - angles = [ -0.000004, -43.710213, -0.0 ] - do_not_discard = true - }, - ] - origin = [ 3.883667, -0.046772, 0.431444 ] - angles = [ 1.362149, -32.342499, 4.890194 ] - do_not_discard = true - }, - { - _class = "Bone" - name = "bip01_l_finger1" - children = - [ - { - _class = "Bone" - name = "bip01_l_finger11" - children = - [ - { - _class = "Bone" - name = "bip01_l_finger12" - origin = [ 1.099663, -0.000008, -0.000004 ] - angles = [ -0.000008, -20.307171, -0.000005 ] - do_not_discard = true - }, - ] - origin = [ 1.719429, -0.000002, -0.000011 ] - angles = [ -0.000001, -28.431828, -0.000008 ] - do_not_discard = true - }, - ] - origin = [ 3.859835, -0.137943, 1.332466 ] - angles = [ -2.775007, -24.387947, 27.729095 ] - do_not_discard = true - }, - { - _class = "Bone" - name = "bip01_l_finger0" - children = - [ - { - _class = "Bone" - name = "bip01_l_finger01" - children = - [ - { - _class = "Bone" - name = "bip01_l_finger02" - origin = [ 1.206974, 0.000004, -0.000011 ] - angles = [ -0.000005, 10.674148, 0.000003 ] - do_not_discard = true - }, - ] - origin = [ 1.789764, -0.000012, -0.000029 ] - angles = [ 0.000003, 12.181085, 0.000005 ] - do_not_discard = true - }, - ] - origin = [ 0.806047, -0.348915, 1.321253 ] - angles = [ -21.007607, -41.389721, -73.770386 ] - do_not_discard = true - }, - ] - origin = [ 11.481651, -0.000019, -0.000069 ] - angles = [ -19.451057, 30.993233, -4.940331 ] - do_not_discard = true - }, - ] - origin = [ 11.692525, -0.000027, -0.000031 ] - angles = [ 0.0, -47.984932, 0.0 ] - do_not_discard = true - }, - ] - origin = [ 7.723854, 3.14325, -1.366092 ] - angles = [ -64.403038, -123.34848, -17.001492 ] - do_not_discard = true - }, - { - _class = "Bone" - name = "arm" - children = - [ - { - _class = "Bone" - name = "hand" - children = - [ - { - _class = "Bone" - name = "python" - children = - [ - { - _class = "Bone" - name = "muzzle" - origin = [ -0.000132, 0.765274, 8.032595 ] - angles = [ -0.0, 0.0, 0.0 ] - do_not_discard = true - }, - { - _class = "Bone" - name = "smdimport02" - origin = [ 0.225976, -4.99025, 1.015465 ] - angles = [ 89.444672, 68.079567, -22.971142 ] - do_not_discard = true - }, - ] - origin = [ 0.09978, 3.177673, 4.325954 ] - angles = [ 0.207296, -1.050805, -0.515146 ] - do_not_discard = true - }, - ] - origin = [ 0.463462, 5.50676, 13.080228 ] - angles = [ -12.374972, 0.0, 0.0 ] - do_not_discard = true - }, - ] - origin = [ -7.018476, -0.538841, 8.058478 ] - angles = [ 12.374972, -0.0, -0.0 ] - do_not_discard = true - }, - ] - origin = [ 0.0, -0.878417, 54.32534 ] - angles = [ -0.0, 0.0, 89.999985 ] - do_not_discard = true - }, - ] - }, { _class = "MaterialGroupList" children = @@ -420,6 +195,7 @@ hidden = false anim_markup_ordered = false disable_compression = false + disable_interpolation = false enable_scale = false source_filename = "models/weapons/v_toolgun_refs/anim/_idle01_0.dmx" start_frame = -1 @@ -455,6 +231,7 @@ hidden = false anim_markup_ordered = false disable_compression = false + disable_interpolation = false enable_scale = false source_filename = "models/weapons/v_toolgun_refs/anim/_fire_1.dmx" start_frame = -1 @@ -477,6 +254,7 @@ hidden = false anim_markup_ordered = false disable_compression = false + disable_interpolation = false enable_scale = false source_filename = "models/weapons/v_toolgun_refs/anim/_draw_2.dmx" start_frame = -1 @@ -556,6 +334,7 @@ hidden = false anim_markup_ordered = false disable_compression = false + disable_interpolation = false enable_scale = false source_filename = "models/weapons/v_toolgun_refs/anim/_reload_3.dmx" start_frame = -1 @@ -578,6 +357,7 @@ hidden = false anim_markup_ordered = false disable_compression = false + disable_interpolation = false enable_scale = false source_filename = "models/weapons/v_toolgun_refs/anim/_holster_4.dmx" start_frame = -1 @@ -600,6 +380,7 @@ hidden = false anim_markup_ordered = false disable_compression = false + disable_interpolation = false enable_scale = false source_filename = "models/weapons/v_toolgun_refs/anim/_idletolow_5.dmx" start_frame = -1 @@ -622,6 +403,7 @@ hidden = false anim_markup_ordered = false disable_compression = false + disable_interpolation = false enable_scale = false source_filename = "models/weapons/v_toolgun_refs/anim/_lowtoidle_6.dmx" start_frame = -1 @@ -644,6 +426,7 @@ hidden = false anim_markup_ordered = false disable_compression = false + disable_interpolation = false enable_scale = false source_filename = "models/weapons/v_toolgun_refs/anim/_lowidle_7.dmx" start_frame = -1 @@ -666,6 +449,7 @@ hidden = false anim_markup_ordered = false disable_compression = false + disable_interpolation = false enable_scale = false source_filename = "models/weapons/v_toolgun_refs/anim/_idle01_0.dmx" start_frame = 0 @@ -688,6 +472,7 @@ hidden = false anim_markup_ordered = false disable_compression = false + disable_interpolation = false enable_scale = false source_filename = "models/weapons/v_toolgun_refs/anim/_fire_1.dmx" start_frame = 0 @@ -710,6 +495,7 @@ hidden = false anim_markup_ordered = false disable_compression = false + disable_interpolation = false enable_scale = false source_filename = "models/weapons/v_toolgun_refs/anim/_draw_2.dmx" start_frame = 0 @@ -732,6 +518,7 @@ hidden = false anim_markup_ordered = false disable_compression = false + disable_interpolation = false enable_scale = false source_filename = "models/weapons/v_toolgun_refs/anim/_reload_3.dmx" start_frame = 0 @@ -754,6 +541,7 @@ hidden = false anim_markup_ordered = false disable_compression = false + disable_interpolation = false enable_scale = false source_filename = "models/weapons/v_toolgun_refs/anim/_holster_4.dmx" start_frame = 0 @@ -776,6 +564,7 @@ hidden = false anim_markup_ordered = false disable_compression = false + disable_interpolation = false enable_scale = false source_filename = "models/weapons/v_toolgun_refs/anim/_idletolow_5.dmx" start_frame = 0 @@ -798,6 +587,7 @@ hidden = false anim_markup_ordered = false disable_compression = false + disable_interpolation = false enable_scale = false source_filename = "models/weapons/v_toolgun_refs/anim/_lowtoidle_6.dmx" start_frame = 0 @@ -820,6 +610,7 @@ hidden = false anim_markup_ordered = false disable_compression = false + disable_interpolation = false enable_scale = false source_filename = "models/weapons/v_toolgun_refs/anim/_lowidle_7.dmx" start_frame = 0 diff --git a/Assets/prefabs/weapons/toolgun/v_toolgun-gmod.prefab b/Assets/prefabs/weapons/toolgun/v_toolgun-gmod.prefab index 1e90286..32d190d 100644 --- a/Assets/prefabs/weapons/toolgun/v_toolgun-gmod.prefab +++ b/Assets/prefabs/weapons/toolgun/v_toolgun-gmod.prefab @@ -7,26 +7,28 @@ "Components": [ { "__type": "Sandbox.SkinnedModelRenderer", - "__guid": "1bb08c2f-5575-4add-9663-7f3769e1f360", - "BodyGroups": 147, + "__guid": "7d871118-8fd3-49b9-a946-89ef43cf4b38", + "BodyGroups": 18446744073709551615, "CreateAttachments": false, - "CreateBoneObjects": true, - "Model": "models/weapons/sbox_pistol_usp/v_usp.vmdl", + "CreateBoneObjects": false, + "Model": "models/weapons/v_toolgun.vmdl", "Morphs": {}, "Parameters": { - "bools": {}, + "bools": { + "fire": false + }, "ints": {}, "floats": {}, "vectors": {}, "rotations": {} }, "RenderOptions": { - "GameLayer": false, + "GameLayer": true, "OverlayLayer": false, "BloomLayer": false, "AfterUILayer": false }, - "RenderType": "Off", + "RenderType": "On", "Sequence": { "Name": null }, @@ -47,464 +49,171 @@ ], "Children": [ { - "__guid": "f7851622-0c8d-44ab-ba1c-15b1133acc90", - "Flags": 4, - "Name": "weapon_root", - "Position": "-2.16535,-0.000000000008270717,3.1496", + "__guid": "76f3f6f0-fa13-46f3-8cc1-54fcdc82d7aa", + "Flags": 0, + "Name": "base", + "Position": "-3.121189,-1.999545,-12.6728", + "Rotation": "0.5,0.4999568,0.5,0.5000431", "Enabled": true, "Children": [ { - "__guid": "61c6f8cc-c232-4509-aa7d-8ac94a4455d9", - "Flags": 4, - "Name": "weapon_root_children", - "Enabled": true, - "Children": [ - { - "__guid": "08a47f24-9f23-40ba-bec2-2e6352f67b76", - "Flags": 4, - "Name": "silencer", - "Position": "6.013762,-0.0000003516906,1.795536", - "Enabled": true - }, - { - "__guid": "f4f13c39-9927-43d6-bb7e-ccd90815377f", - "Flags": 4, - "Name": "slide", - "Position": "1.32287,0.0000001710258,1.630533", - "Enabled": true - }, - { - "__guid": "84f9e44c-6684-4dce-a969-4d416f2e4f8b", - "Flags": 4, - "Name": "slide_catch", - "Position": "2.356294,0.5472428,0.8523614", - "Rotation": "0.00000000000002842171,0.0000001509957,1,-0.0000001509958", - "Enabled": true - }, - { - "__guid": "87d33363-0fcc-417f-8053-8f0e1f9466f3", - "Flags": 4, - "Name": "hammer", - "Position": "-0.9212563,0.0000003579457,0.9763753", - "Rotation": "0.4226182,0.00000007405067,0.9063078,0.00000007256151", - "Enabled": true - }, - { - "__guid": "fe87114d-9393-4370-b6f3-9d2d74ef2f74", - "Flags": 4, - "Name": "safety", - "Position": "-0.9448798,0.5472435,0.9035423", - "Enabled": true - }, - { - "__guid": "93a5c0cf-eccc-4e4a-a15a-b920b112d89b", - "Flags": 4, - "Name": "magazine", - "Position": "-0.07164717,-0.0000001187523,-0.8246388", - "Rotation": "0.00000002971902,0.7986354,0.00000002971902,0.6018152", - "Enabled": true - }, - { - "__guid": "3d2eeeed-86a9-453a-bd05-354c9b792435", - "Flags": 4, - "Name": "trigger", - "Position": "1.952979,-0.0000001178662,0.6523969", - "Rotation": "0.00000002107339,0.7071064,-0.00000002107339,0.7071072", - "Enabled": true - }, - { - "__guid": "c604167a-b9b8-442b-a926-67e829c137e8", - "Flags": 4, - "Name": "weapon_IK_hand_L", - "Position": "0.0000002384186,0.0000001462819,-0.3936996", - "Enabled": true, - "Children": [ - { - "__guid": "429abf03-76e6-4068-9764-087c8158eba7", - "Flags": 4, - "Name": "hand_L_to_weapon_ikrule", - "Position": "3.459822,20.35885,-23.28971", - "Rotation": "0.7375996,0.5432281,-0.1922896,0.3519578", - "Enabled": true - } - ] - }, - { - "__guid": "c1e71be0-7127-444e-8268-0066a9671c09", - "Flags": 4, - "Name": "weapon_IK_hand_R", - "Position": "-0.0000004768372,0.00000004144886,0.3937001", - "Enabled": true, - "Children": [ - { - "__guid": "07cc7d38-2475-4486-87b0-920b7fc8ffcf", - "Flags": 4, - "Name": "hand_R_to_weapon_ikrule", - "Position": "3.459746,-20.35898,-24.07686", - "Rotation": "0.351961,0.1924756,-0.5431402,0.7376144", - "Enabled": true - } - ] - } - ] - }, - { - "__guid": "78f88add-47e3-4fc9-a9d9-ee02a1ac4a28", - "Flags": 0, - "Name": "Object", - "Position": "0.07232965,0.0000009653522,-4.314949", - "Enabled": true, - "Components": [ - { - "__type": "Sandbox.SkinnedModelRenderer", - "__guid": "dca266a1-9edb-4691-b6d9-d874a40ad3d5", - "__enabled": false, - "BodyGroups": 18446744073709551615, - "CreateAttachments": false, - "CreateBoneObjects": false, - "Model": "models/weapons/sbox_toolgun/v_toolgun.vmdl", - "Morphs": {}, - "Parameters": { - "bools": {}, - "ints": {}, - "floats": {}, - "vectors": {}, - "rotations": {} - }, - "RenderOptions": { - "GameLayer": false, - "OverlayLayer": true, - "BloomLayer": false, - "AfterUILayer": false - }, - "RenderType": "Off", - "Sequence": { - "Name": null - }, - "Tint": "1,1,1,0.64", - "UseAnimGraph": true - } - ] - }, - { - "__guid": "1fd9ce11-3d49-4fd5-a861-e0c1b80f7bc9", + "__guid": "998b2226-b118-4cfa-a7b0-fb95c312ec6f", "Flags": 0, - "Name": "v_toolgun", - "Position": "-23.22378,5.869469,5.142288", - "Enabled": true, - "Components": [ - { - "__type": "Sandbox.SkinnedModelRenderer", - "__guid": "eaa1db58-198b-4bb2-b588-1c179834818f", - "BodyGroups": 18446744073709551615, - "CreateAttachments": false, - "CreateBoneObjects": false, - "Model": "models/weapons/v_toolgun.vmdl", - "Morphs": {}, - "Parameters": { - "bools": { - "deploy": true, - "fire": true - }, - "ints": {}, - "floats": {}, - "vectors": {}, - "rotations": {} - }, - "RenderOptions": { - "GameLayer": false, - "OverlayLayer": true, - "BloomLayer": false, - "AfterUILayer": false - }, - "RenderType": "Off", - "Sequence": { - "Name": "@idle01" - }, - "Tint": "1,1,1,1", - "UseAnimGraph": true - } - ] - } - ] - }, - { - "__guid": "ea2d8b8e-dec6-42d5-9e14-d638a364f74d", - "Flags": 4, - "Name": "root", - "Position": "-0.0000001877308,-0.00001887501,-7.874", - "Enabled": true, - "Children": [ - { - "__guid": "a0138af3-3c85-4925-b4d3-0c365a56b1f8", - "Flags": 4, - "Name": "clavicle_R", - "Position": "-1.429641,-0.8201163,2.590545", - "Rotation": "-0.06705476,0.06738581,-0.7037535,0.7040551", + "Name": "bip01_l_upperarm", + "Position": "7.723855,3.143246,-1.366092", + "Rotation": "-0.5228332,-0.1404518,-0.7745524,0.3270891", "Enabled": true, "Children": [ { - "__guid": "8271b6b8-d0fa-41ce-9f82-f6fc49e71d13", - "Flags": 4, - "Name": "arm_upper_R", - "Position": "5.426218,-0.002544641,0.002319813", - "Rotation": "0.1107392,0.4159558,0.00414376,0.9026074", + "__guid": "6035810c-019b-4e0f-a302-10660e8029c0", + "Flags": 0, + "Name": "bip01_l_forearm", + "Position": "11.69252,-0.00002098083,-0.00003290176", + "Rotation": "0,0,-0.4054731,0.914107", "Enabled": true, "Children": [ { - "__guid": "fd8e0fb4-88ae-4a3e-bd96-ba51d065e699", - "Flags": 4, - "Name": "arm_lower_R", - "Position": "10.94515,0.00000667572,0.00005340576", - "Rotation": "-0.01563785,-0.02393212,0.1799621,0.9832578", + "__guid": "2bd363d6-4d26-42c0-ac11-e3f2139b2c19", + "Flags": 0, + "Name": "bip01_l_hand", + "Position": "11.48165,-0.00002193451,-0.0000667572", + "Rotation": "0.003927832,-0.1744216,0.2556544,0.9508956", "Enabled": true, "Children": [ { - "__guid": "0717ed5c-5f5c-4629-a5d2-dc41f4dc4d21", - "Flags": 4, - "Name": "hand_R", - "Position": "10.36437,-0.001419067,-0.001363277", - "Rotation": "0.02638427,0.0006438484,0.01404424,0.999553", + "__guid": "56736d43-e7ce-46b5-bc60-05a249edb06f", + "Flags": 0, + "Name": "bip01_l_finger0", + "Position": "0.8060436,-0.3489163,1.321255", + "Rotation": "0.6035912,-0.07212535,0.3802659,-0.6970463", "Enabled": true, "Children": [ { - "__guid": "e5309e64-e60a-45a6-88ca-04f00c65a97e", - "Flags": 4, - "Name": "finger_index_meta_R", - "Position": "1.00956,0.7745457,0.1725836", - "Rotation": "-0.04047208,0.02566848,0.06541568,0.9967065", - "Enabled": true, - "Children": [ - { - "__guid": "7c73b80f-20fd-4716-ad49-bc8396b0872a", - "Flags": 4, - "Name": "finger_index_0_R", - "Position": "2.741016,-0.00002479553,-0.00001335144", - "Rotation": "-0.001758285,0.1513932,-0.1150074,0.9817587", - "Enabled": true, - "Children": [ - { - "__guid": "d48e0a78-58d7-4416-a9af-f31d0ac4ebfe", - "Flags": 4, - "Name": "finger_index_1_R", - "Position": "1.70854,0.00001716614,0.00005531311", - "Rotation": "0.002091558,0.2310217,0.009050807,0.9729041", - "Enabled": true, - "Children": [ - { - "__guid": "55c22667-89ac-44d6-85f7-7b1c774fadb8", - "Flags": 4, - "Name": "finger_index_2_R", - "Position": "1.148014,0.00002670288,0.00008392334", - "Rotation": "-0.00008957077,0.09341335,0.00001147387,0.9956274", - "Enabled": true - } - ] - } - ] - } - ] - }, - { - "__guid": "c760e826-f81c-4b7b-978e-5ac058325aff", - "Flags": 4, - "Name": "hold_R", - "Position": "2.131824,-0.128933,-2.895808", - "Rotation": "-0.3298892,0.6145935,0.472482,0.5387102", - "Enabled": true - }, - { - "__guid": "93bc9486-7d6f-4217-840f-370aed72ee90", - "Flags": 4, - "Name": "finger_middle_meta_R", - "Position": "1.028294,0.2655582,0.3161802", - "Rotation": "0.02050317,0.02322228,-0.02369354,0.9992391", + "__guid": "b9d7c956-0880-4c04-9b98-87463d509195", + "Flags": 0, + "Name": "bip01_l_finger01", + "Position": "1.789062,-0.000004768372,-0.00001716614", + "Rotation": "0,0,-0.1060946,-0.994356", "Enabled": true, "Children": [ { - "__guid": "8559a2d4-d40f-4eef-9e19-90cd5485b297", - "Flags": 4, - "Name": "finger_middle_0_R", - "Position": "2.707701,-0.0002651215,0.0007266998", - "Rotation": "-0.00003993325,0.205134,-0.1114805,0.972364", - "Enabled": true, - "Children": [ - { - "__guid": "d39a608c-917d-418e-b401-574c610a62d9", - "Flags": 4, - "Name": "finger_middle_1_R", - "Position": "2.135763,0.00003433228,0.00008869171", - "Rotation": "0.0000006854514,0.2358537,-0.000002056357,0.9717885", - "Enabled": true, - "Children": [ - { - "__guid": "120426ee-be3b-42ee-80b1-bd601a71e8fb", - "Flags": 4, - "Name": "finger_middle_2_R", - "Position": "1.302551,0.00003814697,0.000125885", - "Rotation": "-0.000002235171,0.05306637,0.000004291529,0.9985909", - "Enabled": true - } - ] - } - ] + "__guid": "7a7d66ee-580e-4079-a7dc-7f45f32ea1d7", + "Flags": 0, + "Name": "bip01_l_finger02", + "Position": "1.206055,0.000002861023,-0.00001525879", + "Rotation": "0,0,-0.09297307,-0.9956686", + "Enabled": true } ] - }, + } + ] + }, + { + "__guid": "d0e5b87e-9ee5-40fa-bd5b-db3ab9748fc1", + "Flags": 0, + "Name": "bip01_l_finger4", + "Position": "3.859375,-0.142334,-1.191406", + "Rotation": "-0.1941039,0.1487397,-0.4967196,0.8327483", + "Enabled": true, + "Children": [ { - "__guid": "4aff09ae-683b-4cc3-a539-2939577abf3a", - "Flags": 4, - "Name": "finger_ring_meta_R", - "Position": "0.8090363,-0.2103157,0.2046213", - "Rotation": "0.0544576,0.03842242,-0.1190179,0.9906527", + "__guid": "e43066e2-6395-4002-a721-8860d20c61cd", + "Flags": 0, + "Name": "bip01_l_finger41", + "Position": "1.3125,0.00001335144,-0.000007629395", + "Rotation": "0,0,0.2159876,-0.9763961", "Enabled": true, "Children": [ { - "__guid": "01fb4cdb-a1f4-461e-a53b-959664c81b6d", - "Flags": 4, - "Name": "finger_ring_0_R", - "Position": "2.711071,0.00006866455,-0.00009536743", - "Rotation": "0.006056809,0.1630708,-0.04758999,0.9854472", - "Enabled": true, - "Children": [ - { - "__guid": "f4a35931-00ab-4560-a2f0-7573be21819b", - "Flags": 4, - "Name": "finger_ring_1_R", - "Position": "1.850401,0.00001144409,0.0000667572", - "Rotation": "-0.0000001192084,0.2274025,0.00000220537,0.9738008", - "Enabled": true, - "Children": [ - { - "__guid": "048079e1-7d8d-4ae2-90bf-0bd5f0c9ba04", - "Flags": 4, - "Name": "finger_ring_2_R", - "Position": "1.216137,0.00003814697,0.00009536743", - "Rotation": "-0.000003024933,0.0445767,0.000002473591,0.999006", - "Enabled": true - } - ] - } - ] + "__guid": "650e29fc-a2c3-4d74-b037-119b2490611a", + "Flags": 0, + "Name": "bip01_l_finger42", + "Position": "0.7290039,0.000005722046,0.000003814697", + "Rotation": "0,0,0.1197773,-0.9928008", + "Enabled": true } ] - }, + } + ] + }, + { + "__guid": "b91f5afb-8e2c-405d-9070-f747dedcfd86", + "Flags": 0, + "Name": "bip01_l_finger3", + "Position": "3.941406,0.04675293,-0.4313965", + "Rotation": "-0.05481699,0.06388122,-0.3746116,0.9233528", + "Enabled": true, + "Children": [ { - "__guid": "cbf918c0-5d7c-406f-8ac7-866e57c1b6be", - "Flags": 4, - "Name": "finger_pinky_meta_R", - "Position": "0.5258656,-0.6023293,0.0022192", - "Rotation": "0.1081678,0.05519912,-0.1998304,0.9722758", + "__guid": "e33ca56d-a0ef-4d86-b560-bd382b4c8e55", + "Flags": 0, + "Name": "bip01_l_finger31", + "Position": "1.539062,0.000007629395,-0.000007629395", + "Rotation": "0,0,0.2033408,-0.979108", "Enabled": true, "Children": [ { - "__guid": "cf6e782f-3246-487d-b255-b8d8da92e29f", - "Flags": 4, - "Name": "finger_pinky_0_R", - "Position": "2.652506,-0.000125885,0.0008115768", - "Rotation": "0.004825294,0.2119743,-0.03207982,0.9767365", - "Enabled": true, - "Children": [ - { - "__guid": "c792e238-0612-436a-adfa-a4990d42d1f5", - "Flags": 4, - "Name": "finger_pinky_1_R", - "Position": "1.49683,0.00004196167,0.0000705719", - "Rotation": "0.000001549719,0.06950022,-0.000002682207,0.997582", - "Enabled": true, - "Children": [ - { - "__guid": "601ed454-631a-47d6-9e2d-0e88a5f3eef8", - "Flags": 4, - "Name": "finger_pinky_2_R", - "Position": "0.8798122,0.00003814697,0.00005912781", - "Rotation": "-0.000002011654,0.05698804,0.000006929033,0.9983748", - "Enabled": true - } - ] - } - ] + "__guid": "fb577759-28cd-41cc-80d0-a13c8196b938", + "Flags": 0, + "Name": "bip01_l_finger32", + "Position": "1.196289,0.000003814697,-0.000003814697", + "Rotation": "0,0,0.2866454,-0.9580367", + "Enabled": true } ] - }, - { - "__guid": "82d5bcfb-5772-4a53-9b4d-5da9a9f68533", - "Flags": 4, - "Name": "hand_L_to_R_ikrule", - "Position": "-27.10839,6.606201,-29.65517", - "Rotation": "0.1621513,0.6658908,0.0001014471,0.7282143", - "Enabled": true - }, + } + ] + }, + { + "__guid": "47bb3c36-6427-48e3-9968-6ecffc1dd4d6", + "Flags": 0, + "Name": "bip01_l_finger2", + "Position": "3.882812,-0.04675293,0.4313965", + "Rotation": "0.04424206,-0.0004747928,-0.2787034,0.9593575", + "Enabled": true, + "Children": [ { - "__guid": "f2463d0c-7cd8-48b0-b85a-20c075151a0a", - "Flags": 4, - "Name": "finger_thumb_0_R", - "Position": "0.782486,1.041656,-0.7666664", - "Rotation": "-0.5439335,-0.00220798,0.2862355,0.788797", + "__guid": "0dbeeb39-b054-47ce-88a3-96876374ba3a", + "Flags": 0, + "Name": "bip01_l_finger21", + "Position": "1.71875,-0.000008583069,-0.00001811981", + "Rotation": "0,0,-0.3722376,0.9281375", "Enabled": true, "Children": [ { - "__guid": "618b53f8-3e9c-4f1d-baf5-92ff326c8f0c", - "Flags": 4, - "Name": "finger_thumb_1_R", - "Position": "1.872047,0.000003814697,0.000009536743", - "Rotation": "-0.002320164,0.1922001,-0.0545623,0.979835", - "Enabled": true, - "Children": [ - { - "__guid": "a1165812-81a0-468d-826d-d7933c8aea8c", - "Flags": 4, - "Name": "finger_thumb_2_R", - "Position": "1.429722,0.00001525879,0.00002002716", - "Rotation": "-0.00001193582,0.04035185,-0.00007612996,0.9991854", - "Enabled": true - } - ] + "__guid": "ef0a60d2-001e-43dd-a6e5-74ba572c7991", + "Flags": 0, + "Name": "bip01_l_finger22", + "Position": "1.208984,0.000009536743,-0.0000009536743", + "Rotation": "0,0,0.1278919,-0.9917881", + "Enabled": true } ] } ] }, { - "__guid": "bdc9d124-6d1c-40e0-8368-101c892ae919", - "Flags": 4, - "Name": "arm_lower_R_twistctrl0", + "__guid": "9e9604a3-2f4a-437b-b681-eeab5ccd3817", + "Flags": 0, + "Name": "bip01_l_finger1", + "Position": "3.859375,-0.1379395,1.332031", + "Rotation": "0.2291523,-0.07354973,-0.1993267,0.9499203", "Enabled": true, "Children": [ { - "__guid": "51780a9a-5448-4649-a1d1-9a94ca51fb45", - "Flags": 4, - "Name": "arm_lower_R_twist0", - "Enabled": true - }, - { - "__guid": "ef5bd252-dcae-405c-8541-81af729df939", - "Flags": 4, - "Name": "arm_lower_R_twistctrl1", - "Position": "3.454803,0.000003814697,0.00009489059", - "Rotation": "0.006869947,-0.000001654028,-0.000001758336,0.9999764", + "__guid": "887b1b18-9a95-43f4-868d-ae65d35b1d26", + "Flags": 0, + "Name": "bip01_l_finger11", + "Position": "1.71875,-0.0000004768372,-0.000008583069", + "Rotation": "0,0,-0.2455543,0.9693829", "Enabled": true, "Children": [ { - "__guid": "250be2ff-a593-474c-ad68-f1bb7ce739cd", - "Flags": 4, - "Name": "arm_lower_R_twistctrl2", - "Position": "3.454796,0.00001525879,0.00008583069", - "Rotation": "0.01274787,0.0002240984,-0.0002042947,0.9999186", - "Enabled": true, - "Children": [ - { - "__guid": "128e6487-a380-4ea2-ad7a-b68a8c4be7a1", - "Flags": 4, - "Name": "arm_lower_R_twist2", - "Enabled": true - } - ] - }, - { - "__guid": "43721ad4-feb6-4ccf-a7fd-c2a8ed05ba85", - "Flags": 4, - "Name": "arm_lower_R_twist1", + "__guid": "e546ddb4-4c74-4164-b610-2e30f5896754", + "Flags": 0, + "Name": "bip01_l_finger12", + "Position": "1.099609,-0.000007629395,-0.000005722046", + "Rotation": "0,0,-0.1762776,0.9843405", "Enabled": true } ] @@ -518,280 +227,44 @@ ] }, { - "__guid": "0aaa70e9-04e2-42df-ab98-daea5d43b6b6", - "Flags": 4, - "Name": "clavicle_L", - "Position": "-1.429637,0.8201643,2.590543", - "Rotation": "-0.7037544,-0.7040542,0.06705465,0.06738564", + "__guid": "33d11293-532d-4d7b-9ea5-6524627cf0fa", + "Flags": 0, + "Name": "arm", + "Position": "-7.037999,-0.5349399,8.058477", + "Rotation": "0,-0.107778,0,-0.994175", "Enabled": true, "Children": [ { - "__guid": "eb613aa7-3547-4419-8495-85dd3cd25dcd", - "Flags": 4, - "Name": "arm_upper_L", - "Position": "5.426217,0.002570391,0.002308846", - "Rotation": "-0.1252351,-0.4164101,-0.002264485,0.9005075", + "__guid": "fc942f87-4082-4783-ac03-0926bbb9367a", + "Flags": 0, + "Name": "hand", + "Position": "0.4634628,5.506761,13.08023", + "Rotation": "0,0.107778,0.0002661308,-0.994175", "Enabled": true, "Children": [ { - "__guid": "23238f1e-e457-44c5-a1b2-caaf81211c85", - "Flags": 4, - "Name": "arm_lower_L", - "Position": "10.94515,-0.000003814697,0.00004768372", - "Rotation": "0.03165575,0.02099543,0.1803237,0.9828734", + "__guid": "257dc7f2-e951-4a02-a79e-dcf2513daa55", + "Flags": 0, + "Name": "python", + "Position": "0.09977913,3.17767,4.325956", + "Rotation": "0.004445788,-0.001812845,0.009150553,-0.9999466", "Enabled": true, "Children": [ { - "__guid": "ad39ab87-5cec-4cd5-b02e-512fc28c0012", - "Flags": 4, - "Name": "hand_L", - "Position": "10.36445,-0.001377583,0.001556396", - "Rotation": "-0.02650667,-0.0004779093,0.01403562,0.9995499", - "Enabled": true, - "Children": [ - { - "__guid": "4f3bf2a5-e488-40de-bf10-bb133676d185", - "Flags": 4, - "Name": "finger_index_meta_L", - "Position": "1.009544,0.7745352,-0.1725616", - "Rotation": "0.04034133,-0.02579185,0.06547282,0.9967048", - "Enabled": true, - "Children": [ - { - "__guid": "07c33e11-46b2-4980-aeb6-ea2b4cf36bf3", - "Flags": 4, - "Name": "finger_index_0_L", - "Position": "2.740973,-0.00009727478,0.0001602173", - "Rotation": "0.001760619,-0.1513791,-0.1150281,0.9817585", - "Enabled": true, - "Children": [ - { - "__guid": "68007c4e-6222-4ebe-ad02-5dbe434aaf68", - "Flags": 4, - "Name": "finger_index_1_L", - "Position": "1.708509,-0.00004482269,0.00004005432", - "Rotation": "-0.001900692,-0.2311335,0.008941713,0.972879", - "Enabled": true, - "Children": [ - { - "__guid": "7119ab90-7303-4d24-b4f7-2243703ab3c7", - "Flags": 4, - "Name": "finger_index_2_L", - "Position": "1.147953,-0.00004291534,0.00001144409", - "Rotation": "-0.00000354647,-0.09325068,-0.0000039339,0.9956427", - "Enabled": true - } - ] - } - ] - } - ] - }, - { - "__guid": "80373b25-eaf1-4d9d-b40e-a74fdc30d445", - "Flags": 4, - "Name": "finger_middle_meta_L", - "Position": "1.028284,0.2655334,-0.3161545", - "Rotation": "-0.02050316,-0.02322214,-0.02369231,0.9992391", - "Enabled": true, - "Children": [ - { - "__guid": "b67e7b6f-e6ce-456f-94a0-5b19c0b5e187", - "Flags": 4, - "Name": "finger_middle_0_L", - "Position": "2.707668,-0.0003166199,-0.000535965", - "Rotation": "0.00003963709,-0.2051331,-0.1114803,0.9723644", - "Enabled": true, - "Children": [ - { - "__guid": "2d4eaa64-aad0-41d9-837e-e6e7b52e247e", - "Flags": 4, - "Name": "finger_middle_1_L", - "Position": "2.135733,-0.00003528595,0.00002479553", - "Rotation": "-0.000001043081,-0.2358476,0.000000968575,0.9717901", - "Enabled": true, - "Children": [ - { - "__guid": "5b0c4293-3ab4-4b6f-88a1-bc16612bdf8b", - "Flags": 4, - "Name": "finger_middle_2_L", - "Position": "1.302561,-0.00003910065,0.000003814697", - "Rotation": "-0.0000002682202,-0.05306333,-0.000003248449,0.9985911", - "Enabled": true - } - ] - } - ] - } - ] - }, - { - "__guid": "e15a7293-fcab-43c8-8791-25d87f2b4b58", - "Flags": 4, - "Name": "finger_ring_meta_L", - "Position": "0.8090267,-0.2103491,-0.2045956", - "Rotation": "-0.05446089,-0.0384258,-0.1190159,0.9906526", - "Enabled": true, - "Children": [ - { - "__guid": "9e435d6d-5e60-4ac9-9694-fc9a5ab3ed6b", - "Flags": 4, - "Name": "finger_ring_0_L", - "Position": "2.711048,-0.00002098083,0.0003070831", - "Rotation": "-0.006054493,-0.163065,-0.04758894,0.9854482", - "Enabled": true, - "Children": [ - { - "__guid": "b030d9c9-93d6-437e-8095-2e9a74ed4c9c", - "Flags": 4, - "Name": "finger_ring_1_L", - "Position": "1.850407,-0.00002670288,0.00002288818", - "Rotation": "-0.0000005215421,-0.2273964,0.00000327825,0.9738022", - "Enabled": true, - "Children": [ - { - "__guid": "4bf8cd85-b304-4268-8cf5-11a4a647fd3e", - "Flags": 4, - "Name": "finger_ring_2_L", - "Position": "1.216141,-0.00005340576,0.00001907349", - "Rotation": "-0.000000819562,-0.04457451,-0.000005811443,0.999006", - "Enabled": true - } - ] - } - ] - } - ] - }, - { - "__guid": "a85ed067-d1e7-4bff-848b-9a9a5a9270da", - "Flags": 4, - "Name": "finger_pinky_meta_L", - "Position": "0.5258675,-0.6023722,-0.002191544", - "Rotation": "-0.1081741,-0.05520602,-0.1998289,0.9722751", - "Enabled": true, - "Children": [ - { - "__guid": "8b35194d-9882-4f1a-83c2-4f2a8db3f226", - "Flags": 4, - "Name": "finger_pinky_0_L", - "Position": "2.652481,-0.000207901,-0.000617981", - "Rotation": "-0.004820984,-0.211965,-0.03207525,0.9767388", - "Enabled": true, - "Children": [ - { - "__guid": "b1d9dcbe-b4ad-43f7-8813-23e9814128a3", - "Flags": 4, - "Name": "finger_pinky_1_L", - "Position": "1.496832,-0.00001716614,0.00001907349", - "Rotation": "-0.0000009536729,-0.06949321,-0.000001400707,0.9975823", - "Enabled": true, - "Children": [ - { - "__guid": "13ffc34f-28e2-4501-b82b-daa2caba4446", - "Flags": 4, - "Name": "finger_pinky_2_L", - "Position": "0.8798294,-0.00002527237,0.000007629395", - "Rotation": "0.0000006556502,-0.05698914,0.0000001490114,0.9983748", - "Enabled": true - } - ] - } - ] - } - ] - }, - { - "__guid": "a8fff37a-c253-41c9-8edf-3569f71d262e", - "Flags": 4, - "Name": "hold_L", - "Position": "2.130785,-0.1296434,2.896551", - "Rotation": "0.3298808,-0.6147375,0.472468,0.5385633", - "Enabled": true - }, - { - "__guid": "723cefee-b50d-4818-a231-3dfc28a97f71", - "Flags": 4, - "Name": "hand_R_to_L_ikrule", - "Position": "-27.11883,6.598578,29.64734", - "Rotation": "-0.1621506,-0.6658909,-0.0001011789,0.7282146", - "Enabled": true - }, - { - "__guid": "a5ac88d1-919a-4458-9255-841c27cad136", - "Flags": 4, - "Name": "finger_thumb_0_L", - "Position": "0.7824764,1.041647,0.7668552", - "Rotation": "0.5439206,0.002201572,0.286238,0.7888048", - "Enabled": true, - "Children": [ - { - "__guid": "0121f1fc-1214-497e-a57e-dc729271fc4e", - "Flags": 4, - "Name": "finger_thumb_1_L", - "Position": "1.871769,-0.00003433228,0.00002288818", - "Rotation": "0.00234154,-0.1922023,-0.05457207,0.9798338", - "Enabled": true, - "Children": [ - { - "__guid": "e1104b6a-6b2a-47c9-a9bf-5896275bc72a", - "Flags": 4, - "Name": "finger_thumb_2_L", - "Position": "1.429802,-0.00002861023,0.00003433228", - "Rotation": "0.000005446372,-0.04035011,-0.00006930898,0.9991856", - "Enabled": true - } - ] - } - ] - } - ] + "__guid": "a15c0302-70ad-479a-9a31-ac2e1833b568", + "Flags": 0, + "Name": "muzzle", + "Position": "-0.0001182556,0.7652659,8.032595", + "Rotation": "0,0,0,-1", + "Enabled": true }, { - "__guid": "5fa6c80e-78d2-4a1f-8e03-9542e7c75550", - "Flags": 4, - "Name": "arm_lower_L_twistctrl0", - "Enabled": true, - "Children": [ - { - "__guid": "37c79060-0100-42e7-99dd-f98bf93f2940", - "Flags": 4, - "Name": "arm_lower_L_twistctrl1", - "Position": "3.454824,-0.000009536743,-0.00001716614", - "Rotation": "-0.006869581,0.0000009834762,0.000004924831,0.9999764", - "Enabled": true, - "Children": [ - { - "__guid": "fd63ed8a-8165-4873-85b4-b1d4d8ac891e", - "Flags": 4, - "Name": "arm_lower_L_twistctrl2", - "Position": "3.45483,-0.00001764297,-0.00001144409", - "Rotation": "-0.01274831,-0.0002229808,-0.0002084298,0.9999186", - "Enabled": true, - "Children": [ - { - "__guid": "0fedf38a-c66d-4bca-8e6e-13af7e13c923", - "Flags": 4, - "Name": "arm_lower_L_twist2", - "Enabled": true - } - ] - }, - { - "__guid": "14b06047-7e70-4cbb-9a6c-d116915099fc", - "Flags": 4, - "Name": "arm_lower_L_twist1", - "Enabled": true - } - ] - }, - { - "__guid": "f5e635c1-22e6-471b-9a8d-77afea6d4e40", - "Flags": 4, - "Name": "arm_lower_L_twist0", - "Enabled": true - } - ] + "__guid": "e37e45c4-a3db-4408-bf35-e7a204d36aa1", + "Flags": 0, + "Name": "smdimport02", + "Position": "0.2259846,-4.990251,1.015459", + "Rotation": "0.5032372,-0.4921875,-0.5059339,-0.4985325", + "Enabled": true } ] } @@ -800,13 +273,6 @@ ] } ] - }, - { - "__guid": "470ea4e9-313b-4dc7-9109-090b1685dd74", - "Flags": 4, - "Name": "camera", - "Rotation": "-0.0000002682208,-0.00000004470347,0.000002950429,1", - "Enabled": true } ], "__variables": [], @@ -839,9 +305,6 @@ "MenuIcon": null, "DontBreakAsTemplate": false, "ResourceVersion": 1, - "__references": [ - "facepunch.v_toolgun#49561", - "facepunch.v_usp#74471" - ], + "__references": [], "__version": 1 } \ No newline at end of file diff --git a/Code/Components/Weapons/ToolGun.Effects.cs b/Code/Components/Weapons/ToolGun.Effects.cs index f78fb65..dad08d9 100644 --- a/Code/Components/Weapons/ToolGun.Effects.cs +++ b/Code/Components/Weapons/ToolGun.Effects.cs @@ -38,7 +38,7 @@ public partial class ToolGun if ( !IsProxy ) { - ViewModel?.Renderer?.Set( "b_attack", true ); + ViewModel?.Renderer?.Set( "fire", true ); } int soundIndex = new Random().Next( 0, ShootSounds.Length ); From 6ca875db5b7316e21f2164e8834da1af4713f8e4 Mon Sep 17 00:00:00 2001 From: Ben Allison Date: Sun, 5 Jan 2025 14:14:00 -0800 Subject: [PATCH 16/16] Unify all constraints to Sandbox.Joint component system (#79) Closes #57 --- Code/Assembly.cs | 1 + Code/Components/Base/BaseSpawnTool.cs | 14 +- Code/Components/Joint.Extras.cs | 120 ------ Code/Components/PropHelper.Joints.cs | 387 ++++++++++++++++++ Code/Components/PropHelper.cs | 121 +----- Code/Components/Tools/Balloon.cs | 32 +- Code/Components/Tools/Constraint.cs | 249 ++++------- Code/Components/Tools/Lamp.cs | 35 +- Code/Components/Tools/Thruster.cs | 1 - Code/Components/Tools/Weld.cs | 4 +- Code/Components/Tools/Wheel.cs | 3 +- Code/Components/Weapons/PhysGun.cs | 66 +-- .../Utilities/Components/CleanupPanel.razor | 2 +- 13 files changed, 479 insertions(+), 556 deletions(-) delete mode 100644 Code/Components/Joint.Extras.cs create mode 100644 Code/Components/PropHelper.Joints.cs diff --git a/Code/Assembly.cs b/Code/Assembly.cs index 823dbc2..c40df1a 100644 --- a/Code/Assembly.cs +++ b/Code/Assembly.cs @@ -1,5 +1,6 @@ global using System; global using Sandbox; +global using SandboxPlus; global using System.Linq; global using System.Threading.Tasks; global using System.Collections.Generic; diff --git a/Code/Components/Base/BaseSpawnTool.cs b/Code/Components/Base/BaseSpawnTool.cs index b82d2a1..e94daa0 100644 --- a/Code/Components/Base/BaseSpawnTool.cs +++ b/Code/Components/Base/BaseSpawnTool.cs @@ -33,19 +33,7 @@ public override bool Primary( SceneTraceResult tr ) if ( ShouldWeld && tr.Body.IsValid() && !tr.GameObject.IsWorld() ) { - var point1 = PhysicsPoint.World( tr.Body, ent.WorldPosition, ent.WorldRotation ); - var point2 = PhysicsPoint.World( ent.GetComponent().PhysicsBody, ent.WorldPosition, ent.WorldRotation ); - var joint = PhysicsJoint.CreateFixed( - point1, - point2 - ); - joint.Collisions = false; - ent.GetComponent().PhysicsJoints.Add( joint ); - - if ( tr.GameObject.GetComponent() is var propHelper2 && propHelper2.IsValid() ) - { - propHelper2.PhysicsJoints.Add( joint ); - } + tr.GameObject.GetComponent().Weld(ent, noCollide: false, fromBone: tr.Bone); } return true; } diff --git a/Code/Components/Joint.Extras.cs b/Code/Components/Joint.Extras.cs deleted file mode 100644 index 8b933b1..0000000 --- a/Code/Components/Joint.Extras.cs +++ /dev/null @@ -1,120 +0,0 @@ -using Sandbox.Physics; -public static class JointExtensions -{ - // [Event( "joint.spawned" )] - public static void OnJointSpawned( PhysicsJoint spawned, GameObject owner ) - { - var jointTracker1 = spawned.Body1.GetGameObject().GetComponent(); - jointTracker1.PhysicsJoints.Add( spawned ); - var jointTracker2 = spawned.Body2.GetGameObject().GetComponent(); - jointTracker2.PhysicsJoints.Add( spawned ); - - spawned.OnBreak += () => - { - jointTracker1.PhysicsJoints.Remove( spawned ); - jointTracker2.PhysicsJoints.Remove( spawned ); - }; - } - - // ent.PhysicsGroup.Joints only appears to work for ModelDoc joints (eg. within a ragdoll), not for PhysicsJoint.Create'd ones, so lets track it ourselves - public static List GetJoints( this GameObject ent ) - { - var jointTracker = ent.GetComponent(); - if ( jointTracker is not null ) - { - // Due to https://github.com/sboxgame/issues/issues/3949 OnBreak isn't called on Joint.Remove(), so we need to clean up here just in case - jointTracker.PhysicsJoints.RemoveAll( x => !x.IsValid() ); - return jointTracker.PhysicsJoints; - } - return []; - } - - public static IEnumerable GetAttachedGameObjects( this GameObject baseGo, List joints = null ) - { - joints ??= new(); - HashSet objsChecked = new(); - HashSet jointsChecked = joints.ToHashSet(); - Stack objsToCheck = new(); - objsChecked.Add( baseGo ); - objsToCheck.Push( baseGo ); - - while ( objsToCheck.Count > 0 ) - { - GameObject ent = objsToCheck.Pop(); - foreach ( GameObject e in ent.Children ) - { - if ( objsChecked.Add( e ) ) - objsToCheck.Push( e ); - } - if ( ent.Parent.IsValid() && ent.Parent.GetComponent() is not null && objsChecked.Add( ent.Parent ) ) - { - objsToCheck.Push( ent.Parent ); - } - - // if ( ent.GetComponent() is SkinnedModelRenderer ragdoll ) - // { - // for ( int i = 0, end = ragdoll.Model.BoneCount; i < end; ++i ) - // { - // GameObject e = ragdoll.GetBoneObject( i ); - // if ( objsChecked.Add( e ) ) - // objsToCheck.Push( e ); - // } - // } - foreach ( PhysicsJoint j in GetJoints( ent ) ) - { - if ( jointsChecked.Add( j ) ) - { - if ( objsChecked.Add( j.Body1.GetGameObject() ) ) - objsToCheck.Push( j.Body1.GetGameObject() ); - if ( objsChecked.Add( j.Body2.GetGameObject() ) ) - objsToCheck.Push( j.Body2.GetGameObject() ); - } - } - } - joints.AddRange( jointsChecked ); - return objsChecked; - } - - public static IEnumerable GetAttachedGameObjects( this GameObject baseGo, List joints = null ) - { - return baseGo.GetAttachedGameObjects( joints ).Select( x => x.GetComponent() ).Where( x => x is not null ); - } - - public static Sandbox.Tools.ConstraintType GetConstraintType( this Sandbox.Physics.PhysicsJoint joint ) - { - if ( joint is Sandbox.Physics.FixedJoint ) - { - return Sandbox.Tools.ConstraintType.Weld; - } - else if ( joint is Sandbox.Physics.HingeJoint ) - { - return Sandbox.Tools.ConstraintType.Axis; - } - else if ( joint is Sandbox.Physics.BallSocketJoint ) - { - return Sandbox.Tools.ConstraintType.BallSocket; - } - else if ( joint is Sandbox.Physics.SpringJoint springJoint ) - { - if ( springJoint.MinLength <= 0.001f ) - { - if ( springJoint.MaxLength == 9999999 ) - { - return Sandbox.Tools.ConstraintType.Nocollide; - } - return Sandbox.Tools.ConstraintType.Rope; - } - return Sandbox.Tools.ConstraintType.Spring; - } - else if ( joint is Sandbox.Physics.SliderJoint ) - { - return Sandbox.Tools.ConstraintType.Slider; - } - throw new System.Exception( "Unknown joint type" ); - } - - public static bool IsWorld( this GameObject gameObject ) - { - return gameObject.GetComponent() != null; - } -} diff --git a/Code/Components/PropHelper.Joints.cs b/Code/Components/PropHelper.Joints.cs new file mode 100644 index 0000000..529d530 --- /dev/null +++ b/Code/Components/PropHelper.Joints.cs @@ -0,0 +1,387 @@ +namespace SandboxPlus; + +public partial class PropHelper +{ + public List Joints { get; set; } = new(); + // These "make a constraint" functions are not directly RPC'd as components are replicated upon Network.Refresh(), but AddJointToList needs to be RPC'd so everyone can track the joint's existance + public Sandbox.FixedJoint Weld( GameObject to, bool noCollide = true, int fromBone = -1, int toBone = -1 ) + { + var fixedJoint = GetJointGameObject( this.GameObject, fromBone ).Components.Create(); + fixedJoint.Body = GetJointGameObject( to, toBone ); + fixedJoint.EnableCollision = !noCollide; + fixedJoint.LinearDamping = 0; + fixedJoint.LinearFrequency = 0; + fixedJoint.AngularDamping = 0; + fixedJoint.AngularFrequency = 0; + fixedJoint.Network.Refresh(); + + AddJointToList( fixedJoint ); + to.Components.Get()?.AddJointToList( fixedJoint ); + + return fixedJoint; + } + + public Sandbox.HingeJoint Axis( GameObject to, Transform pivot, bool noCollide = true, int fromBone = -1, int toBone = -1, float friction = 0, float minAngle = -180, float maxAngle = 180 ) + { + var goJoint = new GameObject + { + WorldPosition = pivot.Position, + WorldRotation = pivot.Rotation, + Tags = { "jointHelper" } + }; + goJoint.SetParent( GetJointGameObject( this.GameObject, fromBone ) ); + goJoint.NetworkSpawn(); + + var hingeJoint = goJoint.Components.Create(); + hingeJoint.Body = GetJointGameObject( to, toBone ); + hingeJoint.EnableCollision = !noCollide; + hingeJoint.Friction = friction; + if ( !minAngle.AlmostEqual( -180 ) ) hingeJoint.MinAngle = minAngle; // actually setting them to -180/180 doesn't let them smoothly rotate, and I'm unsure how to unset them... + if ( !maxAngle.AlmostEqual( 180 ) ) hingeJoint.MaxAngle = maxAngle; + // also has motor settings + hingeJoint.Network.Refresh(); + + AddJointToList( hingeJoint ); + to.Components.Get()?.AddJointToList( hingeJoint ); + + return hingeJoint; + } + + public Sandbox.BallJoint BallSocket( GameObject to, Transform pivot, bool noCollide = true, int fromBone = -1, int toBone = -1, float friction = 0 ) + { + var goJoint = new GameObject + { + WorldPosition = pivot.Position, + WorldRotation = pivot.Rotation, + Tags = { "jointHelper" } + }; + goJoint.SetParent( GetJointGameObject( this.GameObject, fromBone ) ); + goJoint.NetworkSpawn(); + + var ballJoint = goJoint.Components.Create(); + ballJoint.Body = GetJointGameObject( to, toBone ); + ballJoint.EnableCollision = !noCollide; + ballJoint.Friction = friction; + // ballJoint.SwingLimit + // ballJoint.TwistLimit + ballJoint.Network.Refresh(); + + AddJointToList( ballJoint ); + to.Components.Get()?.AddJointToList( ballJoint ); + + return ballJoint; + } + + public Sandbox.SpringJoint Spring( GameObject to, Vector3 pos1, Vector3 pos2, bool noCollide = true, int fromBone = -1, int toBone = -1, float min = 0, float max = 0, float frequency = 5f, float damping = 0.7f, bool visualRope = true ) + { + var goJoint = new GameObject + { + WorldPosition = pos1, + Tags = { "jointHelper" } + }; + goJoint.SetParent( GetJointGameObject( this.GameObject, fromBone ) ); + goJoint.NetworkSpawn(); + + var toJoint = new GameObject + { + WorldPosition = pos2, + Tags = { "jointHelper" } + }; + toJoint.SetParent( GetJointGameObject( to, toBone ) ); + toJoint.NetworkSpawn(); + + var springJoint = goJoint.Components.Create(); + springJoint.Attachment = Joint.AttachmentMode.LocalFrames; + springJoint.LocalFrame1 = goJoint.LocalTransform; + springJoint.LocalFrame2 = toJoint.LocalTransform; + springJoint.EnableCollision = !noCollide; + springJoint.MinLength = min; + springJoint.MaxLength = max; + springJoint.Frequency = frequency; + springJoint.Damping = damping; + springJoint.Body = toJoint; + springJoint.Network.Refresh(); + + AddJointToList( springJoint ); + to.Components.Get()?.AddJointToList( springJoint ); + + if ( visualRope ) + { + MakeVisualRope( goJoint, pos1, toJoint, pos2 ); + } + + var propHelper2 = to.GetComponent(); + if ( propHelper2.IsValid() ) + { + propHelper2.OnComponentDestroy += () => + { + goJoint.Destroy(); + }; + } + + return springJoint; + } + + public Sandbox.SpringJoint Rope( GameObject to, Vector3 pos1, Vector3 pos2, bool noCollide = true, int fromBone = -1, int toBone = -1, float min = 0, float max = 0, bool visualRope = true ) + { + return Spring( to, pos1, pos2, noCollide, fromBone, toBone, min, max, frequency: 1001, damping: 0.7f, visualRope: visualRope ); + } + public Sandbox.SpringJoint NoCollide( GameObject to, int fromBone = -1, int toBone = -1 ) + { + // this is kinda weird for a nocollide, ideally we'd have a dedicated constraint or maybe a modified FixedJoint + return Spring( to, this.GameObject.WorldPosition, to.WorldPosition, true, fromBone, toBone, 0, 9999999, visualRope: false ); + } + + public Sandbox.SliderJoint Slider( GameObject to, Vector3 pos1, Vector3 pos2, bool noCollide = true, int fromBone = -1, int toBone = -1, float min = 0, float max = 0, float friction = 0, bool visualRope = true ) + { + // Todo: this isn't right yet. Something about positions and rotations. + + var goFrom = GetJointGameObject( this.GameObject, fromBone ); + var goTo = GetJointGameObject( to, toBone ); + var goJoint = new GameObject + { + WorldPosition = pos1, + WorldRotation = goFrom.WorldRotation, + Tags = { "jointHelper" } + }; + goJoint.SetParent( goFrom ); + goJoint.NetworkSpawn(); + + var toJoint = new GameObject + { + WorldPosition = pos2, + WorldRotation = goFrom.WorldRotation, + // WorldRotation = Rotation.LookAt(pos2 - pos1), + Tags = { "jointHelper" } + }; + toJoint.SetParent( goTo ); + toJoint.NetworkSpawn(); + + var sliderJoint = goJoint.Components.Create(); + sliderJoint.Attachment = Joint.AttachmentMode.LocalFrames; + sliderJoint.LocalFrame1 = goJoint.LocalTransform; + sliderJoint.LocalFrame2 = toJoint.LocalTransform; + sliderJoint.EnableCollision = !noCollide; + sliderJoint.MinLength = min; + sliderJoint.MaxLength = max; + sliderJoint.Friction = friction; + sliderJoint.Body = toJoint; + sliderJoint.Network.Refresh(); + + AddJointToList( sliderJoint ); + to.Components.Get()?.AddJointToList( sliderJoint ); + + if ( visualRope ) + { + MakeVisualRope( goJoint, pos1, toJoint, pos2 ); + } + + var propHelper2 = to.GetComponent(); + if ( propHelper2.IsValid() ) + { + propHelper2.OnComponentDestroy += () => + { + goJoint.Destroy(); + }; + } + + return sliderJoint; + } + + [Rpc.Broadcast] + private static void MakeVisualRope( GameObject go1, Vector3 position1, GameObject go2, Vector3 position2 ) + { + var rope = Particles.MakeParticleSystem( "particles/entity/rope.vpcf", go1.WorldTransform, 0, go1 ); + rope.GameObject.SetParent( go1 ); + var RopePoints = new List(); + if ( go1.IsWorld() ) + { + RopePoints.Add( new() { StringCP = "0", Value = ParticleControlPoint.ControlPointValueInput.Vector3, VectorValue = position1 } ); + } + else + { + RopePoints.Add( new() { StringCP = "0", Value = ParticleControlPoint.ControlPointValueInput.GameObject, GameObjectValue = go1 } ); + } + if ( go2.IsWorld() ) + { + RopePoints.Add( new() { StringCP = "1", Value = ParticleControlPoint.ControlPointValueInput.Vector3, VectorValue = position2 } ); + } + else + { + RopePoints.Add( new() { StringCP = "1", Value = ParticleControlPoint.ControlPointValueInput.GameObject, GameObjectValue = go2 } ); + } + rope.ControlPoints = RopePoints; + } + + private static GameObject GetJointGameObject( GameObject go, int bone = -1 ) + { + // Sandbox.Joint's only work with GameObjects, so we need to get the Bone's GameObject + if ( bone > -1 && go.GetComponent() is SkinnedModelRenderer skinnedModelRenderer ) + { + return skinnedModelRenderer.GetBoneObject( bone ); + } + return go; + } + + [Rpc.Broadcast] + private void AddJointToList( Joint joint ) + { + Joints.Add( joint ); + } + + [Rpc.Broadcast] + public void RemoveConstraints( ConstraintType type, GameObject to = null ) + { + foreach ( var j in Joints.AsEnumerable().Reverse() ) // reverse so we can remove items from the list while iterating + { + if ( !j.IsValid() ) + { + Joints.Remove( j ); + continue; + } + + if ( !to.IsValid() || JointMatchesGameObjects( j, to ) ) + { + if ( j.GetConstraintType() == type ) + { + j.Remove(); + } + } + } + } + private bool JointMatchesGameObjects( Joint joint, GameObject to ) + { + var propHelper1 = joint?.GameObject?.GetComponentInParent(); + var propHelper2 = joint?.Body?.GetComponentInParent(); + return (propHelper1?.GameObject == this.GameObject && propHelper2?.GameObject == to) || (propHelper2?.GameObject == this.GameObject && propHelper1?.GameObject == to); + } +} + +public static class JointExtensions +{ + public static void Remove( this Sandbox.Joint joint ) + { + joint.GameObject?.GetComponentInParent()?.Joints.Remove( joint ); + joint.Body?.GetComponentInParent()?.Joints.Remove( joint ); + if ( joint.IsValid() ) + { + if ( joint.GameObject?.Tags.Has( "jointHelper" ) ?? false ) joint.GameObject.Destroy(); + if ( joint.Body?.Tags.Has( "jointHelper" ) ?? false ) joint.Body.Destroy(); + joint.Destroy(); + } + joint?.Destroy(); + } + + // ent.PhysicsGroup.Joints only appears to work for ModelDoc joints (eg. within a ragdoll), not for PhysicsJoint.Create'd ones, so lets track it ourselves + public static List GetJoints( this GameObject ent ) + { + var jointTracker = ent.GetComponent(); + if ( jointTracker is not null ) + { + // Due to https://github.com/sboxgame/issues/issues/3949 OnBreak isn't called on Joint.Remove(), so we need to clean up here just in case + jointTracker.Joints.RemoveAll( x => !x.IsValid() ); + return jointTracker.Joints; + } + return []; + } + + public static IEnumerable GetAttachedGameObjects( this GameObject baseGo, List joints = null ) + { + joints ??= new(); + HashSet objsChecked = new(); + HashSet jointsChecked = joints.ToHashSet(); + Stack objsToCheck = new(); + objsChecked.Add( baseGo ); + objsToCheck.Push( baseGo ); + + while ( objsToCheck.Count > 0 ) + { + GameObject ent = objsToCheck.Pop(); + foreach ( GameObject e in ent.Children ) + { + if ( e.IsValid() && objsChecked.Add( e ) ) + objsToCheck.Push( e ); + } + if ( ent.Parent.IsValid() && ent.Parent.GetComponent() is not null && objsChecked.Add( ent.Parent ) ) + { + objsToCheck.Push( ent.Parent ); + } + + // if ( ent.GetComponent() is SkinnedModelRenderer ragdoll ) + // { + // for ( int i = 0, end = ragdoll.Model.BoneCount; i < end; ++i ) + // { + // GameObject e = ragdoll.GetBoneObject( i ); + // if ( objsChecked.Add( e ) ) + // objsToCheck.Push( e ); + // } + // } + foreach ( Joint j in GetJoints( ent ) ) + { + if ( jointsChecked.Add( j ) ) + { + if ( j.Body1.GetGameObject().IsValid() && objsChecked.Add( j.Body1.GetGameObject() ) ) + objsToCheck.Push( j.Body1.GetGameObject() ); + if ( j.Body2.GetGameObject().IsValid() && objsChecked.Add( j.Body2.GetGameObject() ) ) + objsToCheck.Push( j.Body2.GetGameObject() ); + } + } + } + joints.AddRange( jointsChecked ); + return objsChecked; + } + + public static IEnumerable GetAttachedGameObjects( this GameObject baseGo, List joints = null ) + { + return baseGo.GetAttachedGameObjects( joints ).Select( x => x.GetComponent() ).Where( x => x is not null ); + } + + public static ConstraintType GetConstraintType( this Sandbox.Joint joint ) + { + if ( joint is Sandbox.FixedJoint ) + { + return ConstraintType.Weld; + } + else if ( joint is Sandbox.HingeJoint ) + { + return ConstraintType.Axis; + } + else if ( joint is Sandbox.BallJoint ) + { + return ConstraintType.BallSocket; + } + else if ( joint is Sandbox.SpringJoint springJoint ) + { + if ( springJoint.MaxLength == 9999999 && !springJoint.EnableCollision ) + { + return ConstraintType.Nocollide; + } + if ( springJoint.Frequency > 1000f ) + { + return ConstraintType.Rope; + } + return ConstraintType.Spring; + } + else if ( joint is Sandbox.SliderJoint ) + { + return ConstraintType.Slider; + } + throw new System.Exception( "Unknown joint type" ); + } + + public static bool IsWorld( this GameObject gameObject ) + { + return gameObject.GetComponent() != null; + } +} + +public enum ConstraintType +{ + Weld, + Nocollide, // Generic + Axis, // Revolute + BallSocket, // Spherical + Rope, + Spring, // Winch/Hydraulic + Slider, // Prismatic +} diff --git a/Code/Components/PropHelper.cs b/Code/Components/PropHelper.cs index 279a80d..3d22ae2 100644 --- a/Code/Components/PropHelper.cs +++ b/Code/Components/PropHelper.cs @@ -1,11 +1,13 @@ using Sandbox.ModelEditor.Nodes; using Sandbox.Physics; +using Sandbox.Tools; +namespace SandboxPlus; /// /// A component to help deal with props. /// -public sealed class PropHelper : Component, Component.ICollisionListener +public partial class PropHelper : Component, Component.ICollisionListener { public struct BodyInfo { @@ -36,10 +38,6 @@ public ModelRenderer Renderer } [Sync] public NetDictionary NetworkedBodies { get; set; } = new(); - public List Welds { get; set; } = new(); - public List Joints { get; set; } = new(); - public List PhysicsJoints { get; set; } = new(); - private Vector3 lastPosition = Vector3.Zero; public int MaterialGroupIndex @@ -238,6 +236,7 @@ private PhysicsBody FindRootBody() private ModelPropData GetModelPropData() { + if ( !Prop.IsValid() ) return null; if ( Prop.Model.IsValid() && !Prop.Model.IsError && Prop.Model.TryGetData( out ModelPropData propData ) ) { return propData; @@ -369,116 +368,4 @@ public static void BroadcastExplosion( string path, Vector3 position ) Sound.Play( path, position ); } - - [Rpc.Broadcast] - public void Weld( GameObject to ) - { - if ( IsProxy ) - return; - - - var fixedJoint = Components.Create(); - fixedJoint.Body = to; - fixedJoint.LinearDamping = 0; - fixedJoint.LinearFrequency = 0; - fixedJoint.AngularDamping = 0; - fixedJoint.AngularFrequency = 0; - - Welds.Add( fixedJoint ); - Joints.Add( fixedJoint ); - // todo: PhysicsJoints ? Can we not access the PhysicsJoint from a Sandbox.FixedJoint? Facepunch what is this api - - PropHelper propHelper = to.Components.Get(); - propHelper?.Welds.Add( fixedJoint ); - propHelper?.Joints.Add( fixedJoint ); - } - - [Rpc.Broadcast] - public void Unweld() - { - if ( IsProxy ) - return; - - foreach ( var weld in Welds ) - { - weld?.Destroy(); - } - - RemoveInvalidItemsFromLists(); - } - - [Rpc.Broadcast] - public void Unweld(GameObject from) - { - if ( IsProxy ) - return; - - foreach(var weld in Welds) - { - if ( weld?.Body == from ) - { - weld?.Destroy(); - break; - } - } - - // Update the invalid items lists on the other entity, and ourselves - from.Components.Get().RemoveInvalidItemsFromLists(); - RemoveInvalidItemsFromLists(); - } - - [Rpc.Broadcast] - public void Hinge( GameObject to, Vector3 position, Vector3 normal ) - { - if ( IsProxy ) - return; - - if ( !to.IsValid() ) return; - - - var go = new GameObject - { - WorldPosition = position, - WorldRotation = Rotation.LookAt( Rotation.LookAt( normal ).Up ) - }; - - go.SetParent( to ); - - var hingeJoint = go.Components.Create(); - hingeJoint.Body = GameObject; - - Joints.Add( hingeJoint ); - - PropHelper propHelper = to.Components.Get(); - propHelper?.Joints.Add( hingeJoint ); - } - - // TODO: Figure out a way to also remove the GameObject from the 'from' target - // as well as removing the joint itself. - //[Rpc.Broadcast] - //public void UnHinge( GameObject from ) - //{ - // if ( IsProxy ) - // return; - - // foreach ( var joint in Joints ) - // { - // if ( joint?.Body == from ) - // { - // joint?.Destroy(); - // break; - // } - // } - - // // Update the invalid items lists on the other entity, and ourselves - // from.Components.Get().RemoveInvalidItemsFromLists(); - // RemoveInvalidItemsFromLists(); - //} - - private void RemoveInvalidItemsFromLists() - { - Welds.RemoveAll( item => !item.IsValid() ); - Joints.RemoveAll( item => !item.IsValid() ); - PhysicsJoints.RemoveAll( item => !item.IsValid() ); - } } diff --git a/Code/Components/Tools/Balloon.cs b/Code/Components/Tools/Balloon.cs index a9614c6..6db1267 100644 --- a/Code/Components/Tools/Balloon.cs +++ b/Code/Components/Tools/Balloon.cs @@ -91,36 +91,8 @@ protected GameObject SpawnEntity( SceneTraceResult tr, bool useRope ) var go = SpawnEntity( tr ); if ( useRope ) { - var body = go.GetComponent().PhysicsBody; - var point1 = PhysicsPoint.World( tr.Body, tr.EndPosition, tr.Body.Rotation ); - var point2 = PhysicsPoint.World( body, tr.EndPosition, body.Rotation ); - var length = BalloonRopeLength; - var joint = PhysicsJoint.CreateLength( - point1, - point2, - length - ); - joint.SpringLinear = new( 1000.0f, 0.7f ); - joint.Collisions = true; - - var rope = ConstraintTool.MakeRope( body, go.WorldPosition, tr.Body, tr.HitPosition ); - - var trPropHelper = tr.GameObject.GetComponent(); - if ( trPropHelper.IsValid() ) - { - trPropHelper.PhysicsJoints.Add( joint ); - } - go.GetComponent().PhysicsJoints.Add( joint ); - joint.OnBreak += () => - { - rope?.Destroy(); - joint.Remove(); - }; - go.GetComponent().OnPropBreak += () => - { - rope?.Destroy(); - joint.Remove(); - }; + var propHelper = go.GetComponent(); + propHelper.Rope(tr.GameObject, tr.HitPosition, tr.HitPosition, noCollide: false, toBone: tr.Bone, max: BalloonRopeLength, visualRope: true); } return go; } diff --git a/Code/Components/Tools/Constraint.cs b/Code/Components/Tools/Constraint.cs index d87892b..b3608ec 100644 --- a/Code/Components/Tools/Constraint.cs +++ b/Code/Components/Tools/Constraint.cs @@ -51,7 +51,8 @@ private enum ConstraintToolStage private ConstraintToolStage stage { get; set; } = ConstraintToolStage.Waiting; private SceneTraceResult trace1; private SceneTraceResult trace2; - private PhysicsJoint createdJoint; + private Transform localTransform1; + private Joint createdJoint; private Func createdUndo; private bool wasMoved; private bool wasFrozen; @@ -62,7 +63,7 @@ private enum ConstraintToolStage private const float RotateSpeed = 30.0f; // Dynamic entrypoint for optional Wirebox support, if installed - public static Action> CreateWireboxConstraintController; + public static Action> CreateWireboxConstraintController; private static bool WireboxSupport { get => CreateWireboxConstraintController != null; @@ -140,6 +141,10 @@ public override bool Primary( SceneTraceResult trace ) if ( stage == ConstraintToolStage.Waiting ) { trace1 = trace; + localTransform1 = trace1.Body.Transform.ToLocal( new Transform( + Input.Down( "run" ) ? trace1.Body.MassCenter : trace1.HitPosition, + Rotation.LookAt( trace1.Normal, trace1.Direction ) * Rotation.From( new Angles( 90, 0, 0 ) ) + ) ); stage = ConstraintToolStage.Moving; return true; } @@ -152,6 +157,16 @@ public override bool Primary( SceneTraceResult trace ) ResetTool(); return false; } + if ( trace1.GameObject.IsWorld() ) + { + trace2 = trace1; + trace1 = trace; + } + if ( trace1.GameObject.GetComponent() is null ) + { + ResetTool(); + return false; + } if ( trace1.GameObject.IsWorld() && trace2.GameObject.IsWorld() ) { @@ -209,7 +224,11 @@ public override bool Primary( SceneTraceResult trace ) if ( stage == ConstraintToolStage.Applying ) { - return ApplyConstraint(); + if ( !IsProxy ) + { + ApplyConstraint(); + } + return true; } else if ( stage == ConstraintToolStage.ConstraintController ) { @@ -279,22 +298,14 @@ protected bool ApplyConstraint() protected void ApplyWeld() { - var point1 = PhysicsPoint.World( trace1.Body, trace2.EndPosition, trace2.Body.Rotation ); - var point2 = PhysicsPoint.World( trace2.Body, trace2.EndPosition, trace2.Body.Rotation ); - var joint = PhysicsJoint.CreateFixed( - point1, - point2 - ); - joint.Collisions = GetConvarValue( "tool_constraint_nocollide_target" ) == "0" || ConnectedToWorld(); - - trace1.GameObject.GetComponent()?.PhysicsJoints.Add( joint ); - trace2.GameObject.GetComponent()?.PhysicsJoints.Add( joint ); + var noCollide = GetConvarValue( "tool_constraint_nocollide_target" ) != "0" && !ConnectedToWorld(); + var joint = trace1.GameObject.GetComponent().Weld( trace2.GameObject, noCollide, trace1.Bone, trace2.Bone ); FinishConstraintCreation( joint, () => { if ( joint.IsValid() ) { joint.Remove(); - return $"Removed {Type} constraint"; + return $"Removed Weld constraint"; } return ""; } ); @@ -302,18 +313,7 @@ protected void ApplyWeld() protected void ApplyNocollide() { - var point1 = PhysicsPoint.World( trace1.Body, trace1.EndPosition, trace2.Body.Rotation ); - var point2 = PhysicsPoint.World( trace2.Body, trace2.EndPosition, trace2.Body.Rotation ); - // this is kinda weird for a nocollide, ideally we'd have a dedicated constraint or maybe a modified FixedJoint - var joint = PhysicsJoint.CreateLength( - point1, - point2, - 9999999 - ); - joint.Collisions = false; - - trace1.GameObject.GetComponent().PhysicsJoints.Add( joint ); - trace2.GameObject.GetComponent().PhysicsJoints.Add( joint ); + var joint = trace1.GameObject.GetComponent().NoCollide( trace2.GameObject, trace1.Bone, trace2.Bone ); FinishConstraintCreation( joint, () => { if ( joint.IsValid() ) @@ -327,25 +327,23 @@ protected void ApplyNocollide() protected void ApplySpring() { + var noCollide = GetConvarValue( "tool_constraint_nocollide_target" ) != "0" && !ConnectedToWorld(); var position1 = wasMoved ? trace2.EndPosition : trace1.EndPosition; - var point1 = PhysicsPoint.World( trace1.Body, position1, trace2.Body.Rotation ); - var point2 = PhysicsPoint.World( trace2.Body, trace2.EndPosition, trace2.Body.Rotation ); var length = position1.Distance( trace2.EndPosition ); - var joint = PhysicsJoint.CreateSpring( - point1, - point2, - length, - length - ); - joint.SpringLinear = new( 5.0f, 0.7f ); - joint.Collisions = GetConvarValue( "tool_constraint_nocollide_target" ) == "0" || ConnectedToWorld(); - var rope = MakeRope( trace1.Body, position1, trace2.Body, trace2.EndPosition ); - trace1.GameObject.GetComponent().PhysicsJoints.Add( joint ); - trace2.GameObject.GetComponent().PhysicsJoints.Add( joint ); + var joint = trace1.GameObject.GetComponent().Spring( + trace2.GameObject, + position1, + trace2.EndPosition, + noCollide, + trace1.Bone, + trace2.Bone, + min: length, + max: length, + visualRope: true + ); FinishConstraintCreation( joint, () => { - rope?.Destroy(); if ( joint.IsValid() ) { joint.Remove(); @@ -357,30 +355,20 @@ protected void ApplySpring() protected void ApplyRope() { + var noCollide = GetConvarValue( "tool_constraint_nocollide_target" ) != "0" && !ConnectedToWorld(); var position1 = wasMoved ? trace2.EndPosition : trace1.EndPosition; - var point1 = PhysicsPoint.World( trace1.Body, position1, trace2.Body.Rotation ); - var point2 = PhysicsPoint.World( trace2.Body, trace2.EndPosition, trace2.Body.Rotation ); var lengthOffset = float.Parse( GetConvarValue( "tool_constraint_rope_extra_length" ) ); var length = position1.Distance( trace2.EndPosition ) + lengthOffset; - var joint = PhysicsJoint.CreateLength( - point1, - point2, - length - ); - joint.SpringLinear = new( 1000.0f, 0.7f ); - joint.Collisions = GetConvarValue( "tool_constraint_nocollide_target" ) == "0" || ConnectedToWorld(); + var minLength = 0f; if ( GetConvarValue( "tool_constraint_rope_rigid" ) == "1" ) { - joint.MinLength = length; + minLength = length; } - var rope = MakeRope( trace1.Body, position1, trace2.Body, trace2.EndPosition ); - trace1.GameObject.GetComponent()?.PhysicsJoints.Add( joint ); - trace2.GameObject.GetComponent()?.PhysicsJoints.Add( joint ); + var joint = trace1.GameObject.GetComponent().Rope( trace2.GameObject, position1, trace2.EndPosition, noCollide, trace1.Bone, trace2.Bone, min: minLength, max: length, visualRope: true ); FinishConstraintCreation( joint, () => { - rope?.Destroy(); if ( joint.IsValid() ) { joint.Remove(); @@ -392,22 +380,9 @@ protected void ApplyRope() protected void ApplyAxis() { - var position1 = wasMoved ? trace2.EndPosition : trace1.EndPosition; - var pivot = Input.Down( "run" ) - ? trace1.Body.MassCenter - : position1; - - var pivotTransform = new Transform( pivot, Rotation.LookAt( Rotation.LookAt( trace1.Normal ).Up ) ); - var joint = PhysicsJoint.CreateHinge( - trace1.Body, - trace2.Body, - trace1.Body.Transform.ToLocal( pivotTransform ), - trace2.Body.Transform.ToLocal( pivotTransform ) - ); - joint.Collisions = GetConvarValue( "tool_constraint_nocollide_target" ) == "0" || ConnectedToWorld(); - - trace1.GameObject.GetComponent().PhysicsJoints.Add( joint ); - trace2.GameObject.GetComponent().PhysicsJoints.Add( joint ); + var noCollide = GetConvarValue( "tool_constraint_nocollide_target" ) != "0" && !ConnectedToWorld(); + var pivotTransform = trace1.Body.Transform.ToWorld( localTransform1 ); + var joint = trace1.GameObject.GetComponent().Axis( trace2.GameObject, pivotTransform, noCollide, trace1.Bone, trace2.Bone ); FinishConstraintCreation( joint, () => { if ( joint.IsValid() ) @@ -421,19 +396,9 @@ protected void ApplyAxis() protected void ApplyBallsocket() { - var position1 = wasMoved ? trace2.EndPosition : trace1.EndPosition; - var pivot = Input.Down( "run" ) - ? trace1.Body.MassCenter - : position1; - - var joint = PhysicsJoint.CreateBallSocket( - PhysicsPoint.World( trace1.Body, pivot, trace1.Body.Rotation ), - PhysicsPoint.World( trace2.Body, pivot, trace2.Body.Rotation ) - ); - joint.Collisions = GetConvarValue( "tool_constraint_nocollide_target" ) == "0" || ConnectedToWorld(); - - trace1.GameObject.GetComponent().PhysicsJoints.Add( joint ); - trace2.GameObject.GetComponent().PhysicsJoints.Add( joint ); + var noCollide = GetConvarValue( "tool_constraint_nocollide_target" ) != "0" && !ConnectedToWorld(); + var pivotTransform = trace1.Body.Transform.ToWorld( localTransform1 ); + var joint = trace1.GameObject.GetComponent().BallSocket( trace2.GameObject, pivotTransform, noCollide, trace1.Bone, trace2.Bone ); FinishConstraintCreation( joint, () => { if ( joint.IsValid() ) @@ -447,23 +412,12 @@ protected void ApplyBallsocket() protected void ApplySlider() { + var noCollide = GetConvarValue( "tool_constraint_nocollide_target" ) != "0" && !ConnectedToWorld(); var position1 = wasMoved ? trace2.EndPosition : trace1.EndPosition; - var point1 = PhysicsPoint.World( trace1.Body, position1, trace2.Body.Rotation ); - var point2 = PhysicsPoint.World( trace2.Body, trace2.EndPosition, trace2.Body.Rotation ); - var joint = PhysicsJoint.CreateSlider( - point1, - point2, - 0, - 0 // can be used like a rope hybrid, to limit max length - ); - joint.Collisions = GetConvarValue( "tool_constraint_nocollide_target" ) == "0" || ConnectedToWorld(); - - var rope = MakeRope( trace1.Body, position1, trace2.Body, trace2.EndPosition ); - trace1.GameObject.GetComponent().PhysicsJoints.Add( joint ); - trace2.GameObject.GetComponent().PhysicsJoints.Add( joint ); + // todo: UI to limit max length, friction? + var joint = trace1.GameObject.GetComponent().Slider( trace2.GameObject, position1, trace2.EndPosition, noCollide, trace1.Bone, trace2.Bone, visualRope: true ); FinishConstraintCreation( joint, () => { - rope?.Destroy(); if ( joint.IsValid() ) { joint.Remove(); @@ -494,10 +448,11 @@ public override bool Reload( SceneTraceResult trace ) stage = ConstraintToolStage.Removing; if ( Input.Down( "walk" ) ) { - RemoveConstraints( Type, trace ); + var propHelper = trace.GameObject.GetComponent(); + propHelper?.RemoveConstraints( Type ); ResetTool(); - return true; } + return true; } else if ( stage == ConstraintToolStage.Removing ) { @@ -507,7 +462,19 @@ public override bool Reload( SceneTraceResult trace ) ResetTool(); return false; } - RemoveConstraintBetweenEnts( Type, trace1, trace2 ); + var propHelper = trace1.GameObject.GetComponent(); + if ( !propHelper.IsValid() ) + { + trace1 = trace2; + trace2 = trace; + propHelper = trace1.GameObject.GetComponent(); + } + if ( !propHelper.IsValid() ) + { + ResetTool(); + return false; + } + propHelper?.RemoveConstraints( Type, trace2.GameObject ); ResetTool(); return true; } @@ -552,31 +519,6 @@ private bool ConnectedToWorld() return trace1.GameObject.IsWorld() || trace2.GameObject.IsWorld(); } - private void RemoveConstraints( ConstraintType type, SceneTraceResult tr ) - { - tr.GameObject.GetComponent().PhysicsJoints.ForEach( j => - { - if ( j.GetConstraintType() == type ) - { - j.Remove(); - } - } ); - } - - private void RemoveConstraintBetweenEnts( ConstraintType type, SceneTraceResult trace1, SceneTraceResult trace2 ) - { - trace1.GameObject.GetComponent().PhysicsJoints.ForEach( j => - { - if ( (j.Body1 == trace1.Body || j.Body2 == trace1.Body) && (j.Body1 == trace2.Body || j.Body2 == trace2.Body) ) - { - if ( j.GetConstraintType() == type ) - { - j.Remove(); - } - } - } ); - } - private void SelectNextType() { IEnumerable possibleEnums = Enum.GetValues(); @@ -618,6 +560,10 @@ private string CalculateDescription() desc += $"\n{Input.GetButtonOrigin( "reload" )} to select an entity to remove {Type} constraint ({Input.GetButtonOrigin( "walk" )} to remove all {Type} constraints)"; desc += $"\n{Input.GetButtonOrigin( "drop" )} to cycle to next constraint type"; } + if ( stage == ConstraintToolStage.Removing ) + { + desc += $"\nNow, {Input.GetButtonOrigin( "reload" )} the second entity to remove the {Type} constraint between them, or {Input.GetButtonOrigin( "reload" )} the same entity to remove all {Type}'s"; + } if ( WireboxSupport ) { if ( stage == ConstraintToolStage.Moving ) @@ -632,7 +578,7 @@ private string CalculateDescription() return desc; } - private void FinishConstraintCreation( PhysicsJoint joint, Func undo ) + private void FinishConstraintCreation( Sandbox.Joint joint, Func undo ) { joint.OnBreak += () => { undo(); }; @@ -650,46 +596,6 @@ private void FinishConstraintCreation( PhysicsJoint joint, Func undo ) ResetTool(); } - public static LegacyParticleSystem MakeRope( PhysicsBody body1, Vector3 position1, PhysicsBody body2, Vector3 position2 ) - { - var go1 = body1.GetGameObject(); - var go2 = body2.GetGameObject(); - var rope = Particles.MakeParticleSystem( "particles/entity/rope.vpcf", go1.WorldTransform, 0, go1 ); - rope.GameObject.SetParent( go1 ); - var propHelper2 = go2.GetComponent(); - if ( propHelper2.IsValid() ) - { - propHelper2.OnComponentDestroy += () => rope?.Destroy(); - } - var RopePoints = new List(); - if ( go1.IsWorld() ) - { - RopePoints.Add( new() { StringCP = "0", Value = ParticleControlPoint.ControlPointValueInput.Vector3, VectorValue = position1 } ); - } - else - { - var p = new GameObject(); - p.SetParent( go1 ); - p.LocalPosition = body1.Transform.PointToLocal( position1 ); - - RopePoints.Add( new() { StringCP = "0", Value = ParticleControlPoint.ControlPointValueInput.GameObject, GameObjectValue = p } ); - } - if ( go2.IsWorld() ) - { - RopePoints.Add( new() { StringCP = "1", Value = ParticleControlPoint.ControlPointValueInput.Vector3, VectorValue = position2 } ); - } - else - { - var p = new GameObject(); - p.SetParent( go2 ); - p.LocalPosition = body2.Transform.PointToLocal( position2 ); - RopePoints.Add( new() { StringCP = "1", Value = ParticleControlPoint.ControlPointValueInput.GameObject, GameObjectValue = p } ); - } - rope.ControlPoints = RopePoints; - - return rope; - } - protected void ResetTool() { stage = ConstraintToolStage.Waiting; @@ -773,15 +679,4 @@ private static Transform CalculateNewTransform( Transform originalTransform, Vec return transform; } } - - public enum ConstraintType - { - Weld, - Nocollide, // Generic - Axis, // Revolute - BallSocket, // Spherical - Rope, - Spring, // Winch/Hydraulic - Slider, // Prismatic - } } diff --git a/Code/Components/Tools/Lamp.cs b/Code/Components/Tools/Lamp.cs index 69dcd69..ebf3e78 100644 --- a/Code/Components/Tools/Lamp.cs +++ b/Code/Components/Tools/Lamp.cs @@ -67,40 +67,11 @@ public GameObject SpawnEntity( SceneTraceResult tr, bool useRope ) if ( useRope ) { - var body = go.GetComponent().PhysicsBody; - var bounds = body.GetBounds(); - - var point1 = PhysicsPoint.World( tr.Body, tr.EndPosition, tr.Body.Rotation ); - var position2 = body.Transform.PointToWorld( new Vector3( bounds.Size.x * -1 + 2, 0, 0 ) ); - var point2 = PhysicsPoint.World( body, position2, body.Rotation ); var lengthOffset = float.Parse( GetConvarValue( "tool_balloon_rope_length", "100" ) ); - var length = lengthOffset; - var joint = PhysicsJoint.CreateLength( - point1, - point2, - length - ); - joint.SpringLinear = new( 1000.0f, 0.7f ); - joint.Collisions = true; - - var rope = ConstraintTool.MakeRope( body, position2, tr.Body, tr.HitPosition ); + var body = go.GetComponent().PhysicsBody; + var position1 = body.Transform.PointToWorld( new Vector3( body.GetBounds().Size.x * -1 + 2, 0, 0 ) ); - var trPropHelper = tr.GameObject.GetComponent(); - if ( trPropHelper.IsValid() ) - { - trPropHelper.PhysicsJoints.Add( joint ); - } - go.GetComponent().PhysicsJoints.Add( joint ); - joint.OnBreak += () => - { - rope?.Destroy(); - joint.Remove(); - }; - go.GetComponent().OnPropBreak += () => - { - rope?.Destroy(); - joint.Remove(); - }; + go.GetComponent().Rope(tr.GameObject, position1, tr.HitPosition, noCollide: false, toBone: tr.Bone, max: lengthOffset, visualRope: true); } return go; } diff --git a/Code/Components/Tools/Thruster.cs b/Code/Components/Tools/Thruster.cs index 904adc8..5312255 100644 --- a/Code/Components/Tools/Thruster.cs +++ b/Code/Components/Tools/Thruster.cs @@ -74,7 +74,6 @@ private Func ReadyUndo( GameObject wheel, GameObject other ) { return () => { - // TODO: When UnHinge works, uncomment this wheel.Destroy(); return "Undid thruster creation"; }; diff --git a/Code/Components/Tools/Weld.cs b/Code/Components/Tools/Weld.cs index f1c9a19..81c46c4 100644 --- a/Code/Components/Tools/Weld.cs +++ b/Code/Components/Tools/Weld.cs @@ -37,7 +37,7 @@ public override bool Reload( SceneTraceResult trace ) if ( Input.Pressed( "reload" ) && trace.GameObject.Components.TryGet( out var propHelper ) ) { - propHelper.Unweld(); + propHelper.RemoveConstraints( ConstraintType.Weld ); welded = null; return true; @@ -50,7 +50,7 @@ private Func ReadyUndo( PropHelper propHelper, GameObject from) { return () => { - propHelper.Unweld( from ); + propHelper.RemoveConstraints( ConstraintType.Weld, from ); return "Un-welded two objects"; }; diff --git a/Code/Components/Tools/Wheel.cs b/Code/Components/Tools/Wheel.cs index 7944ba2..feea8e1 100644 --- a/Code/Components/Tools/Wheel.cs +++ b/Code/Components/Tools/Wheel.cs @@ -33,7 +33,8 @@ public override bool Primary( SceneTraceResult trace ) if ( !propHelper.IsValid() ) return true; - propHelper.Hinge( trace.GameObject, trace.EndPosition, trace.Normal ); + var rotation = Rotation.LookAt( trace.Normal, trace.Direction ) * Rotation.From( new Angles( 90, 0, 0 ) ); + propHelper.Axis( trace.GameObject, new Transform( trace.EndPosition, rotation ), toBone: trace.Bone ); UndoSystem.Add( creator: this.Owner, callback: ReadyUndo( wheel, trace.GameObject ), prop: trace.GameObject ); diff --git a/Code/Components/Weapons/PhysGun.cs b/Code/Components/Weapons/PhysGun.cs index 62794d1..8819f3f 100644 --- a/Code/Components/Weapons/PhysGun.cs +++ b/Code/Components/Weapons/PhysGun.cs @@ -212,14 +212,11 @@ private void TryUnfreezeAll() if ( !rootEnt.IsValid() ) return; - var weldContexts = GetAllConnectedProps( rootEnt ); + foreach(var attachedEnt in rootEnt.GetAttachedGameObjects()) { + ModelPhysics modelPhysics = attachedEnt.GetComponent(); + Rigidbody rigidbody = attachedEnt.GetComponent(); - for ( int i = 0; i < weldContexts.Count; i++ ) - { - ModelPhysics modelPhysics = weldContexts[i]?.GetComponent(); - Rigidbody rigidbody = weldContexts[i]?.GetComponent(); - - var body = modelPhysics.IsValid() ? modelPhysics?.PhysicsGroup?.GetBody( 0 ) : (rigidbody.IsValid() ? weldContexts[i]?.GetComponent()?.PhysicsBody : null); + var body = modelPhysics.IsValid() ? modelPhysics?.PhysicsGroup?.GetBody( 0 ) : rigidbody?.PhysicsBody; if ( !body.IsValid() ) continue; @@ -240,61 +237,6 @@ private void TryUnfreezeAll() } } - public static List GetAllConnectedProps( GameObject gameObject ) - { - PropHelper propHelper = gameObject.Components.Get(); - - if ( !propHelper.IsValid() ) - return null; - - var result = new List(); - var visited = new HashSet(); - - CollectWelds( propHelper, result, visited ); - - List returned = new List { gameObject }; - - foreach ( Joint joint in result ) - { - GameObject object1 = joint?.Body1?.GetGameObject(); - GameObject object2 = joint?.Body2?.GetGameObject(); - - if ( object1.IsValid() && !returned.Contains( object1 ) ) returned.Add( object1 ); - if ( object2.IsValid() && !returned.Contains( object2 ) ) returned.Add( object2 ); - } - - return returned; - } - - private static void CollectWelds( PropHelper propHelper, List result, HashSet visited ) - { - if ( visited.Contains( propHelper ) ) - return; - - visited.Add( propHelper ); - result.AddRange( propHelper.Joints ); - - foreach ( var joint in propHelper.Joints ) - { - GameObject jointObject = joint.Body1?.GetGameObject(); - - if ( jointObject == propHelper.GameObject ) - { - jointObject = joint.Body2?.GetGameObject(); - } - - if ( !jointObject.IsValid() ) - return; - - PropHelper propHelper1 = jointObject.Components.GetInParentOrSelf(); - - if ( !propHelper1.IsValid() ) - return; - - CollectWelds( propHelper1, result, visited ); - } - } - Vector3 heldPos; Rotation heldRot; float heldMass; diff --git a/Code/UI/Utilities/Components/CleanupPanel.razor b/Code/UI/Utilities/Components/CleanupPanel.razor index 1e612c1..62ce489 100644 --- a/Code/UI/Utilities/Components/CleanupPanel.razor +++ b/Code/UI/Utilities/Components/CleanupPanel.razor @@ -53,7 +53,7 @@ { if (prop.Components.TryGet(out var joint)) { - joint.Destroy(); + joint.Remove(); prop.GameObject.Root.Network.Refresh(); } }