├── config ├── terrys-summer-car.fgd ├── plugs │ ├── cube.plug_c │ └── cube.plug ├── props │ ├── hamster.prop_c │ └── hamster.prop ├── sockets │ ├── cube.socket_c │ └── cube.socket ├── plug.asset ├── socket.asset └── prop.asset ├── README.md ├── .addon ├── .gitattributes ├── models └── props │ ├── hamster.vmdl_c │ └── hamster.vmdl ├── .gitignore ├── materials ├── props │ ├── hamster.vmat_c │ └── hamster.vmat └── default │ ├── default_ao_tga_559f1ac6.vtex_c │ └── default_normal_tga_7be61377.vtex_c ├── textures ├── props │ └── hamster │ │ ├── hamster.gif │ │ ├── hamster.png │ │ ├── hamster_translucent.png │ │ └── hamster_png_d51e27fa.vtex_c └── hamster_png_2054fab7.vtex_c ├── code ├── ui │ ├── InventoryPanel.cs │ ├── tschud.scss │ ├── Health.cs │ └── TSCHud.cs ├── readme.txt ├── plugs │ └── PlugEntity.cs ├── props │ └── TSCPropEntity.cs ├── sockets │ └── SocketEntity.cs ├── TPoseAnimator.cs ├── Player.cs ├── assets │ ├── Plug.cs │ ├── Socket.cs │ └── Prop.cs ├── Game.cs └── Hands.cs ├── maps └── editor │ └── _bakeresourcecache │ └── toolscene_default_baked │ ├── env_cubemap_16.txt │ ├── env_cubemap_16.exr │ ├── env_cubemap_16.vtex_c │ ├── env_light_probe_volume_16.exr │ ├── env_light_probe_volume_16.vtex_c │ ├── env_cubemap_16.vtex │ └── env_light_probe_volume_16.vtex └── LICENSE /config/terrys-summer-car.fgd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Terry's Summer Car 2 | 3 | WIP -------------------------------------------------------------------------------- /.addon: -------------------------------------------------------------------------------- 1 | { 2 | "sharedassets": "*.*", 3 | "ident": "tesa.tsc" 4 | } 5 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /config/plugs/cube.plug_c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/terrys-summer-car/master/config/plugs/cube.plug_c -------------------------------------------------------------------------------- /config/props/hamster.prop_c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/terrys-summer-car/master/config/props/hamster.prop_c -------------------------------------------------------------------------------- /models/props/hamster.vmdl_c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/terrys-summer-car/master/models/props/hamster.vmdl_c -------------------------------------------------------------------------------- /config/sockets/cube.socket_c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/terrys-summer-car/master/config/sockets/cube.socket_c -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | code/*.csproj 2 | code/obj 3 | code/code 4 | code/Properties 5 | .intermediate 6 | tools_*.bin 7 | _bakeresourcecache -------------------------------------------------------------------------------- /materials/props/hamster.vmat_c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/terrys-summer-car/master/materials/props/hamster.vmat_c -------------------------------------------------------------------------------- /textures/props/hamster/hamster.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/terrys-summer-car/master/textures/props/hamster/hamster.gif -------------------------------------------------------------------------------- /textures/props/hamster/hamster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/terrys-summer-car/master/textures/props/hamster/hamster.png -------------------------------------------------------------------------------- /textures/hamster_png_2054fab7.vtex_c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/terrys-summer-car/master/textures/hamster_png_2054fab7.vtex_c -------------------------------------------------------------------------------- /code/ui/InventoryPanel.cs: -------------------------------------------------------------------------------- 1 | using Sandbox.UI; 2 | 3 | namespace TSC 4 | { 5 | public partial class InventoryPanel : Panel 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /textures/props/hamster/hamster_translucent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/terrys-summer-car/master/textures/props/hamster/hamster_translucent.png -------------------------------------------------------------------------------- /maps/editor/_bakeresourcecache/toolscene_default_baked/env_cubemap_16.txt: -------------------------------------------------------------------------------- 1 | "TextureOptions" 2 | { 3 | "ggx_cubemap_blur_accumulation_pass_count" "1" 4 | } 5 | -------------------------------------------------------------------------------- /materials/default/default_ao_tga_559f1ac6.vtex_c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/terrys-summer-car/master/materials/default/default_ao_tga_559f1ac6.vtex_c -------------------------------------------------------------------------------- /materials/default/default_normal_tga_7be61377.vtex_c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/terrys-summer-car/master/materials/default/default_normal_tga_7be61377.vtex_c -------------------------------------------------------------------------------- /textures/props/hamster/hamster_png_d51e27fa.vtex_c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/terrys-summer-car/master/textures/props/hamster/hamster_png_d51e27fa.vtex_c -------------------------------------------------------------------------------- /code/readme.txt: -------------------------------------------------------------------------------- 1 | This is the code for your game. 2 | 3 | You don't need to manually add files to any project, files you add here will automatically be 4 | compiled. Even if they're deep in subfolders. -------------------------------------------------------------------------------- /maps/editor/_bakeresourcecache/toolscene_default_baked/env_cubemap_16.exr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/terrys-summer-car/master/maps/editor/_bakeresourcecache/toolscene_default_baked/env_cubemap_16.exr -------------------------------------------------------------------------------- /maps/editor/_bakeresourcecache/toolscene_default_baked/env_cubemap_16.vtex_c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/terrys-summer-car/master/maps/editor/_bakeresourcecache/toolscene_default_baked/env_cubemap_16.vtex_c -------------------------------------------------------------------------------- /config/plug.asset: -------------------------------------------------------------------------------- 1 | // 2 | // TSC.Plug 3 | // 4 | @BaseClass = plug : "" 5 | [ 6 | title(string) : "Title" : : "" 7 | type(string) : "Type" : : "" 8 | model(resource:vmdl) : "Model" : : "" 9 | ] 10 | 11 | -------------------------------------------------------------------------------- /code/plugs/PlugEntity.cs: -------------------------------------------------------------------------------- 1 | 2 | using Sandbox; 3 | 4 | namespace TSC 5 | { 6 | public class PlugEntity : ModelEntity 7 | { 8 | public string PlugType; 9 | 10 | public PlugEntity() 11 | { 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /maps/editor/_bakeresourcecache/toolscene_default_baked/env_light_probe_volume_16.exr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/terrys-summer-car/master/maps/editor/_bakeresourcecache/toolscene_default_baked/env_light_probe_volume_16.exr -------------------------------------------------------------------------------- /maps/editor/_bakeresourcecache/toolscene_default_baked/env_light_probe_volume_16.vtex_c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rndtrash/terrys-summer-car/master/maps/editor/_bakeresourcecache/toolscene_default_baked/env_light_probe_volume_16.vtex_c -------------------------------------------------------------------------------- /config/plugs/cube.plug: -------------------------------------------------------------------------------- 1 | 2 | { 3 | data = 4 | { 5 | title = "Cube1" 6 | type = "structural" 7 | model = resource:"models/dev/error.vmdl" 8 | } 9 | } -------------------------------------------------------------------------------- /config/socket.asset: -------------------------------------------------------------------------------- 1 | // 2 | // TSC.Socket 3 | // 4 | @BaseClass = socket : "" 5 | [ 6 | title(string) : "Title" : : "" 7 | type(string) : "Type" : : "" 8 | model(resource:vmdl) : "Model" : : "" 9 | triggerzonemins(vector) : "Trigger Zone Mins" : : "" 10 | triggerzonemaxs(vector) : "Trigger Zone Maxs" : : "" 11 | ] 12 | 13 | -------------------------------------------------------------------------------- /code/props/TSCPropEntity.cs: -------------------------------------------------------------------------------- 1 | using Sandbox; 2 | using System.Collections.Generic; 3 | 4 | namespace TSC 5 | { 6 | public class TSCPropEntity : Sandbox.Prop 7 | { 8 | public List Sockets = new(); 9 | public List Plugs = new(); 10 | 11 | public TSCPropEntity() : base() 12 | { 13 | // 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /config/sockets/cube.socket: -------------------------------------------------------------------------------- 1 | 2 | { 3 | data = 4 | { 5 | title = "Cube1" 6 | type = "structural" 7 | model = resource:"models/dev/error.vmdl" 8 | triggerzonemins = [ -25.0, -25.0, -25.0 ] 9 | triggerzonemaxs = [ 25.0, 25.0, 25.0 ] 10 | } 11 | } -------------------------------------------------------------------------------- /config/prop.asset: -------------------------------------------------------------------------------- 1 | // 2 | // TSC.Prop 3 | // 4 | @BaseClass = prop : "" 5 | [ 6 | title(string) : "Title" : : "" 7 | description(string) : "Description" : : "" 8 | type(string) : "Type" : : "" 9 | model(resource:vmdl) : "Model" : : "" 10 | plugattachmentpoints(array:string) : "Plug Attachment Points" : : "" 11 | socketattachmentpoints(array:string) : "Socket Attachment Points" : : "" 12 | ] 13 | 14 | -------------------------------------------------------------------------------- /code/ui/tschud.scss: -------------------------------------------------------------------------------- 1 | Health { 2 | position: absolute; 3 | background-color: rgba( black, 0.5 ); 4 | border-radius: 3px; 5 | right: 100px; 6 | bottom: 48px; 7 | font-size: 40px; 8 | font-weight: bold; 9 | font-family: Poppins; 10 | color: white; 11 | height: 80px; 12 | padding: 0 20px; 13 | align-items: center; 14 | 15 | .icon { 16 | font-size: 30px; 17 | padding-right: 10px; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /config/props/hamster.prop: -------------------------------------------------------------------------------- 1 | 2 | { 3 | data = 4 | { 5 | title = "Hamster" 6 | description = "Hamster :)" 7 | type = "generic" 8 | model = resource:"models/props/hamster.vmdl" 9 | plugattachmentpoints = 10 | [ 11 | "plug;cube", 12 | ] 13 | socketattachmentpoints = 14 | [ 15 | "socket;cube", 16 | ] 17 | } 18 | } -------------------------------------------------------------------------------- /code/sockets/SocketEntity.cs: -------------------------------------------------------------------------------- 1 | using Sandbox; 2 | using System; 3 | 4 | namespace TSC 5 | { 6 | public partial class SocketEntity : ModelEntity 7 | { 8 | public string SocketType; 9 | 10 | [Net] 11 | public BaseTrigger PlugTrigger { get; set; } 12 | 13 | public SocketEntity() 14 | { 15 | } 16 | 17 | // TODO: remove 18 | [Event.Tick.Server] 19 | public void TickServer() 20 | { 21 | DebugOverlay.Box( 0, PlugTrigger.Position - PlugTrigger.CollisionBounds.Maxs / 2, PlugTrigger.Position + PlugTrigger.CollisionBounds.Maxs / 2, Color.Red, false ); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /code/ui/Health.cs: -------------------------------------------------------------------------------- 1 | using Sandbox; 2 | using Sandbox.UI; 3 | using Sandbox.UI.Construct; 4 | 5 | namespace TSC 6 | { 7 | public class Health : Panel 8 | { 9 | public Label Label; 10 | 11 | public Health() 12 | { 13 | Add.Label( "🩸", "icon" ); 14 | Label = Add.Label( "100", "value" ); 15 | } 16 | 17 | public override void Tick() 18 | { 19 | var player = Local.Pawn; 20 | if ( player == null ) return; 21 | 22 | Label.Text = $"{player.Health:n0}"; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /code/TPoseAnimator.cs: -------------------------------------------------------------------------------- 1 | using Sandbox; 2 | 3 | namespace TSC 4 | { 5 | class TPoseAnimator : PawnAnimator 6 | { 7 | public override void Simulate() 8 | { 9 | Rotation = Rotation.LookAt( Input.Rotation.Forward.WithZ( 0 ), Vector3.Up ); 10 | 11 | // 12 | // Look in the direction what the player's input is facing 13 | // 14 | 15 | SetLookAt( "aim_eyes", Pawn.EyePos + Input.Rotation.Forward * 200 ); 16 | 17 | if ( Pawn.ActiveChild is BaseCarriable carry ) 18 | { 19 | carry.SimulateAnimator( this ); 20 | } 21 | } 22 | 23 | public override void OnEvent( string name ) 24 | { 25 | base.OnEvent( name ); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /code/ui/TSCHud.cs: -------------------------------------------------------------------------------- 1 | using Sandbox.UI; 2 | 3 | // 4 | // You don't need to put things in a namespace, but it doesn't hurt. 5 | // 6 | namespace TSC 7 | { 8 | /// 9 | /// This is the HUD entity. It creates a RootPanel clientside, which can be accessed 10 | /// via RootPanel on this entity, or Local.Hud. 11 | /// 12 | public partial class TSCHudEntity : Sandbox.HudEntity 13 | { 14 | public TSCHudEntity() 15 | { 16 | if ( IsClient ) 17 | { 18 | //RootPanel.SetTemplate( "/ui/tschud.html" ); 19 | RootPanel.StyleSheet.Load( "/ui/tschud.scss" ); 20 | 21 | RootPanel.AddChild(); 22 | RootPanel.AddChild(); 23 | RootPanel.AddChild(); 24 | RootPanel.AddChild>(); 25 | RootPanel.AddChild(); 26 | 27 | RootPanel.AddChild(); 28 | } 29 | } 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Ivan Kuzmenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /code/Player.cs: -------------------------------------------------------------------------------- 1 | using Sandbox; 2 | 3 | namespace TSC 4 | { 5 | public partial class TSCPlayer : Player 6 | { 7 | public override void Respawn() 8 | { 9 | SetModel( "models/citizen/citizen.vmdl" ); 10 | 11 | // 12 | // Use WalkController for movement (you can make your own PlayerController for 100% control) 13 | // 14 | Controller = new WalkController(); 15 | 16 | // T POSE 17 | Animator = new TPoseAnimator(); 18 | 19 | // 20 | // Use ThirdPersonCamera (you can make your own Camera for 100% control) 21 | // 22 | Camera = new FirstPersonCamera(); 23 | 24 | EnableAllCollisions = true; 25 | EnableDrawing = true; 26 | EnableHideInFirstPerson = true; 27 | EnableShadowInFirstPerson = true; 28 | 29 | var h = new Hands(); 30 | h.OnCarryStart( this ); 31 | ActiveChild = h; 32 | h.OnActive(); 33 | 34 | base.Respawn(); 35 | } 36 | 37 | /// 38 | /// Called every tick, clientside and serverside. 39 | /// 40 | public override void Simulate( Client cl ) 41 | { 42 | base.Simulate( cl ); 43 | 44 | SimulateActiveChild( cl, ActiveChild ); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /code/assets/Plug.cs: -------------------------------------------------------------------------------- 1 | using Sandbox; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace TSC 6 | { 7 | [Library( "plug" ), AutoGenerate] 8 | public partial class Plug : Asset 9 | { 10 | public static IReadOnlyDictionary All => _all; 11 | internal static Dictionary _all = new(); 12 | 13 | [Property] 14 | public string Title { get; set; } 15 | [Property] 16 | public string Type { get; set; } 17 | [Property, ResourceType( "vmdl" )] 18 | public string Model { get; set; } 19 | 20 | public Plug() : base() 21 | { 22 | Log.Info( "New plug!" ); 23 | } 24 | 25 | protected override void PostLoad() 26 | { 27 | base.PostLoad(); 28 | 29 | if ( !_all.ContainsKey( Name ) ) 30 | _all.Add( Name, this ); 31 | } 32 | 33 | public PlugEntity Spawn() 34 | { 35 | PlugEntity o; 36 | switch ( Type ) 37 | { 38 | case "structural": 39 | o = new PlugEntity(); 40 | break; 41 | default: 42 | throw new ArgumentException( $"WTF?? No constructor for {Type}???" ); 43 | } 44 | 45 | o.PlugType = Type; 46 | o.SetModel( Model ); 47 | o.SetupPhysicsFromModel( PhysicsMotionType.Static ); // TODO: Static? 48 | 49 | return o; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /code/Game.cs: -------------------------------------------------------------------------------- 1 | using Sandbox; 2 | 3 | // 4 | // You don't need to put things in a namespace, but it doesn't hurt. 5 | // 6 | namespace TSC 7 | { 8 | public partial class TSCGame : Game 9 | { 10 | public TSCGame() 11 | { 12 | if ( IsServer ) 13 | { 14 | _ = new TSCHudEntity(); 15 | } 16 | } 17 | 18 | /// 19 | /// A client has joined the server. Make them a pawn to play with 20 | /// 21 | public override void ClientJoined( Client client ) 22 | { 23 | base.ClientJoined( client ); 24 | 25 | var player = new TSCPlayer(); 26 | client.Pawn = player; 27 | 28 | player.Respawn(); 29 | } 30 | 31 | [AdminCmd( "tsc_spawn" )] 32 | public static void tsc_spawn( string name = "" ) 33 | { 34 | Assert.NotNull( ConsoleSystem.Caller ); 35 | 36 | if ( name == "" ) 37 | { 38 | if ( Prop.All.Count > 0 ) 39 | Log.Error( $"Available entities to spawn:\n- {string.Join( "\n- ", Prop.All.Keys )}" ); 40 | return; 41 | } 42 | 43 | if ( Prop.All.ContainsKey( name ) ) 44 | { 45 | var o = Prop.All[name].Spawn(); 46 | 47 | var p = ConsoleSystem.Caller.Pawn; 48 | o.Position = p.Position + p.Rotation.Forward.Normal * 100.0f; 49 | } 50 | else 51 | Log.Warning( $"tsc_spawn: not found {name}." ); 52 | } 53 | 54 | [ServerCmd( "tsc_stats" )] 55 | public static void tsc_stats() 56 | { 57 | Log.Info( $"Plugs: {Plug.All.Count}; Sockets: {Socket.All.Count}; Props: {Prop.All.Count}" ); 58 | } 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /materials/props/hamster.vmat: -------------------------------------------------------------------------------- 1 | // THIS FILE IS AUTO-GENERATED 2 | 3 | Layer0 4 | { 5 | shader "complex.vfx" 6 | 7 | //---- Animation ---- 8 | F_TEXTURE_ANIMATION 1 9 | 10 | //---- Rendering ---- 11 | F_RENDER_BACKFACES 1 12 | 13 | //---- Translucent ---- 14 | F_TRANSLUCENT 1 15 | 16 | //---- Ambient Occlusion ---- 17 | g_flAmbientOcclusionDirectDiffuse "0.000" 18 | g_flAmbientOcclusionDirectSpecular "0.000" 19 | TextureAmbientOcclusion "materials/default/default_ao.tga" 20 | 21 | //---- Color ---- 22 | g_flModelTintAmount "1.000" 23 | g_vColorTint "[1.000000 1.000000 1.000000 0.000000]" 24 | TextureColor "textures/props/hamster/hamster.png" 25 | 26 | //---- Fade ---- 27 | g_flFadeExponent "1.000" 28 | 29 | //---- Fog ---- 30 | g_bFogEnabled "0" 31 | 32 | //---- Lighting ---- 33 | g_flDirectionalLightmapMinZ "0.050" 34 | g_flDirectionalLightmapStrength "1.000" 35 | 36 | //---- Metalness ---- 37 | g_flMetalness "0.000" 38 | 39 | //---- Normal ---- 40 | TextureNormal "materials/default/default_normal.tga" 41 | 42 | //---- Roughness ---- 43 | TextureRoughness "materials/default/default_rough.tga" 44 | 45 | //---- Texture Animation ---- 46 | g_flAnimationFrame "0.000" 47 | g_flAnimationTimeOffset "0.000" 48 | g_flAnimationTimePerFrame "0.100" 49 | g_nNumAnimationCells "23" 50 | g_vAnimationGrid "[8 8]" 51 | 52 | //---- Texture Coordinates ---- 53 | g_nScaleTexCoordUByModelScaleAxis "0" 54 | g_nScaleTexCoordVByModelScaleAxis "0" 55 | g_vTexCoordOffset "[0.000 0.000]" 56 | g_vTexCoordScale "[1.000 1.000]" 57 | 58 | //---- Translucent ---- 59 | g_flOpacityScale "1.000" 60 | TextureTranslucency "textures/props/hamster/hamster_translucent.png" 61 | } -------------------------------------------------------------------------------- /code/assets/Socket.cs: -------------------------------------------------------------------------------- 1 | using Sandbox; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace TSC 6 | { 7 | [Library( "socket" ), AutoGenerate] 8 | public partial class Socket : Asset 9 | { 10 | public static IReadOnlyDictionary All => _all; 11 | internal static Dictionary _all = new(); 12 | 13 | [Property] 14 | public string Title { get; set; } 15 | [Property] 16 | public string Type { get; set; } 17 | [Property, ResourceType( "vmdl" )] 18 | public string Model { get; set; } 19 | [Property] 20 | public Vector3 TriggerZoneMins { get; set; } 21 | [Property] 22 | public Vector3 TriggerZoneMaxs { get; set; } 23 | 24 | public class TestTrigger : BaseTrigger 25 | { 26 | public override void Touch( Entity other ) 27 | { 28 | Log.Info( $"Touch! {other.EngineEntityName}" ); 29 | 30 | base.Touch( other ); 31 | } 32 | } 33 | 34 | protected override void PostLoad() 35 | { 36 | base.PostLoad(); 37 | 38 | if ( !_all.ContainsKey( Name ) ) 39 | _all.Add( Name, this ); 40 | } 41 | 42 | public SocketEntity Spawn() 43 | { 44 | SocketEntity o; 45 | switch ( Type ) 46 | { 47 | case "structural": 48 | o = new SocketEntity(); 49 | break; 50 | default: 51 | throw new ArgumentException( $"WTF?? No constructor for {Type}???" ); 52 | } 53 | 54 | o.SocketType = Type; 55 | o.SetModel( Model ); 56 | o.SetupPhysicsFromModel( PhysicsMotionType.Static ); // TODO: Static? 57 | 58 | var t = new TestTrigger(); 59 | t.Tags.Add( "socket" ); 60 | t.SetupPhysicsFromAABB( PhysicsMotionType.Static, TriggerZoneMins, TriggerZoneMaxs ); 61 | 62 | t.Parent = o; 63 | o.PlugTrigger = t; 64 | 65 | return o; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /maps/editor/_bakeresourcecache/toolscene_default_baked/env_cubemap_16.vtex: -------------------------------------------------------------------------------- 1 | 2 | "CDmeVtex" 3 | { 4 | "m_inputTextureArray" "element_array" 5 | [ 6 | "CDmeInputTexture" 7 | { 8 | "m_name" "string" "inputTexture0" 9 | "m_fileName" "string" "maps/editor/_bakeresourcecache/toolscene_default_baked/env_cubemap_16.exr" 10 | "m_colorSpace" "string" "linear" 11 | "m_fileExt" "string" "" 12 | "m_nMinBitsPerChannel" "int" "-1" 13 | "m_typeString" "string" "CUBE" 14 | "m_imageProcessorArray" "element_array" 15 | [ 16 | ] 17 | "m_bPassThroughToCompiledVtex" "bool" "0" 18 | "m_n3DSliceCount" "int" "-1" 19 | "m_n3DSliceWidth" "int" "-1" 20 | "m_n3DSliceHeight" "int" "-1" 21 | } 22 | ] 23 | "m_outputTypeString" "string" "CUBEARRAY" 24 | "m_outputFormat" "string" "BC6H" 25 | "m_outputClearColor" "vector4" "0 0 0 0" 26 | "m_nOutputMinDimension" "int" "0" 27 | "m_nOutputMaxDimension" "int" "0" 28 | "m_nOutputDimensionReduce" "int" "0" 29 | "m_textureOutputChannelArray" "element_array" 30 | [ 31 | "CDmeTextureOutputChannel" 32 | { 33 | "m_srcChannels" "string" "rgba" 34 | "m_dstChannels" "string" "rgba" 35 | "m_mipAlgorithm" "CDmeImageProcessor" 36 | { 37 | "m_algorithm" "string" "GGXCubeMapBlur" 38 | "m_stringArg" "string" "" 39 | "m_vFloat4Arg" "vector4" "0 0 0 0" 40 | } 41 | 42 | "m_outputColorSpace" "string" "linear" 43 | "m_inputTextureArray" "string_array" 44 | [ 45 | "inputTexture0" 46 | ] 47 | } 48 | ] 49 | "m_vClamp" "vector3" "0 0 0" 50 | "m_bNoLod" "bool" "0" 51 | "m_bHiddenAssetFlag" "bool" "1" 52 | "m_bCreateLinearColorSpaceApiTexture" "bool" "0" 53 | "m_nDisplayRectWidth" "int" "0" 54 | "m_nDisplayRectHeight" "int" "0" 55 | "m_nMotionVectorsMaxDistanceInPixels" "int" "0" 56 | } 57 | 58 | -------------------------------------------------------------------------------- /models/props/hamster.vmdl: -------------------------------------------------------------------------------- 1 | 2 | { 3 | rootNode = 4 | { 5 | _class = "RootNode" 6 | children = 7 | [ 8 | { 9 | _class = "RenderMeshList" 10 | children = 11 | [ 12 | { 13 | _class = "RenderPrimitivePlane" 14 | name = "hamster" 15 | parent_bone = "" 16 | material_name = "materials/props/hamster.vmat" 17 | origin = [ 0.0, 0.0, 0.0 ] 18 | angles = [ 0.0, 0.0, 0.0 ] 19 | max_u = 1.0 20 | max_v = 1.0 21 | width = 100.0 22 | height = 100.0 23 | segments_x = 1 24 | segments_y = 1 25 | }, 26 | ] 27 | }, 28 | { 29 | _class = "PhysicsShapeList" 30 | children = 31 | [ 32 | { 33 | _class = "PhysicsShapeBox" 34 | parent_bone = "" 35 | surface_prop = "metal" 36 | collision_prop = "default" 37 | origin = [ 0.0, 0.0, 0.0 ] 38 | angles = [ 0.0, 0.0, 0.0 ] 39 | dimensions = [ 100.0, 100.0, 1.0 ] 40 | }, 41 | ] 42 | }, 43 | { 44 | _class = "AttachmentList" 45 | children = 46 | [ 47 | { 48 | _class = "Attachment" 49 | name = "plug" 50 | parent_bone = "" 51 | relative_origin = [ -50.0, 0.0, 10.0 ] 52 | relative_angles = [ 0.0, 0.0, 0.0 ] 53 | weight = 1.0 54 | ignore_rotation = false 55 | }, 56 | { 57 | _class = "Attachment" 58 | name = "socket" 59 | parent_bone = "" 60 | relative_origin = [ 50.0, 0.0, 10.0 ] 61 | relative_angles = [ 0.0, 0.0, 0.0 ] 62 | weight = 1.0 63 | ignore_rotation = false 64 | }, 65 | ] 66 | }, 67 | ] 68 | model_archetype = "" 69 | primary_associated_entity = "" 70 | anim_graph_name = "" 71 | } 72 | } -------------------------------------------------------------------------------- /maps/editor/_bakeresourcecache/toolscene_default_baked/env_light_probe_volume_16.vtex: -------------------------------------------------------------------------------- 1 | 2 | "CDmeVtex" 3 | { 4 | "m_inputTextureArray" "element_array" 5 | [ 6 | "CDmeInputTexture" 7 | { 8 | "m_name" "string" "inputTexture0" 9 | "m_fileName" "string" "maps/editor/_bakeresourcecache/toolscene_default_baked/env_light_probe_volume_16.exr" 10 | "m_colorSpace" "string" "linear" 11 | "m_fileExt" "string" "" 12 | "m_nMinBitsPerChannel" "int" "-1" 13 | "m_typeString" "string" "3D" 14 | "m_imageProcessorArray" "element_array" 15 | [ 16 | "CDmeImageProcessor" 17 | { 18 | "m_algorithm" "string" "None" 19 | "m_stringArg" "string" "" 20 | "m_vFloat4Arg" "vector4" "0 0 0 0" 21 | } 22 | ] 23 | "m_bPassThroughToCompiledVtex" "bool" "0" 24 | "m_n3DSliceCount" "int" "48" 25 | "m_n3DSliceWidth" "int" "12" 26 | "m_n3DSliceHeight" "int" "16" 27 | } 28 | ] 29 | "m_outputTypeString" "string" "3D" 30 | "m_outputFormat" "string" "BC6H" 31 | "m_outputClearColor" "vector4" "0 0 0 0" 32 | "m_nOutputMinDimension" "int" "0" 33 | "m_nOutputMaxDimension" "int" "0" 34 | "m_nOutputDimensionReduce" "int" "0" 35 | "m_textureOutputChannelArray" "element_array" 36 | [ 37 | "CDmeTextureOutputChannel" 38 | { 39 | "m_srcChannels" "string" "rgba" 40 | "m_dstChannels" "string" "rgba" 41 | "m_mipAlgorithm" "CDmeImageProcessor" 42 | { 43 | "m_algorithm" "string" "None" 44 | "m_stringArg" "string" "" 45 | "m_vFloat4Arg" "vector4" "0 0 0 0" 46 | } 47 | 48 | "m_outputColorSpace" "string" "linear" 49 | "m_inputTextureArray" "string_array" 50 | [ 51 | "inputTexture0" 52 | ] 53 | } 54 | ] 55 | "m_vClamp" "vector3" "0 0 0" 56 | "m_bNoLod" "bool" "0" 57 | "m_bHiddenAssetFlag" "bool" "1" 58 | "m_bCreateLinearColorSpaceApiTexture" "bool" "0" 59 | "m_nDisplayRectWidth" "int" "0" 60 | "m_nDisplayRectHeight" "int" "0" 61 | "m_nMotionVectorsMaxDistanceInPixels" "int" "0" 62 | } 63 | 64 | -------------------------------------------------------------------------------- /code/assets/Prop.cs: -------------------------------------------------------------------------------- 1 | using Sandbox; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace TSC 6 | { 7 | [Library( "prop" ), AutoGenerate] 8 | public partial class Prop : Asset 9 | { 10 | public static IReadOnlyDictionary All => _all; 11 | internal static Dictionary _all = new(); 12 | 13 | [Property] 14 | public string Title { get; set; } 15 | [Property] 16 | public string Description { get; set; } 17 | [Property] 18 | public string Type { get; set; } 19 | [Property, ResourceType( "vmdl" )] 20 | public string Model { get; set; } 21 | [Property] 22 | public string[] PlugAttachmentPoints { get; set; } // Format: name;type 23 | [Property] 24 | public string[] SocketAttachmentPoints { get; set; } // Format: name;type 25 | 26 | protected override void PostLoad() 27 | { 28 | base.PostLoad(); 29 | 30 | if ( !_all.ContainsKey( Name ) ) 31 | _all.Add( Name, this ); 32 | } 33 | 34 | public TSCPropEntity Spawn() 35 | { 36 | TSCPropEntity o; 37 | switch ( Type ) 38 | { 39 | case "generic": 40 | o = new TSCPropEntity(); 41 | break; 42 | default: 43 | throw new ArgumentException( $"WTF?? No constructor for {Type}???" ); 44 | } 45 | 46 | o.SetModel( Model ); 47 | o.SetupPhysicsFromModel( PhysicsMotionType.Dynamic ); 48 | 49 | foreach ( var socketAttachmentPoint in SocketAttachmentPoints ) 50 | { 51 | var split = socketAttachmentPoint.Split( ";" ); 52 | if ( split.Length != 2 ) 53 | throw new ArgumentException( "Invalid socket attachment point format, should be \"attpointname;socketname\"" ); 54 | 55 | var att = o.GetAttachment( split[0] ); 56 | if ( !att.HasValue ) 57 | throw new ArgumentException( $"Invalid attachment point: {split[0]}" ); 58 | 59 | Socket socket; 60 | try 61 | { 62 | socket = Socket.All[split[1]]; 63 | } 64 | catch ( KeyNotFoundException ) 65 | { 66 | throw new ArgumentException( $"Invalid socket: {split[1]}" ); 67 | } 68 | 69 | SocketEntity so = socket.Spawn(); 70 | so.Position = att.Value.Position; 71 | so.Parent = o; 72 | so.Rotation = att.Value.Rotation; 73 | o.Sockets.Add( so ); 74 | } 75 | 76 | foreach ( var plugAttachmentPoint in PlugAttachmentPoints ) 77 | { 78 | var split = plugAttachmentPoint.Split( ";" ); 79 | if ( split.Length != 2 ) 80 | throw new ArgumentException( "Invalid plug attachment point format, should be \"attpointname;plugname\"" ); 81 | 82 | var att = o.GetAttachment( split[0] ); 83 | if ( !att.HasValue ) 84 | throw new ArgumentException( $"Invalid attachment point: {split[0]}" ); 85 | 86 | Plug plug; 87 | try 88 | { 89 | plug = Plug.All[split[1]]; 90 | } 91 | catch ( KeyNotFoundException ) 92 | { 93 | throw new ArgumentException( $"Invalid plug: {split[1]}" ); 94 | } 95 | 96 | PlugEntity po = plug.Spawn(); 97 | po.Position = att.Value.Position; 98 | po.Parent = o; 99 | po.Rotation = att.Value.Rotation; 100 | o.Plugs.Add( po ); 101 | } 102 | 103 | return o; 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /code/Hands.cs: -------------------------------------------------------------------------------- 1 | using Sandbox; 2 | using Sandbox.Joints; 3 | using System; 4 | using System.Linq; 5 | 6 | namespace TSC 7 | { 8 | public partial class Hands : BaseCarriable 9 | { 10 | public override string ViewModelPath => "weapons/rust_pistol/v_rust_pistol.vmdl"; 11 | 12 | private PhysicsBody holdBody; 13 | private WeldJoint holdJoint; 14 | 15 | public PhysicsBody HeldBody { get; private set; } 16 | public Rotation HeldRot { get; private set; } 17 | public ModelEntity HeldEntity { get; private set; } 18 | public CollisionGroup HeldCollisionGroup { get; private set; } 19 | 20 | protected virtual float LinearFrequency => 10.0f; 21 | protected virtual float LinearDampingRatio => 1.0f; 22 | protected virtual float AngularFrequency => 10.0f; 23 | protected virtual float AngularDampingRatio => 1.0f; 24 | protected virtual float ThrowForce => 1000.0f; 25 | protected virtual float HoldDistance => 150.0f; 26 | protected virtual float AttachDistance => 300.0f; 27 | protected virtual float DropCooldown => 0.5f; 28 | protected virtual float BreakLinearForce => 2000.0f; 29 | 30 | private TimeSince timeSinceDrop; 31 | 32 | public override void Spawn() 33 | { 34 | base.Spawn(); 35 | 36 | SetModel( "weapons/rust_pistol/rust_pistol.vmdl" ); 37 | 38 | CollisionGroup = CollisionGroup.Weapon; 39 | SetInteractsAs( CollisionLayer.Debris ); 40 | } 41 | 42 | public override void Simulate( Client client ) 43 | { 44 | if ( Owner is not Player owner ) return; 45 | 46 | if ( !IsServer ) 47 | return; 48 | 49 | using ( Prediction.Off() ) 50 | { 51 | var eyePos = owner.EyePos; 52 | var eyeRot = owner.EyeRot; 53 | var eyeDir = owner.EyeRot.Forward; 54 | 55 | if ( HeldBody.IsValid() && HeldBody.PhysicsGroup != null ) 56 | { 57 | if ( holdJoint.IsValid && !holdJoint.IsActive ) 58 | { 59 | GrabEnd(); 60 | } 61 | else if ( Input.Pressed( InputButton.Attack1 ) ) 62 | { 63 | if ( HeldBody.PhysicsGroup.BodyCount > 1 ) 64 | { 65 | // Don't throw ragdolls as hard 66 | HeldBody.PhysicsGroup.ApplyImpulse( eyeDir * (ThrowForce * 0.5f), true ); 67 | HeldBody.PhysicsGroup.ApplyAngularImpulse( Vector3.Random * ThrowForce, true ); 68 | } 69 | else 70 | { 71 | HeldBody.ApplyImpulse( eyeDir * (HeldBody.Mass * ThrowForce) ); 72 | HeldBody.ApplyAngularImpulse( Vector3.Random * (HeldBody.Mass * ThrowForce) ); 73 | } 74 | 75 | GrabEnd(); 76 | } 77 | else if ( Input.Pressed( InputButton.Use ) ) 78 | { 79 | timeSinceDrop = 0; 80 | 81 | GrabEnd(); 82 | } 83 | else 84 | { 85 | GrabMove( eyePos, eyeDir, eyeRot ); 86 | } 87 | 88 | return; 89 | } 90 | 91 | if ( timeSinceDrop < DropCooldown ) 92 | return; 93 | 94 | var tr = Trace.Ray( eyePos, eyePos + eyeDir * AttachDistance ) 95 | .UseHitboxes() 96 | .Ignore( owner, false ) 97 | .Radius( 2.0f ) 98 | .HitLayer( CollisionLayer.Debris ) 99 | .Run(); 100 | 101 | if ( !tr.Hit || !tr.Body.IsValid() || !tr.Entity.IsValid() || tr.Entity.IsWorld ) 102 | return; 103 | 104 | if ( tr.Entity.PhysicsGroup == null ) 105 | return; 106 | 107 | var modelEnt = tr.Entity as ModelEntity; 108 | if ( !modelEnt.IsValid() ) 109 | return; 110 | 111 | var body = tr.Body; 112 | 113 | if ( Input.Down( InputButton.Use ) ) 114 | { 115 | var physicsGroup = tr.Entity.PhysicsGroup; 116 | 117 | if ( physicsGroup.BodyCount > 1 ) 118 | { 119 | body = modelEnt.PhysicsBody; 120 | if ( !body.IsValid() ) 121 | return; 122 | } 123 | 124 | if ( eyePos.Distance( body.Position ) <= AttachDistance ) 125 | { 126 | GrabStart( modelEnt, body, eyePos + eyeDir * HoldDistance, eyeRot ); 127 | } 128 | } 129 | } 130 | } 131 | 132 | private void Activate() 133 | { 134 | if ( !holdBody.IsValid() ) 135 | { 136 | holdBody = new PhysicsBody 137 | { 138 | BodyType = PhysicsBodyType.Keyframed 139 | }; 140 | } 141 | } 142 | 143 | private void Deactivate() 144 | { 145 | GrabEnd(); 146 | 147 | holdBody?.Remove(); 148 | holdBody = null; 149 | } 150 | 151 | public override void ActiveStart( Entity ent ) 152 | { 153 | base.ActiveStart( ent ); 154 | 155 | if ( IsServer ) 156 | { 157 | Activate(); 158 | } 159 | } 160 | 161 | public override void ActiveEnd( Entity ent, bool dropped ) 162 | { 163 | base.ActiveEnd( ent, dropped ); 164 | 165 | if ( IsServer ) 166 | { 167 | Deactivate(); 168 | } 169 | } 170 | 171 | protected override void OnDestroy() 172 | { 173 | base.OnDestroy(); 174 | 175 | if ( IsServer ) 176 | { 177 | Deactivate(); 178 | } 179 | } 180 | 181 | public override void OnCarryDrop( Entity dropper ) 182 | { 183 | } 184 | 185 | private static bool IsBodyGrabbed( PhysicsBody body ) 186 | { 187 | // There for sure is a better way to deal with this 188 | if ( All.OfType().Any( x => x?.HeldBody?.PhysicsGroup == body?.PhysicsGroup ) ) return true; 189 | 190 | return false; 191 | } 192 | 193 | private void GrabStart( ModelEntity entity, PhysicsBody body, Vector3 grabPos, Rotation grabRot ) 194 | { 195 | if ( !body.IsValid() ) 196 | return; 197 | 198 | if ( body.PhysicsGroup == null ) 199 | return; 200 | 201 | if ( IsBodyGrabbed( body ) ) 202 | return; 203 | 204 | GrabEnd(); 205 | 206 | HeldBody = body; 207 | HeldRot = grabRot.Inverse * HeldBody.Rotation; 208 | 209 | holdBody.Position = grabPos; 210 | holdBody.Rotation = HeldBody.Rotation; 211 | 212 | HeldBody.Wake(); 213 | HeldBody.EnableAutoSleeping = false; 214 | 215 | holdJoint = PhysicsJoint.Weld 216 | .From( holdBody ) 217 | .To( HeldBody, HeldBody.LocalMassCenter ) 218 | .WithLinearSpring( LinearFrequency, LinearDampingRatio, 0.0f ) 219 | .WithAngularSpring( AngularFrequency, AngularDampingRatio, 0.0f ) 220 | .Breakable( HeldBody.Mass * BreakLinearForce, 0 ) 221 | .Create(); 222 | 223 | HeldEntity = entity; 224 | HeldCollisionGroup = HeldEntity.CollisionGroup; 225 | HeldEntity.CollisionGroup = CollisionGroup.Debris; 226 | 227 | var client = GetClientOwner(); 228 | client?.Pvs.Add( HeldEntity ); 229 | } 230 | 231 | private void GrabEnd() 232 | { 233 | if ( holdJoint.IsValid ) 234 | { 235 | holdJoint.Remove(); 236 | } 237 | 238 | if ( HeldBody.IsValid() ) 239 | { 240 | HeldBody.EnableAutoSleeping = true; 241 | } 242 | 243 | if ( HeldEntity.IsValid() ) 244 | { 245 | HeldEntity.CollisionGroup = HeldCollisionGroup; 246 | 247 | var client = GetClientOwner(); 248 | client?.Pvs.Remove( HeldEntity ); 249 | } 250 | 251 | HeldBody = null; 252 | HeldRot = Rotation.Identity; 253 | HeldEntity = null; 254 | } 255 | 256 | private void GrabMove( Vector3 startPos, Vector3 dir, Rotation rot ) 257 | { 258 | if ( !HeldBody.IsValid() ) 259 | return; 260 | 261 | holdBody.Position = startPos + dir * HoldDistance; 262 | holdBody.Rotation = rot * HeldRot; 263 | } 264 | } 265 | } 266 | --------------------------------------------------------------------------------