├── .gitattributes ├── .gitignore ├── LICENSE.md ├── README.md ├── demo ├── .idea │ ├── .idea.SofiaConsole.dir │ │ └── .idea │ │ │ ├── .gitignore │ │ │ └── indexLayout.xml │ └── .idea.SofiaConsole │ │ └── .idea │ │ ├── .gitignore │ │ ├── indexLayout.xml │ │ └── vcs.xml ├── Player.cs ├── PlayerCamera.cs ├── SofiaConsole.csproj ├── SofiaConsole.sln ├── addons │ └── sofiaconsole │ │ ├── Commands │ │ ├── ClearCommand.cs │ │ ├── DebugCamera.cs │ │ ├── DebugCameraCommand.cs │ │ ├── FpsCounterCommand.cs │ │ ├── HelloWorldCommand.cs │ │ ├── HelpCommand.cs │ │ ├── InfoCommand.cs │ │ ├── ReloadCommand.cs │ │ ├── TimeCommand.cs │ │ └── ToggleConsoleCommand.cs │ │ ├── Console.cs │ │ ├── Console.tscn │ │ ├── ConsoleCommandAttribute.cs │ │ ├── ConsoleCommandReference.cs │ │ ├── SofiaConsole.cs │ │ ├── icon.svg │ │ ├── icon.svg.import │ │ └── plugin.cfg ├── demo.tscn ├── icon.svg ├── icon.svg.import ├── models │ ├── LICENSE │ ├── gdbot │ │ ├── LICENSE.gdbot.md │ │ ├── custom_animations │ │ │ ├── custom_lib.res │ │ │ └── default_heartbeat.tres │ │ ├── gdbot.glb │ │ ├── gdbot.glb.import │ │ ├── gdbot_face.gd │ │ ├── gdbot_face.tscn │ │ ├── gdbot_skin.gd │ │ ├── gdbot_skin.tscn │ │ ├── materials │ │ │ ├── gdbot_face_mat.tres │ │ │ ├── glass_mat.tres │ │ │ └── heart_core_mat.tres │ │ └── texture │ │ │ ├── closed.png │ │ │ ├── closed.png.import │ │ │ ├── open.png │ │ │ ├── open.png.import │ │ │ └── parts │ │ │ ├── eye_close.png │ │ │ ├── eye_close.png.import │ │ │ ├── eye_happy.png │ │ │ ├── eye_happy.png.import │ │ │ ├── eye_open.png │ │ │ ├── eye_open.png.import │ │ │ ├── eye_spiral.png │ │ │ ├── eye_spiral.png.import │ │ │ ├── open_mouth.png │ │ │ ├── open_mouth.png.import │ │ │ ├── smile.png │ │ │ └── smile.png.import │ └── shared │ │ ├── shaders │ │ └── screen_shader.gdshader │ │ └── textures │ │ ├── eye_mask.png │ │ └── eye_mask.png.import └── project.godot └── docs ├── icon_512.png └── screenshot.png /.gitattributes: -------------------------------------------------------------------------------- 1 | # Normalize EOL for all files that Git considers text files. 2 | * text=auto eol=lf 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | demo/.idea/ 2 | 3 | # Godot 4+ specific ignores 4 | demo/.godot/ 5 | 6 | # Godot-specific ignores 7 | demo/.import/ 8 | demo/export.cfg 9 | demo/export_presets.cfg 10 | 11 | # Imported translations (automatically generated from CSV files) 12 | demo/*.translation 13 | 14 | # Mono-specific ignores 15 | demo/.mono/ 16 | demo/data_*/ 17 | demo/mono_crash.*.json -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2023 Laura Sofia Heimann 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SofiaConsole 2 | An easy to use in-game dev console for Godot 4 (C#) 3 | 4 | ![](/docs/screenshot.png) 5 | 6 | ## Getting Started 7 | ### How to install 8 | - Copy the `addons/sofiaconsole` folder into your project 9 | - Build your project 10 | - Enable the plugin 11 | - Make sure, that `res://addons/sofiaconsole/Console.tscn` is a global autoload with the name `Console` 12 | 13 | ### How to use 14 | - Press `F3` in-game to open the console 15 | - You can create an input action named "toggle_console" to define a custom key/button 16 | 17 | ## Commands 18 | ### How to add commands 19 | Simply add the `[ConsoleCommand]` attribute to a method to register it as a command. A command must always provide a command name to be executed. You can also optionally provide a `Description` and `Usage` string. 20 | 21 | #### Examples 22 | - `[ConsoleCommand("mycommand")]` 23 | - `[ConsoleCommand("mycommand", Description = "This should describe my command")]` 24 | - `[ConsoleCommand("move", Description = "Moves player", Usage = "move [x] [y] [z]")]` 25 | 26 | #### Helpers 27 | There are a few helper methods your command can call. 28 | - `Console.Instance.ClearConsole();` - clears the console 29 | - `Console.Instance.Space();` - adds a blank line 30 | - `Console.Instance.Space(n);` - adds n blank lines 31 | - `Console.Instance.Print("Hello World");` - adds a string as output (PrintType is Default) 32 | - `Console.Instance.Print("Hello World", Console.PrintType.Default);` - white 33 | - `Console.Instance.Print("Hello World", Console.PrintType.Hint);` - grey 34 | - `Console.Instance.Print("Hello World", Console.PrintType.Warning);` - orange 35 | - `Console.Instance.Print("Hello World", Console.PrintType.Error);` - red 36 | - `Console.Instance.Print("Hello World", Console.PrintType.Success);` - green 37 | 38 | ### Built in commands 39 | We have created a few default commands that are always available. 40 | 41 | - `clear` 42 | - Clears the console history 43 | - `devcam` 44 | - Toggles between the current camera and a free-flying camera 45 | - `fps / togglefps` 46 | - Toggles the FPS counter 47 | - `maxfps [fps]` 48 | - Adds an fps limit, 0 (or no parameter value) disabled the limiter 49 | - `helloworld` 50 | - Prints 'Hello World!' in the console 51 | - `help [command?]` 52 | - Shows all registered commands. If command is specified, it will display the description and usage of a single command 53 | - `info` 54 | - Prints general information about your game, engine and PC 55 | - `reload` 56 | - Reloads the current scene 57 | - `timescale` 58 | - Sets the timescale 59 | - `toggleconsole` 60 | - Toggles the console 61 | 62 | ### Demo Project 63 | This repository contains a demo project that implements a `noclip` console command to showcase the usage of this addon. -------------------------------------------------------------------------------- /demo/.idea/.idea.SofiaConsole.dir/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Rider ignored files 5 | /modules.xml 6 | /contentModel.xml 7 | /projectSettingsUpdater.xml 8 | /.idea.SofiaConsole.iml 9 | # Editor-based HTTP Client requests 10 | /httpRequests/ 11 | # Datasource local storage ignored files 12 | /dataSources/ 13 | /dataSources.local.xml 14 | -------------------------------------------------------------------------------- /demo/.idea/.idea.SofiaConsole.dir/.idea/indexLayout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /demo/.idea/.idea.SofiaConsole/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Rider ignored files 5 | /modules.xml 6 | /contentModel.xml 7 | /.idea.SofiaConsole.iml 8 | /projectSettingsUpdater.xml 9 | # Editor-based HTTP Client requests 10 | /httpRequests/ 11 | # Datasource local storage ignored files 12 | /dataSources/ 13 | /dataSources.local.xml 14 | -------------------------------------------------------------------------------- /demo/.idea/.idea.SofiaConsole/.idea/indexLayout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /demo/.idea/.idea.SofiaConsole/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /demo/Player.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using media.Laura.SofiaConsole; 3 | 4 | public partial class Player : RigidBody3D 5 | { 6 | private Vector3 _input; 7 | private bool _noclipOn = false; 8 | private Node3D _gdBotSkin; 9 | 10 | public override void _EnterTree() 11 | { 12 | base._EnterTree(); 13 | 14 | _gdBotSkin = GetNode("GDbotSkin"); 15 | } 16 | 17 | public override void _Process(double delta) 18 | { 19 | _input = Vector3.Zero; 20 | 21 | if (!Console.Instance.Open) 22 | { 23 | if (Input.IsActionPressed("move_left")) _input.X -= 5f; 24 | if (Input.IsActionPressed("move_right")) _input.X += 5f; 25 | if (Input.IsActionPressed("move_forward")) _input.Z -= 5f; 26 | if (Input.IsActionPressed("move_backward")) _input.Z += 5f; 27 | 28 | if (_noclipOn) 29 | { 30 | if (Input.IsActionPressed("move_up")) _input.Y += 5f; 31 | if (Input.IsActionPressed("move_down")) _input.Y -= 5f; 32 | } 33 | 34 | if (Input.IsActionJustPressed("jump")) 35 | { 36 | _gdBotSkin.Call("jump"); 37 | ApplyImpulse(Vector3.Up * 10f); 38 | } 39 | } 40 | 41 | if (_input != Vector3.Zero) 42 | { 43 | _gdBotSkin.Call("walk"); 44 | } 45 | if (_input == Vector3.Zero) 46 | { 47 | _gdBotSkin.Call("idle"); 48 | } 49 | 50 | if (_noclipOn) 51 | { 52 | _gdBotSkin.Call("fall"); 53 | } 54 | } 55 | 56 | public override void _IntegrateForces(PhysicsDirectBodyState3D state) 57 | { 58 | base._IntegrateForces(state); 59 | 60 | if(!_noclipOn) 61 | state.LinearVelocity = new Vector3(_input.X, LinearVelocity.Y, _input.Z); 62 | } 63 | 64 | public override void _PhysicsProcess(double delta) 65 | { 66 | base._PhysicsProcess(delta); 67 | 68 | var lookDirection = new Vector3(Position.X + _input.X * 2f, Position.Y, Position.Z + _input.Z * 2f); 69 | 70 | if (lookDirection != Position) 71 | { 72 | LookAt(lookDirection, Vector3.Up); 73 | } 74 | 75 | if (_noclipOn) 76 | { 77 | Position += _input * 2f * (float)delta; 78 | } 79 | } 80 | 81 | [ConsoleCommand("noclip", Description = "Allows you to move the player without physics")] 82 | public void DebugToggleNoclip() 83 | { 84 | _noclipOn = !_noclipOn; 85 | 86 | if (_noclipOn) 87 | { 88 | Freeze = true; 89 | Console.Instance.Print("Noclip on"); 90 | } 91 | else 92 | { 93 | Freeze = false; 94 | Console.Instance.Print("Noclip off"); 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /demo/PlayerCamera.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | 4 | public partial class PlayerCamera : Camera3D 5 | { 6 | [Export] public Node3D FollowTarget; 7 | [Export] public Vector3 Offset; 8 | 9 | public override void _PhysicsProcess(double delta) 10 | { 11 | base._PhysicsProcess(delta); 12 | 13 | Position = FollowTarget.Position + Offset; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /demo/SofiaConsole.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net6.0 4 | true 5 | 6 | -------------------------------------------------------------------------------- /demo/SofiaConsole.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio 2012 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SofiaConsole", "SofiaConsole.csproj", "{8740F8CA-0EA1-4006-A168-5DD8F84404C8}" 4 | EndProject 5 | Global 6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 7 | Debug|Any CPU = Debug|Any CPU 8 | ExportDebug|Any CPU = ExportDebug|Any CPU 9 | ExportRelease|Any CPU = ExportRelease|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {8740F8CA-0EA1-4006-A168-5DD8F84404C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {8740F8CA-0EA1-4006-A168-5DD8F84404C8}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {8740F8CA-0EA1-4006-A168-5DD8F84404C8}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU 15 | {8740F8CA-0EA1-4006-A168-5DD8F84404C8}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU 16 | {8740F8CA-0EA1-4006-A168-5DD8F84404C8}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU 17 | {8740F8CA-0EA1-4006-A168-5DD8F84404C8}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU 18 | EndGlobalSection 19 | EndGlobal 20 | -------------------------------------------------------------------------------- /demo/addons/sofiaconsole/Commands/ClearCommand.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable once CheckNamespace 2 | namespace media.Laura.SofiaConsole.Commands; 3 | 4 | public class ClearCommand 5 | { 6 | [ConsoleCommand("clear", Description = "Clears the console history")] 7 | public void ClearConsole() 8 | { 9 | Console.Instance.ClearConsole(); 10 | } 11 | } -------------------------------------------------------------------------------- /demo/addons/sofiaconsole/Commands/DebugCamera.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | 4 | public partial class DebugCamera : Camera3D 5 | { 6 | private Vector3 _input; 7 | 8 | public override void _Process(double delta) 9 | { 10 | _input = Vector3.Zero; 11 | 12 | // Forward/Backward/Left/Right 13 | if (Input.IsKeyPressed(Key.Kp8)) _input.Z -= 1f; 14 | if (Input.IsKeyPressed(Key.Kp2)) _input.Z += 1f; 15 | if (Input.IsKeyPressed(Key.Kp4)) _input.X -= 1f; 16 | if (Input.IsKeyPressed(Key.Kp6)) _input.X += 1f; 17 | 18 | // Up/Down 19 | if (Input.IsKeyPressed(Key.Kp7)) _input.Y += 1f; 20 | if (Input.IsKeyPressed(Key.Kp9)) _input.Y -= 1f; 21 | 22 | // Rotate Left/Right 23 | if (Input.IsKeyPressed(Key.Kp1)) RotateY(5f * (float)delta); 24 | if (Input.IsKeyPressed(Key.Kp3)) RotateY(-5f * (float)delta); 25 | 26 | Translate(_input * 5f * (float)delta); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /demo/addons/sofiaconsole/Commands/DebugCameraCommand.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable once CheckNamespace 2 | namespace media.Laura.SofiaConsole.Commands; 3 | 4 | using Godot; 5 | 6 | public partial class DebugCameraCommand : Node 7 | { 8 | private Camera3D _currentCamera; 9 | private Camera3D _debugCamera; 10 | private bool _active = false; 11 | 12 | public override void _EnterTree() 13 | { 14 | base._EnterTree(); 15 | 16 | _debugCamera = GetNode("DebugCamera"); 17 | } 18 | 19 | [ConsoleCommand("devcam", Description = "Toggles between the current camera and a free-flying camera")] 20 | public void ToggleDebugCamera() 21 | { 22 | _active = !_active; 23 | 24 | if (_active) 25 | { 26 | _currentCamera = GetViewport().GetCamera3D(); 27 | 28 | _debugCamera.Fov = _currentCamera.Fov; 29 | _debugCamera.Position = _currentCamera.Position; 30 | _debugCamera.Rotation = _currentCamera.Rotation; 31 | _debugCamera.Visible = true; 32 | _debugCamera.MakeCurrent(); 33 | 34 | Console.Instance.Print("Dev camera on"); 35 | } 36 | else 37 | { 38 | _currentCamera.MakeCurrent(); 39 | _debugCamera.Visible = false; 40 | 41 | Console.Instance.Print("Dev camera off"); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /demo/addons/sofiaconsole/Commands/FpsCounterCommand.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable once CheckNamespace 2 | namespace media.Laura.SofiaConsole.Commands; 3 | 4 | using Godot; 5 | 6 | public partial class FpsCounterCommand : Node 7 | { 8 | private CanvasLayer _canvas; 9 | private Label _label; 10 | 11 | public override void _EnterTree() 12 | { 13 | base._EnterTree(); 14 | 15 | _canvas = GetNode("CounterCanvas"); 16 | _label = GetNode