From 4d212f2ff8c76833415e4075ed4bf7d77486c5c2 Mon Sep 17 00:00:00 2001 From: Oscar Date: Sun, 25 May 2025 19:14:50 +0300 Subject: [PATCH] sas --- Assets/prefabs/Player.prefab | 4 +- Assets/scenes/minimal.scene | 171 +++++++------ Code/Gravity/NormalGravityTrigger.cs | 28 +++ Code/{ => Gravity}/Teleporter.cs | 10 +- Code/NormalGravityTrigger.cs | 26 -- Code/{ => Player}/Dedugan.cs | 0 Code/{ => Player}/PlayerDresser.cs | 0 Code/{ => Player}/RagdollController.cs | 1 - Code/{ => Sounds}/DspReverb.cs | 0 Code/Sounds/MusicPlayerInteractions.cs | 13 + .../MyMusicPlayer.cs} | 2 +- Code/Test.cs | 9 - Code/VectorExtension.cs | 6 - Code/button.cs | 15 -- .../.bin/manifest.json | 4 + .../package.guusconl.simpleinteractions.cll | Bin 0 -> 3145 bytes .../package.guusconl.simpleinteractions.xml | 28 +++ .../guusconl.simpleinteractions/.version | 1 + .../Assets/InteractionsPanel.prefab | 63 +++++ .../Assets/Materials/library_material.vmat | 22 ++ .../Code/SimpleInteraction.cs | 227 ++++++++++++++++++ .../Code/UI/InteractionPanel.razor | 66 +++++ .../Code/UI/InteractionPanel.razor.scss | 78 ++++++ .../Editor/ComponentTemplate.cs | 43 ++++ Libraries/guusconl.simpleinteractions/LICENSE | 21 ++ .../guusconl.simpleinteractions/README.md | 26 ++ .../simpleinteractions.sbproj | 13 + 27 files changed, 735 insertions(+), 142 deletions(-) create mode 100644 Code/Gravity/NormalGravityTrigger.cs rename Code/{ => Gravity}/Teleporter.cs (62%) delete mode 100644 Code/NormalGravityTrigger.cs rename Code/{ => Player}/Dedugan.cs (100%) rename Code/{ => Player}/PlayerDresser.cs (100%) rename Code/{ => Player}/RagdollController.cs (98%) rename Code/{ => Sounds}/DspReverb.cs (100%) create mode 100644 Code/Sounds/MusicPlayerInteractions.cs rename Code/{MusicPlayer.cs => Sounds/MyMusicPlayer.cs} (98%) delete mode 100644 Code/Test.cs delete mode 100644 Code/VectorExtension.cs delete mode 100644 Code/button.cs create mode 100644 Libraries/guusconl.simpleinteractions/.bin/manifest.json create mode 100644 Libraries/guusconl.simpleinteractions/.bin/package.guusconl.simpleinteractions.cll create mode 100644 Libraries/guusconl.simpleinteractions/.bin/package.guusconl.simpleinteractions.xml create mode 100644 Libraries/guusconl.simpleinteractions/.version create mode 100644 Libraries/guusconl.simpleinteractions/Assets/InteractionsPanel.prefab create mode 100644 Libraries/guusconl.simpleinteractions/Assets/Materials/library_material.vmat create mode 100644 Libraries/guusconl.simpleinteractions/Code/SimpleInteraction.cs create mode 100644 Libraries/guusconl.simpleinteractions/Code/UI/InteractionPanel.razor create mode 100644 Libraries/guusconl.simpleinteractions/Code/UI/InteractionPanel.razor.scss create mode 100644 Libraries/guusconl.simpleinteractions/Editor/ComponentTemplate.cs create mode 100644 Libraries/guusconl.simpleinteractions/LICENSE create mode 100644 Libraries/guusconl.simpleinteractions/README.md create mode 100644 Libraries/guusconl.simpleinteractions/simpleinteractions.sbproj diff --git a/Assets/prefabs/Player.prefab b/Assets/prefabs/Player.prefab index 07d5811..c13d20a 100644 --- a/Assets/prefabs/Player.prefab +++ b/Assets/prefabs/Player.prefab @@ -105,14 +105,14 @@ }, "CamOffsetX": 72, "DuckSpeed": 100, - "JumpStrength": 500, + "JumpStrength": 350, "OnComponentDestroy": null, "OnComponentDisabled": null, "OnComponentEnabled": null, "OnComponentFixedUpdate": null, "OnComponentStart": null, "OnComponentUpdate": null, - "RunSpeed": 500, + "RunSpeed": 350, "WalkSpeed": 200 }, { diff --git a/Assets/scenes/minimal.scene b/Assets/scenes/minimal.scene index 9973fb1..ae93c80 100644 --- a/Assets/scenes/minimal.scene +++ b/Assets/scenes/minimal.scene @@ -183,7 +183,7 @@ "Mins": "-8159.455,-4074.396,-8423.556", "Maxs": "8402.695,3846.003,8167.05" }, - "FalloffExponent": 0.26, + "FalloffExponent": 0.2370001, "OnComponentDestroy": null, "OnComponentDisabled": null, "OnComponentEnabled": null, @@ -387,6 +387,49 @@ } ], "Children": [] + }, + { + "__guid": "9166999a-aeae-4d37-b268-3126e2feb9a3", + "Flags": 0, + "Name": "NormalGravity", + "Position": "31.83635,-19.53155,195.1224", + "Rotation": "-0.00484778,-0.004847862,-0.70709,0.7070903", + "Scale": "5.599995,6.799998,3.799999", + "Components": [ + { + "__type": "NormalGravityTrigger", + "__guid": "71846c11-20ac-4814-b369-e5b7fa6153cd", + "OnComponentDestroy": null, + "OnComponentDisabled": null, + "OnComponentEnabled": null, + "OnComponentFixedUpdate": null, + "OnComponentStart": null, + "OnComponentUpdate": null, + "TriggerOnEnter": true + }, + { + "__type": "Sandbox.BoxCollider", + "__guid": "8a088c30-0f57-4c82-a3f9-3c8311d65a71", + "Center": "-0.2596588,7.563915,-14.42428", + "Friction": null, + "IsTrigger": true, + "OnComponentDestroy": null, + "OnComponentDisabled": null, + "OnComponentEnabled": null, + "OnComponentFixedUpdate": null, + "OnComponentStart": null, + "OnComponentUpdate": null, + "OnObjectTriggerEnter": null, + "OnObjectTriggerExit": null, + "OnTriggerEnter": null, + "OnTriggerExit": null, + "Scale": "88.76582,118.9528,128.8486", + "Static": true, + "Surface": null, + "SurfaceVelocity": "0,0,0" + } + ], + "Children": [] } ] }, @@ -1102,7 +1145,8 @@ "__guid": "4fe4f239-d8dc-43ba-a375-99056e22d6c6", "Flags": 0, "Name": "ClubTeleportPosition", - "Position": "521.1795,58.51978,-452.6237", + "Position": "769.3529,-524.0504,-333.4725", + "Rotation": "0,0,1,-0.00000004371139", "Scale": "1.666667,1.666667,1.666667", "Enabled": true, "Components": [], @@ -1119,6 +1163,7 @@ { "__type": "Sandbox.ModelRenderer", "__guid": "bb9a6471-baa0-411c-8825-cc4388863ddc", + "__enabled": false, "BodyGroups": 18446744073709551615, "CreateAttachments": false, "MaterialGroup": null, @@ -1163,6 +1208,7 @@ { "__type": "Teleporter", "__guid": "76f3c916-1052-42fd-9e9d-a7bad9f383d8", + "Building": null, "OnComponentDestroy": null, "OnComponentDisabled": null, "OnComponentEnabled": null, @@ -1192,7 +1238,8 @@ "OnComponentEnabled": null, "OnComponentFixedUpdate": null, "OnComponentStart": null, - "OnComponentUpdate": null + "OnComponentUpdate": null, + "TriggerOnEnter": false }, { "__type": "Sandbox.BoxCollider", @@ -2156,13 +2203,15 @@ "__guid": "285c9910-d341-4fa0-9e80-c89a2e31f4cb", "Flags": 0, "Name": "TeleportToClub", - "Position": "1.621101,-302.5153,-740.4399", + "Position": "132.7686,525.2025,-686.1906", + "Rotation": "0,-0.1031487,0,0.9946659", "Scale": "1.954177,1.954177,1.954177", "Enabled": true, "Components": [ { "__type": "Sandbox.ModelRenderer", "__guid": "5481c2cb-7d0a-4b6e-ac58-dbe01f527e8e", + "__enabled": false, "BodyGroups": 18446744073709551615, "CreateAttachments": false, "MaterialGroup": null, @@ -2186,7 +2235,7 @@ { "__type": "Sandbox.BoxCollider", "__guid": "d8862ade-55d3-457e-9307-bcf4b2698233", - "Center": "0,0,0", + "Center": "2.781189,0,0", "Friction": null, "IsTrigger": true, "OnComponentDestroy": null, @@ -2199,7 +2248,7 @@ "OnObjectTriggerExit": null, "OnTriggerEnter": null, "OnTriggerExit": null, - "Scale": "50,50,50", + "Scale": "76.94324,50,50", "Static": true, "Surface": null, "SurfaceVelocity": "0,0,0" @@ -2207,6 +2256,7 @@ { "__type": "Teleporter", "__guid": "587a82f6-7821-40db-9fdc-e62d098430f0", + "Building": null, "OnComponentDestroy": null, "OnComponentDisabled": null, "OnComponentEnabled": null, @@ -2224,7 +2274,7 @@ "__guid": "15224d57-c82e-410a-beea-e0cb76e40e0f", "Flags": 0, "Name": "Out", - "Position": "9.995585,41.46935,-23.90106", + "Position": "9.99558,-62.89205,-23.90107", "Scale": "0.5117243,0.5117243,0.5117243", "Enabled": true, "Components": [], @@ -2305,8 +2355,8 @@ "__type": "Sandbox.DSPReverb", "__guid": "1fd82892-2a6d-42bd-8f19-a3792bb23f6a", "Bounds": { - "Mins": "-370.7,-356.5996,-81.70001", - "Maxs": "464.7,443,145.1001" + "Mins": "-370.7,-597.2996,-147.1001", + "Maxs": "464.7,443,267.5002" }, "FadeDuration": 1, "OnComponentDestroy": null, @@ -2333,8 +2383,8 @@ "NetworkMode": 1, "Components": [ { - "__type": "Sandbox.MusicPlayer", - "__guid": "c556fb67-e030-4b1b-aa6f-b47904bfc2ce", + "__type": "Sandbox.MyMusicPlayer", + "__guid": "b1b3132b-9530-43ac-ad37-c3319cd6844b", "_sounds": [], "_speakers": [], "OnComponentDestroy": null, @@ -2342,7 +2392,8 @@ "OnComponentEnabled": null, "OnComponentFixedUpdate": null, "OnComponentStart": null, - "OnComponentUpdate": null + "OnComponentUpdate": null, + "PlayOnStart": false } ], "Children": [ @@ -2587,7 +2638,7 @@ { "__guid": "dcf53b7e-d474-43bf-973b-b56e3d0ad19d", "Flags": 0, - "Name": "Cube", + "Name": "NextTrackInteraction", "Position": "-175.5451,372.674,4760.318", "Rotation": "0,0,-0.4159509,0.9093871", "Scale": "0.4874838,1.38488,0.08132961", @@ -2617,73 +2668,6 @@ "RenderType": "On", "Tint": "1,1,1,1" }, - { - "__type": "Sandbox.ButtonComponent", - "__guid": "0f2a90d6-0c9d-4c6a-93e6-e57e95065b88", - "OnClick": { - "__version": 9, - "__guid": "ad39acdb-cfd4-4416-aa98-cf387c135e41", - "__changeId": 22, - "UserData": { - "Title": "On Click", - "ReferencedComponentTypes": [] - }, - "Variables": [], - "Nodes": [ - { - "Id": 0, - "Type": "input" - }, - { - "Id": 4, - "Type": "scene.ref", - "UserData": { - "Position": "12,36" - } - }, - { - "Id": 7, - "Type": "call", - "Properties": { - "_isStatic": false, - "_name": "Next", - "_type": "Sandbox.MusicPlayer" - }, - "UserData": { - "Position": "192,24" - } - } - ], - "Links": [ - { - "SrcId": 0, - "SrcName": "_signal", - "DstId": 7, - "DstName": "_signal" - }, - { - "SrcId": 4, - "SrcName": "_result", - "DstId": 7, - "DstName": "_target" - } - ], - "Defaults": { - "$4.component": { - "_type": "component", - "component_id": "c556fb67-e030-4b1b-aa6f-b47904bfc2ce", - "go": "c3d837ce-6d50-4121-88df-7ce18b8cb3b5", - "component_type": "MusicPlayer" - } - } - }, - "OnComponentDestroy": null, - "OnComponentDisabled": null, - "OnComponentEnabled": null, - "OnComponentFixedUpdate": null, - "OnComponentStart": null, - "OnComponentUpdate": null - }, { "__type": "Sandbox.BoxCollider", "__guid": "dc47d030-3ddf-41a6-836f-d6aaed8928dc", @@ -2704,6 +2688,33 @@ "Static": true, "Surface": null, "SurfaceVelocity": "0,0,0" + }, + { + "__type": "MusicPlayerInteractions", + "__guid": "a9465371-6855-4fb1-b0de-777e7f0cc2c2", + "Collider": { + "_type": "component", + "component_id": "dc47d030-3ddf-41a6-836f-d6aaed8928dc", + "go": "dcf53b7e-d474-43bf-973b-b56e3d0ad19d", + "component_type": "BoxCollider" + }, + "InteractionDistance": 120, + "InteractionEnabled": true, + "InteractionHold": false, + "InteractionHoldDuration": 0.5, + "InteractionString": "Next track", + "MusicPlayer": { + "_type": "component", + "component_id": "b1b3132b-9530-43ac-ad37-c3319cd6844b", + "go": "c3d837ce-6d50-4121-88df-7ce18b8cb3b5", + "component_type": "MyMusicPlayer" + }, + "OnComponentDestroy": null, + "OnComponentDisabled": null, + "OnComponentEnabled": null, + "OnComponentFixedUpdate": null, + "OnComponentStart": null, + "OnComponentUpdate": null } ], "Children": [] diff --git a/Code/Gravity/NormalGravityTrigger.cs b/Code/Gravity/NormalGravityTrigger.cs new file mode 100644 index 0000000..5749451 --- /dev/null +++ b/Code/Gravity/NormalGravityTrigger.cs @@ -0,0 +1,28 @@ +using Sandbox; + +public sealed class NormalGravityTrigger : Component, Component.ITriggerListener +{ + [Property] public bool TriggerOnEnter { get; set; } = false; + + public void OnTriggerEnter(Collider other) + { + if ( !TriggerOnEnter ) return; + + var otherEntity = other.GameObject; + + if (otherEntity.Components.TryGet(out var controller)) + { + controller.OverrideGravity = WorldRotation.Down; + } + } + + public void OnTriggerExit(Collider other) + { + var otherEntity = other.GameObject; + + if (otherEntity.Components.TryGet(out var controller)) + { + controller.OverrideGravity = Vector3.Zero; + } + } +} diff --git a/Code/Teleporter.cs b/Code/Gravity/Teleporter.cs similarity index 62% rename from Code/Teleporter.cs rename to Code/Gravity/Teleporter.cs index db2e5a2..2e460fd 100644 --- a/Code/Teleporter.cs +++ b/Code/Gravity/Teleporter.cs @@ -4,6 +4,7 @@ public sealed class Teleporter : Component, Component.ITriggerListener { [Property] public GameObject ToPosGameObject { get; set; } + [Property] public GameObject Building { get; set; } public void OnTriggerEnter( Collider other ) { @@ -18,8 +19,13 @@ public sealed class Teleporter : Component, Component.ITriggerListener otherEntity.WorldPosition = ToPosGameObject.WorldPosition; controller.OverrideGravity = Vector3.Down; - controller.EyeAngles = new Angles( 0, 180, 0 ).ToRotation(); - controller.Renderer.LocalRotation = new Angles( 0, 180, 0 ).ToRotation(); + controller.EyeAngles = new Angles( 0, ToPosGameObject.WorldRotation.Yaw(), 0 ).ToRotation(); + controller.Renderer.LocalRotation = new Angles( 0, ToPosGameObject.WorldRotation.Yaw(), 0 ).ToRotation(); + + if ( Building != null ) + { + Building.Enabled = !Building.Enabled; + } } } } diff --git a/Code/NormalGravityTrigger.cs b/Code/NormalGravityTrigger.cs deleted file mode 100644 index 16687df..0000000 --- a/Code/NormalGravityTrigger.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Sandbox; - -public sealed class NormalGravityTrigger : Component, Component.ITriggerListener -{ - // public void OnTriggerEnter(Collider other) - // { - // var otherEntity = other.GameObject; - // - // if (otherEntity.Components.TryGet(out var controller)) - // { - // Log.Info($"{otherEntity.Name} вошел в зону нормальной гравитации"); - // - // controller.OverrideGravity = Vector3.Down; - // } - // } - - public void OnTriggerExit(Collider other) - { - var otherEntity = other.GameObject; - - if (otherEntity.Components.TryGet(out var controller)) - { - controller.OverrideGravity = Vector3.Zero; - } - } -} diff --git a/Code/Dedugan.cs b/Code/Player/Dedugan.cs similarity index 100% rename from Code/Dedugan.cs rename to Code/Player/Dedugan.cs diff --git a/Code/PlayerDresser.cs b/Code/Player/PlayerDresser.cs similarity index 100% rename from Code/PlayerDresser.cs rename to Code/Player/PlayerDresser.cs diff --git a/Code/RagdollController.cs b/Code/Player/RagdollController.cs similarity index 98% rename from Code/RagdollController.cs rename to Code/Player/RagdollController.cs index e62c737..ac972b4 100644 --- a/Code/RagdollController.cs +++ b/Code/Player/RagdollController.cs @@ -14,7 +14,6 @@ public sealed class RagdollController : Component bodyPhysics.Enabled = value; bodyPhysics.MotionEnabled = value; bodyRenderer.UseAnimGraph = !value; - bodyPhysics. if ( !value ) { diff --git a/Code/DspReverb.cs b/Code/Sounds/DspReverb.cs similarity index 100% rename from Code/DspReverb.cs rename to Code/Sounds/DspReverb.cs diff --git a/Code/Sounds/MusicPlayerInteractions.cs b/Code/Sounds/MusicPlayerInteractions.cs new file mode 100644 index 0000000..f913995 --- /dev/null +++ b/Code/Sounds/MusicPlayerInteractions.cs @@ -0,0 +1,13 @@ +using Sandbox; + +public sealed class MusicPlayerInteractions : SimpleInteractions.SimpleInteraction +{ + [Property] public MyMusicPlayer MusicPlayer { get; set; } + + [Rpc.Broadcast] + protected override void OnInteract() + { + // Log.Info($"{Rpc.Caller.DisplayName} interacted with {this.GameObject.Name}!"); + MusicPlayer.Next(); + } +} diff --git a/Code/MusicPlayer.cs b/Code/Sounds/MyMusicPlayer.cs similarity index 98% rename from Code/MusicPlayer.cs rename to Code/Sounds/MyMusicPlayer.cs index 1a1aece..7c7b28f 100644 --- a/Code/MusicPlayer.cs +++ b/Code/Sounds/MyMusicPlayer.cs @@ -1,6 +1,6 @@  namespace Sandbox; -public sealed class MusicPlayer : Component +public sealed class MyMusicPlayer : Component { [Property] private List _sounds; [Property] private List _speakers; diff --git a/Code/Test.cs b/Code/Test.cs deleted file mode 100644 index 3b16996..0000000 --- a/Code/Test.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Sandbox; - -public sealed class Test : Component -{ - protected override void OnUpdate() - { - - } -} diff --git a/Code/VectorExtension.cs b/Code/VectorExtension.cs deleted file mode 100644 index 6ff3c99..0000000 --- a/Code/VectorExtension.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Sandbox; - -public class VectorExtension -{ - -} diff --git a/Code/button.cs b/Code/button.cs deleted file mode 100644 index ff35424..0000000 --- a/Code/button.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using Sandbox; -using Sandbox.UI; - -namespace Sandbox; - -public sealed class ButtonComponent : Component, IInteractable -{ - [Property] public Action OnClick { get; set; } - - public void OnUse() - { - OnClick?.Invoke(); - } -} diff --git a/Libraries/guusconl.simpleinteractions/.bin/manifest.json b/Libraries/guusconl.simpleinteractions/.bin/manifest.json new file mode 100644 index 0000000..0e4b336 --- /dev/null +++ b/Libraries/guusconl.simpleinteractions/.bin/manifest.json @@ -0,0 +1,4 @@ +[ + "package.base", + "package.guusconl.simpleinteractions" +] \ No newline at end of file diff --git a/Libraries/guusconl.simpleinteractions/.bin/package.guusconl.simpleinteractions.cll b/Libraries/guusconl.simpleinteractions/.bin/package.guusconl.simpleinteractions.cll new file mode 100644 index 0000000000000000000000000000000000000000..eb6e0a5e962043d19f3c838191bdcb0693db0c55 GIT binary patch literal 3145 zcmV-P47T$hiwFP!000023e_5GZ`-=H!v+ld4g11+cYrgvjGdyd7{-#=X|92`$&$1k z76$=s(Y9`6(Ics(Zs5PPf42Xyb4W>{C@GI37Z*#BRN~{jUp&+wo;`bZ@Ug%9-`_to zKYxbbS(2!Uh$E`P#WLbythrSN1uG*JUNQ42Sr;;;Wo|>{qaR8S@5gSMRcI4|k)I186Zft9rz`!w&I8*$i2!P^F ztFfyTUyP&GF`shD;|cCPJ8w0Hvsg&}UPJ*$1ZNE%gjz@-A&En+IY5L}1ArXH6I~5u zeF;)L%fv!YR!Z{)K*$F6;~7ZF8F(K8?fxo&8F3?a7z9aQvKgmi;K5mQ09t6A_Xwc7 zX`J$Jz;0s}i7|^vqCivx^q|8D$<_~1mobazfmwvxb47MXaulDjl%s88;cRbP@*Q$$ z#`Q<8S->=Fl2OubZ*A=cfrw8-9dY~KO2>X4znsMky1B3M2Hh4x>=7DrN>DgNO~$c%s}{ z%fN>){&#uwbPmZRusTzhb{qc2StKOofJJVyRU^H*xoPzCvagcGg2|P6*}t8%+lk|x z1i2S6y0ZsjvjWE15L`SnAT5%~{DLi)MYGgrCeStuA(l8Kd&`%}ID$kli9p+B{>V1z z7b&#-YQS?O#ga?CI?qN@P-7t?7vX-4DL5cE;09fy;LjQi8MANqR(1}&7O@?X}1(`$WIOgEUgaeKhkPUA2OQJNSXflBlmAkgi?VP!XdRvNm07p;oR}5}$mRlN= z6EG~VLj~o6Cf6c?h;Jyfkr^jBrPPIp%)9Z%u{3vC(dcy9*3(#309Cd+e_zr1v`f^| zqsFs)_;&&LtTYU)5|p+3T6mFMCo(RXVg7o|Rz$*YkDN?EAG8lv300t zSypKuA_2tjG{r(v+NklRdvsVdeGoF_I>{lhDpP_dXz14I$Vwz665cVAj;M+V zP!fgK4BjXxfwa{g@swG#!t zU=fvIvNqW7L38D8+nZj78j^MOd`=!5B>)*NKNZkJv!4&!B_0X_id*~t%l`T@BY zV~3?KP4*eq-8fv7m1kpIwx+q!{o%txiCN@e0MX?x@^7B{koZ7iv0QXi%_3}Gub?ip zFey2LTLZ{8G3S9omzMUX(^Qit$`UqXp&L0(qN=5`j_3Obb)eRPsI$d=hN*!5BVhry z9w)>2FwxDtMYdVjp)A@!Mu6F4eXdu#^A5XwY<2Yzqx2K0-<~kXHb9W(I$CXPCFGS| z#2@gj>U7A|D#m7E+Pj3yl47o}%!akekhlg^9g@qT)QlI$AdphK+!9kvCD#m2P)I7y zvegNPb4Q?>(7og;$qp?gxW0Lm17UhZ98g;FPQ>7Eu2xAssW zq7Pz5&G!qX;>o&WJq?gs=r<=eO&?>cT+ z7_Gln+X-VRrbDfWr%0T0?%OQfoB^YH316Am`>LL0b*DL0Iq87+@98y9SUB#%RhE6o z+AMaocv+DCZ}2>S@q*xGt|IT+HfTnPBAqr-0xF}d35N#_MiwEuPXzZEfu2)xm^bgR zgp$}ywS}s4fX7Q+5{JO$ix&kV4DuknD)5-a#yyr^RKShbD&py^-D!|-?=<~5`Zr|2 zmPkPU#$UT6?T40^T0%%Wm!SYXzy<3z>2y6Y<}>YXv2m3P891`{GQf<(VJ7NIK0okj z0fN)HO>3wHeC|@%;#loLv|7$nI?-qo$$L8{ji+y$p1SppDOLQ!sV+}d(_DF_mXd!f zRbLEVCU~@@j>FmfZc*Jqr}HsRx_PHubJmhwN2?u2|13`IOyKJ(d~h0PdG@f1A+DCX zg{$d@Tz}I?WNX` zhHf0~gYKY#xfo+3xuB+2StqTsI9tBZ+-CDbZ+UVrbn%&>m@-9FeMy$>xyc^z z$A&J)$~W9u{7EY-AO(~FcU+)tlyd}SD>_9^v&v+UZS1)FH>{Y!I<2OBYyIZbejbiSH3Gd$ j*saFJjK>$%vlo*s_V)GLS8dDr9V+`DcbS|=!z=&*3qJ|w literal 0 HcmV?d00001 diff --git a/Libraries/guusconl.simpleinteractions/.bin/package.guusconl.simpleinteractions.xml b/Libraries/guusconl.simpleinteractions/.bin/package.guusconl.simpleinteractions.xml new file mode 100644 index 0000000..7142c0b --- /dev/null +++ b/Libraries/guusconl.simpleinteractions/.bin/package.guusconl.simpleinteractions.xml @@ -0,0 +1,28 @@ + + + + package.guusconl.simpleinteractions + + + + + Simple interaction component + + + + + If not set, will try to find a collider on the same GameObject. + + + + + the hash determines if the system should be rebuilt. If it changes, it will be rebuilt + + + + + Triggers the interaction animation. + + + + diff --git a/Libraries/guusconl.simpleinteractions/.version b/Libraries/guusconl.simpleinteractions/.version new file mode 100644 index 0000000..716abf6 --- /dev/null +++ b/Libraries/guusconl.simpleinteractions/.version @@ -0,0 +1 @@ +1.0.84848 \ No newline at end of file diff --git a/Libraries/guusconl.simpleinteractions/Assets/InteractionsPanel.prefab b/Libraries/guusconl.simpleinteractions/Assets/InteractionsPanel.prefab new file mode 100644 index 0000000..f78e07d --- /dev/null +++ b/Libraries/guusconl.simpleinteractions/Assets/InteractionsPanel.prefab @@ -0,0 +1,63 @@ +{ + "RootObject": { + "__guid": "43c5a0e3-1bec-414e-a5b7-101e4f3070c7", + "Flags": 0, + "Name": "interactionspanel", + "Enabled": true, + "NetworkMode": 0, + "Components": [ + { + "__type": "Sandbox.WorldPanel", + "__guid": "e77429f1-f1a2-46f9-a266-6758afc60489", + "HorizontalAlign": "Left", + "InteractionRange": 0, + "LookAtCamera": false, + "PanelSize": "1024,512", + "RenderOptions": { + "GameLayer": true, + "OverlayLayer": true, + "BloomLayer": false, + "AfterUILayer": false + }, + "RenderScale": 1, + "VerticalAlign": "Center" + }, + { + "__type": "Sandbox.InteractionPanel", + "__guid": "127b843f-1d34-4b1e-b2f9-3e0229d52935" + } + ], + "Children": [], + "__variables": [], + "__properties": { + "FixedUpdateFrequency": 50, + "MaxFixedUpdates": 5, + "NetworkFrequency": 30, + "NetworkInterpolation": true, + "PhysicsSubSteps": 1, + "ThreadedAnimation": true, + "TimeScale": 1, + "UseFixedUpdate": true, + "Metadata": {}, + "NavMesh": { + "Enabled": false, + "IncludeStaticBodies": true, + "IncludeKeyframedBodies": true, + "EditorAutoUpdate": true, + "AgentHeight": 64, + "AgentRadius": 16, + "AgentStepSize": 18, + "AgentMaxSlope": 40, + "ExcludedBodies": "", + "IncludedBodies": "" + } + } + }, + "ShowInMenu": false, + "MenuPath": null, + "MenuIcon": null, + "DontBreakAsTemplate": false, + "ResourceVersion": 1, + "__references": [], + "__version": 1 +} \ No newline at end of file diff --git a/Libraries/guusconl.simpleinteractions/Assets/Materials/library_material.vmat b/Libraries/guusconl.simpleinteractions/Assets/Materials/library_material.vmat new file mode 100644 index 0000000..8e21dcc --- /dev/null +++ b/Libraries/guusconl.simpleinteractions/Assets/Materials/library_material.vmat @@ -0,0 +1,22 @@ +"Layer0" +{ + "shader" "shaders/complex.shader" + "g_flAmbientOcclusionDirectDiffuse" "0.000000" + "g_flAmbientOcclusionDirectSpecular" "0.000000" + "TextureAmbientOcclusion" "materials/default/default_ao.tga" + "g_flModelTintAmount" "1.000000" + "g_vColorTint" "[1.000000 1.000000 1.000000 0.000000]" + "TextureColor" "materials/default/default_color.tga" + "g_flFadeExponent" "1.000000" + "g_bFogEnabled" "1" + "g_flDirectionalLightmapMinZ" "0.050000" + "g_flDirectionalLightmapStrength" "1.000000" + "g_flMetalness" "0.000000" + "TextureNormal" "materials/default/default_normal.tga" + "TextureRoughness" "materials/default/default_rough.tga" + "g_nScaleTexCoordUByModelScaleAxis" "0" + "g_nScaleTexCoordVByModelScaleAxis" "0" + "g_vTexCoordOffset" "[0.000 0.000]" + "g_vTexCoordScale" "[1.000 1.000]" + "g_vTexCoordScrollSpeed" "[0.000 0.000]" +} diff --git a/Libraries/guusconl.simpleinteractions/Code/SimpleInteraction.cs b/Libraries/guusconl.simpleinteractions/Code/SimpleInteraction.cs new file mode 100644 index 0000000..68a304a --- /dev/null +++ b/Libraries/guusconl.simpleinteractions/Code/SimpleInteraction.cs @@ -0,0 +1,227 @@ +using Sandbox; +using Sandbox.Utility; +using Sandbox.Diagnostics; +using System.Linq; +using System.Threading.Tasks; + +namespace SimpleInteractions { + + /// + /// Simple interaction component + /// + [Icon( "touch_app" )] + [Title( "Simple Interaction" )] + public class SimpleInteraction : Component + { + [Property] + public bool InteractionEnabled {get; set;} = true; + + [Property, Title("Interaction Name")] + public string InteractionString {get; set;} = "Interact"; + + [Property] + public float InteractionDistance {get; set;} = 120f; + + [Property, ToggleGroup("InteractionHold")] + public bool InteractionHold {get; set;} = false; + + [Property, Group("InteractionHold")] + public float InteractionHoldDuration {get; set;} = 0.5f; + + + /// + /// If not set, will try to find a collider on the same GameObject. + /// + [Property, Title("Override collider")] + public Collider Collider { get; set; } + + private GameObject CurrentPanel = null; + + private TimeSince HoldTime = 0; + private bool Holding = false; + private bool HoldingInteractionHappened = false; + + static protected GameObject InteractionPanelPrefab ; + + protected override void OnStart() + { + InteractionPanelPrefab = GameObject.GetPrefab("InteractionsPanel.prefab"); + + Assert.True(InteractionPanelPrefab.IsValid(), $"No InteractionPanel prefab found for {this.GameObject.Name}!"); + + if (!Collider.IsValid()) { + + Collider = this.GameObject.GetComponent(); + + Assert.True(Collider.IsValid(), $"No collider found for {this.GameObject.Name}!"); + } + this.GameObject.Tags.Add("Interact"); + } + + protected override void OnUpdate() + { + if (!InteractionEnabled) + { + // Reset everything just in case + Holding = false; + HoldingInteractionHappened = false; + + // Delete the Interaction panel otherwise it would just float there... + if (CurrentPanel.IsValid()) + { + InteractionPanel panel = CurrentPanel.GetComponent(); + if (panel.IsValid()) { + _ = DeletePanel(); + } + } + return; + } + + Ray ray = Scene.Camera.GameObject.Transform.World.ForwardRay; + + var traces = Scene.Trace.Ray(ray, InteractionDistance) + .WithoutTags("IgnoreInteract") + .HitTriggers() + .RunAll(); + + // Gizmo.Draw.Line(tr.StartPosition, tr.EndPosition); + + if (traces.Count() <= 0) + { + _ = DeletePanel(); + + // Force repressing use in case you looked away while holding down. + HoldingInteractionHappened = true; + return; + } + + foreach (var tr in traces) + { + + Collider HitCollider = tr.Shape.Collider as Collider; + + // If it's a trigger and it doesn't have the interact tag, skip it. + // We can see through it. + if (HitCollider.IsTrigger && !HitCollider.GameObject.Tags.Has("Interact")) + { + continue; + } else if (!HitCollider.IsTrigger && !HitCollider.GameObject.Tags.Has("Interact")) + { + // Something is blocking the interaction. + _ = DeletePanel(); + + // Force repressing use in case you looked away while holding down. + HoldingInteractionHappened = true; + break; + } + + Vector3 offset = Vector3.Zero; + + if (HitCollider is BoxCollider) + { + offset = (HitCollider as BoxCollider).Center; + } else if (HitCollider is SphereCollider) + { + offset = new Vector3((HitCollider as SphereCollider).Center); + } + + + if (HitCollider == Collider) + { + Vector3 pos = new Vector3(offset.x, offset.y, - offset.z); + OnHover(HitCollider.GameObject.WorldPosition - pos); + break; + } else + { + _ = DeletePanel(); + + // Force repressing use in case you looked away while holding down. + HoldingInteractionHappened = true; + } + } + } + + private void OnHover(Vector3 pos) + { + if (!CurrentPanel.IsValid()) + { + CurrentPanel = InteractionPanelPrefab.Clone(); + } + + CurrentPanel.WorldPosition = pos; + + // Flip the panel to face the camera + Rotation camRotation = Scene.Camera.WorldRotation; + + Angles ang = camRotation.Angles(); + ang.roll += 180; + ang.pitch += 180; + Rotation rot = ang.ToRotation(); + CurrentPanel.WorldRotation = rot; + + InteractionPanel panel = CurrentPanel.GetComponent(); + panel.InteractionString = InteractionString; + panel.IsHoldInteraction = InteractionHold; + panel.ProgressionHold = 0; + + + + if (!InteractionHold) + { + if (Input.Pressed("use")) + { + _ = panel.TriggerInteractAnimation(); + OnInteract(); + } + return; + } + + + if (!Input.Down("use")) + { + Holding = false; + HoldingInteractionHappened = false; + return; + } + + // Interaction already happened. Player needs to release and press again. + if (HoldingInteractionHappened) + { + return; + } + + if (Holding) + { + panel.ProgressionHold = Easing.QuadraticInOut(HoldTime / InteractionHoldDuration); + if (HoldTime >= InteractionHoldDuration) + { + HoldingInteractionHappened = true; + OnInteract(); + } + } else + { + // Started holding. + Holding = true; + HoldTime = 0; + _ = panel.TriggerInteractAnimation(); + } + } + + async private Task DeletePanel() + { + if(!CurrentPanel.IsValid()) return; + + CurrentPanel.GetComponent().Panel.Delete(); + await Task.DelaySeconds( 0.1f ); + CurrentPanel.Destroy(); + } + + [Rpc.Broadcast] + protected virtual void OnInteract() + { + Log.Error($"Interaction not implemented for {this.GameObject.Name}!"); + } + + } + +} \ No newline at end of file diff --git a/Libraries/guusconl.simpleinteractions/Code/UI/InteractionPanel.razor b/Libraries/guusconl.simpleinteractions/Code/UI/InteractionPanel.razor new file mode 100644 index 0000000..bdcc3bd --- /dev/null +++ b/Libraries/guusconl.simpleinteractions/Code/UI/InteractionPanel.razor @@ -0,0 +1,66 @@ +@using Sandbox; +@using Sandbox.UI; +@using System.Threading.Tasks; +@inherits PanelComponent +@namespace Sandbox + + + + +
+ +
+ + @if (IsHoldInteraction) + { +
Hold
+ } +
+ +
+
@InteractionString
+
+ +
+ +@code +{ + + private Texture InputTexture; + public string InteractionString {get; set;} + private bool IsInteracting = false; + public bool IsHoldInteraction = false; + public float ProgressionHold = 0; + + + /// + /// the hash determines if the system should be rebuilt. If it changes, it will be rebuilt + /// + protected override int BuildHash() => System.HashCode.Combine( InputTexture, InteractionString, IsHoldInteraction, ProgressionHold); + + protected override void OnUpdate() + { + InputTexture = Input.GetGlyph("use", InputGlyphSize.Medium, true); + } + + /// + /// Triggers the interaction animation. + /// + public async Task TriggerInteractAnimation() + { + if (IsInteracting) + return; // Prevent overlapping animations + + IsInteracting = true; + StateHasChanged(); + + // Wait for the animation duration (e.g., 300ms) + await Task.Delay(100); + + IsInteracting = false; + StateHasChanged(); + } +} \ No newline at end of file diff --git a/Libraries/guusconl.simpleinteractions/Code/UI/InteractionPanel.razor.scss b/Libraries/guusconl.simpleinteractions/Code/UI/InteractionPanel.razor.scss new file mode 100644 index 0000000..76b6e82 --- /dev/null +++ b/Libraries/guusconl.simpleinteractions/Code/UI/InteractionPanel.razor.scss @@ -0,0 +1,78 @@ +InteractionPanel +{ + position: absolute; + top: 0; + left: 0; + background-color: #444; + justify-content: center; + align-items: center; + font-weight: bold; + border-radius: 20px; + font-size: 25px; + font-family: Poppins; + color: #fff; + text-stroke: 8px black; + transform-origin: left center; + + + transition: all 0.1s ease-out; + transform: scale( 1 ); + + // When the element is created make it expand from nothing. + &:intro { + transform: scale( 0 ); + } + + &:outro { + transform: scale( 0 ); + } + + + .InteractionTitle + { + color: #fff; + margin-right: 15px; + white-space: normal; + max-width: 300px; + align-items: center; + } + + .ProgressBar { + position: absolute; /* Place the progress bar within the root */ + top: 0; + left: 0; + height: 100%; /* Fill the entire height of the root */ + z-index: 0; /* Ensure it is below the content */ + border-radius: 20px; + background-color: #a2a2a2; + } + + .Left + { + flex-direction: column; + align-items: center; + padding-left: 20px; + min-width: 110px; + + } + + .Right + { + width: 100%; + align-items: center; + margin-left: 30px; + + } + + .InteractionHold + { + margin-top: -13px; + margin-bottom: 5px; + + } + + &.interact { + transition: all 0.1s ease-out; + transform: scale(0.98); + } +} \ No newline at end of file diff --git a/Libraries/guusconl.simpleinteractions/Editor/ComponentTemplate.cs b/Libraries/guusconl.simpleinteractions/Editor/ComponentTemplate.cs new file mode 100644 index 0000000..7c3a746 --- /dev/null +++ b/Libraries/guusconl.simpleinteractions/Editor/ComponentTemplate.cs @@ -0,0 +1,43 @@ +using Editor; + + +[Icon( "touch_app" )] +[Title( "SimpleInteraction" )] +[Description( "A simple interaction component so you can interact with objects" )] +public partial class SimpleInteractionTemplate : ComponentTemplate +{ + public override void Create( string componentName, string path ) + { + var content = $$""" + using Sandbox; + + public sealed class {{componentName}} : SimpleInteractions.SimpleInteraction + { + protected override void OnStart() + { + base.OnStart(); + + // Put your initialization code here if you have any + } + + protected override void OnUpdate() + { + base.OnUpdate(); + + // Put your update code here if you have any + } + + + [Rpc.Broadcast] + protected override void OnInteract() + { + Log.Info($"{Rpc.Caller.DisplayName} interacted with {this.GameObject.Name}!"); + } + } + + """; + + var directory = System.IO.Path.GetDirectoryName( path ); + System.IO.File.WriteAllText( System.IO.Path.Combine( directory, componentName + Suffix ), content ); + } +} \ No newline at end of file diff --git a/Libraries/guusconl.simpleinteractions/LICENSE b/Libraries/guusconl.simpleinteractions/LICENSE new file mode 100644 index 0000000..f06e8dc --- /dev/null +++ b/Libraries/guusconl.simpleinteractions/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 GuuscoNL + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Libraries/guusconl.simpleinteractions/README.md b/Libraries/guusconl.simpleinteractions/README.md new file mode 100644 index 0000000..afc6a00 --- /dev/null +++ b/Libraries/guusconl.simpleinteractions/README.md @@ -0,0 +1,26 @@ +# Simple Interactions +Simple Interactions is an interaction system that focusses on keeping it simple. It is mostly meant for prototypes where it is handy for players to interact with object. For example you are creating particle effects and you have a demo game were people can see them in action. You can use this library so people can press buttons that activate your particles. + +Only first person is supported using the build in player controller. + +Feel free to fork this and make your own changes. I hope it helps you out! + +# How to use +Once installed you can go to `add new component` and select `New component`. Under `Create Script From Template` select `New SimpleInteraction` component. + +`OnInteract()` is called when the player interacts with the object. You can use this to do whatever you want. For example, you can make a door open, play a sound, or spawn a particle effect. + +`InteractionString` is the text that is displayed when the player can interact with the object. For example, you can set this to 'Open door'. Available in the editor. + +`InteractionEnabled` is a boolean that you can use to enable or disable the interaction. For example, you can set this to false when the door is already open. Available in the editor. + +`InteractionDistance` is the distance the player has to be from the object to interact with it. Available in the editor. + +`InteractionHold` is a boolean that you can use to make the player hold the interaction button to interact with the object. Available in the editor. + +`InteractionHoldDuration` is the duration the player has to hold the interaction button to interact with the object. Available in the editor. + +`Collider` is the collider the interaction system uses to check if the player is looking at the object. This is automatically set to the object's collider. But you can override this by setting it to another collider. Within the editor. Available in the editor. + +# Demo +I made a demo scene to show you how to use the library. You can find it [here](https://sbox.game/guusconl/simple_interactions_demo) \ No newline at end of file diff --git a/Libraries/guusconl.simpleinteractions/simpleinteractions.sbproj b/Libraries/guusconl.simpleinteractions/simpleinteractions.sbproj new file mode 100644 index 0000000..0345ed7 --- /dev/null +++ b/Libraries/guusconl.simpleinteractions/simpleinteractions.sbproj @@ -0,0 +1,13 @@ +{ + "Title": "SimpleInteractions", + "Type": "library", + "Org": "guusconl", + "Ident": "simpleinteractions", + "Schema": 1, + "IncludeSourceFiles": false, + "Resources": null, + "PackageReferences": [], + "EditorReferences": null, + "IsWhitelistDisabled": false, + "Metadata": {} +} \ No newline at end of file