Allow client to run headlessly. (#727)

AKA Without Godot.

Still links against GodotSharp, but this does mean that you can run headless or not from the same binary.
This commit is contained in:
Pieter-Jan Briers
2019-01-19 18:23:41 +01:00
committed by GitHub
parent 58fb11a989
commit dbc88e253b
129 changed files with 3938 additions and 1315 deletions

View File

@@ -4,4 +4,5 @@
*.import
# Negation would be like this:
#!/Textures/UserInterface/1pxwhite.png.import
!/Scenes/SS14Window/closewindow.png.import
/I_MADE_THE_SYMLINK

View File

@@ -1,6 +1,6 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://Scenes/SS14Window/SS14Window.tscn" type="PackedScene" id=1]
[ext_resource path="res://Engine/Scenes/SS14Window/SS14Window.tscn" type="PackedScene" id=1]
[node name="SS14Window" index="0" instance=ExtResource( 1 )]

View File

@@ -1,7 +1,7 @@
[gd_scene load_steps=6 format=2]
[ext_resource path="res://Art/background.png" type="Texture" id=1]
[ext_resource path="res://Scenes/MainMenu/MainMenuTheme.tres" type="Theme" id=2]
[ext_resource path="res://Engine/Scenes/MainMenu/MainMenuTheme.tres" type="Theme" id=2]
[ext_resource path="res://Art/bootsplash.png" type="Texture" id=3]
[ext_resource path="res://Engine/Fonts/Animal Silence.otf" type="DynamicFontData" id=4]

View File

@@ -1,6 +1,6 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://Scenes/SS14Window/SS14Window.tscn" type="PackedScene" id=1]
[ext_resource path="res://Engine/Scenes/SS14Window/SS14Window.tscn" type="PackedScene" id=1]
[node name="SS14Window" instance=ExtResource( 1 )]

View File

@@ -1,6 +1,6 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://Scenes/SS14Window/SS14Window.tscn" type="PackedScene" id=1]
[ext_resource path="res://Engine/Scenes/SS14Window/SS14Window.tscn" type="PackedScene" id=1]
[node name="SS14Window" instance=ExtResource( 1 )]

View File

@@ -1,6 +1,6 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://Scenes/SS14Window/SS14Window.tscn" type="PackedScene" id=1]
[ext_resource path="res://Engine/Scenes/SS14Window/SS14Window.tscn" type="PackedScene" id=1]
[node name="SS14Window" index="0" instance=ExtResource( 1 )]

View File

@@ -0,0 +1,48 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://Engine/Scenes/SS14Window/closewindow.png" type="Texture" id=1]
[sub_resource type="StyleBoxFlat" id=1]
bg_color = Color( 0.234375, 0.234375, 0.234375, 1 )
[node name="SS14Window" type="Panel"]
margin_left = 100.0
margin_top = 38.0
margin_right = 878.0
margin_bottom = 519.0
[node name="Contents" type="Container" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 10.0
margin_top = 40.0
margin_right = -10.0
margin_bottom = -10.0
rect_min_size = Vector2( 50, 50 )
mouse_filter = 2
[node name="Header" type="Panel" parent="."]
anchor_right = 1.0
margin_bottom = 25.0
mouse_filter = 2
custom_styles/panel = SubResource( 1 )
[node name="Header Text" type="Label" parent="Header"]
anchor_right = 1.0
anchor_bottom = 1.0
margin_right = -25.0
text = "Exemplary Window Title Here"
align = 1
valign = 1
clip_text = true
[node name="CloseButton" type="TextureButton" parent="Header"]
anchor_left = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = -25.0
texture_normal = ExtResource( 1 )
expand = true
stretch_mode = 5

View File

Before

Width:  |  Height:  |  Size: 239 B

After

Width:  |  Height:  |  Size: 239 B

View File

@@ -2,18 +2,19 @@
importer="texture"
type="StreamTexture"
path="res://.import/closewindow.png-7b2f9cb6cf73c832ec12a5ebfba82490.stex"
path="res://.import/closewindow.png-27200ff550a4cc91ea5c13546f44ca18.stex"
[deps]
source_file="res://Scenes/SS14Window/closewindow.png"
dest_files=[ "res://.import/closewindow.png-7b2f9cb6cf73c832ec12a5ebfba82490.stex" ]
source_file="res://Engine/Scenes/SS14Window/closewindow.png"
dest_files=[ "res://.import/closewindow.png-27200ff550a4cc91ea5c13546f44ca18.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=false
@@ -23,6 +24,7 @@ flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
stream=false
size_limit=0
detect_3d=true

View File

@@ -1,6 +1,6 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://Scenes/SpriteMirror/SpriteView.cs" type="Script" id=1]
[ext_resource path="res://Engine/Scenes/SpriteMirror/SpriteView.cs" type="Script" id=1]
[node name="SpriteView" type="Control"]
anchor_left = 0.0

View File

@@ -44,7 +44,7 @@
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="Scenes\SpriteMirror\SpriteView.cs" />
<Compile Include="SpriteView.cs" />
<Compile Include="SS14Loader.cs" />
<Compile Include="ControlWrap.cs" />
<Compile Include="SignalSubscriber\BaseGodotSignalSubscriber.cs" />

View File

@@ -44,7 +44,7 @@ namespace SS14.Client.GodotGlue
Assembly.LoadFile(System.IO.Path.Combine(path, "../bin/Client/ICSharpCode.SharpZipLib.dll"));
Started = true;
SS14Assembly = Assembly.LoadFrom("../bin/Client/SS14.Client.dll");
SS14Assembly = Assembly.LoadFrom("../bin/Client/SS14.Client.exe");
var entryType = typeof(ClientEntryPoint);
foreach (var type in SS14Assembly.GetTypes())
{

View File

@@ -1,125 +0,0 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://Scenes/SS14Window/closewindow.png" type="Texture" id=1]
[sub_resource type="StyleBoxFlat" id=1]
content_margin_left = -1.0
content_margin_right = -1.0
content_margin_top = -1.0
content_margin_bottom = -1.0
bg_color = Color( 0.234375, 0.234375, 0.234375, 1 )
draw_center = true
border_width_left = 0
border_width_top = 0
border_width_right = 0
border_width_bottom = 0
border_color = Color( 0.8, 0.8, 0.8, 1 )
border_blend = false
corner_radius_top_left = 0
corner_radius_top_right = 0
corner_radius_bottom_right = 0
corner_radius_bottom_left = 0
corner_detail = 8
expand_margin_left = 0.0
expand_margin_right = 0.0
expand_margin_top = 0.0
expand_margin_bottom = 0.0
shadow_color = Color( 0, 0, 0, 0.6 )
shadow_size = 0
anti_aliasing = true
anti_aliasing_size = 1
[node name="SS14Window" type="Panel"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 100.0
margin_top = 38.0
margin_right = 878.0
margin_bottom = 519.0
rect_pivot_offset = Vector2( 0, 0 )
mouse_filter = 0
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
[node name="Contents" type="Container" parent="." index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 10.0
margin_top = 40.0
margin_right = -10.0
margin_bottom = -10.0
rect_min_size = Vector2( 50, 50 )
rect_pivot_offset = Vector2( 0, 0 )
mouse_filter = 2
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
_sections_unfolded = [ "Anchor", "Margin", "Mouse", "Rect" ]
[node name="Header" type="Panel" parent="." index="1"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 1.0
anchor_bottom = 0.0
margin_bottom = 25.0
rect_pivot_offset = Vector2( 0, 0 )
mouse_filter = 2
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
custom_styles/panel = SubResource( 1 )
_sections_unfolded = [ "Margin", "Mouse", "custom_styles" ]
[node name="Header Text" type="Label" parent="Header" index="0"]
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 1.0
anchor_bottom = 1.0
margin_right = -25.0
rect_pivot_offset = Vector2( 0, 0 )
mouse_filter = 2
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 4
text = "Exemplary Window Title Here"
align = 1
valign = 1
clip_text = true
percent_visible = 1.0
lines_skipped = 0
max_lines_visible = -1
_sections_unfolded = [ "Margin", "Mouse" ]
[node name="CloseButton" type="TextureButton" parent="Header" index="1"]
anchor_left = 1.0
anchor_top = 0.0
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = -25.0
rect_pivot_offset = Vector2( 0, 0 )
focus_mode = 2
mouse_filter = 0
mouse_default_cursor_shape = 0
size_flags_horizontal = 1
size_flags_vertical = 1
toggle_mode = false
enabled_focus_mode = 2
shortcut = null
group = null
texture_normal = ExtResource( 1 )
expand = true
stretch_mode = 5
_sections_unfolded = [ "Margin", "Textures" ]

View File

@@ -0,0 +1,9 @@
using Godot;
namespace SS14.Client.GodotGlue
{
public class SpriteView : Control
{
}
}

View File

@@ -65,6 +65,7 @@ ssao_radius2 = 0.0
ssao_intensity2 = 1.0
ssao_bias = 0.01
ssao_light_affect = 0.0
ssao_ao_channel_affect = 0.0
ssao_color = Color( 0, 0, 0, 1 )
ssao_quality = 0
ssao_blur = 3

View File

@@ -6,7 +6,12 @@
; [section] ; section goes between []
; param=value ; assign values to parameters
config_version=3
config_version=4
_global_script_classes=[ ]
_global_script_class_icons={
}
[application]
@@ -31,6 +36,7 @@ limits/debugger_stdout/max_chars_per_second=8128
[rendering]
quality/driver/driver_name="GLES2"
quality/intended_usage/framebuffer_allocation=0
quality/2d/use_pixel_snap=true
environment/default_clear_color=Color( 0, 0, 0, 1 )

View File

@@ -6,7 +6,7 @@ namespace SS14.Client.Audio
{
internal abstract Godot.AudioStream GodotAudioStream { get; }
public TimeSpan Length => TimeSpan.FromSeconds(GodotAudioStream.GetLength());
public TimeSpan Length => TimeSpan.FromSeconds(GodotAudioStream?.GetLength() ?? 0);
}
internal class GodotAudioStreamSource : AudioStream

View File

@@ -1,5 +1,4 @@
using SS14.Client.Console;
using SS14.Client.GodotGlue;
using SS14.Client.Interfaces;
using SS14.Client.Interfaces.GameObjects;
using SS14.Client.Interfaces.GameStates;
@@ -34,6 +33,7 @@ using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;
using JetBrains.Annotations;
using SS14.Client.Utility;
using SS14.Client.ViewVariables;
using SS14.Shared;
@@ -43,92 +43,58 @@ using SS14.Shared.Interfaces.Resources;
namespace SS14.Client
{
// Gets automatically ran by SS14.Client.Godot.
public sealed partial class GameController : ClientEntryPoint, IGameController
[UsedImplicitly]
public sealed partial class GameController : IGameController
{
internal static bool OnGodot { get; private set; }
/// <summary>
/// QueueFreeing a Godot node during finalization can cause segfaults.
/// As such, this var is set as soon as we tell Godot to shut down proper.
/// </summary>
public static bool ShuttingDownHard { get; private set; } = false;
[Dependency]
readonly IConfigurationManager _configurationManager;
[Dependency]
readonly IResourceCache _resourceCache;
[Dependency]
readonly IResourceManager _resourceManager;
[Dependency]
readonly ISS14Serializer _serializer;
[Dependency]
readonly IPrototypeManager _prototypeManager;
[Dependency]
readonly IClientTileDefinitionManager _tileDefinitionManager;
[Dependency]
readonly IClientNetManager _networkManager;
[Dependency]
readonly IMapManager _mapManager;
[Dependency]
readonly IStateManager _stateManager;
[Dependency]
readonly IUserInterfaceManager _userInterfaceManager;
[Dependency]
readonly IBaseClient _client;
[Dependency]
readonly IInputManager inputManager;
[Dependency]
readonly IClientChatConsole _console;
[Dependency]
readonly ILightManager lightManager;
[Dependency]
readonly IDisplayManager displayManager;
[Dependency]
readonly ITimerManager _timerManager;
[Dependency]
readonly IClientEntityManager _entityManager;
[Dependency]
readonly IEyeManager eyeManager;
[Dependency]
readonly GameTiming gameTiming;
[Dependency]
readonly IPlacementManager placementManager;
[Dependency]
readonly IClientGameStateManager gameStateManager;
[Dependency]
readonly IOverlayManager overlayManager;
[Dependency]
readonly ILogManager logManager;
[Dependency]
private readonly ITaskManager _taskManager;
[Dependency] private readonly IConfigurationManager _configurationManager;
[Dependency] private readonly IResourceCache _resourceCache;
[Dependency] private readonly IResourceManager _resourceManager;
[Dependency] private readonly ISS14Serializer _serializer;
[Dependency] private readonly IPrototypeManager _prototypeManager;
[Dependency] private readonly IClientTileDefinitionManager _tileDefinitionManager;
[Dependency] private readonly IClientNetManager _networkManager;
[Dependency] private readonly IMapManager _mapManager;
[Dependency] private readonly IStateManager _stateManager;
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager;
[Dependency] private readonly IBaseClient _client;
[Dependency] private readonly IInputManager _inputManager;
[Dependency] private readonly IClientChatConsole _console;
[Dependency] private readonly ILightManager _lightManager;
[Dependency] private readonly IDisplayManager _displayManager;
[Dependency] private readonly ITimerManager _timerManager;
[Dependency] private readonly IClientEntityManager _entityManager;
[Dependency] private readonly IEyeManager _eyeManager;
[Dependency] private readonly IPlacementManager _placementManager;
[Dependency] private readonly IClientGameStateManager _gameStateManager;
[Dependency] private readonly IOverlayManager _overlayManager;
[Dependency] private readonly ILogManager _logManager;
[Dependency] private readonly ITaskManager _taskManager;
[Dependency] private readonly IViewVariablesManagerInternal _viewVariablesManager;
public override void Main(Godot.SceneTree tree)
private void Startup()
{
#if !X64
throw new InvalidOperationException("The client cannot start outside x64.");
#endif
ThreadUtility.MainThread = Thread.CurrentThread;
PreInitIoC();
IoCManager.Resolve<ISceneTreeHolder>().Initialize(tree);
InitIoC();
Godot.OS.SetWindowTitle("Space Station 14");
SetupLogging();
// Set up custom synchronization context.
// Sorry Godot.
_taskManager.Initialize();
tree.SetAutoAcceptQuit(false);
// Load config.
_configurationManager.LoadFromFile(PathHelpers.ExecutableRelativeFile("client_config.toml"));
displayManager.Initialize();
// Ensure Godot's side of the resources are up to date.
#if DEBUG
GodotResourceCopy.DoDirCopy("../Resources", "Engine");
#endif
_displayManager.Initialize();
_displayManager.SetWindowTitle("Space Station 14");
// Init resources.
// Doesn't do anything right now because TODO Godot asset management is a bit ad-hoc.
@@ -149,21 +115,21 @@ namespace SS14.Client
// Call Init in game assemblies.
AssemblyLoader.BroadcastRunLevel(AssemblyLoader.RunLevel.Init);
eyeManager.Initialize();
_eyeManager.Initialize();
_serializer.Initialize();
_userInterfaceManager.Initialize();
_networkManager.Initialize(false);
inputManager.Initialize();
_inputManager.Initialize();
_console.Initialize();
_prototypeManager.LoadDirectory(new ResourcePath(@"/Prototypes/"));
_prototypeManager.Resync();
_tileDefinitionManager.Initialize();
_mapManager.Initialize();
placementManager.Initialize();
lightManager.Initialize();
_placementManager.Initialize();
_lightManager.Initialize();
_entityManager.Initialize();
gameStateManager.Initialize();
overlayManager.Initialize();
_gameStateManager.Initialize();
_overlayManager.Initialize();
_viewVariablesManager.Initialize();
_client.Initialize();
@@ -172,18 +138,13 @@ namespace SS14.Client
_stateManager.RequestStateChange<MainScreen>();
var args = (ICollection<string>) Godot.OS.GetCmdlineArgs();
var args = GetCommandLineArgs();
if (args.Contains("--connect"))
{
_client.ConnectToServer("127.0.0.1", 1212);
}
}
public override void QuitRequest()
{
Shutdown("OS quit request");
}
public void Shutdown(string reason = null)
{
if (reason != null)
@@ -194,6 +155,7 @@ namespace SS14.Client
{
Logger.Info("Shutting down!");
}
Logger.Debug("Goodbye");
IoCManager.Clear();
ShuttingDownHard = true;
@@ -202,72 +164,38 @@ namespace SS14.Client
Environment.Exit(0);
}
public override void PhysicsProcess(float delta)
private void Update(float frameTime)
{
// Can't be too certain.
gameTiming.InSimulation = true;
gameTiming._tickRemainderTimer.Restart();
try
{
if (!gameTiming.Paused)
{
gameTiming.CurTick++;
_networkManager.ProcessPackets();
var eventArgs = new ProcessFrameEventArgs(delta);
AssemblyLoader.BroadcastUpdate(AssemblyLoader.UpdateLevel.PreEngine, eventArgs.Elapsed);
_timerManager.UpdateTimers(delta);
_taskManager.ProcessPendingTasks();
_userInterfaceManager.Update(eventArgs);
_stateManager.Update(eventArgs);
AssemblyLoader.BroadcastUpdate(AssemblyLoader.UpdateLevel.PostEngine, eventArgs.Elapsed);
}
}
finally
{
gameTiming.InSimulation = false;
}
}
public override void FrameProcess(float delta)
{
gameTiming.InSimulation = false; // Better safe than sorry.
gameTiming.RealFrameTime = TimeSpan.FromSeconds(delta);
gameTiming.TickRemainder = gameTiming._tickRemainderTimer.Elapsed;
var eventArgs = new RenderFrameEventArgs(delta);
AssemblyLoader.BroadcastUpdate(AssemblyLoader.UpdateLevel.FramePreEngine, eventArgs.Elapsed);
lightManager.FrameUpdate(eventArgs);
_stateManager.FrameUpdate(eventArgs);
overlayManager.FrameUpdate(eventArgs);
AssemblyLoader.BroadcastUpdate(AssemblyLoader.UpdateLevel.FramePostEngine, eventArgs.Elapsed);
}
public override void HandleException(Exception exception)
{
try
{
if (logManager != null)
{
logManager.GetSawmill("root").Error($"Unhandled exception:\n{exception}");
}
else
{
Godot.GD.Print($"Unhandled exception:\n{exception}");
}
}
catch (Exception e)
{
Godot.GD.Print($"Welp. The unhandled exception handler threw an exception.\n{e}\nException that was being handled:\n{exception}");
}
_networkManager.ProcessPackets();
var eventArgs = new ProcessFrameEventArgs(frameTime);
AssemblyLoader.BroadcastUpdate(AssemblyLoader.UpdateLevel.PreEngine, eventArgs.Elapsed);
_timerManager.UpdateTimers(frameTime);
_taskManager.ProcessPendingTasks();
_userInterfaceManager.Update(eventArgs);
_stateManager.Update(eventArgs);
AssemblyLoader.BroadcastUpdate(AssemblyLoader.UpdateLevel.PostEngine, eventArgs.Elapsed);
}
private void SetupLogging()
{
logManager.RootSawmill.AddHandler(new GodotLogHandler());
logManager.GetSawmill("res.typecheck").Level = LogLevel.Info;
logManager.GetSawmill("res.tex").Level = LogLevel.Info;
logManager.GetSawmill("console").Level = LogLevel.Info;
logManager.GetSawmill("go.sys").Level = LogLevel.Info;
if (OnGodot)
{
_logManager.RootSawmill.AddHandler(new GodotLogHandler());
}
else
{
_logManager.RootSawmill.AddHandler(new ConsoleLogHandler());
}
_logManager.GetSawmill("res.typecheck").Level = LogLevel.Info;
_logManager.GetSawmill("res.tex").Level = LogLevel.Info;
_logManager.GetSawmill("console").Level = LogLevel.Info;
_logManager.GetSawmill("go.sys").Level = LogLevel.Info;
}
public static ICollection<string> GetCommandLineArgs()
{
return OnGodot ? Godot.OS.GetCmdlineArgs() : Environment.GetCommandLineArgs();
}
}
}

View File

@@ -1,84 +0,0 @@
using System;
using SS14.Shared.Timing;
using SS14.Shared.Interfaces.Timing;
namespace SS14.Client
{
public sealed partial class GameController
{
// TODO: This class is basically just a bunch of stubs.
private class GameTiming : IGameTiming
{
private static readonly IStopwatch _realTimer = new Stopwatch();
public readonly IStopwatch _tickRemainderTimer = new Stopwatch();
public GameTiming()
{
_realTimer.Start();
// Not sure if Restart() starts it implicitly so...
_tickRemainderTimer.Start();
}
public bool InSimulation { get; set; }
public bool Paused { get; set; }
public TimeSpan CurTime => CalcCurTime();
public TimeSpan RealTime => _realTimer.Elapsed;
public TimeSpan FrameTime => CalcFrameTime();
public TimeSpan RealFrameTime { get; set; }
public TimeSpan RealFrameTimeAvg => throw new NotImplementedException();
public TimeSpan RealFrameTimeStdDev => throw new NotImplementedException();
public double FramesPerSecondAvg => throw new NotImplementedException();
public uint CurTick { get; set; }
public int TickRate
{
get => Godot.Engine.IterationsPerSecond;
set => Godot.Engine.IterationsPerSecond = value;
}
public TimeSpan TickPeriod => TimeSpan.FromTicks((long)(1.0 / TickRate * TimeSpan.TicksPerSecond));
public TimeSpan TickRemainder { get; set; }
public void ResetRealTime()
{
throw new NotImplementedException();
}
public void StartFrame()
{
throw new NotImplementedException();
}
private TimeSpan CalcCurTime()
{
// calculate simulation CurTime
var time = TimeSpan.FromTicks(TickPeriod.Ticks * CurTick);
if (!InSimulation) // rendering can draw frames between ticks
return time + TickRemainder;
return time;
}
private TimeSpan CalcFrameTime()
{
// calculate simulation FrameTime
if (InSimulation)
{
return TimeSpan.FromTicks(TickPeriod.Ticks);
}
else
{
return Paused ? TimeSpan.Zero : RealFrameTime;
}
}
}
}
}

View File

@@ -0,0 +1,247 @@
using System;
using System.Collections.Generic;
using SS14.Client.GodotGlue;
using SS14.Client.Input;
using SS14.Client.Interfaces;
using SS14.Client.Utility;
using SS14.Shared.ContentPack;
using SS14.Shared.Interfaces.Timing;
using SS14.Shared.IoC;
using SS14.Shared.Timing;
namespace SS14.Client
{
public partial class GameController : ClientEntryPoint
{
private GameTimingGodot _gameTimingGodotGodot;
public override void Main(Godot.SceneTree tree)
{
#if !X64
throw new InvalidOperationException("The client cannot start outside x64.");
#endif
OnGodot = true;
tree.SetAutoAcceptQuit(false);
IoCManager.Register<ISceneTreeHolder, SceneTreeHolder>();
IoCManager.BuildGraph();
IoCManager.Resolve<ISceneTreeHolder>().Initialize(tree);
#if DEBUG
// Ensure Godot's side of the resources are up to date.
GodotResourceCopy.DoDirCopy("../Resources", "Engine");
#endif
Startup();
_gameTimingGodotGodot = IoCManager.Resolve<GameTimingGodot>();
}
public override void QuitRequest()
{
Shutdown("OS quit request");
}
public override void PhysicsProcess(float delta)
{
// Can't be too certain.
_gameTimingGodotGodot.InSimulation = true;
_gameTimingGodotGodot._tickRemainderTimer.Restart();
try
{
if (!_gameTimingGodotGodot.Paused)
{
_gameTimingGodotGodot.CurTick++;
Update(delta);
}
}
finally
{
_gameTimingGodotGodot.InSimulation = false;
}
}
public override void FrameProcess(float delta)
{
_gameTimingGodotGodot.InSimulation = false; // Better safe than sorry.
_gameTimingGodotGodot.RealFrameTime = TimeSpan.FromSeconds(delta);
_gameTimingGodotGodot.TickRemainder = _gameTimingGodotGodot._tickRemainderTimer.Elapsed;
var eventArgs = new RenderFrameEventArgs(delta);
AssemblyLoader.BroadcastUpdate(AssemblyLoader.UpdateLevel.FramePreEngine, eventArgs.Elapsed);
_lightManager.FrameUpdate(eventArgs);
_stateManager.FrameUpdate(eventArgs);
_overlayManager.FrameUpdate(eventArgs);
AssemblyLoader.BroadcastUpdate(AssemblyLoader.UpdateLevel.FramePostEngine, eventArgs.Elapsed);
}
public override void HandleException(Exception exception)
{
try
{
if (_logManager != null)
{
_logManager.GetSawmill("root").Error($"Unhandled exception:\n{exception}");
}
else
{
Godot.GD.Print($"Unhandled exception:\n{exception}");
}
}
catch (Exception e)
{
Godot.GD.Print($"Welp. The unhandled exception handler threw an exception.\n{e}\nException that was being handled:\n{exception}");
}
}
// Override that converts and distributes the input events
// to the more sane methods above.
public override void Input(Godot.InputEvent inputEvent)
{
switch (inputEvent)
{
case Godot.InputEventKey keyEvent:
var keyEventArgs = (KeyEventArgs)keyEvent;
if (keyEvent.Echo)
{
return;
}
else if (keyEvent.Pressed)
{
KeyDown(keyEventArgs);
}
else
{
KeyUp(keyEventArgs);
}
break;
case Godot.InputEventMouseButton mouseButtonEvent:
if (mouseButtonEvent.ButtonIndex >= (int)Godot.ButtonList.WheelUp && mouseButtonEvent.ButtonIndex <= (int)Godot.ButtonList.WheelRight)
{
// Mouse wheel event.
var mouseWheelEventArgs = (MouseWheelEventArgs)mouseButtonEvent;
MouseWheel(mouseWheelEventArgs);
}
else
{
// Mouse button event.
var mouseButtonEventArgs = (MouseButtonEventArgs)mouseButtonEvent;
if (mouseButtonEvent.Pressed)
{
KeyDown((KeyEventArgs) mouseButtonEvent);
MouseDown(mouseButtonEventArgs);
}
else
{
KeyUp((KeyEventArgs)mouseButtonEvent);
MouseUp(mouseButtonEventArgs);
}
}
break;
case Godot.InputEventMouseMotion mouseMotionEvent:
var mouseMoveEventArgs = (MouseMoveEventArgs)mouseMotionEvent;
MouseMove(mouseMoveEventArgs);
break;
}
}
public override void PreInput(Godot.InputEvent inputEvent)
{
if (inputEvent is Godot.InputEventKey keyEvent)
{
var keyEventArgs = (KeyEventArgs)keyEvent;
if (keyEvent.Echo)
{
return;
}
else if (keyEvent.Pressed)
{
// TODO: these hacks are in right now for toggling the debug console.
// Somehow find a way to make the console use the key binds system?
_userInterfaceManager.PreKeyDown(keyEventArgs);
}
else
{
_userInterfaceManager.PreKeyUp(keyEventArgs);
}
}
}
// TODO: This class is basically just a bunch of stubs.
private class GameTimingGodot : IGameTiming
{
private static readonly IStopwatch _realTimer = new Stopwatch();
public readonly IStopwatch _tickRemainderTimer = new Stopwatch();
public GameTimingGodot()
{
_realTimer.Start();
// Not sure if Restart() starts it implicitly so...
_tickRemainderTimer.Start();
}
public bool InSimulation { get; set; }
public bool Paused { get; set; }
public TimeSpan CurTime => CalcCurTime();
public TimeSpan RealTime => _realTimer.Elapsed;
public TimeSpan FrameTime => CalcFrameTime();
public TimeSpan RealFrameTime { get; set; }
public TimeSpan RealFrameTimeAvg => throw new NotImplementedException();
public TimeSpan RealFrameTimeStdDev => throw new NotImplementedException();
public double FramesPerSecondAvg => throw new NotImplementedException();
public uint CurTick { get; set; }
public int TickRate
{
get => Godot.Engine.IterationsPerSecond;
set => Godot.Engine.IterationsPerSecond = value;
}
public TimeSpan TickPeriod => TimeSpan.FromTicks((long)(1.0 / TickRate * TimeSpan.TicksPerSecond));
public TimeSpan TickRemainder { get; set; }
public void ResetRealTime()
{
throw new NotImplementedException();
}
public void StartFrame()
{
throw new NotImplementedException();
}
private TimeSpan CalcCurTime()
{
// calculate simulation CurTime
var time = TimeSpan.FromTicks(TickPeriod.Ticks * CurTick);
if (!InSimulation) // rendering can draw frames between ticks
return time + TickRemainder;
return time;
}
private TimeSpan CalcFrameTime()
{
// calculate simulation FrameTime
if (InSimulation)
{
return TimeSpan.FromTicks(TickPeriod.Ticks);
}
else
{
return Paused ? TimeSpan.Zero : RealFrameTime;
}
}
}
}
}

View File

@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using SS14.Client.Interfaces;
using SS14.Shared.Interfaces.Timing;
using SS14.Shared.IoC;
using SS14.Shared.Timing;
namespace SS14.Client
{
public partial class GameController
{
private GameLoop _mainLoop;
[Dependency] private IGameTiming _gameTimingHeadless;
public static void Main()
{
#if !X64
throw new InvalidOperationException("The client cannot start outside x64.");
#endif
IoCManager.Register<ISceneTreeHolder, SceneTreeHolder>();
IoCManager.BuildGraph();
var gc = new GameController();
gc.Startup();
gc.MainLoop();
}
private void MainLoop()
{
_mainLoop = new GameLoop(_gameTimingHeadless)
{
SleepMode = SleepMode.Delay
};
_mainLoop.Tick += (sender, args) => Update(args.DeltaSeconds);
// set GameLoop.Running to false to return from this function.
_mainLoop.Run();
}
}
}

View File

@@ -1,5 +1,4 @@
using Godot;
using SS14.Client.Input;
using SS14.Client.Input;
namespace SS14.Client
{
@@ -10,7 +9,7 @@ namespace SS14.Client
/// </summary>
private void KeyDown(KeyEventArgs keyEvent)
{
inputManager.KeyDown(keyEvent);
_inputManager.KeyDown(keyEvent);
}
/// <summary>
@@ -18,7 +17,7 @@ namespace SS14.Client
/// </summary>
private void KeyUp(KeyEventArgs keyEvent)
{
inputManager.KeyUp(keyEvent);
_inputManager.KeyUp(keyEvent);
}
/// <summary>
@@ -54,80 +53,5 @@ namespace SS14.Client
{
_stateManager.MouseWheelMove(mouseWheelEventArgs);
}
// Override that converts and distributes the input events
// to the more sane methods above.
public override void Input(InputEvent inputEvent)
{
switch (inputEvent)
{
case InputEventKey keyEvent:
var keyEventArgs = (KeyEventArgs)keyEvent;
if (keyEvent.Echo)
{
return;
}
else if (keyEvent.Pressed)
{
KeyDown(keyEventArgs);
}
else
{
KeyUp(keyEventArgs);
}
break;
case InputEventMouseButton mouseButtonEvent:
if (mouseButtonEvent.ButtonIndex >= (int)ButtonList.WheelUp && mouseButtonEvent.ButtonIndex <= (int)ButtonList.WheelRight)
{
// Mouse wheel event.
var mouseWheelEventArgs = (MouseWheelEventArgs)mouseButtonEvent;
MouseWheel(mouseWheelEventArgs);
}
else
{
// Mouse button event.
var mouseButtonEventArgs = (MouseButtonEventArgs)mouseButtonEvent;
if (mouseButtonEvent.Pressed)
{
KeyDown((KeyEventArgs) mouseButtonEvent);
MouseDown(mouseButtonEventArgs);
}
else
{
KeyUp((KeyEventArgs)mouseButtonEvent);
MouseUp(mouseButtonEventArgs);
}
}
break;
case InputEventMouseMotion mouseMotionEvent:
var mouseMoveEventArgs = (MouseMoveEventArgs)mouseMotionEvent;
MouseMove(mouseMoveEventArgs);
break;
}
}
public override void PreInput(InputEvent inputEvent)
{
if (inputEvent is InputEventKey keyEvent)
{
var keyEventArgs = (KeyEventArgs)keyEvent;
if (keyEvent.Echo)
{
return;
}
else if (keyEvent.Pressed)
{
// TODO: these hacks are in right now for toggling the debug console.
// Somehow find a way to make the console use the key binds system?
_userInterfaceManager.PreKeyDown(keyEventArgs);
}
else
{
_userInterfaceManager.PreKeyUp(keyEventArgs);
}
}
}
}
}

View File

@@ -57,19 +57,13 @@ using SS14.Client.Graphics.Overlays;
using SS14.Client.ViewVariables;
using SS14.Shared.Asynchronous;
using SS14.Shared.Interfaces.Resources;
using SS14.Shared.Map;
namespace SS14.Client
{
// Partial of GameController to initialize IoC and some other low-level systems like it.
public sealed partial class GameController
{
// Aaaaaah init order hurts.
private void PreInitIoC()
{
IoCManager.Register<ISceneTreeHolder, SceneTreeHolder>();
IoCManager.BuildGraph();
}
private void InitIoC()
{
RegisterIoC();
@@ -79,7 +73,7 @@ namespace SS14.Client
// We are not IoC-managed (SS14.Client.Godot spawns us), but we still want the dependencies.
IoCManager.InjectDependencies(this);
var proxy = (GameControllerProxy)IoCManager.Resolve<IGameControllerProxy>();
var proxy = (GameControllerProxy) IoCManager.Resolve<IGameControllerProxy>();
proxy.GameController = this;
}
@@ -94,9 +88,18 @@ namespace SS14.Client
IoCManager.Register<INetManager, NetManager>();
IoCManager.Register<IEntitySystemManager, EntitySystemManager>();
IoCManager.Register<IEntityManager, ClientEntityManager>();
IoCManager.Register<IComponentFactory, GodotComponentFactory>();
if (OnGodot)
{
IoCManager.Register<IComponentFactory, GodotComponentFactory>();
IoCManager.Register<IMapManager, GodotMapManager>();
}
else
{
IoCManager.Register<IComponentFactory, ClientComponentFactory>();
IoCManager.Register<IMapManager, MapManager>();
}
IoCManager.Register<IComponentManager, ComponentManager>();
IoCManager.Register<IMapManager, ClientMapManager>();
IoCManager.Register<IPhysicsManager, PhysicsManager>();
IoCManager.Register<ITimerManager, TimerManager>();
IoCManager.Register<ITaskManager, TaskManager>();
@@ -104,6 +107,7 @@ namespace SS14.Client
// Client stuff.
IoCManager.Register<IReflectionManager, ClientReflectionManager>();
IoCManager.Register<IResourceManager, ResourceCache>();
IoCManager.Register<IResourceManagerInternal, ResourceCache>();
IoCManager.Register<IResourceCache, ResourceCache>();
IoCManager.Register<IClientTileDefinitionManager, ClientTileDefinitionManager>();
IoCManager.Register<IClientNetManager, NetManager>();
@@ -115,16 +119,32 @@ namespace SS14.Client
IoCManager.Register<IStateManager, StateManager>();
IoCManager.Register<IUserInterfaceManager, UserInterfaceManager>();
IoCManager.Register<IGameControllerProxy, GameControllerProxy>();
IoCManager.Register<IInputManager, GodotInputManager>();
if (OnGodot)
{
IoCManager.Register<IInputManager, GodotInputManager>();
}
else
{
IoCManager.Register<IInputManager, InputManager>();
}
IoCManager.Register<IDebugDrawing, DebugDrawing>();
IoCManager.Register<IClientConsole, ClientChatConsole>();
IoCManager.Register<IClientChatConsole, ClientChatConsole>();
IoCManager.Register<ILightManager, LightManager>();
IoCManager.Register<IDisplayManager, DisplayManager>();
IoCManager.Register<IEyeManager, EyeManager>();
IoCManager.Register<IGameTiming, GameController.GameTiming>();
// Only GameController can acess this because the type is private so it's fine.
IoCManager.Register<GameController.GameTiming, GameController.GameTiming>();
if (OnGodot)
{
IoCManager.Register<IGameTiming, GameController.GameTimingGodot>();
// Only GameController can access this because the type is private so it's fine.
IoCManager.Register<GameController.GameTimingGodot, GameController.GameTimingGodot>();
}
else
{
IoCManager.Register<IGameTiming, GameTiming>();
}
IoCManager.Register<IPlacementManager, PlacementManager>();
IoCManager.Register<IOverlayManager, OverlayManager>();
IoCManager.Register<IViewVariablesManager, ViewVariablesManager>();

View File

@@ -16,6 +16,7 @@ namespace SS14.Client.GameObjects
// Horrible hack to get around ordering issues.
private bool setCurrentOnInitialize = false;
private Vector2 setZoomOnInitialize = Vector2.One;
[ViewVariables(VVAccess.ReadWrite)]
public bool Current
{
@@ -27,6 +28,7 @@ namespace SS14.Client.GameObjects
setCurrentOnInitialize = value;
return;
}
eye.Current = value;
}
}
@@ -53,21 +55,29 @@ namespace SS14.Client.GameObjects
public override void Initialize()
{
base.Initialize();
transform = Owner.GetComponent<IGodotTransformComponent>();
eye = new Eye
if (GameController.OnGodot)
{
Current = setCurrentOnInitialize,
MapId = transform.MapID,
Zoom = setZoomOnInitialize,
};
transform.SceneNode.AddChild(eye.GodotCamera);
transform.OnMove += Transform_OnMove;
transform = Owner.GetComponent<IGodotTransformComponent>();
eye = new Eye
{
Current = setCurrentOnInitialize,
MapId = transform.MapID,
Zoom = setZoomOnInitialize,
};
transform.SceneNode.AddChild(eye.GodotCamera);
transform.OnMove += Transform_OnMove;
}
}
public override void OnRemove()
{
base.OnRemove();
transform.OnMove -= Transform_OnMove;
if (GameController.OnGodot)
{
transform.OnMove -= Transform_OnMove;
}
eye.Dispose();
eye = null;
}

View File

@@ -28,8 +28,7 @@ namespace SS14.Client.GameObjects
public override Type StateType => typeof(PointLightComponentState);
private ILight Light;
[Dependency]
private ILightManager lightManager;
[Dependency] private ILightManager lightManager;
[ViewVariables(VVAccess.ReadWrite)]
public Color Color
@@ -46,6 +45,7 @@ namespace SS14.Client.GameObjects
}
private LightState state = LightState.On;
[ViewVariables(VVAccess.ReadWrite)]
public LightState State
{
@@ -91,13 +91,23 @@ namespace SS14.Client.GameObjects
if (value)
{
if (Owner.Transform.Parent == null) return;
Light.ParentTo((GodotTransformComponent) Owner.Transform.Parent);
if (GameController.OnGodot)
{
Light.ParentTo((GodotTransformComponent) Owner.Transform.Parent);
}
_lightOnParent = true;
}
else
{
if (!_lightOnParent) return;
Light.ParentTo((GodotTransformComponent) Owner.Transform);
if (GameController.OnGodot)
{
Light.ParentTo((GodotTransformComponent) Owner.Transform);
}
_lightOnParent = false;
}
}
@@ -118,9 +128,16 @@ namespace SS14.Client.GameObjects
{
radius = FloatMath.Clamp(value, 2, 10);
var mgr = IoCManager.Resolve<IResourceCache>();
var tex = mgr.GetResource<TextureResource>(new ResourcePath("/Textures/Effects/Light/") / $"lighting_falloff_{(int)radius}.png");
// TODO: Maybe editing the global texture resource is not a good idea.
tex.Texture.GodotTexture.SetFlags(tex.Texture.GodotTexture.GetFlags() | (int)Godot.Texture.FlagsEnum.Filter);
var tex = mgr.GetResource<TextureResource>(new ResourcePath("/Textures/Effects/Light/") /
$"lighting_falloff_{(int) radius}.png");
if (GameController.OnGodot)
{
// TODO: Maybe editing the global texture resource is not a good idea.
tex.Texture.GodotTexture.SetFlags(tex.Texture.GodotTexture.GetFlags() |
(int) Godot.Texture.FlagsEnum.Filter);
}
Light.Texture = tex.Texture;
}
}
@@ -129,7 +146,11 @@ namespace SS14.Client.GameObjects
{
base.Initialize();
Light.ParentTo((GodotTransformComponent)Owner.Transform);
if (GameController.OnGodot)
{
Light.ParentTo((GodotTransformComponent) Owner.Transform);
}
Owner.Transform.OnParentChanged += TransformOnOnParentChanged;
}
@@ -143,12 +164,20 @@ namespace SS14.Client.GameObjects
if (obj.New.IsValid() && Owner.EntityManager.TryGetEntity(obj.New, out var entity))
{
Light.ParentTo((GodotTransformComponent) entity.Transform);
if (GameController.OnGodot)
{
Light.ParentTo((GodotTransformComponent) entity.Transform);
}
_lightOnParent = true;
}
else
{
Light.ParentTo((GodotTransformComponent) Owner.Transform);
if (GameController.OnGodot)
{
Light.ParentTo((GodotTransformComponent) Owner.Transform);
}
_lightOnParent = false;
}
}
@@ -183,7 +212,7 @@ namespace SS14.Client.GameObjects
/// <inheritdoc />
public override void HandleComponentState(ComponentState state)
{
var newState = (PointLightComponentState)state;
var newState = (PointLightComponentState) state;
State = newState.State;
Color = newState.Color;
Light.ModeClass = newState.Mode;

View File

@@ -48,41 +48,41 @@ namespace SS14.Client.GameObjects
base.Initialize();
IoCManager.InjectDependencies(this);
var transform = Owner.GetComponent<IGodotTransformComponent>();
var transform = Owner.Transform;
SnapGrid = Owner.GetComponent<SnapGridComponent>();
SnapGrid.OnPositionChanged += SnapGridPositionChanged;
const float halfSize = (-SideSize / 2) * EyeManager.PIXELSPERMETER;
var ne = new Godot.Vector2(halfSize, -halfSize);
var se = new Godot.Vector2(halfSize, halfSize);
var sw = new Godot.Vector2(-halfSize, halfSize);
var nw = new Godot.Vector2(-halfSize, -halfSize);
var ne = new Vector2(halfSize, -halfSize);
var se = new Vector2(halfSize, halfSize);
var sw = new Vector2(-halfSize, halfSize);
var nw = new Vector2(-halfSize, -halfSize);
// North occluder.
var occluder = lightManager.MakeOccluder();
occluder.CullMode = OccluderCullMode.Clockwise;
occluder.SetGodotPolygon(new Godot.Vector2[] { nw, ne });
occluder.SetPolygon(new Vector2[] { nw, ne });
occluders[(int)OccluderDir.North] = occluder;
occluder.ParentTo(transform);
// East occluder.
occluder = lightManager.MakeOccluder();
occluder.CullMode = OccluderCullMode.Clockwise;
occluder.SetGodotPolygon(new Godot.Vector2[] { ne, se });
occluder.SetPolygon(new Vector2[] { ne, se });
occluders[(int)OccluderDir.East] = occluder;
occluder.ParentTo(transform);
// South occluder.
occluder = lightManager.MakeOccluder();
occluder.CullMode = OccluderCullMode.Clockwise;
occluder.SetGodotPolygon(new Godot.Vector2[] { se, sw });
occluder.SetPolygon(new Vector2[] { se, sw });
occluders[(int)OccluderDir.South] = occluder;
occluder.ParentTo(transform);
// West occluder.
occluder = lightManager.MakeOccluder();
occluder.CullMode = OccluderCullMode.Clockwise;
occluder.SetGodotPolygon(new Godot.Vector2[] { sw, nw });
occluder.SetPolygon(new Vector2[] { sw, nw });
occluders[(int)OccluderDir.West] = occluder;
occluder.ParentTo(transform);

View File

@@ -63,7 +63,8 @@ namespace SS14.Client.GameObjects
set
{
drawDepth = value;
if (SceneNode != null)
if (GameController.OnGodot && SceneNode != null)
{
SceneNode.ZIndex = (int) value;
}
@@ -82,7 +83,7 @@ namespace SS14.Client.GameObjects
set
{
scale = value;
if (SceneNode != null)
if (GameController.OnGodot && SceneNode != null)
{
SceneNode.Scale = value.Convert();
}
@@ -98,7 +99,7 @@ namespace SS14.Client.GameObjects
set
{
rotation = value;
if (SceneNode != null)
if (GameController.OnGodot && SceneNode != null)
{
SceneNode.Rotation = (float) value;
}
@@ -117,7 +118,7 @@ namespace SS14.Client.GameObjects
set
{
offset = value;
if (SceneNode != null)
if (GameController.OnGodot && SceneNode != null)
{
SceneNode.Position = value.Convert() * EyeManager.PIXELSPERMETER;
}
@@ -133,7 +134,7 @@ namespace SS14.Client.GameObjects
set
{
color = value;
if (SceneNode != null)
if (GameController.OnGodot && SceneNode != null)
{
SceneNode.Modulate = value.Convert();
}
@@ -198,10 +199,8 @@ namespace SS14.Client.GameObjects
}
}
[ViewVariables]
private Dictionary<object, int> LayerMap = new Dictionary<object, int>();
[ViewVariables]
private bool _layerMapShared;
[ViewVariables] private Dictionary<object, int> LayerMap = new Dictionary<object, int>();
[ViewVariables] private bool _layerMapShared;
// To a future Clusterfack:
// REALLY BIG OPTIMIZATION POTENTIAL:
@@ -211,8 +210,7 @@ namespace SS14.Client.GameObjects
// It may be a good idea to re-implement this list to use Layer[],
// use ref locals EVERYWHERE, and handle the resizing ourselves.
// This may be worth the overhead of basically reimplementing List<T>.
[ViewVariables]
private List<Layer> Layers;
[ViewVariables] private List<Layer> Layers;
private Godot.Node2D SceneNode;
@@ -996,9 +994,17 @@ namespace SS14.Client.GameObjects
public ISpriteProxy CreateProxy()
{
var item = VS.CanvasItemCreate();
RedrawQueued = true;
return CreateMirror(item);
if (GameController.OnGodot)
{
var item = VS.CanvasItemCreate();
RedrawQueued = true;
return CreateMirror(item);
}
var key = NextMirrorKey++;
var mirror = new SpriteMirror(key, this);
Mirrors.Add(key, new MirrorData());
return mirror;
}
ISpriteProxy CreateMirror(Godot.RID item)
@@ -1018,15 +1024,19 @@ namespace SS14.Client.GameObjects
public override void OnAdd()
{
base.OnAdd();
SceneNode = new Godot.Node2D()
if (GameController.OnGodot)
{
Name = "Sprite",
ZIndex = (int) drawDepth,
Scale = scale.Convert(),
Position = offset.Convert(),
Modulate = color.Convert(),
Rotation = (float) rotation,
};
SceneNode = new Godot.Node2D()
{
Name = "Sprite",
ZIndex = (int) drawDepth,
Scale = scale.Convert(),
Position = offset.Convert(),
Modulate = color.Convert(),
Rotation = (float) rotation,
};
}
}
public override void OnRemove()
@@ -1039,13 +1049,22 @@ namespace SS14.Client.GameObjects
}
MainMirror.Dispose();
SceneNode.QueueFree();
if (GameController.OnGodot)
{
SceneNode.QueueFree();
}
}
public override void Initialize()
{
base.Initialize();
if (!GameController.OnGodot)
{
return;
}
MainMirror = CreateMirror(SceneNode.GetCanvasItem());
var mir = Mirrors[0];
mir.DontFree = true;
@@ -1055,6 +1074,11 @@ namespace SS14.Client.GameObjects
private void ClearDraw()
{
if (!GameController.OnGodot)
{
return;
}
foreach (var data in Mirrors.Values)
{
foreach (var item in data.Children)
@@ -1070,6 +1094,11 @@ namespace SS14.Client.GameObjects
{
ClearDraw();
if (!GameController.OnGodot)
{
return;
}
foreach (var data in Mirrors.Values)
{
if (!data.Visible)
@@ -1301,7 +1330,11 @@ namespace SS14.Client.GameObjects
var dirChanged = false;
if (Directional)
{
SceneNode.Rotation = (float) (Owner.Transform.WorldRotation - Rotation) - MathHelper.PiOver2;
if (GameController.OnGodot)
{
SceneNode.Rotation = (float) (Owner.Transform.WorldRotation - Rotation) - MathHelper.PiOver2;
}
dirWeAreFacing = GetDir();
if (LastDir != dirWeAreFacing || _recalcDirections)
{
@@ -1556,7 +1589,7 @@ namespace SS14.Client.GameObjects
// TODO: Doing a full redraw when a mirror is disposed is kinda a waste.
ClearDraw();
RedrawQueued = true;
if (!val.DontFree)
if (!val.DontFree && GameController.OnGodot)
{
VS.FreeRid(val.Root);
}
@@ -1633,8 +1666,7 @@ namespace SS14.Client.GameObjects
{
readonly int Key;
readonly SpriteComponent Master;
Godot.RID CanvasItem;
private Godot.RID CanvasItem;
private Godot.RID Parent;
private Vector2 _offset;
@@ -1661,16 +1693,20 @@ namespace SS14.Client.GameObjects
}
}
public SpriteMirror(int key, SpriteComponent master, Godot.RID canvasItem)
public SpriteMirror(int key, SpriteComponent master, Godot.RID canvasItem) : this(key, master)
{
Master = master;
Key = key;
CanvasItem = canvasItem;
}
public bool Disposed => CanvasItem == null;
public SpriteMirror(int key, SpriteComponent master)
{
Master = master;
Key = key;
}
void CheckDisposed()
public bool Disposed { get; private set; }
private void CheckDisposed()
{
if (Disposed)
{
@@ -1680,6 +1716,11 @@ namespace SS14.Client.GameObjects
private void UpdateTransform()
{
if (!GameController.OnGodot)
{
return;
}
var transform = new Godot.Transform2D(0, Offset.Convert());
VS.CanvasItemSetTransform(CanvasItem, transform);
}
@@ -1710,7 +1751,13 @@ namespace SS14.Client.GameObjects
void Dispose(bool disposing)
{
Master.DisposeMirror(Key);
CanvasItem = null;
if (GameController.OnGodot)
{
CanvasItem = null;
}
Disposed = true;
}
}

View File

@@ -60,6 +60,10 @@ namespace SS14.Client.GameObjects.EntitySystems
/// <param name="stream">The audio stream to play.</param>
public void Play(AudioStream stream, AudioParams? audioParams = null)
{
if (!GameController.OnGodot)
{
return;
}
var player = new Godot.AudioStreamPlayer()
{
Stream = stream.GodotAudioStream,
@@ -94,6 +98,10 @@ namespace SS14.Client.GameObjects.EntitySystems
/// <param name="entity">The entity "emitting" the audio.</param>
public void Play(AudioStream stream, IEntity entity, AudioParams? audioParams = null)
{
if (!GameController.OnGodot)
{
return;
}
var parent = entity.GetComponent<IGodotTransformComponent>().SceneNode;
var player = new Godot.AudioStreamPlayer2D()
{
@@ -130,6 +138,10 @@ namespace SS14.Client.GameObjects.EntitySystems
/// <param name="coordinates">The coordinates at which to play the audio.</param>
public void Play(AudioStream stream, GridCoordinates coordinates, AudioParams? audioParams = null)
{
if (!GameController.OnGodot)
{
return;
}
var player = new Godot.AudioStreamPlayer2D()
{
Stream = stream.GodotAudioStream,

View File

@@ -48,6 +48,10 @@ namespace SS14.Client.GameObjects
{
base.Initialize();
IoCManager.InjectDependencies(this);
if (!GameController.OnGodot)
{
return;
}
DrawingNode = new Godot.Node2D()
{
Name = "EffectSystem",
@@ -73,6 +77,10 @@ namespace SS14.Client.GameObjects
public override void Shutdown()
{
base.Shutdown();
if (!GameController.OnGodot)
{
return;
}
VS.FreeRid(ShadedCanvasItem);
VS.FreeRid(UnshadedCanvasItem);
UnshadedMaterial.Dispose();
@@ -153,6 +161,10 @@ namespace SS14.Client.GameObjects
{
var map = eyeManager.CurrentMap;
if (GameController.OnGodot)
{
return;
}
VS.CanvasItemClear(ShadedCanvasItem);
VS.CanvasItemClear(UnshadedCanvasItem);
using (var shadedHandle = new DrawingHandleScreen(ShadedCanvasItem))

View File

@@ -12,6 +12,7 @@ namespace SS14.Client.Graphics.ClientEye
protected IEyeManager eyeManager;
public Godot.Camera2D GodotCamera { get; private set; }
private bool disposed = false;
public bool Current
{
get => eyeManager.CurrentEye == this;
@@ -34,23 +35,31 @@ namespace SS14.Client.Graphics.ClientEye
}
public Vector2 Zoom
{
get => GodotCamera.Zoom.Convert();
set => GodotCamera.Zoom = value.Convert();
get => GameController.OnGodot ? GodotCamera.Zoom.Convert() : default;
set
{
if (GameController.OnGodot)
{
GodotCamera.Zoom = value.Convert();
}
}
}
public MapId MapId { get; set; } = MapId.Nullspace;
public Eye()
{
GodotCamera = new Godot.Camera2D()
{
DragMarginHEnabled = false,
DragMarginVEnabled = false,
};
eyeManager = IoCManager.Resolve<IEyeManager>();
if (GameController.OnGodot)
{
GodotCamera = new Godot.Camera2D()
{
DragMarginHEnabled = false,
DragMarginVEnabled = false,
};
}
}
protected virtual void Dispose(bool disposing)
@@ -63,6 +72,10 @@ namespace SS14.Client.Graphics.ClientEye
eyeManager = null;
}
if (!GameController.OnGodot)
{
return;
}
GodotCamera.QueueFree();
GodotCamera.Dispose();
GodotCamera = null;
@@ -74,6 +87,7 @@ namespace SS14.Client.Graphics.ClientEye
{
return;
}
Dispose(true);
GC.SuppressFinalize(this);
}

View File

@@ -33,7 +33,11 @@ namespace SS14.Client.Graphics.ClientEye
return;
}
currentEye.GodotCamera.Current = false;
if (GameController.OnGodot)
{
currentEye.GodotCamera.Current = false;
}
if (value != null)
{
currentEye = value;
@@ -43,7 +47,10 @@ namespace SS14.Client.Graphics.ClientEye
currentEye = defaultEye;
}
currentEye.GodotCamera.Current = true;
if (GameController.OnGodot)
{
currentEye.GodotCamera.Current = true;
}
}
}
@@ -51,6 +58,11 @@ namespace SS14.Client.Graphics.ClientEye
public Box2 GetWorldViewport()
{
if (!GameController.OnGodot)
{
return default;
}
var vpSize = sceneTree.SceneTree.Root.Size.Convert();
var topLeft = ScreenToWorld(Vector2.Zero);
@@ -70,7 +82,11 @@ namespace SS14.Client.Graphics.ClientEye
{
defaultEye = new FixedEye();
currentEye = defaultEye;
currentEye.GodotCamera.Current = true;
if (GameController.OnGodot)
{
currentEye.GodotCamera.Current = true;
}
}
public void Dispose()
@@ -80,6 +96,10 @@ namespace SS14.Client.Graphics.ClientEye
public Vector2 WorldToScreen(Vector2 point)
{
if (!GameController.OnGodot)
{
return default;
}
var transform = sceneTree.WorldRoot.GetViewportTransform();
return transform.Xform(point.Convert() * PIXELSPERMETER * new Godot.Vector2(1, -1)).Convert();
}
@@ -96,6 +116,10 @@ namespace SS14.Client.Graphics.ClientEye
public GridCoordinates ScreenToWorld(Vector2 point)
{
if (!GameController.OnGodot)
{
return default;
}
var matrix = Matrix3.Invert(MatrixViewPortTransform(sceneTree));
var worldPos = matrix.Transform(point) / PIXELSPERMETER * new Vector2(1, -1);
IMapGrid grid ;

View File

@@ -11,12 +11,17 @@ namespace SS14.Client.Graphics.ClientEye
public class FixedEye : Eye
{
private Vector2 position;
public Vector2 Position
{
get => position;
set
{
GodotCamera.Position = value.Convert();
if (GameController.OnGodot)
{
GodotCamera.Position = value.Convert();
}
position = value;
}
}
@@ -25,6 +30,11 @@ namespace SS14.Client.Graphics.ClientEye
public FixedEye()
{
if (!GameController.OnGodot)
{
return;
}
sceneTree = IoCManager.Resolve<ISceneTreeHolder>();
sceneTree.WorldRoot.AddChild(GodotCamera);
}

View File

@@ -1,4 +1,5 @@
using System;
using SS14.Client.Interfaces;
using SS14.Client.Interfaces.Graphics;
using SS14.Client.Utility;
using SS14.Shared.Configuration;
@@ -21,8 +22,7 @@ namespace SS14.Client.Graphics
/// </summary>
public class DisplayManager : IDisplayManager, IPostInjectInit
{
[Dependency]
readonly IConfigurationManager configurationManager;
[Dependency] readonly IConfigurationManager configurationManager;
public WindowMode WindowMode { get; private set; } = WindowMode.Windowed;
public bool VSync { get; private set; } = false;
@@ -30,7 +30,15 @@ namespace SS14.Client.Graphics
void IPostInjectInit.PostInject()
{
configurationManager.RegisterCVar("display.vsync", VSync, CVar.ARCHIVE);
configurationManager.RegisterCVar("display.windowmode", (int)WindowMode, CVar.ARCHIVE);
configurationManager.RegisterCVar("display.windowmode", (int) WindowMode, CVar.ARCHIVE);
}
public void SetWindowTitle(string title)
{
if (GameController.OnGodot)
{
Godot.OS.SetWindowTitle(title);
}
}
public void Initialize()
@@ -40,11 +48,14 @@ namespace SS14.Client.Graphics
public void ReadConfig()
{
WindowMode = (WindowMode)configurationManager.GetCVar<int>("display.windowmode");
WindowMode = (WindowMode) configurationManager.GetCVar<int>("display.windowmode");
VSync = configurationManager.GetCVar<bool>("display.vsync");
Godot.OS.VsyncEnabled = VSync;
Godot.OS.WindowFullscreen = WindowMode == WindowMode.Fullscreen;
if (GameController.OnGodot)
{
Godot.OS.VsyncEnabled = VSync;
Godot.OS.WindowFullscreen = WindowMode == WindowMode.Fullscreen;
}
}
}
}

View File

@@ -13,20 +13,31 @@ namespace SS14.Client.Graphics.Drawing
{
// Use RIDs in the theoretical case some nerd wants to draw something WITHOUT consulting the scene tree.
// Also it's probably faster or some shit.
internal Godot.RID Item { get; private set; }
internal Godot.RID Item { get; }
public bool Disposed { get; private set; }
internal DrawingHandle(Godot.RID item)
{
Item = item ?? throw new ArgumentNullException(nameof(item));
}
internal DrawingHandle()
{
}
public void Dispose()
{
Item = null;
Disposed = true;
}
public void SetTransform(Vector2 position, Angle rotation, Vector2 scale)
{
if (!GameController.OnGodot)
{
return;
}
CheckDisposed();
var transform = Godot.Transform2D.Identity.Rotated((float) rotation.Theta).Scaled(scale.Convert());
SetTransform2DRotationAndScale(ref transform, rotation.Theta, scale);
@@ -36,6 +47,11 @@ namespace SS14.Client.Graphics.Drawing
public void SetTransform(Matrix3 matrix)
{
if (!GameController.OnGodot)
{
return;
}
CheckDisposed();
VS.CanvasItemAddSetTransform(Item, matrix.Convert());
}
@@ -49,7 +65,7 @@ namespace SS14.Client.Graphics.Drawing
protected void CheckDisposed()
{
if (Item == null)
if (Disposed)
{
throw new ObjectDisposedException(nameof(DrawingHandle));
}
@@ -72,14 +88,28 @@ namespace SS14.Client.Graphics.Drawing
{
}
internal DrawingHandleWorld() : base()
{
}
public override void DrawCircle(Vector2 position, float radius, Color color)
{
if (!GameController.OnGodot)
{
return;
}
CheckDisposed();
VS.CanvasItemAddCircle(Item, ToPixelCoords(position), radius * PPM, color.Convert());
}
public override void DrawLine(Vector2 from, Vector2 to, Color color, float width = 1, bool antiAliased = false)
{
if (!GameController.OnGodot)
{
return;
}
CheckDisposed();
VS.CanvasItemAddLine(Item, ToPixelCoords(from), ToPixelCoords(to), color.Convert(), width, antiAliased);
}
@@ -87,6 +117,11 @@ namespace SS14.Client.Graphics.Drawing
public override void DrawTexture(Texture texture, Vector2 position, Color? modulate = null,
Texture normalMap = null)
{
if (!GameController.OnGodot)
{
return;
}
CheckDisposed();
texture.GodotTexture.Draw(Item, ToPixelCoords(position), modulate?.Convert(), false, normalMap);
}
@@ -94,12 +129,22 @@ namespace SS14.Client.Graphics.Drawing
public void DrawTextureRect(Texture texture, Box2 rect, bool tile, Color? modulate = null,
bool transpose = false, Texture normalMap = null)
{
if (!GameController.OnGodot)
{
return;
}
CheckDisposed();
texture.GodotTexture.DrawRect(Item, ToPixelCoords(rect), tile, modulate?.Convert(), transpose, normalMap);
}
public void DrawRect(Box2 rect, Color color, bool filled = true)
{
if (!GameController.OnGodot)
{
return;
}
CheckDisposed();
if (filled)
{
@@ -116,6 +161,11 @@ namespace SS14.Client.Graphics.Drawing
public void DrawStyleBox(StyleBox styleBox, UIBox2 box)
{
if (!GameController.OnGodot)
{
return;
}
CheckDisposed();
styleBox.GodotStyleBox.Draw(Item, box.Convert());
}
@@ -137,26 +187,51 @@ namespace SS14.Client.Graphics.Drawing
{
}
internal DrawingHandleScreen() : base()
{
}
public override void DrawCircle(Vector2 position, float radius, Color color)
{
if (!GameController.OnGodot)
{
return;
}
CheckDisposed();
VS.CanvasItemAddCircle(Item, position.Convert(), radius, color.Convert());
}
public void DrawStyleBox(StyleBox styleBox, UIBox2 box)
{
if (!GameController.OnGodot)
{
return;
}
CheckDisposed();
styleBox.GodotStyleBox.Draw(Item, box.Convert());
}
public override void DrawLine(Vector2 from, Vector2 to, Color color, float width = 1, bool antiAliased = false)
{
if (!GameController.OnGodot)
{
return;
}
CheckDisposed();
VS.CanvasItemAddLine(Item, from.Convert(), to.Convert(), color.Convert(), width, antiAliased);
}
public void DrawRect(UIBox2 rect, Color color, bool filled = true)
{
if (!GameController.OnGodot)
{
return;
}
CheckDisposed();
if (filled)
{
@@ -174,6 +249,11 @@ namespace SS14.Client.Graphics.Drawing
public override void DrawTexture(Texture texture, Vector2 position, Color? modulate = null,
Texture normalMap = null)
{
if (!GameController.OnGodot)
{
return;
}
CheckDisposed();
texture.GodotTexture.Draw(Item, position.Convert(), modulate?.Convert(), false, normalMap);
}
@@ -181,6 +261,11 @@ namespace SS14.Client.Graphics.Drawing
public void DrawTextureRect(Texture texture, UIBox2 rect, bool tile, Color? modulate = null,
bool transpose = false, Texture normalMap = null)
{
if (!GameController.OnGodot)
{
return;
}
CheckDisposed();
texture.GodotTexture.DrawRect(Item, rect.Convert(), tile, modulate?.Convert(), transpose, normalMap);
}

View File

@@ -42,11 +42,16 @@ namespace SS14.Client.Graphics.Drawing
public class StyleBoxTexture : StyleBox
{
private readonly Godot.StyleBoxTexture stylebox;
internal override Godot.StyleBox GodotStyleBox => stylebox;
public StyleBoxTexture()
{
if (!GameController.OnGodot)
{
return;
}
stylebox = new Godot.StyleBoxTexture();
}
@@ -65,43 +70,85 @@ namespace SS14.Client.Graphics.Drawing
public float MarginLeft
{
get => stylebox.MarginLeft;
set => stylebox.MarginLeft = value;
get => GameController.OnGodot ? stylebox.MarginLeft : default;
set
{
if (GameController.OnGodot)
{
stylebox.MarginLeft = value;
}
}
}
public float MarginRight
{
get => stylebox.MarginRight;
set => stylebox.MarginRight = value;
get => GameController.OnGodot ? stylebox.MarginRight : default;
set
{
if (GameController.OnGodot)
{
stylebox.MarginRight = value;
}
}
}
public float MarginTop
{
get => stylebox.MarginTop;
set => stylebox.MarginTop = value;
get => GameController.OnGodot ? stylebox.MarginTop : default;
set
{
if (GameController.OnGodot)
{
stylebox.MarginTop = value;
}
}
}
public float MarginBottom
{
get => stylebox.MarginBottom;
set => stylebox.MarginBottom = value;
get => GameController.OnGodot ? stylebox.MarginBottom : default;
set
{
if (GameController.OnGodot)
{
stylebox.MarginBottom = value;
}
}
}
public Color Modulate
{
get => stylebox.ModulateColor.Convert();
set => stylebox.ModulateColor = value.Convert();
get => GameController.OnGodot ? stylebox.ModulateColor.Convert() : default;
set
{
if (GameController.OnGodot)
{
stylebox.ModulateColor = value.Convert();
}
}
}
private Texture cachedTexture;
public Texture Texture
{
get
{
return cachedTexture ?? new GodotTextureSource((Godot.Texture)stylebox.Texture);
if (!GameController.OnGodot)
{
return null;
}
return cachedTexture ?? new GodotTextureSource((Godot.Texture) stylebox.Texture);
}
// Woo implicit casts.
set => stylebox.Texture = cachedTexture = value;
set
{
if (GameController.OnGodot)
{
stylebox.Texture = cachedTexture = value;
}
}
}
/// <summary>
@@ -135,8 +182,14 @@ namespace SS14.Client.Graphics.Drawing
{
public Color BackgroundColor
{
get => stylebox.BgColor.Convert();
set => stylebox.BgColor = value.Convert();
get => GameController.OnGodot ? stylebox.BgColor.Convert() : default;
set
{
if (GameController.OnGodot)
{
stylebox.BgColor = value.Convert();
}
}
}
private readonly Godot.StyleBoxFlat stylebox;
@@ -145,31 +198,58 @@ namespace SS14.Client.Graphics.Drawing
public StyleBoxFlat()
{
stylebox = new Godot.StyleBoxFlat();
if (GameController.OnGodot)
{
stylebox = new Godot.StyleBoxFlat();
}
}
public float MarginLeft
{
get => stylebox.ContentMarginLeft;
set => stylebox.ContentMarginLeft = value;
get => GameController.OnGodot ? stylebox.ContentMarginLeft : default;
set
{
if (GameController.OnGodot)
{
stylebox.ContentMarginLeft = value;
}
}
}
public float MarginRight
{
get => stylebox.ContentMarginRight;
set => stylebox.ContentMarginRight = value;
get => GameController.OnGodot ? stylebox.ContentMarginRight : default;
set
{
if (GameController.OnGodot)
{
stylebox.ContentMarginRight = value;
}
}
}
public float MarginTop
{
get => stylebox.ContentMarginTop;
set => stylebox.ContentMarginTop = value;
get => GameController.OnGodot ? stylebox.ContentMarginTop : default;
set
{
if (GameController.OnGodot)
{
stylebox.ContentMarginTop = value;
}
}
}
public float MarginBottom
{
get => stylebox.ContentMarginBottom;
set => stylebox.ContentMarginBottom = value;
get => GameController.OnGodot ? stylebox.ContentMarginBottom : default;
set
{
if (GameController.OnGodot)
{
stylebox.ContentMarginBottom = value;
}
}
}

View File

@@ -1,4 +1,5 @@
using SS14.Client.ResourceManagement;
using System;
using SS14.Client.ResourceManagement;
namespace SS14.Client.Graphics
{
@@ -21,28 +22,107 @@ namespace SS14.Client.Graphics
/// </summary>
public class VectorFont : Font
{
public int ExtraSpacingTop { get => _font.ExtraSpacingTop; set => _font.ExtraSpacingTop = value; }
public int ExtraSpacingBottom { get => _font.ExtraSpacingBottom; set => _font.ExtraSpacingBottom = value; }
public int ExtraSpacingChar { get => _font.ExtraSpacingChar; set => _font.ExtraSpacingChar = value; }
public int ExtraSpacingSpace { get => _font.ExtraSpacingSpace; set => _font.ExtraSpacingSpace = value; }
public int ExtraSpacingTop
{
get => GameController.OnGodot ? _font.ExtraSpacingTop : default;
set
{
if (GameController.OnGodot)
{
_font.ExtraSpacingTop = value;
}
}
}
public int Size { get => _font.Size; set => _font.Size = value; }
public bool UseFilter { get => _font.UseFilter; set => _font.UseFilter = value; }
public bool UseMipmaps { get => _font.UseMipmaps; set => _font.UseMipmaps = value; }
public int ExtraSpacingBottom
{
get => GameController.OnGodot ? _font.ExtraSpacingBottom : default;
set
{
if (GameController.OnGodot)
{
_font.ExtraSpacingBottom = value;
}
}
}
public int ExtraSpacingChar
{
get => GameController.OnGodot ? _font.ExtraSpacingChar : default;
set
{
if (GameController.OnGodot)
{
_font.ExtraSpacingChar = value;
}
}
}
public int ExtraSpacingSpace
{
get => GameController.OnGodot ? _font.ExtraSpacingSpace : default;
set
{
if (GameController.OnGodot)
{
_font.ExtraSpacingSpace = value;
}
}
}
public int Size
{
get => _font.Size;
set
{
if (GameController.OnGodot)
{
_font.Size = value;
}
}
}
public bool UseFilter
{
get => _font.UseFilter;
set
{
if (GameController.OnGodot)
{
_font.UseFilter = value;
}
}
}
public bool UseMipmaps
{
get => _font.UseMipmaps;
set
{
if (GameController.OnGodot)
{
_font.UseMipmaps = value;
}
}
}
internal override Godot.Font GodotFont => _font;
private readonly Godot.DynamicFont _font;
public VectorFont(FontResource res) : this(res.FontData)
public VectorFont(FontResource res)
: this(res.FontData)
{
}
internal VectorFont(Godot.DynamicFontData data)
{
_font = new Godot.DynamicFont
if (GameController.OnGodot)
{
FontData = data,
};
_font = new Godot.DynamicFont
{
FontData = data,
};
}
}
}

View File

@@ -5,6 +5,7 @@ using SS14.Shared;
using SS14.Shared.Maths;
using System;
using SS14.Shared.Enums;
using SS14.Shared.Interfaces.GameObjects.Components;
namespace SS14.Client.Graphics.Lighting
{
@@ -14,17 +15,30 @@ namespace SS14.Client.Graphics.Lighting
{
public Vector2 Offset
{
get => Light2D.Offset.Convert();
set => Light2D.Offset = value.Convert();
get => GameController.OnGodot ? Light2D.Offset.Convert() : default;
set
{
if (GameController.OnGodot)
{
Light2D.Offset = value.Convert();
}
}
}
public Angle Rotation
{
get => new Angle(Light2D.GlobalRotation);
set => Light2D.Rotation = (float)value;
get => GameController.OnGodot ? new Angle(Light2D.GlobalRotation) : default;
set
{
if (GameController.OnGodot)
{
Light2D.GlobalRotation = (float) value.Theta;
}
}
}
private Color color;
public Color Color
{
get => color;
@@ -36,11 +50,16 @@ namespace SS14.Client.Graphics.Lighting
}
color = value;
Light2D.Color = value.Convert();
if (GameController.OnGodot)
{
Light2D.Color = value.Convert();
}
}
}
private float textureScale;
public float TextureScale
{
get => textureScale;
@@ -52,11 +71,16 @@ namespace SS14.Client.Graphics.Lighting
}
textureScale = value;
Light2D.TextureScale = value;
if (GameController.OnGodot)
{
Light2D.TextureScale = value;
}
}
}
private float energy;
public float Energy
{
get => energy;
@@ -68,7 +92,10 @@ namespace SS14.Client.Graphics.Lighting
}
energy = value;
Light2D.Energy = value;
if (GameController.OnGodot)
{
Light2D.Energy = value;
}
}
}
@@ -94,6 +121,7 @@ namespace SS14.Client.Graphics.Lighting
}
private Texture texture;
public Texture Texture
{
get => texture;
@@ -103,12 +131,17 @@ namespace SS14.Client.Graphics.Lighting
{
return;
}
texture = value;
Light2D.Texture = value;
if (GameController.OnGodot)
{
Light2D.Texture = value;
}
}
}
private bool enabled;
public bool Enabled
{
get => enabled;
@@ -119,32 +152,37 @@ namespace SS14.Client.Graphics.Lighting
}
}
private Godot.Light2D Light2D;
public bool Disposed { get; private set; }
private LightManager Manager;
private LightingSystem System => Manager.System;
private Godot.Light2D Light2D;
private IGodotTransformComponent parentTransform;
private Godot.Vector2 CurrentPos;
public Light(LightManager manager)
{
Manager = manager;
Light2D = new Godot.Light2D()
{
// TODO: Allow this to be modified.
ShadowEnabled = true,
ShadowFilter = Godot.Light2D.ShadowFilterEnum.Pcf5,
};
if (Manager.System == LightingSystem.Disabled)
if (GameController.OnGodot)
{
Light2D.Enabled = Light2D.Visible = false;
Light2D = new Godot.Light2D()
{
// TODO: Allow this to be modified.
ShadowEnabled = true,
ShadowFilter = Godot.Light2D.ShadowFilterEnum.Pcf5,
};
if (Manager.System == LightingSystem.Disabled)
{
Light2D.Enabled = Light2D.Visible = false;
}
}
Mode = new LightModeConstant();
Mode.Start(this);
if (System == LightingSystem.Deferred)
if (GameController.OnGodot && System == LightingSystem.Deferred)
{
Manager.deferredViewport.AddChild(Light2D);
}
@@ -152,45 +190,62 @@ namespace SS14.Client.Graphics.Lighting
public void DeParent()
{
if (System == LightingSystem.Deferred)
if (GameController.OnGodot)
{
Light2D.Position = new Godot.Vector2(0, 0);
}
else
{
parentTransform.SceneNode.RemoveChild(Light2D);
if (System == LightingSystem.Deferred)
{
Light2D.Position = new Godot.Vector2(0, 0);
}
else
{
parentTransform.SceneNode.RemoveChild(Light2D);
}
}
UpdateEnabled();
}
public void ParentTo(IGodotTransformComponent node)
public void ParentTo(ITransformComponent node)
{
if (!GameController.OnGodot)
{
return;
}
if (System != LightingSystem.Deferred)
{
if (parentTransform != null)
{
DeParent();
}
node.SceneNode.AddChild(Light2D);
((IGodotTransformComponent) node).SceneNode.AddChild(Light2D);
}
parentTransform = node;
parentTransform = (IGodotTransformComponent) node;
UpdateEnabled();
}
public void Dispose()
{
// Already disposed.
if (Light2D == null)
if (Disposed)
{
return;
}
Manager.RemoveLight(this);
Manager = null;
Disposed = true;
if (!GameController.OnGodot)
{
return;
}
Light2D.QueueFree();
Light2D.Dispose();
Light2D = null;
}
private static ILightMode GetModeInstance(LightModeClass modeClass)
@@ -207,19 +262,25 @@ namespace SS14.Client.Graphics.Lighting
public void UpdateEnabled()
{
Light2D.Visible = Enabled && Manager.Enabled && parentTransform != null;
if (GameController.OnGodot)
{
Light2D.Visible = Enabled && Manager.Enabled && parentTransform != null;
}
}
public void FrameProcess(FrameEventArgs args)
{
// TODO: Maybe use OnMove events to make this less expensive.
if (System == LightingSystem.Deferred && parentTransform != null)
// TODO: Maybe use OnMove events to make this less expensive.
if (!GameController.OnGodot || Manager.System != LightingSystem.Deferred ||
parentTransform == null)
{
var newpos = parentTransform.SceneNode.GlobalPosition;
if (CurrentPos != newpos)
{
Light2D.Position = newpos;
}
return;
}
var newpos = parentTransform.SceneNode.GlobalPosition;
if (CurrentPos != newpos)
{
Light2D.Position = newpos;
}
}
}

View File

@@ -3,6 +3,7 @@ using System.Linq;
using SS14.Client.Interfaces.GameObjects.Components;
using SS14.Client.Interfaces.Graphics.Lighting;
using SS14.Client.Utility;
using SS14.Shared.Interfaces.GameObjects.Components;
using SS14.Shared.Maths;
namespace SS14.Client.Graphics.Lighting
@@ -12,6 +13,7 @@ namespace SS14.Client.Graphics.Lighting
sealed class Occluder : IOccluder
{
private bool visible = true;
public bool Enabled
{
get => visible;
@@ -22,6 +24,8 @@ namespace SS14.Client.Graphics.Lighting
}
}
public bool Disposed { get; private set; }
private LightManager Manager;
private Godot.OccluderPolygon2D occluderPolygon;
@@ -31,10 +35,17 @@ namespace SS14.Client.Graphics.Lighting
public OccluderCullMode CullMode
{
get => (OccluderCullMode)occluderPolygon.CullMode;
set => occluderPolygon.CullMode = (Godot.OccluderPolygon2D.CullModeEnum)value;
get => GameController.OnGodot ? (OccluderCullMode) occluderPolygon.CullMode : default;
set
{
if (GameController.OnGodot)
{
occluderPolygon.CullMode = (Godot.OccluderPolygon2D.CullModeEnum) value;
}
}
}
private IGodotTransformComponent parentTransform;
private Godot.Vector2 CurrentPos;
@@ -42,6 +53,11 @@ namespace SS14.Client.Graphics.Lighting
{
Manager = manager;
if (!GameController.OnGodot)
{
return;
}
occluderPolygon = new Godot.OccluderPolygon2D();
occluder = new Godot.LightOccluder2D()
{
@@ -57,39 +73,48 @@ namespace SS14.Client.Graphics.Lighting
public void Dispose()
{
// Already disposed.
if (occluder == null)
if (Disposed)
{
return;
}
Manager.RemoveOccluder(this);
Manager = null;
Disposed = true;
if (!GameController.OnGodot)
{
return;
}
occluder.QueueFree();
occluder.Dispose();
occluder = null;
occluderPolygon.Dispose();
occluderPolygon = null;
}
public void SetPolygon(Vector2[] polygon)
{
if (!GameController.OnGodot)
{
return;
}
var converted = new Godot.Vector2[polygon.Length];
for (var i = 0; i < polygon.Length; i++)
{
converted[i] = polygon[i].Convert();
}
occluderPolygon.Polygon = converted;
}
public void SetGodotPolygon(Godot.Vector2[] polygon)
{
occluderPolygon.Polygon = polygon;
occluderPolygon.Polygon = converted;
}
public void DeParent()
{
if (!GameController.OnGodot)
{
return;
}
if (Deferred)
{
occluder.Position = new Godot.Vector2(0, 0);
@@ -98,26 +123,42 @@ namespace SS14.Client.Graphics.Lighting
{
parentTransform.SceneNode.RemoveChild(occluder);
}
UpdateEnabled();
}
public void ParentTo(IGodotTransformComponent node)
public void ParentTo(ITransformComponent node)
{
if (!GameController.OnGodot)
{
return;
}
if (!Deferred)
{
node.SceneNode.AddChild(occluder);
((IGodotTransformComponent) node).SceneNode.AddChild(occluder);
}
parentTransform = node;
parentTransform = (IGodotTransformComponent) node;
UpdateEnabled();
}
private void UpdateEnabled()
{
occluder.Visible = parentTransform != null && Enabled;
if (GameController.OnGodot)
{
occluder.Visible = parentTransform != null && Enabled;
}
}
public void FrameProcess(FrameEventArgs args)
{
if (!GameController.OnGodot)
{
return;
}
// TODO: Maybe use OnMove events to make this less expensive.
if (Deferred && parentTransform != null)
{

View File

@@ -24,14 +24,12 @@ namespace SS14.Client.Graphics.Lighting
{
public sealed partial class LightManager : ILightManager, IDisposable, IPostInjectInit
{
[Dependency]
readonly ISceneTreeHolder sceneTreeHolder;
[Dependency]
readonly IConfigurationManager configManager;
[Dependency]
readonly IResourceCache resourceCache;
[Dependency] readonly ISceneTreeHolder sceneTreeHolder;
[Dependency] readonly IConfigurationManager configManager;
[Dependency] readonly IResourceCache resourceCache;
private bool enabled = true;
public bool Enabled
{
get => enabled;
@@ -64,12 +62,18 @@ namespace SS14.Client.Graphics.Lighting
public void PostInject()
{
configManager.RegisterCVar("display.lighting_system", LightingSystem.Normal, Shared.Configuration.CVar.ARCHIVE);
configManager.RegisterCVar("display.lighting_system", LightingSystem.Normal,
Shared.Configuration.CVar.ARCHIVE);
}
public void Initialize()
{
System = configManager.GetCVar<LightingSystem>("display.lighting_system");
if (!GameController.OnGodot)
{
return;
}
canvasModulate = new Godot.CanvasModulate()
{
// Black
@@ -89,7 +93,8 @@ namespace SS14.Client.Graphics.Lighting
deferredViewport.AddChild(canvasModulate);
rootViewport.AddChild(deferredViewport);
var whiteTex = resourceCache.GetResource<TextureResource>(new ResourcePath(@"/Textures/Effects/Light/white.png"));
var whiteTex =
resourceCache.GetResource<TextureResource>(new ResourcePath(@"/Textures/Effects/Light/white.png"));
deferredMaskBackground = new Godot.Sprite()
{
Name = "DeferredMaskBackground",
@@ -118,6 +123,7 @@ namespace SS14.Client.Graphics.Lighting
}
}
private void OnWindowSizeChanged()
{
if (System == LightingSystem.Deferred)
@@ -153,6 +159,7 @@ namespace SS14.Client.Graphics.Lighting
deferredMaskLayer.AddChild(deferredMaskSprite);
}
public void Dispose()
{
if (disposed)
@@ -166,6 +173,11 @@ namespace SS14.Client.Graphics.Lighting
light.Dispose();
}
if (!GameController.OnGodot)
{
return;
}
if (System == LightingSystem.Deferred)
{
deferredSizeChangedSubscriber.Disconnect(rootViewport, "size_changed");
@@ -230,10 +242,15 @@ namespace SS14.Client.Graphics.Lighting
private void UpdateEnabled()
{
if (!GameController.OnGodot)
{
return;
}
if (System == LightingSystem.Deferred)
{
deferredMaskSprite.Visible = Enabled;
}
foreach (var light in lights)
{
light.UpdateEnabled();
@@ -242,7 +259,7 @@ namespace SS14.Client.Graphics.Lighting
public void FrameUpdate(RenderFrameEventArgs args)
{
if (System == LightingSystem.Deferred)
if (GameController.OnGodot && System == LightingSystem.Deferred)
{
var transform = rootViewport.CanvasTransform;
deferredViewport.CanvasTransform = transform;

View File

@@ -23,13 +23,14 @@ namespace SS14.Client.Graphics.Overlays
public virtual OverlaySpace Space => OverlaySpace.ScreenSpace;
private Shader _shader;
public Shader Shader
{
get => _shader;
set
{
_shader = value;
if (MainCanvasItem != null)
if (GameController.OnGodot && MainCanvasItem != null)
{
VS.CanvasItemSetMaterial(MainCanvasItem, value?.GodotMaterial?.GetRid());
}
@@ -37,6 +38,7 @@ namespace SS14.Client.Graphics.Overlays
}
private int? _zIndex;
public int? ZIndex
{
get => _zIndex;
@@ -46,6 +48,7 @@ namespace SS14.Client.Graphics.Overlays
{
throw new ArgumentOutOfRangeException(nameof(value));
}
_zIndex = value;
UpdateZIndex();
}
@@ -55,6 +58,7 @@ namespace SS14.Client.Graphics.Overlays
private bool _isDirty = true;
private Godot.RID MainCanvasItem;
private readonly List<Godot.RID> CanvasItems = new List<Godot.RID>();
@@ -75,6 +79,7 @@ namespace SS14.Client.Graphics.Overlays
{
Shader.ApplyToCanvasItem(MainCanvasItem);
}
UpdateZIndex();
}
@@ -84,6 +89,7 @@ namespace SS14.Client.Graphics.Overlays
{
return;
}
Dispose(true);
Disposed = true;
GC.SuppressFinalize(this);
@@ -108,6 +114,25 @@ namespace SS14.Client.Graphics.Overlays
throw new InvalidOperationException("Can only allocate new handles while drawing.");
}
if (!GameController.OnGodot)
{
DrawingHandle handle;
switch (Space)
{
case OverlaySpace.ScreenSpace:
handle = new DrawingHandleScreen();
break;
case OverlaySpace.WorldSpace:
handle = new DrawingHandleWorld();
break;
default:
throw new ArgumentOutOfRangeException();
}
TempHandles.Add(handle);
return handle;
}
var item = VS.CanvasItemCreate();
VS.CanvasItemSetParent(item, MainCanvasItem);
CanvasItems.Add(item);
@@ -120,21 +145,24 @@ namespace SS14.Client.Graphics.Overlays
VS.CanvasItemSetUseParentMaterial(item, SubHandlesUseMainShader);
}
DrawingHandle handle;
switch (Space)
{
case OverlaySpace.ScreenSpaceBelowWorld:
case OverlaySpace.ScreenSpace:
handle = new DrawingHandleScreen(item);
break;
case OverlaySpace.WorldSpace:
handle = new DrawingHandleWorld(item);
break;
default:
throw new ArgumentOutOfRangeException();
DrawingHandle handle;
switch (Space)
{
case OverlaySpace.ScreenSpaceBelowWorld:
case OverlaySpace.ScreenSpace:
handle = new DrawingHandleScreen(item);
break;
case OverlaySpace.WorldSpace:
handle = new DrawingHandleWorld(item);
break;
default:
throw new ArgumentOutOfRangeException();
}
TempHandles.Add(handle);
return handle;
}
TempHandles.Add(handle);
return handle;
}
public void Dirty()
@@ -144,7 +172,7 @@ namespace SS14.Client.Graphics.Overlays
public void FrameUpdate(RenderFrameEventArgs args)
{
if (!IsDirty)
if (!IsDirty || !GameController.OnGodot)
{
return;
}
@@ -167,6 +195,7 @@ namespace SS14.Client.Graphics.Overlays
default:
throw new ArgumentOutOfRangeException();
}
Draw(handle);
}
finally
@@ -176,12 +205,18 @@ namespace SS14.Client.Graphics.Overlays
{
handle.Dispose();
}
TempHandles.Clear();
}
}
private void ClearDraw()
{
if (!GameController.OnGodot)
{
return;
}
foreach (var item in CanvasItems)
{
VS.FreeRid(item);
@@ -194,7 +229,7 @@ namespace SS14.Client.Graphics.Overlays
private void UpdateZIndex()
{
if (MainCanvasItem == null)
if (MainCanvasItem == null || !GameController.OnGodot)
{
return;
}

View File

@@ -18,21 +18,26 @@ namespace SS14.Client.Graphics.Overlays
private Godot.Node2D RootNodeScreen;
private Godot.Node2D RootNodeScreenBelowWorld;
[Dependency]
readonly ISceneTreeHolder sceneTreeHolder;
[Dependency] readonly ISceneTreeHolder sceneTreeHolder;
private readonly Dictionary<string, (IOverlay overlay, Godot.RID canvasItem)> overlays = new Dictionary<string, (IOverlay, Godot.RID)>();
private readonly Dictionary<string, (IOverlay overlay, Godot.RID canvasItem)> overlays =
new Dictionary<string, (IOverlay, Godot.RID)>();
public void Initialize()
{
if (!GameController.OnGodot)
{
return;
}
RootNodeScreenBelowWorld = new Godot.Node2D { Name = "OverlayRoot" };
sceneTreeHolder.BelowWorldScreenSpace.AddChild(RootNodeScreenBelowWorld);
RootNodeWorld = new Godot.Node2D { Name = "OverlayRoot" };
sceneTreeHolder.WorldRoot.AddChild(RootNodeWorld);
RootNodeWorld.ZIndex = (int)DrawDepth.Overlays;
RootNodeWorld.ZIndex = (int) DrawDepth.Overlays;
RootNodeScreen = new Godot.Node2D { Name = "OverlayRoot" };
RootNodeScreen = new Godot.Node2D {Name = "OverlayRoot"};
sceneTreeHolder.SceneTree.Root.GetNode("UILayer").AddChild(RootNodeScreen);
}
@@ -46,10 +51,16 @@ namespace SS14.Client.Graphics.Overlays
public void AddOverlay(IOverlay overlay)
{
if (!GameController.OnGodot)
{
return;
}
if (overlays.ContainsKey(overlay.ID))
{
throw new InvalidOperationException($"We already have an overlay with ID '{overlay.ID}'");
}
Godot.RID parent;
switch (overlay.Space)
{
@@ -65,6 +76,7 @@ namespace SS14.Client.Graphics.Overlays
default:
throw new NotImplementedException($"Unknown overlay space: {overlay.Space}");
}
var item = VS.CanvasItemCreate();
VS.CanvasItemSetParent(item, parent);
@@ -74,25 +86,36 @@ namespace SS14.Client.Graphics.Overlays
public IOverlay GetOverlay(string id)
{
return overlays[id].overlay;
if (GameController.OnGodot)
{
return overlays[id].overlay;
}
throw new NotImplementedException();
}
public T GetOverlay<T>(string id) where T : IOverlay
{
return (T)GetOverlay(id);
return (T) GetOverlay(id);
}
public bool HasOverlay(string id)
{
return overlays.ContainsKey(id);
if (GameController.OnGodot)
{
return overlays.ContainsKey(id);
}
throw new NotImplementedException();
}
public void RemoveOverlay(string id)
{
if (!overlays.TryGetValue(id, out var value))
if (!GameController.OnGodot || !overlays.TryGetValue(id, out var value))
{
return;
}
var (overlay, item) = value;
overlay.Dispose();
VS.FreeRid(item);
@@ -101,12 +124,13 @@ namespace SS14.Client.Graphics.Overlays
public bool TryGetOverlay(string id, out IOverlay overlay)
{
if (overlays.TryGetValue(id, out var value))
if (GameController.OnGodot && overlays.TryGetValue(id, out var value))
{
overlay = value.overlay;
return true;
}
overlay = null;
overlay = default;
return false;
}
@@ -114,9 +138,10 @@ namespace SS14.Client.Graphics.Overlays
{
if (overlays.TryGetValue(id, out var value))
{
overlay = (T)value.overlay;
overlay = (T) value.overlay;
return true;
}
overlay = default;
return false;
}

View File

@@ -10,6 +10,11 @@ namespace SS14.Client.Graphics.Shaders
// ReSharper disable once CollectionNeverQueried.Local
private static readonly List<Shader> LeakyLeaky = new List<Shader>();
internal Shader()
{
}
internal Shader(Godot.Material godotMaterial)
{
LeakyLeaky.Add(this);

View File

@@ -34,6 +34,11 @@ namespace SS14.Client.Graphics.Shaders
/// </summary>
public Shader Instance()
{
if (!GameController.OnGodot)
{
return new Shader();
}
Godot.Material mat;
switch (Kind)
@@ -51,6 +56,7 @@ namespace SS14.Client.Graphics.Shaders
shaderMat.SetShaderParam(pair.Key, pair.Value);
}
}
break;
case ShaderKind.Canvas:
mat = new Godot.CanvasItemMaterial
@@ -113,6 +119,11 @@ namespace SS14.Client.Graphics.Shaders
private void ReadCanvasKind(YamlMappingNode mapping)
{
if (!GameController.OnGodot)
{
return;
}
if (mapping.TryGetNode("light_mode", out var node))
{
switch (node.AsString())
@@ -166,6 +177,10 @@ namespace SS14.Client.Graphics.Shaders
private object ParseShaderParamFor(YamlNode node, ShaderParamType type)
{
if (!GameController.OnGodot)
{
throw new NotImplementedException();
}
switch (type)
{
case ShaderParamType.Void:
@@ -196,6 +211,7 @@ namespace SS14.Client.Graphics.Shaders
var path = node.AsResourcePath();
var resc = IoCManager.Resolve<IResourceCache>();
return resc.GetResource<TextureResource>(path).Texture.GodotTexture;
// If something's not handled here, then that's probably because I was lazy.
default:
throw new NotImplementedException();

View File

@@ -1,4 +1,5 @@
using System.IO;
using System;
using System.IO;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.PixelFormats;
@@ -13,8 +14,9 @@ namespace SS14.Client.Graphics
{
internal abstract Godot.Texture GodotTexture { get; }
public int Width => GodotTexture.GetWidth();
public int Height => GodotTexture.GetHeight();
public int Width => GameController.OnGodot ? GodotTexture.GetWidth() : default;
public int Height => GameController.OnGodot ? GodotTexture.GetHeight() : default;
public Vector2i Size => new Vector2i(Width, Height);
public static implicit operator Godot.Texture(Texture src)
@@ -24,6 +26,10 @@ namespace SS14.Client.Graphics
public static Texture LoadFromImage<T>(Image<T> image) where T : struct, IPixel<T>
{
if (!GameController.OnGodot)
{
return new BlankTexture();
}
var stream = new MemoryStream();
try
@@ -50,6 +56,11 @@ namespace SS14.Client.Graphics
public static Texture LoadFromPNGStream(Stream stream)
{
if (!GameController.OnGodot)
{
return new BlankTexture();
}
using (var memoryStream = new MemoryStream())
{
stream.CopyTo(memoryStream);
@@ -76,6 +87,14 @@ namespace SS14.Client.Graphics
}
}
/// <summary>
/// Blank dummy texture.
/// </summary>
public class BlankTexture : Texture
{
internal override Godot.Texture GodotTexture => null;
}
/// <summary>
/// Wraps a texture returned by Godot itself,
/// for example when the texture was set in a GUI scene.

View File

@@ -45,6 +45,11 @@ namespace SS14.Client.Input
/// </summary>
public void Handle()
{
if (!GameController.OnGodot)
{
return;
}
var tree = IoCManager.Resolve<ISceneTreeHolder>();
tree.SceneTree.SetInputAsHandled();
}
@@ -74,11 +79,11 @@ namespace SS14.Client.Input
public static explicit operator KeyEventArgs(Godot.InputEventKey args)
{
return new KeyEventArgs(Keyboard.ConvertGodotKey(args.Scancode),
(UInt32)args.Unicode,
args.Alt,
args.Control,
args.Shift,
args.Command);
(UInt32) args.Unicode,
args.Alt,
args.Control,
args.Shift,
args.Command);
}
public static explicit operator KeyEventArgs(Godot.InputEventMouseButton args)
@@ -102,11 +107,11 @@ namespace SS14.Client.Input
public Vector2 Position { get; }
protected MouseEventArgs(Mouse.ButtonMask buttonMask,
Vector2 position,
bool alt,
bool control,
bool shift,
bool system)
Vector2 position,
bool alt,
bool control,
bool shift,
bool system)
: base(alt, control, shift, system)
{
ButtonMask = buttonMask;
@@ -146,6 +151,7 @@ namespace SS14.Client.Input
default:
return type;
}
if (Alt)
type |= ClickType.Alt;
if (Control)
@@ -160,13 +166,13 @@ namespace SS14.Client.Input
// ALL the parameters!
public MouseButtonEventArgs(Mouse.Button button,
bool doubleClick,
Mouse.ButtonMask buttonMask,
Vector2 position,
bool alt,
bool control,
bool shift,
bool system)
bool doubleClick,
Mouse.ButtonMask buttonMask,
Vector2 position,
bool alt,
bool control,
bool shift,
bool system)
: base(buttonMask, position, alt, control, shift, system)
{
Button = button;
@@ -177,14 +183,14 @@ namespace SS14.Client.Input
{
// Before cutting this up,
// this line was 281 characters long.
return new MouseButtonEventArgs((Mouse.Button)inputEvent.ButtonIndex,
inputEvent.Doubleclick,
(Mouse.ButtonMask)inputEvent.ButtonMask,
inputEvent.Position.Convert(),
inputEvent.Alt,
inputEvent.Control,
inputEvent.Shift,
inputEvent.Command);
return new MouseButtonEventArgs((Mouse.Button) inputEvent.ButtonIndex,
inputEvent.Doubleclick,
(Mouse.ButtonMask) inputEvent.ButtonMask,
inputEvent.Position.Convert(),
inputEvent.Alt,
inputEvent.Control,
inputEvent.Shift,
inputEvent.Command);
}
}
@@ -197,12 +203,12 @@ namespace SS14.Client.Input
// ALL the parameters!
public MouseWheelEventArgs(Mouse.Wheel wheelDirection,
Mouse.ButtonMask buttonMask,
Vector2 position,
bool alt,
bool control,
bool shift,
bool system)
Mouse.ButtonMask buttonMask,
Vector2 position,
bool alt,
bool control,
bool shift,
bool system)
: base(buttonMask, position, alt, control, shift, system)
{
WheelDirection = wheelDirection;
@@ -212,13 +218,13 @@ namespace SS14.Client.Input
{
// Before cutting this up,
// this line was 281 characters long.
return new MouseWheelEventArgs((Mouse.Wheel)inputEvent.ButtonIndex,
(Mouse.ButtonMask)inputEvent.ButtonMask,
inputEvent.Position.Convert(),
inputEvent.Alt,
inputEvent.Control,
inputEvent.Shift,
inputEvent.Command);
return new MouseWheelEventArgs((Mouse.Wheel) inputEvent.ButtonIndex,
(Mouse.ButtonMask) inputEvent.ButtonMask,
inputEvent.Position.Convert(),
inputEvent.Alt,
inputEvent.Control,
inputEvent.Shift,
inputEvent.Command);
}
}
@@ -238,13 +244,13 @@ namespace SS14.Client.Input
// ALL the parameters!
public MouseMoveEventArgs(Vector2 relative,
Vector2 speed,
Mouse.ButtonMask buttonMask,
Vector2 position,
bool alt,
bool control,
bool shift,
bool system)
Vector2 speed,
Mouse.ButtonMask buttonMask,
Vector2 position,
bool alt,
bool control,
bool shift,
bool system)
: base(buttonMask, position, alt, control, shift, system)
{
Relative = relative;
@@ -254,13 +260,13 @@ namespace SS14.Client.Input
public static explicit operator MouseMoveEventArgs(Godot.InputEventMouseMotion inputEvent)
{
return new MouseMoveEventArgs(inputEvent.Relative.Convert(),
inputEvent.Speed.Convert(),
(Mouse.ButtonMask)inputEvent.ButtonMask,
inputEvent.Position.Convert(),
inputEvent.Alt,
inputEvent.Control,
inputEvent.Shift,
inputEvent.Command);
inputEvent.Speed.Convert(),
(Mouse.ButtonMask) inputEvent.ButtonMask,
inputEvent.Position.Convert(),
inputEvent.Alt,
inputEvent.Control,
inputEvent.Shift,
inputEvent.Command);
}
}
}

View File

@@ -1,11 +1,10 @@
using Godot;
using System;
using System;
namespace SS14.Client.Input
{
public static class Mouse
{
public static bool IsButtonPressed(Button button) => Godot.Input.IsMouseButtonPressed((int)button);
public static bool IsButtonPressed(Button button) => GameController.OnGodot ? Godot.Input.IsMouseButtonPressed((int) button) : default;
// TODO: People will definitely want support for extra mouse buttons,
// Godot doesn't seem to support this though.
@@ -14,9 +13,9 @@ namespace SS14.Client.Input
/// </summary>
public enum Button
{
Left = ButtonList.Left,
Middle = ButtonList.Middle,
Right = ButtonList.Right,
Left = 1,
Middle = 2,
Right = 3,
}
/// <summary>
@@ -25,10 +24,11 @@ namespace SS14.Client.Input
[Flags]
public enum ButtonMask
{
// These match Godot's
None = 0,
Left = Godot.ButtonList.MaskLeft,
Middle = Godot.ButtonList.MaskMiddle,
Right = Godot.ButtonList.MaskRight,
Left = 1,
Middle = 2,
Right = 4,
}
/// <summary>
@@ -36,10 +36,11 @@ namespace SS14.Client.Input
/// </summary>
public enum Wheel
{
Up = Godot.ButtonList.WheelUp,
Down = Godot.ButtonList.WheelDown,
Left = Godot.ButtonList.WheelLeft,
Right = Godot.ButtonList.WheelRight,
// These match Godot's
Up = 4,
Down = 5,
Left = 6,
Right = 7,
}
public static Keyboard.Key ConvertGodotMouseButton(Button button)
@@ -60,21 +61,6 @@ namespace SS14.Client.Input
public static class Keyboard
{
/// <summary>
/// Checks whether the provided key on the keyboard is currently held down.
/// </summary>
/// <param name="key">The key to check for.</param>
/// <returns>True if the provided key is currently held down, false otherwise.</returns>
public static bool IsKeyPressed(Key key) => Godot.Input.IsKeyPressed((int)key);
/// <summary>
/// Checks whether a key is printable.
/// </summary>
/// <param name="key">The key to check.</param>
/// <returns>True if the key is printable, false otherwise.</returns>
// See Godot docs: SPKEY = 16777216 — Scancodes with this bit applied are non printable.
public static bool IsKeyPrintable(Key key) => ((int)key & GD.Spkey) == 0;
/// <summary>
/// Represents a key on the keyboard.
/// </summary>
@@ -198,7 +184,7 @@ namespace SS14.Client.Input
// They don't even prevent overlap if you remove the SPKEY flag (they totally could too...).
// The macOS, X11 and Windows platform layers *all* have scancode translation tables so it literally can't be "oh they took them from X11!"
// Also there are dumb scan codes like YACCUTE which *literally don't get fired ever*.
switch ((Godot.KeyList)key)
switch ((Godot.KeyList) key)
{
// Dear mother of .NET optimize this nicely for me.
case Godot.KeyList.A:

View File

@@ -10,6 +10,7 @@ namespace SS14.Client.Interfaces.GameObjects.Components
public interface IGodotTransformComponent : ITransformComponent
{
new IGodotTransformComponent Parent { get; }
Godot.Node2D SceneNode { get; }
}
}

View File

@@ -190,7 +190,10 @@ namespace SS14.Client.Interfaces.GameObjects.Components
{
public static void AttachToControl(this ISpriteProxy mirror, Control control)
{
mirror.AttachToItem(control.SceneControl.GetCanvasItem());
if (GameController.OnGodot)
{
mirror.AttachToItem(control.SceneControl.GetCanvasItem());
}
}
}
}

View File

@@ -5,6 +5,7 @@ namespace SS14.Client.Interfaces.Graphics
/// </summary>
public interface IDisplayManager
{
void SetWindowTitle(string title);
void Initialize();
void ReadConfig();
}

View File

@@ -4,6 +4,7 @@ using SS14.Shared;
using SS14.Shared.Maths;
using SS14.Client.Interfaces.GameObjects.Components;
using SS14.Shared.Enums;
using SS14.Shared.Interfaces.GameObjects.Components;
namespace SS14.Client.Interfaces.Graphics.Lighting
{
@@ -19,7 +20,7 @@ namespace SS14.Client.Interfaces.Graphics.Lighting
Texture Texture { get; set; }
bool Enabled { get; set; }
void ParentTo(IGodotTransformComponent node);
void ParentTo(ITransformComponent node);
void DeParent();
}
}

View File

@@ -1,5 +1,6 @@
using System;
using SS14.Client.Interfaces.GameObjects.Components;
using SS14.Shared.Interfaces.GameObjects.Components;
using SS14.Shared.Maths;
namespace SS14.Client.Interfaces.Graphics.Lighting
@@ -11,16 +12,16 @@ namespace SS14.Client.Interfaces.Graphics.Lighting
OccluderCullMode CullMode { get; set; }
void SetPolygon(Vector2[] polygon);
void SetGodotPolygon(Godot.Vector2[] polygon);
void ParentTo(IGodotTransformComponent node);
void ParentTo(ITransformComponent node);
void DeParent();
}
public enum OccluderCullMode
{
Disabled = Godot.OccluderPolygon2D.CullModeEnum.Disabled,
Clockwise = Godot.OccluderPolygon2D.CullModeEnum.Clockwise,
CounterClockwise = Godot.OccluderPolygon2D.CullModeEnum.CounterClockwise,
// These match Godot's OccluderPolygon2D.CullMode
Disabled = 0,
Clockwise = 1,
CounterClockwise = 2
}
}

View File

@@ -9,7 +9,6 @@ namespace SS14.Client.Interfaces.Graphics.Overlays
OverlaySpace Space { get; }
void FrameUpdate(RenderFrameEventArgs args);
void AssignCanvasItem(Godot.RID canvasItem);
}

View File

@@ -1,11 +1,10 @@
using Godot;
using SS14.Shared.Interfaces.Log;
using SS14.Shared.Interfaces.Log;
using SS14.Shared.Log;
namespace SS14.Client.Log
{
/// <summary>
/// Handles logs using Godot's <see cref="GD.Print(object[])"/>.
/// Handles logs using Godot's <see cref="Godot.GD.Print(object[])"/>.
/// </summary>
class GodotLogHandler : ILogHandler
{
@@ -17,7 +16,7 @@ namespace SS14.Client.Log
var msg = $"[{name}] {message.SawmillName}: {message.Message}";
lock (locker)
{
GD.Print(msg);
Godot.GD.Print(msg);
}
}
}

View File

@@ -14,21 +14,35 @@ namespace SS14.Client.Map
/// </summary>
public class ClientTileDefinitionManager : TileDefinitionManager, IClientTileDefinitionManager
{
[Dependency]
readonly IResourceCache resourceCache;
[Dependency] readonly IResourceCache resourceCache;
public Godot.TileSet TileSet { get; private set; } = new Godot.TileSet();
public Godot.TileSet TileSet { get; private set; }
private Dictionary<ushort, TextureResource> Textures = new Dictionary<ushort, TextureResource>();
public ClientTileDefinitionManager()
{
if (GameController.OnGodot)
{
TileSet = new Godot.TileSet();
}
}
public override ushort Register(ITileDefinition tileDef)
{
if (!GameController.OnGodot)
{
return base.Register(tileDef);
}
var ret = base.Register(tileDef);
TileSet.CreateTile(ret);
if (!string.IsNullOrEmpty(tileDef.SpriteName))
{
var texture = resourceCache.GetResource<TextureResource>(new ResourcePath("/Textures/Tiles/") / $@"{tileDef.SpriteName}.png");
var texture =
resourceCache.GetResource<TextureResource>(
new ResourcePath("/Textures/Tiles/") / $@"{tileDef.SpriteName}.png");
TileSet.TileSetTexture(ret, texture.Texture.GodotTexture);
Textures[ret] = texture;
}

View File

@@ -9,7 +9,7 @@ using SS14.Client.Graphics.ClientEye;
namespace SS14.Client.Map
{
public class ClientMapManager : MapManager
public class GodotMapManager : MapManager
{
[Dependency]
private IClientTileDefinitionManager tileDefinitionManager;
@@ -18,8 +18,12 @@ namespace SS14.Client.Map
private Dictionary<GridId, Godot.TileMap> RenderTileMaps = new Dictionary<GridId, Godot.TileMap>();
public ClientMapManager()
public GodotMapManager()
{
if (!GameController.OnGodot)
{
return;
}
TileChanged += UpdateTileMapOnUpdate;
OnGridCreated += UpdateOnGridCreated;
OnGridRemoved += UpdateOnGridRemoved;

View File

@@ -20,7 +20,7 @@ namespace SS14.Client.Placement.Modes
public override void Render()
{
if (onGrid)
if (GameController.OnGodot && onGrid)
{
const int ppm = EyeManager.PIXELSPERMETER;
var viewportSize = pManager.sceneTree.SceneTree.Root.Size.Convert();

View File

@@ -18,7 +18,7 @@ namespace SS14.Client.Placement.Modes
public override void Render()
{
if (onGrid)
if (GameController.OnGodot && onGrid)
{
const int ppm = EyeManager.PIXELSPERMETER;
var viewportSize = pManager.sceneTree.SceneTree.Root.Size.Convert();

View File

@@ -147,6 +147,7 @@ namespace SS14.Client.Placement
return;
}
}
_colliderAABB = new Box2(0f, 0f, 0f, 0f);
}
}
@@ -186,21 +187,24 @@ namespace SS14.Client.Placement
_mapMan.TileChanged += HandleTileChanged;
var unshadedMaterial = new Godot.CanvasItemMaterial()
if (GameController.OnGodot)
{
LightMode = Godot.CanvasItemMaterial.LightModeEnum.Unshaded
};
var unshadedMaterial = new Godot.CanvasItemMaterial()
{
LightMode = Godot.CanvasItemMaterial.LightModeEnum.Unshaded
};
DrawNode = new Godot.Node2D()
{
Name = "Placement Manager Sprite",
ZIndex = 100,
Material = unshadedMaterial
};
sceneTree.WorldRoot.AddChild(DrawNode);
drawNodeDrawSubscriber = new GodotGlue.GodotSignalSubscriber0();
drawNodeDrawSubscriber.Connect(DrawNode, "draw");
drawNodeDrawSubscriber.Signal += Render;
DrawNode = new Godot.Node2D()
{
Name = "Placement Manager Sprite",
ZIndex = 100,
Material = unshadedMaterial
};
sceneTree.WorldRoot.AddChild(DrawNode);
drawNodeDrawSubscriber = new GodotGlue.GodotSignalSubscriber0();
drawNodeDrawSubscriber.Connect(DrawNode, "draw");
drawNodeDrawSubscriber.Signal += Render;
}
// a bit ugly, oh well
_baseClient.PlayerJoinedServer += (sender, args) => SetupInput(_entitySystemManager);
@@ -292,7 +296,7 @@ namespace SS14.Client.Placement
private void SwitchEditorContext(bool enabled)
{
if(enabled)
if (enabled)
{
_inputManager.Contexts.SetActiveContext("editor");
}
@@ -300,11 +304,15 @@ namespace SS14.Client.Placement
{
_entitySystemManager.GetEntitySystem<InputSystem>().SetEntityContextActive();
}
}
public void Dispose()
{
if (!GameController.OnGodot)
{
return;
}
drawNodeDrawSubscriber.Disconnect(DrawNode, "draw");
drawNodeDrawSubscriber.Dispose();
DrawNode.QueueFree();
@@ -346,7 +354,11 @@ namespace SS14.Client.Placement
Eraser = false;
PlacementOffset = Vector2i.Zero;
// Make it draw again to remove the drawn things.
DrawNode?.Update();
if (GameController.OnGodot)
{
DrawNode?.Update();
}
}
public void Rotate()
@@ -385,6 +397,7 @@ namespace SS14.Client.Placement
{
RequestPlacement(coordinate);
}
DeactivateSpecialPlacement();
break;
case PlacementTypes.Grid:
@@ -392,6 +405,7 @@ namespace SS14.Client.Placement
{
RequestPlacement(coordinate);
}
DeactivateSpecialPlacement();
break;
}
@@ -447,7 +461,7 @@ namespace SS14.Client.Placement
}
var modeType = _modeDictionary.First(pair => pair.Key.Equals(CurrentPermission.PlacementOption)).Value;
CurrentMode = (PlacementMode)Activator.CreateInstance(modeType, this);
CurrentMode = (PlacementMode) Activator.CreateInstance(modeType, this);
if (hijack != null)
{
@@ -468,9 +482,9 @@ namespace SS14.Client.Placement
// Try to get current map.
var map = MapId.Nullspace;
var ent = PlayerManager.LocalPlayer.ControlledEntity;
if (ent != null && ent.TryGetComponent<IGodotTransformComponent>(out var component))
if (ent != null)
{
map = component.MapID;
map = ent.Transform.MapID;
}
if (map == MapId.Nullspace || CurrentPermission == null || CurrentMode == null)
@@ -498,7 +512,10 @@ namespace SS14.Client.Placement
if (_placenextframe && CurrentPermission.IsTile)
HandlePlacement();
DrawNode.Update();
if (GameController.OnGodot)
{
DrawNode.Update();
}
}
private void ActivateLineMode()
@@ -548,7 +565,12 @@ namespace SS14.Client.Placement
var pos = PlayerManager.LocalPlayer.ControlledEntity.Transform.WorldPosition;
const int ppm = EyeManager.PIXELSPERMETER;
DrawNode.DrawCircle(pos.Convert() * new Godot.Vector2(1, -1) * ppm, CurrentPermission.Range * ppm, new Godot.Color(1, 1, 1, 0.25f));
if (GameController.OnGodot)
{
DrawNode.DrawCircle(pos.Convert() * new Godot.Vector2(1, -1) * ppm, CurrentPermission.Range * ppm,
new Godot.Color(1, 1, 1, 0.25f));
}
}
private void HandleStartPlacement(MsgPlacement msg)
@@ -577,7 +599,8 @@ namespace SS14.Client.Placement
private void PreparePlacementTile()
{
CurrentBaseSprite = ResourceCache.GetResource<TextureResource>(new ResourcePath("/Textures/UserInterface/tilebuildoverlay.png")).Texture;
CurrentBaseSprite = ResourceCache
.GetResource<TextureResource>(new ResourcePath("/Textures/UserInterface/tilebuildoverlay.png")).Texture;
IsActive = true;
}

View File

@@ -85,6 +85,10 @@ namespace SS14.Client.Placement
public virtual void Render()
{
if (!GameController.OnGodot)
{
return;
}
if (SpriteToDraw == null)
{
SetSprite();

View File

@@ -95,7 +95,7 @@ namespace SS14.Client.Player
}
eye.Current = true;
var transform = ControlledEntity.GetComponent<IGodotTransformComponent>();
var transform = ControlledEntity.Transform;
transform.OnMove += OnPlayerMoved;
EntityAttached?.Invoke(this, EventArgs.Empty);

View File

@@ -12,6 +12,10 @@ namespace SS14.Client.ResourceManagement
public override void Load(IResourceCache cache, ResourcePath path)
{
if (!GameController.OnGodot)
{
return;
}
if (!cache.ContentFileExists(path))
{
throw new FileNotFoundException("Content file does not exist for audio sample.");

View File

@@ -16,10 +16,16 @@ namespace SS14.Client.ResourceManagement
public override void Load(IResourceCache cache, ResourcePath path)
{
if (!GameController.OnGodot)
{
return;
}
if (!cache.ContentFileExists(path))
{
throw new FileNotFoundException("Content file does not exist for texture");
}
if (!cache.TryGetDiskFilePath(path, out string diskPath))
{
throw new InvalidOperationException("Textures can only be loaded from disk.");
@@ -44,8 +50,10 @@ namespace SS14.Client.ResourceManagement
public override void Dispose()
{
FontData.Dispose();
FontData = null;
if (GameController.OnGodot)
{
FontData.Dispose();
}
}
}
}

View File

@@ -0,0 +1,22 @@
using System.IO;
using System.Text;
using SS14.Client.Interfaces.ResourceManagement;
using SS14.Client.Utility;
using SS14.Shared.Utility;
namespace SS14.Client.ResourceManagement.ResourceTypes
{
internal class GodotAssetResource : BaseResource
{
public GodotAsset Asset { get; private set; }
public override void Load(IResourceCache cache, ResourcePath path)
{
using (var stream = cache.ContentFileRead(path))
using (var reader = new StreamReader(stream, Encoding.UTF8))
{
Asset = GodotParser.Parse(reader);
}
}
}
}

View File

@@ -101,7 +101,7 @@ namespace SS14.Client.ResourceManagement
var delayList = delays[i];
if (delayList.Length == 0)
{
delays[i] = new float[] { 1 };
delays[i] = new float[] {1};
}
}
}
@@ -111,7 +111,7 @@ namespace SS14.Client.ResourceManagement
// No delays specified, default to 1 frame per dir.
for (var i = 0; i < dirValue; i++)
{
delays[i] = new float[] { 1 };
delays[i] = new float[] {1};
}
}
@@ -126,14 +126,19 @@ namespace SS14.Client.ResourceManagement
// Amount of icons per row of the sprite sheet.
var sheetWidth = texture.Width / size.X;
var iconFrames = new(Texture, float)[dirValue][];
var iconFrames = new (Texture, float)[dirValue][];
var counter = 0;
for (var j = 0; j < iconFrames.Length; j++)
{
var delayList = delays[j];
var directionFrames = new(Texture, float)[delayList.Length];
var directionFrames = new (Texture, float)[delayList.Length];
for (var i = 0; i < delayList.Length; i++)
{
if (!GameController.OnGodot)
{
directionFrames[i] = (new BlankTexture(), delayList[i]);
continue;
}
var PosX = (counter % sheetWidth) * size.X;
var PosY = (counter / sheetWidth) * size.Y;
@@ -146,6 +151,7 @@ namespace SS14.Client.ResourceManagement
directionFrames[i] = (new GodotTextureSource(atlasTexture), delayList[i]);
counter++;
}
iconFrames[j] = directionFrames;
}
@@ -186,14 +192,19 @@ namespace SS14.Client.ResourceManagement
public RSILoadException()
{
}
public RSILoadException(string message) : base(message)
{
}
public RSILoadException(string message, Exception inner) : base(message, inner)
{
}
protected RSILoadException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context)
{
}
}
}

View File

@@ -20,6 +20,10 @@ namespace SS14.Client.ResourceManagement.ResourceTypes
public override void Load(IResourceCache cache, ResourcePath path)
{
if (!GameController.OnGodot)
{
return;
}
using (var stream = cache.ContentFileRead(path))
using (var reader = new StreamReader(stream, Encoding.UTF8))
{
@@ -44,6 +48,10 @@ namespace SS14.Client.ResourceManagement.ResourceTypes
private ShaderParamType DetectParamType(IDictionary<object, object> dict)
{
if (!GameController.OnGodot)
{
throw new NotImplementedException();
}
var type = (Godot.Variant.Type)dict["type"];
var hint = (Godot.PropertyHint)dict["hint"];
var hint_string = (string)dict["hint_string"];

View File

@@ -14,6 +14,12 @@ namespace SS14.Client.ResourceManagement
public override void Load(IResourceCache cache, ResourcePath path)
{
if (!GameController.OnGodot)
{
Texture = new BlankTexture();
return;
}
if (!cache.ContentFileExists(path))
{
throw new FileNotFoundException("Content file does not exist for texture");
@@ -33,7 +39,7 @@ namespace SS14.Client.ResourceManagement
}
// Disable filter by default because pixel art.
godotTexture.SetFlags(godotTexture.GetFlags() & ~(int)Godot.Texture.FlagsEnum.Filter);
godotTexture.SetFlags(godotTexture.GetFlags() & ~(int) Godot.Texture.FlagsEnum.Filter);
Texture = new GodotTextureSource(godotTexture);
// Primarily for tracking down iCCP sRGB errors in the image files.
Logger.DebugS("res.tex", $"Loaded texture {path}.");
@@ -46,8 +52,10 @@ namespace SS14.Client.ResourceManagement
public override void Dispose()
{
godotTexture.Dispose();
godotTexture = null;
if (GameController.OnGodot)
{
godotTexture.Dispose();
}
}
}
}

View File

@@ -6,7 +6,7 @@
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x64</Platform>
<ProjectGuid>{83429BD6-6358-4B18-BE51-401DF8EA2673}</ProjectGuid>
<OutputType>Library</OutputType>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SS14.Client</RootNamespace>
<AssemblyName>SS14.Client</AssemblyName>
@@ -18,6 +18,7 @@
<Prefer32Bit>false</Prefer32Bit>
<NoWarn>0649</NoWarn>
<LangVersion>7.2</LangVersion>
<Godot>true</Godot>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -79,7 +80,7 @@
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="System.Drawing" />
<Reference Include="GodotSharp">
<Reference Include="GodotSharp" Condition="'$(Godot)' == 'true'">
<HintPath>..\SS14.Client.Godot\.mono\assemblies\GodotSharp.dll</HintPath>
</Reference>
</ItemGroup>
@@ -93,9 +94,10 @@
<Compile Include="Console\IClientConsole.cs" />
<Compile Include="GameController.cs" />
<Compile Include="GameController\FrameEventArgs.cs" />
<Compile Include="GameController\GameController.Godot.cs" />
<Compile Include="GameController\GameController.Headless.cs" />
<Compile Include="GameController\GameController.Input.cs" />
<Compile Include="GameController\GameController.IoC.cs" />
<Compile Include="GameController\GameController.GameTiming.cs" />
<Compile Include="GameObjects\Components\Appearance\AppearanceComponent.cs" />
<Compile Include="GameObjects\Components\Input\InputComponent.cs" />
<Compile Include="GameObjects\Components\UserInterface\ClientUserInterfaceComponent.cs" />
@@ -163,13 +165,14 @@
<Compile Include="Log\DebugConsoleLogHandler.cs" />
<Compile Include="Log\GodotLogHandler.cs" />
<Compile Include="Map\ClientTileDefinitionManager.cs" />
<Compile Include="Map\ClientMapManager.cs" />
<Compile Include="Map\GodotMapManager.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Reflection\ClientReflectionManager.cs" />
<Compile Include="Interfaces\ResourceManagement\IResourceCache.cs" />
<Compile Include="ResourceManagement\BaseResource.cs" />
<Compile Include="ResourceManagement\ResourceCache.cs" />
<Compile Include="ResourceManagement\ResourceTypes\AudioResource.cs" />
<Compile Include="ResourceManagement\ResourceTypes\GodotAssetResource.cs" />
<Compile Include="ResourceManagement\ResourceTypes\ShaderSourceResource.cs" />
<Compile Include="ResourceManagement\ResourceTypes\FontResource.cs" />
<Compile Include="Graphics\RSI\RSI.cs" />
@@ -193,6 +196,8 @@
<Compile Include="UserInterface\CustomControls\Chatbox.cs" />
<Compile Include="UserInterface\CustomControls\DebugTimePanel.cs" />
<Compile Include="Utility\DirExt.cs" />
<Compile Include="Utility\GodotParser.cs" />
<Compile Include="Utility\GodotPathUtility.cs" />
<Compile Include="Utility\GodotResourceCopy.cs" />
<Compile Include="Utility\ImageSharpExt.cs" />
<Compile Include="Utility\Rand.cs" />
@@ -305,7 +310,7 @@
<Project>{59250baf-0000-0000-0000-000000000000}</Project>
<Name>Lidgren.Network</Name>
</ProjectReference>
<ProjectReference Include="..\SS14.Client.Godot\SS14.Client.Godot.csproj">
<ProjectReference Include="..\SS14.Client.Godot\SS14.Client.Godot.csproj" Condition="'$(Godot)' == 'true'">
<Project>{8af31169-49b1-4a12-b8f4-2a0674a9e7cb}</Project>
<Name>SS14.Client.Godot</Name>
</ProjectReference>
@@ -332,4 +337,4 @@
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\MSBuild\SS14.Engine.targets" />
<Target Name="AfterBuild" DependsOnTargets="CopySS14Noise" />
</Project>
</Project>

View File

@@ -1,10 +1,6 @@
using SS14.Client.Graphics;
using SS14.Client.Interfaces;
using SS14.Client.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SS14.Client.Graphics;
namespace SS14.Client
{

View File

@@ -13,6 +13,7 @@ using SS14.Shared.Log;
using SS14.Client.Interfaces.State;
using SS14.Client.UserInterface.Controls;
using SS14.Client.UserInterface.CustomControls;
using SS14.Shared.Utility;
namespace SS14.Client.State.States
{
@@ -29,7 +30,7 @@ namespace SS14.Client.State.States
[Dependency]
readonly IStateManager stateManager;
private Control MainMenuControl;
private MainMenuControl _mainMenuControl;
private OptionsMenu OptionsMenu;
@@ -41,12 +42,10 @@ namespace SS14.Client.State.States
{
IoCManager.InjectDependencies(this);
var scene = (Godot.PackedScene)Godot.ResourceLoader.Load("res://Scenes/MainMenu/MainMenu.tscn");
MainMenuControl = Control.InstanceScene(scene);
_mainMenuControl = new MainMenuControl();
userInterfaceManager.StateRoot.AddChild(_mainMenuControl);
userInterfaceManager.StateRoot.AddChild(MainMenuControl);
var VBox = MainMenuControl.GetChild("VBoxContainer");
var VBox = _mainMenuControl.GetChild("VBoxContainer");
VBox.GetChild<Button>("ExitButton").OnPressed += ExitButtonPressed;
VBox.GetChild<Button>("OptionsButton").OnPressed += OptionsButtonPressed;
VBox.GetChild<Button>("ConnectButton").OnPressed += ConnectButtonPressed;
@@ -66,7 +65,7 @@ namespace SS14.Client.State.States
{
_client.RunLevelChanged -= RunLevelChanged;
MainMenuControl.Dispose();
_mainMenuControl.Dispose();
OptionsMenu.Dispose();
}
@@ -82,7 +81,7 @@ namespace SS14.Client.State.States
private void ConnectButtonPressed(BaseButton.ButtonEventArgs args)
{
var input = MainMenuControl.GetChild("VBoxContainer").GetChild<LineEdit>("IPBox");
var input = _mainMenuControl.GetChild("VBoxContainer").GetChild<LineEdit>("IPBox");
TryConnect(input.Text);
}
@@ -149,5 +148,10 @@ namespace SS14.Client.State.States
}
}
}
private class MainMenuControl : Control
{
protected override ResourcePath ScenePath => new ResourcePath("/Scenes/MainMenu/MainMenu.tscn");
}
}
}

View File

@@ -20,6 +20,7 @@ namespace SS14.Client.UserInterface
}
public event Action<GUIMouseButtonEventArgs> OnMouseDown;
protected virtual void MouseDown(GUIMouseButtonEventArgs args)
{
OnMouseDown?.Invoke(args);
@@ -34,6 +35,7 @@ namespace SS14.Client.UserInterface
}
public event Action<GUIKeyEventArgs> OnKeyDown;
protected virtual void KeyDown(GUIKeyEventArgs args)
{
OnKeyDown?.Invoke(args);
@@ -53,12 +55,12 @@ namespace SS14.Client.UserInterface
{
case Godot.InputEventKey keyEvent:
var keyEventArgs = new GUIKeyEventArgs(this,
Keyboard.ConvertGodotKey(keyEvent.Scancode),
(UInt32)keyEvent.Unicode,
keyEvent.Alt,
keyEvent.Control,
keyEvent.Shift,
keyEvent.Command);
Keyboard.ConvertGodotKey(keyEvent.Scancode),
(UInt32) keyEvent.Unicode,
keyEvent.Alt,
keyEvent.Control,
keyEvent.Shift,
keyEvent.Command);
if (keyEvent.Echo)
{
KeyHeld(keyEventArgs);
@@ -71,36 +73,38 @@ namespace SS14.Client.UserInterface
{
KeyUp(keyEventArgs);
}
break;
case Godot.InputEventMouseButton buttonEvent:
if (buttonEvent.ButtonIndex >= (int)Godot.ButtonList.WheelUp && buttonEvent.ButtonIndex <= (int)Godot.ButtonList.WheelRight)
if (buttonEvent.ButtonIndex >= (int) Godot.ButtonList.WheelUp &&
buttonEvent.ButtonIndex <= (int) Godot.ButtonList.WheelRight)
{
// Mouse wheel event.
var mouseWheelEventArgs = new GUIMouseWheelEventArgs((Mouse.Wheel)buttonEvent.ButtonIndex,
this,
(Mouse.ButtonMask)buttonEvent.ButtonMask,
buttonEvent.GlobalPosition.Convert(),
buttonEvent.Position.Convert(),
buttonEvent.Alt,
buttonEvent.Control,
buttonEvent.Shift,
buttonEvent.Command);
var mouseWheelEventArgs = new GUIMouseWheelEventArgs((Mouse.Wheel) buttonEvent.ButtonIndex,
this,
(Mouse.ButtonMask) buttonEvent.ButtonMask,
buttonEvent.GlobalPosition.Convert(),
buttonEvent.Position.Convert(),
buttonEvent.Alt,
buttonEvent.Control,
buttonEvent.Shift,
buttonEvent.Command);
MouseWheel(mouseWheelEventArgs);
}
else
{
// Mouse button event.
var mouseButtonEventArgs = new GUIMouseButtonEventArgs((Mouse.Button)buttonEvent.ButtonIndex,
buttonEvent.Doubleclick,
this,
(Mouse.ButtonMask)buttonEvent.ButtonMask,
buttonEvent.GlobalPosition.Convert(),
buttonEvent.Position.Convert(),
buttonEvent.Alt,
buttonEvent.Control,
buttonEvent.Shift,
buttonEvent.Command);
var mouseButtonEventArgs = new GUIMouseButtonEventArgs((Mouse.Button) buttonEvent.ButtonIndex,
buttonEvent.Doubleclick,
this,
(Mouse.ButtonMask) buttonEvent.ButtonMask,
buttonEvent.GlobalPosition.Convert(),
buttonEvent.Position.Convert(),
buttonEvent.Alt,
buttonEvent.Control,
buttonEvent.Shift,
buttonEvent.Command);
if (buttonEvent.Pressed)
{
MouseDown(mouseButtonEventArgs);
@@ -110,19 +114,20 @@ namespace SS14.Client.UserInterface
MouseUp(mouseButtonEventArgs);
}
}
break;
case Godot.InputEventMouseMotion motionEvent:
var mouseMoveEventArgs = new GUIMouseMoveEventArgs(motionEvent.Relative.Convert(),
motionEvent.Speed.Convert(),
this,
(Mouse.ButtonMask)motionEvent.ButtonMask,
motionEvent.GlobalPosition.Convert(),
motionEvent.Position.Convert(),
motionEvent.Alt,
motionEvent.Control,
motionEvent.Shift,
motionEvent.Command);
motionEvent.Speed.Convert(),
this,
(Mouse.ButtonMask) motionEvent.ButtonMask,
motionEvent.GlobalPosition.Convert(),
motionEvent.Position.Convert(),
motionEvent.Alt,
motionEvent.Control,
motionEvent.Shift,
motionEvent.Command);
MouseMove(mouseMoveEventArgs);
break;
}
@@ -142,16 +147,19 @@ namespace SS14.Client.UserInterface
/// </summary>
public new void Handle()
{
SourceControl.SceneControl.AcceptEvent();
if (GameController.OnGodot)
{
SourceControl.SceneControl.AcceptEvent();
}
}
public GUIKeyEventArgs(Control sourceControl,
Keyboard.Key key,
uint unicode,
bool alt,
bool control,
bool shift,
bool system)
Keyboard.Key key,
uint unicode,
bool alt,
bool control,
bool shift,
bool system)
: base(key, unicode, alt, control, shift, system)
{
SourceControl = sourceControl;
@@ -187,17 +195,20 @@ namespace SS14.Client.UserInterface
/// </summary>
public new void Handle()
{
SourceControl.SceneControl.AcceptEvent();
if (GameController.OnGodot)
{
SourceControl.SceneControl.AcceptEvent();
}
}
protected GUIMouseEventArgs(Control sourceControl,
Mouse.ButtonMask buttonMask,
Vector2 globalPosition,
Vector2 relativePosition,
bool alt,
bool control,
bool shift,
bool system)
Mouse.ButtonMask buttonMask,
Vector2 globalPosition,
Vector2 relativePosition,
bool alt,
bool control,
bool shift,
bool system)
: base(alt, control, shift, system)
{
SourceControl = sourceControl;
@@ -221,15 +232,15 @@ namespace SS14.Client.UserInterface
public bool DoubleClick { get; }
public GUIMouseButtonEventArgs(Mouse.Button button,
bool doubleClick,
Control sourceControl,
Mouse.ButtonMask buttonMask,
Vector2 globalPosition,
Vector2 relativePosition,
bool alt,
bool control,
bool shift,
bool system)
bool doubleClick,
Control sourceControl,
Mouse.ButtonMask buttonMask,
Vector2 globalPosition,
Vector2 relativePosition,
bool alt,
bool control,
bool shift,
bool system)
: base(sourceControl, buttonMask, globalPosition, relativePosition, alt, control, shift, system)
{
Button = button;
@@ -253,15 +264,15 @@ namespace SS14.Client.UserInterface
// ALL the parameters!
public GUIMouseMoveEventArgs(Vector2 relative,
Vector2 speed,
Control sourceControl,
Mouse.ButtonMask buttonMask,
Vector2 globalPosition,
Vector2 relativePosition,
bool alt,
bool control,
bool shift,
bool system)
Vector2 speed,
Control sourceControl,
Mouse.ButtonMask buttonMask,
Vector2 globalPosition,
Vector2 relativePosition,
bool alt,
bool control,
bool shift,
bool system)
: base(sourceControl, buttonMask, globalPosition, relativePosition, alt, control, shift, system)
{
Relative = relative;
@@ -277,14 +288,14 @@ namespace SS14.Client.UserInterface
public Mouse.Wheel WheelDirection { get; }
public GUIMouseWheelEventArgs(Mouse.Wheel wheelDirection,
Control sourceControl,
Mouse.ButtonMask buttonMask,
Shared.Maths.Vector2 globalPosition,
Shared.Maths.Vector2 relativePosition,
bool alt,
bool control,
bool shift,
bool system)
Control sourceControl,
Mouse.ButtonMask buttonMask,
Shared.Maths.Vector2 globalPosition,
Shared.Maths.Vector2 relativePosition,
bool alt,
bool control,
bool shift,
bool system)
: base(sourceControl, buttonMask, globalPosition, relativePosition, alt, control, shift, system)
{
WheelDirection = wheelDirection;

View File

@@ -111,7 +111,7 @@ namespace SS14.Client.UserInterface
private void __guiInputHook(object ev)
{
HandleGuiInput((Godot.InputEvent)ev);
HandleGuiInput((Godot.InputEvent) ev);
}
private void __focusEnteredHook()

View File

@@ -14,8 +14,10 @@ using SS14.Client.Graphics.Drawing;
using SS14.Shared.Utility;
using SS14.Client.Interfaces.ResourceManagement;
using System.IO;
using System.Linq;
using JetBrains.Annotations;
using SS14.Client.Graphics;
using SS14.Client.ResourceManagement.ResourceTypes;
namespace SS14.Client.UserInterface
{
@@ -58,7 +60,11 @@ namespace SS14.Client.UserInterface
}
_name = value;
SceneControl.SetName(_name);
if (GameController.OnGodot)
{
SceneControl.SetName(_name);
}
if (Parent != null)
{
@@ -101,115 +107,223 @@ namespace SS14.Client.UserInterface
public float AnchorBottom
{
get => SceneControl.AnchorBottom;
set => SceneControl.AnchorBottom = value;
get => GameController.OnGodot ? GameController.OnGodot ? SceneControl.AnchorBottom : default : default;
set
{
if (GameController.OnGodot)
{
SceneControl.AnchorBottom = value;
}
}
}
public float AnchorLeft
{
get => SceneControl.AnchorLeft;
set => SceneControl.AnchorLeft = value;
get => GameController.OnGodot ? SceneControl.AnchorLeft : default;
set
{
if (GameController.OnGodot)
{
SceneControl.AnchorLeft = value;
}
}
}
public float AnchorRight
{
get => SceneControl.AnchorRight;
set => SceneControl.AnchorRight = value;
get => GameController.OnGodot ? SceneControl.AnchorRight : default;
set
{
if (GameController.OnGodot)
{
SceneControl.AnchorRight = value;
}
}
}
public float AnchorTop
{
get => SceneControl.AnchorTop;
set => SceneControl.AnchorTop = value;
get => GameController.OnGodot ? SceneControl.AnchorTop : default;
set
{
if (GameController.OnGodot)
{
SceneControl.AnchorTop = value;
}
}
}
public float MarginRight
{
get => SceneControl.MarginRight;
set => SceneControl.MarginRight = value;
get => GameController.OnGodot ? SceneControl.MarginRight : default;
set
{
if (GameController.OnGodot)
{
SceneControl.MarginRight = value;
}
}
}
public float MarginLeft
{
get => SceneControl.MarginLeft;
set => SceneControl.MarginLeft = value;
get => GameController.OnGodot ? SceneControl.MarginLeft : default;
set
{
if (GameController.OnGodot)
{
SceneControl.MarginLeft = value;
}
}
}
public float MarginTop
{
get => SceneControl.MarginTop;
set => SceneControl.MarginTop = value;
get => GameController.OnGodot ? SceneControl.MarginTop : default;
set
{
if (GameController.OnGodot)
{
SceneControl.MarginTop = value;
}
}
}
public float MarginBottom
{
get => SceneControl.MarginBottom;
set => SceneControl.MarginBottom = value;
get => GameController.OnGodot ? SceneControl.MarginBottom : default;
set
{
if (GameController.OnGodot)
{
SceneControl.MarginBottom = value;
}
}
}
public bool Visible
{
get => SceneControl.Visible;
set => SceneControl.Visible = value;
get => GameController.OnGodot ? SceneControl.Visible : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Visible = value;
}
}
}
public Vector2 Size
{
get => SceneControl.GetSize().Convert();
set => SceneControl.SetSize(value.Convert());
get => GameController.OnGodot ? SceneControl.GetSize().Convert() : default;
set
{
if (GameController.OnGodot)
{
SceneControl.SetSize(value.Convert());
}
}
}
public Vector2 Position
{
get => SceneControl.GetPosition().Convert();
set => SceneControl.SetPosition(value.Convert());
get => GameController.OnGodot ? SceneControl.GetPosition().Convert() : default;
set
{
if (GameController.OnGodot)
{
SceneControl.SetPosition(value.Convert());
}
}
}
public UIBox2 Rect
{
get => SceneControl.GetRect().Convert();
get => GameController.OnGodot ? SceneControl.GetRect().Convert() : default;
}
public Vector2 Scale
{
get => SceneControl.RectScale.Convert();
set => SceneControl.RectScale = value.Convert();
get => GameController.OnGodot ? SceneControl.RectScale.Convert() : default;
set
{
if (GameController.OnGodot)
{
SceneControl.RectScale = value.Convert();
}
}
}
public string ToolTip
{
get => SceneControl.GetTooltip();
set => SceneControl.SetTooltip(value);
get => GameController.OnGodot ? SceneControl.GetTooltip() : default;
set
{
if (GameController.OnGodot)
{
SceneControl.SetTooltip(value);
}
}
}
public MouseFilterMode MouseFilter
{
get => (MouseFilterMode) SceneControl.MouseFilter;
set => SceneControl.MouseFilter = (Godot.Control.MouseFilterEnum) value;
get => GameController.OnGodot ? (MouseFilterMode) SceneControl.MouseFilter : default;
set
{
if (GameController.OnGodot)
{
SceneControl.MouseFilter = (Godot.Control.MouseFilterEnum) value;
}
}
}
public SizeFlags SizeFlagsHorizontal
{
get => (SizeFlags) SceneControl.SizeFlagsHorizontal;
set => SceneControl.SizeFlagsHorizontal = (int) value;
get => GameController.OnGodot ? (SizeFlags) SceneControl.SizeFlagsHorizontal : default;
set
{
if (GameController.OnGodot)
{
SceneControl.SizeFlagsHorizontal = (int) value;
}
}
}
public float SizeFlagsStretchRatio
{
get => SceneControl.SizeFlagsStretchRatio;
set => SceneControl.SizeFlagsStretchRatio = value;
get => GameController.OnGodot ? SceneControl.SizeFlagsStretchRatio : default;
set
{
if (GameController.OnGodot)
{
SceneControl.SizeFlagsStretchRatio = value;
}
}
}
public SizeFlags SizeFlagsVertical
{
get => (SizeFlags) SceneControl.SizeFlagsVertical;
set => SceneControl.SizeFlagsVertical = (int) value;
get => GameController.OnGodot ? (SizeFlags) SceneControl.SizeFlagsVertical : default;
set
{
if (GameController.OnGodot)
{
SceneControl.SizeFlagsVertical = (int) value;
}
}
}
public bool RectClipContent
{
get => SceneControl.RectClipContent;
set => SceneControl.RectClipContent = value;
get => GameController.OnGodot ? SceneControl.RectClipContent : default;
set
{
if (GameController.OnGodot)
{
SceneControl.RectClipContent = value;
}
}
}
public Color Modulate
@@ -225,7 +339,7 @@ namespace SS14.Client.UserInterface
/// </summary>
public Vector2 CombinedMinimumSize
{
get => SceneControl.GetCombinedMinimumSize().Convert();
get => GameController.OnGodot ? SceneControl.GetCombinedMinimumSize().Convert() : default;
}
/// <summary>
@@ -235,13 +349,19 @@ namespace SS14.Client.UserInterface
/// <seealso cref="CombinedMinimumSize" />
public Vector2 CustomMinimumSize
{
get => SceneControl.RectMinSize.Convert();
set => SceneControl.RectMinSize = value.Convert();
get => GameController.OnGodot ? SceneControl.RectMinSize.Convert() : default;
set
{
if (GameController.OnGodot)
{
SceneControl.RectMinSize = value.Convert();
}
}
}
public Vector2 GlobalMousePosition
{
get => SceneControl.GetGlobalMousePosition().Convert();
get => GameController.OnGodot ? SceneControl.GetGlobalMousePosition().Convert() : default;
}
private readonly Dictionary<string, Control> _children = new Dictionary<string, Control>();
@@ -253,7 +373,17 @@ namespace SS14.Client.UserInterface
public Control()
{
UserInterfaceManager = IoCManager.Resolve<IUserInterfaceManager>();
SetupSceneControl();
if (GameController.OnGodot)
{
SetupSceneControl();
}
else if (ScenePath != null)
{
_manualNodeSetup();
}
Name = GetType().Name;
Initialize();
}
@@ -267,11 +397,21 @@ namespace SS14.Client.UserInterface
}
UserInterfaceManager = IoCManager.Resolve<IUserInterfaceManager>();
SetupSceneControl();
if (GameController.OnGodot)
{
SetupSceneControl();
}
else if (ScenePath != null)
{
_manualNodeSetup();
}
Name = name;
Initialize();
}
/// <summary>
/// Wrap the provided Godot control with this one.
/// This does NOT set up parenting correctly!
@@ -294,6 +434,182 @@ namespace SS14.Client.UserInterface
{
}
private static Dictionary<string, Type> _manualNodeTypeTranslations;
private void _manualNodeSetup()
{
DebugTools.AssertNotNull(ScenePath);
if (_manualNodeTypeTranslations == null)
{
_initManualNodeTypeTranslations();
}
DebugTools.AssertNotNull(_manualNodeTypeTranslations);
var resourceCache = IoCManager.Resolve<IResourceCache>();
var asset = (GodotAssetScene) resourceCache.GetResource<GodotAssetResource>(ScenePath).Asset;
// Go over the inherited scenes with a stack,
// because you can theoretically have very deep scene inheritance.
var (_, inheritedSceneStack) = _manualFollowSceneInheritance(asset, resourceCache, false);
_manualApplyInheritedSceneStack(this, inheritedSceneStack, asset, resourceCache);
}
private static void _manualApplyInheritedSceneStack(Control baseControl,
Stack<GodotAssetScene> inheritedSceneStack, GodotAssetScene asset,
IResourceCache resourceCache)
{
var parentMapping = new Dictionary<string, Control> {["."] = baseControl};
// Go over the inherited scenes bottom-first.
while (inheritedSceneStack.Count != 0)
{
var inheritedAsset = inheritedSceneStack.Pop();
foreach (var node in inheritedAsset.Nodes)
{
// It's the base control.
if (node.Parent == null)
{
continue;
}
Control childControl;
if (node.Type != null)
{
if (!_manualNodeTypeTranslations.TryGetValue(node.Type, out var type))
{
type = typeof(Control);
}
childControl = (Control) Activator.CreateInstance(type);
childControl.Name = node.Name;
}
else if (node.Instance != null)
{
var extResource = asset.GetExtResource(node.Instance.Value);
DebugTools.Assert(extResource.Type == "PackedScene");
if (_manualNodeTypeTranslations.TryGetValue(extResource.Path, out var type))
{
childControl = (Control) Activator.CreateInstance(type);
}
else
{
var subScene =
(GodotAssetScene) resourceCache
.GetResource<GodotAssetResource>(
GodotPathUtility.GodotPathToResourcePath(extResource.Path)).Asset;
childControl = ManualSpawnFromScene(subScene);
}
childControl.Name = node.Name;
}
else
{
continue;
}
parentMapping[node.Parent].AddChild(childControl);
if (node.Parent == ".")
{
parentMapping[node.Name] = childControl;
}
else
{
parentMapping[$"{node.Parent}/{node.Name}"] = childControl;
}
}
}
}
internal static Control ManualSpawnFromScene(GodotAssetScene scene)
{
if (_manualNodeTypeTranslations == null)
{
_initManualNodeTypeTranslations();
}
DebugTools.AssertNotNull(_manualNodeTypeTranslations);
var resourceCache = IoCManager.Resolve<IResourceCache>();
var (controlType, inheritedSceneStack) = _manualFollowSceneInheritance(scene, resourceCache, true);
var control = (Control) Activator.CreateInstance(controlType);
control.Name = scene.Nodes[0].Name;
_manualApplyInheritedSceneStack(control, inheritedSceneStack, scene, resourceCache);
return control;
}
private static (Type, Stack<GodotAssetScene>) _manualFollowSceneInheritance(GodotAssetScene scene,
IResourceCache resourceCache, bool getType)
{
// Go over the inherited scenes with a stack,
// because you can theoretically have very deep scene inheritance.
var inheritedSceneStack = new Stack<GodotAssetScene>();
inheritedSceneStack.Push(scene);
Type controlType = null;
while (scene.Nodes[0].Instance != null)
{
var extResource = scene.GetExtResource(scene.Nodes[0].Instance.Value);
DebugTools.Assert(extResource.Type == "PackedScene");
if (getType && _manualNodeTypeTranslations.TryGetValue(extResource.Path, out controlType))
{
break;
}
scene = (GodotAssetScene) resourceCache.GetResource<GodotAssetResource>(
GodotPathUtility.GodotPathToResourcePath(extResource.Path)).Asset;
inheritedSceneStack.Push(scene);
}
if (controlType == null)
{
if (!getType
|| scene.Nodes[0].Type == null
|| !_manualNodeTypeTranslations.TryGetValue(scene.Nodes[0].Type, out controlType))
{
controlType = typeof(Control);
}
}
return (controlType, inheritedSceneStack);
}
private static void _initManualNodeTypeTranslations()
{
DebugTools.AssertNull(_manualNodeTypeTranslations);
_manualNodeTypeTranslations = new Dictionary<string, Type>();
var reflectionManager = IoCManager.Resolve<IReflectionManager>();
foreach (var type in reflectionManager.FindTypesWithAttribute<ControlWrapAttribute>())
{
var attr = type.GetCustomAttribute<ControlWrapAttribute>();
if (attr.InstanceString != null)
{
_manualNodeTypeTranslations[attr.InstanceString] = type;
}
if (attr.ConcreteType != null)
{
_manualNodeTypeTranslations[attr.ConcreteType.Name] = type;
}
}
}
private void SetupSceneControl()
{
Godot.Control newSceneControl;
@@ -378,7 +694,10 @@ namespace SS14.Client.UserInterface
public void UpdateDraw()
{
SceneControl.Update();
if (GameController.OnGodot)
{
SceneControl.Update();
}
}
/// <summary>
@@ -419,9 +738,13 @@ namespace SS14.Client.UserInterface
OnKeyDown = null;
}
DisposeSignalHooks();
if (!GameController.ShuttingDownHard)
if (GameController.OnGodot)
{
DisposeSignalHooks();
}
if (GameController.OnGodot && !GameController.ShuttingDownHard)
{
WrappedSceneControl?.QueueFree();
WrappedSceneControl?.Dispose();
@@ -468,11 +791,15 @@ namespace SS14.Client.UserInterface
child.Parent = this;
child.Parented(this);
SceneControl.AddChild(child.SceneControl, LegibleUniqueName);
// Godot changes the name automtically if you would cause a naming conflict.
if (child.SceneControl.GetName() != child._name)
if (GameController.OnGodot)
{
child._name = child.SceneControl.GetName();
SceneControl.AddChild(child.SceneControl, LegibleUniqueName);
// Godot changes the name automtically if you would cause a naming conflict.
if (child.SceneControl.GetName() != child._name)
{
child._name = child.SceneControl.GetName();
}
}
_children[child.Name] = child;
@@ -502,7 +829,10 @@ namespace SS14.Client.UserInterface
_children.Remove(child.Name);
child.Parent = null;
SceneControl.RemoveChild(child.SceneControl);
if (GameController.OnGodot)
{
SceneControl.RemoveChild(child.SceneControl);
}
}
/// <summary>
@@ -528,7 +858,10 @@ namespace SS14.Client.UserInterface
/// </summary>
public void MinimumSizeChanged()
{
SceneControl.MinimumSizeChanged();
if (GameController.OnGodot)
{
SceneControl.MinimumSizeChanged();
}
}
protected virtual bool HasPoint(Vector2 point)
@@ -604,7 +937,10 @@ namespace SS14.Client.UserInterface
throw new InvalidOperationException("No parent to change position in.");
}
Parent.SceneControl.MoveChild(SceneControl, 0);
if (GameController.OnGodot)
{
Parent.SceneControl.MoveChild(SceneControl, 0);
}
}
/// <summary>
@@ -629,7 +965,10 @@ namespace SS14.Client.UserInterface
throw new InvalidOperationException("No parent to change position in.");
}
SetPositionInParent(Parent.SceneControl.GetChildCount());
if (GameController.OnGodot)
{
SetPositionInParent(Parent.SceneControl.GetChildCount());
}
}
/// <summary>
@@ -650,17 +989,23 @@ namespace SS14.Client.UserInterface
public bool HasFocus()
{
return SceneControl.HasFocus();
return GameController.OnGodot ? SceneControl.HasFocus() : default;
}
public void GrabFocus()
{
SceneControl.GrabFocus();
if (GameController.OnGodot)
{
SceneControl.GrabFocus();
}
}
public void ReleaseFocus()
{
SceneControl?.ReleaseFocus();
if (GameController.OnGodot)
{
SceneControl?.ReleaseFocus();
}
}
protected virtual void Resized()
@@ -769,7 +1114,11 @@ namespace SS14.Client.UserInterface
continue;
}
var godotType = attr.GodotType;
var godotType = attr.ConcreteType;
if (godotType == null)
{
continue;
}
if (GodotTranslationCache.TryGetValue(godotType, out var dupe))
{
@@ -791,42 +1140,48 @@ namespace SS14.Client.UserInterface
public void SetAnchorPreset(LayoutPreset preset, bool keepMargin = false)
{
SceneControl.SetAnchorsPreset((Godot.Control.LayoutPreset) preset, keepMargin);
if (GameController.OnGodot)
{
SceneControl.SetAnchorsPreset((Godot.Control.LayoutPreset) preset, keepMargin);
}
}
public void SetMarginsPreset(LayoutPreset preset, LayoutPresetMode resizeMode = LayoutPresetMode.Minsize,
int margin = 0)
{
SceneControl.SetMarginsPreset((Godot.Control.LayoutPreset) preset,
(Godot.Control.LayoutPresetMode) resizeMode, margin);
if (GameController.OnGodot)
{
SceneControl.SetMarginsPreset((Godot.Control.LayoutPreset) preset,
(Godot.Control.LayoutPresetMode) resizeMode, margin);
}
}
public enum LayoutPreset : byte
{
TopLeft = Godot.Control.LayoutPreset.TopLeft,
TopRight = Godot.Control.LayoutPreset.TopRight,
BottomLeft = Godot.Control.LayoutPreset.BottomLeft,
BottomRight = Godot.Control.LayoutPreset.BottomRight,
CenterLeft = Godot.Control.LayoutPreset.CenterLeft,
CenterTop = Godot.Control.LayoutPreset.CenterTop,
CenterRight = Godot.Control.LayoutPreset.CenterRight,
CenterBottom = Godot.Control.LayoutPreset.CenterBottom,
Center = Godot.Control.LayoutPreset.Center,
LeftWide = Godot.Control.LayoutPreset.LeftWide,
TopWide = Godot.Control.LayoutPreset.TopWide,
RightWide = Godot.Control.LayoutPreset.RightWide,
BottomWide = Godot.Control.LayoutPreset.BottomWide,
VerticalCenterWide = Godot.Control.LayoutPreset.VcenterWide,
HorizontalCenterWide = Godot.Control.LayoutPreset.VcenterWide,
Wide = Godot.Control.LayoutPreset.Wide,
TopLeft = 0,
TopRight = 1,
BottomLeft = 2,
BottomRight = 3,
CenterLeft = 4,
CenterTop = 5,
CenterRight = 6,
CenterBottom = 7,
Center = 8,
LeftWide = 9,
TopWide = 10,
RightWide = 11,
BottomWide = 12,
VerticalCenterWide = 13,
HorizontalCenterWide = 14,
Wide = 15,
}
public enum LayoutPresetMode : byte
{
Minsize = Godot.Control.LayoutPresetMode.Minsize,
KeepWidth = Godot.Control.LayoutPresetMode.KeepWidth,
KeepHeight = Godot.Control.LayoutPresetMode.KeepHeight,
KeepSize = Godot.Control.LayoutPresetMode.KeepSize,
Minsize = 0,
KeepWidth = 1,
KeepHeight = 2,
KeepSize = 3,
}
/// <summary>
@@ -868,6 +1223,10 @@ namespace SS14.Client.UserInterface
protected void SetColorOverride(string name, Color? color)
{
if (!GameController.OnGodot)
{
return;
}
// So here's an interesting one.
// Godot's AddColorOverride and such API on controls
// Doesn't actually have a way to REMOVE the override.
@@ -884,11 +1243,19 @@ namespace SS14.Client.UserInterface
protected Color? GetColorOverride(string name)
{
if (!GameController.OnGodot)
{
return default;
}
return SceneControl.HasColorOverride(name) ? SceneControl.GetColor(name).Convert() : (Color?) null;
}
protected void SetConstantOverride(string name, int? constant)
{
if (!GameController.OnGodot)
{
return;
}
if (constant != null)
{
SceneControl.AddConstantOverride(name, constant.Value);
@@ -901,27 +1268,47 @@ namespace SS14.Client.UserInterface
protected int? GetConstantOverride(string name)
{
if (!GameController.OnGodot)
{
return default;
}
return SceneControl.HasConstantOverride(name) ? SceneControl.GetConstant(name) : (int?) null;
}
protected void SetStyleBoxOverride(string name, StyleBox styleBox)
{
if (!GameController.OnGodot)
{
return;
}
SceneControl.AddStyleboxOverride(name, styleBox.GodotStyleBox);
}
protected StyleBox GetStyleBoxOverride(string name)
{
if (!GameController.OnGodot)
{
return default;
}
var box = SceneControl.HasStyleboxOverride(name) ? SceneControl.GetStylebox(name) : null;
return box == null ? null : new GodotStyleBoxWrap(box);
}
protected void SetFontOverride(string name, Font font)
{
if (!GameController.OnGodot)
{
return;
}
SceneControl.AddFontOverride(name, font);
}
protected Font GetFontOverride(string name)
{
if (!GameController.OnGodot)
{
return default;
}
var font = SceneControl.HasFontOverride(name) ? SceneControl.GetFont(name) : null;
return font == null ? null : new GodotWrapFont(font);
}
@@ -941,29 +1328,35 @@ namespace SS14.Client.UserInterface
public enum CursorShape
{
Arrow = Godot.Control.CursorShape.Arrow,
IBeam = Godot.Control.CursorShape.Ibeam,
PointingHand = Godot.Control.CursorShape.PointingHand,
Cross = Godot.Control.CursorShape.Cross,
Wait = Godot.Control.CursorShape.Wait,
Busy = Godot.Control.CursorShape.Busy,
Drag = Godot.Control.CursorShape.Drag,
CanDrop = Godot.Control.CursorShape.CanDrop,
Forbidden = Godot.Control.CursorShape.Forbidden,
VSize = Godot.Control.CursorShape.Vsize,
HSize = Godot.Control.CursorShape.Hsize,
BDiagSize = Godot.Control.CursorShape.Bdiagsize,
FDiagSize = Godot.Control.CursorShape.Fdiagsize,
Move = Godot.Control.CursorShape.Move,
VSplit = Godot.Control.CursorShape.Vsplit,
HSplit = Godot.Control.CursorShape.Hsplit,
Help = Godot.Control.CursorShape.Help,
Arrow = 0,
IBeam = 1,
PointingHand = 2,
Cross = 3,
Wait = 4,
Busy = 5,
Drag = 6,
CanDrop = 7,
Forbidden = 8,
VSize = 9,
HSize = 10,
BDiagSize = 11,
FDiagSize = 12,
Move = 13,
VSplit = 14,
HSplit = 15,
Help = 16,
}
public CursorShape DefaultCursorShape
{
get => (CursorShape) SceneControl.GetDefaultCursorShape();
set => SceneControl.SetDefaultCursorShape((Godot.Control.CursorShape) value);
get => GameController.OnGodot ? (CursorShape) SceneControl.GetDefaultCursorShape() : default;
set
{
if (GameController.OnGodot)
{
SceneControl.SetDefaultCursorShape((Godot.Control.CursorShape) value);
}
}
}
/// <summary>
@@ -971,23 +1364,23 @@ namespace SS14.Client.UserInterface
/// </summary>
public enum MouseFilterMode
{
/// <summary>
/// The control will not be considered at all, and will not have any effects.
/// </summary>
Ignore = Godot.Control.MouseFilterEnum.Ignore,
/// <summary>
/// The control will be able to receive mouse buttons events.
/// Furthermore, if a control with this mode does get clicked,
/// the event automatically gets marked as handled.
/// </summary>
Pass = Godot.Control.MouseFilterEnum.Pass,
Pass = 1,
/// <summary>
/// The control will be able to receive mouse button events like <see cref="Pass"/>,
/// but the event will be stopped and handled even if the relevant events do not handle it.
/// </summary>
Stop = Godot.Control.MouseFilterEnum.Stop,
Stop = 0,
/// <summary>
/// The control will not be considered at all, and will not have any effects.
/// </summary>
Ignore = 2,
}
/// <summary>
@@ -1001,15 +1394,27 @@ namespace SS14.Client.UserInterface
return (Godot.Control) scene2.Instance();
}
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
[BaseTypeRequired(typeof(Control))]
internal class ControlWrapAttribute : Attribute
{
public readonly Type GodotType;
public readonly string InstanceString;
public readonly Type ConcreteType;
public ControlWrapAttribute(Type type)
public ControlWrapAttribute(Type concreteType)
{
GodotType = type;
ConcreteType = concreteType;
}
public ControlWrapAttribute(Type concreteType, string instanceString)
{
ConcreteType = concreteType;
InstanceString = instanceString;
}
public ControlWrapAttribute(string instanceString)
{
InstanceString = instanceString;
}
}
}

View File

@@ -1,4 +1,6 @@
namespace SS14.Client.UserInterface.Controls
using System;
namespace SS14.Client.UserInterface.Controls
{
[ControlWrap(typeof(Godot.AcceptDialog))]
public class AcceptDialog : WindowDialog
@@ -6,9 +8,11 @@
public AcceptDialog() : base()
{
}
public AcceptDialog(string name) : base(name)
{
}
internal AcceptDialog(Godot.AcceptDialog control) : base(control)
{
}
@@ -20,8 +24,14 @@
public string DialogText
{
get => (string)SceneControl.Get("dialog_text");
set => SceneControl.Set("dialog_text", value);
get => GameController.OnGodot ? (string)SceneControl.Get("dialog_text") : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Set("dialog_text", value);
}
}
}
}
}

View File

@@ -9,50 +9,82 @@ namespace SS14.Client.UserInterface.Controls
public BaseButton() : base()
{
}
public BaseButton(string name) : base(name)
{
}
internal BaseButton(Godot.BaseButton button) : base(button)
{
}
public ActionMode Mode
{
get => (ActionMode)SceneControl.Get("action_mode");
set => SceneControl.Set("action_mode", (Godot.BaseButton.ActionModeEnum)value);
get => GameController.OnGodot ? (ActionMode)SceneControl.Get("action_mode") : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Set("action_mode", (Godot.BaseButton.ActionModeEnum) value);
}
}
}
public bool Disabled
{
get => (bool)SceneControl.Get("disabled");
set => SceneControl.Set("disabled", value);
get => GameController.OnGodot ? (bool)SceneControl.Get("disabled") : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Set("disabled", value);
}
}
}
public bool Pressed
{
get => (bool)SceneControl.Get("pressed");
set => SceneControl.Set("pressed", value);
get => GameController.OnGodot ? (bool)SceneControl.Get("pressed") : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Set("pressed", value);
}
}
}
public bool ToggleMode
{
get => (bool)SceneControl.Get("toggle_mode");
set => SceneControl.Set("toggle_mode", value);
get => GameController.OnGodot ? (bool)SceneControl.Get("toggle_mode") : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Set("toggle_mode", value);
}
}
}
public enum ActionMode
{
Press = Godot.BaseButton.ActionModeEnum.Press,
Release = Godot.BaseButton.ActionModeEnum.Release,
Press = 0,
Release = 1,
}
public bool IsHovered => (bool)SceneControl.Call("is_hovered");
public DrawModeEnum DrawMode => (DrawModeEnum)SceneControl.Call("get_draw_mode");
public bool IsHovered => GameController.OnGodot ? (bool)SceneControl.Call("is_hovered") : default;
public DrawModeEnum DrawMode => GameController.OnGodot ? (DrawModeEnum)SceneControl.Call("get_draw_mode") : default;
public ButtonGroup ButtonGroup
{
get => new ButtonGroup((Godot.ButtonGroup)SceneControl.Call("get_button_group"));
set => SceneControl.Call("set_button_group", value?.GodotGroup);
get => GameController.OnGodot ? new ButtonGroup((Godot.ButtonGroup)SceneControl.Call("get_button_group")) : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Call("set_button_group", value?.GodotGroup);
}
}
}
public event Action<ButtonEventArgs> OnButtonDown;
@@ -62,10 +94,10 @@ namespace SS14.Client.UserInterface.Controls
public enum DrawModeEnum
{
Normal = Godot.BaseButton.DrawMode.Normal,
Pressed = Godot.BaseButton.DrawMode.Pressed,
Hover = Godot.BaseButton.DrawMode.Hover,
Disabled = Godot.BaseButton.DrawMode.Disabled,
Normal = 0,
Pressed = 1,
Hover = 2,
Disabled = 3,
}
public class ButtonEventArgs : EventArgs
@@ -170,7 +202,7 @@ namespace SS14.Client.UserInterface.Controls
private void __toggledHook(object state)
{
OnToggled?.Invoke(new ButtonToggledEventArgs((bool)state, this));
OnToggled?.Invoke(new ButtonToggledEventArgs((bool) state, this));
}
}
@@ -178,7 +210,14 @@ namespace SS14.Client.UserInterface.Controls
{
public Godot.ButtonGroup GodotGroup { get; }
public ButtonGroup() : this(new Godot.ButtonGroup()) { }
public ButtonGroup()
{
if (GameController.OnGodot)
{
GodotGroup = new Godot.ButtonGroup();
}
}
public ButtonGroup(Godot.ButtonGroup group)
{
GodotGroup = group;

View File

@@ -1,6 +1,6 @@
namespace SS14.Client.UserInterface.Controls
{
[ControlWrap(typeof(Godot.BoxContainer))]
[ControlWrap(typeof(BoxContainer))]
public abstract class BoxContainer : Container
{
public BoxContainer() : base()

View File

@@ -13,9 +13,11 @@ namespace SS14.Client.UserInterface.Controls
public Button() : base()
{
}
public Button(string name) : base(name)
{
}
internal Button(Godot.Button button) : base(button)
{
}
@@ -27,26 +29,50 @@ namespace SS14.Client.UserInterface.Controls
public AlignMode TextAlign
{
get => (AlignMode)SceneControl.Get("align");
set => SceneControl.Set("align", (Godot.Button.TextAlign)value);
get => GameController.OnGodot ? (AlignMode)SceneControl.Get("align") : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Set("align", (Godot.Button.TextAlign) value);
}
}
}
public bool ClipText
{
get => (bool)SceneControl.Get("clip_text");
set => SceneControl.Set("clip_text", value);
get => GameController.OnGodot ? (bool)SceneControl.Get("clip_text") : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Set("clip_text", value);
}
}
}
public bool Flat
{
get => (bool)SceneControl.Get("flat");
set => SceneControl.Set("flat", value);
get => GameController.OnGodot ? (bool)SceneControl.Get("flat") : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Set("flat", value);
}
}
}
public string Text
{
get => (string)SceneControl.Get("text");
set => SceneControl.Set("text", value);
get => GameController.OnGodot ? (string)SceneControl.Get("text") : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Set("text", value);
}
}
}
private Color? _fontColorOverride;
@@ -83,9 +109,9 @@ namespace SS14.Client.UserInterface.Controls
public enum AlignMode
{
Left = Godot.Button.TextAlign.Left,
Center = Godot.Button.TextAlign.Center,
Right = Godot.Button.TextAlign.Right,
Left = 0,
Center = 1,
Right = 2,
}
}
}

View File

@@ -3,9 +3,17 @@
[ControlWrap(typeof(Godot.Container))]
public class Container : Control
{
public Container() : base() {}
public Container(string name) : base(name) {}
internal Container(Godot.Container sceneControl) : base(sceneControl) {}
public Container() : base()
{
}
public Container(string name) : base(name)
{
}
internal Container(Godot.Container sceneControl) : base(sceneControl)
{
}
private protected override Godot.Control SpawnSceneControl()
{

View File

@@ -1,12 +1,21 @@
using System;
namespace SS14.Client.UserInterface.Controls
{
[ControlWrap(typeof(Godot.GridContainer))]
public class GridContainer : Control
{
public GridContainer() : base() { }
public GridContainer(string name) : base(name) { }
internal GridContainer(Godot.GridContainer sceneControl) : base(sceneControl) { }
public GridContainer() : base()
{
}
public GridContainer(string name) : base(name)
{
}
internal GridContainer(Godot.GridContainer sceneControl) : base(sceneControl)
{
}
private protected override Godot.Control SpawnSceneControl()
{
@@ -15,8 +24,14 @@ namespace SS14.Client.UserInterface.Controls
public int Columns
{
get => (int)SceneControl.Get("columns");
set => SceneControl.Set("columns", value);
get => GameController.OnGodot ? (int)SceneControl.Get("columns") : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Set("columns", value);
}
}
}
}
}

View File

@@ -3,9 +3,17 @@
[ControlWrap(typeof(Godot.HBoxContainer))]
public class HBoxContainer : BoxContainer
{
public HBoxContainer() : base() { }
public HBoxContainer(string name) : base(name) { }
internal HBoxContainer(Godot.HBoxContainer sceneControl) : base(sceneControl) { }
public HBoxContainer() : base()
{
}
public HBoxContainer(string name) : base(name)
{
}
internal HBoxContainer(Godot.HBoxContainer sceneControl) : base(sceneControl)
{
}
private protected override Godot.Control SpawnSceneControl()
{

View File

@@ -1,4 +1,5 @@
using SS14.Client.Graphics;
using System;
using SS14.Client.Graphics;
using SS14.Client.Utility;
using SS14.Shared.Maths;
@@ -7,11 +8,19 @@ namespace SS14.Client.UserInterface.Controls
[ControlWrap(typeof(Godot.ItemList))]
public class ItemList : Control
{
public int ItemCount => (int)SceneControl.Call("get_item_count");
public int ItemCount => GameController.OnGodot ? (int)SceneControl.Call("get_item_count") : default;
public ItemList() : base() { }
public ItemList(string name) : base(name) { }
internal ItemList(Godot.ItemList control) : base(control) { }
public ItemList()
{
}
public ItemList(string name) : base(name)
{
}
internal ItemList(Godot.ItemList control) : base(control)
{
}
private protected override Godot.Control SpawnSceneControl()
{
@@ -20,92 +29,140 @@ namespace SS14.Client.UserInterface.Controls
public void AddItem(string text, Texture icon = null, bool selectable = true)
{
SceneControl.Call("add_item", text, icon, selectable);
if (GameController.OnGodot)
{
SceneControl.Call("add_item", text, icon, selectable);
}
}
public void AddIconItem(Texture icon, bool selectable = true)
{
SceneControl.Call("add_icon_item", icon, selectable);
if (GameController.OnGodot)
{
SceneControl.Call("add_icon_item", icon, selectable);
}
}
public void Clear()
{
SceneControl.Call("clear");
if (GameController.OnGodot)
{
SceneControl.Call("clear");
}
}
public void EnsureCurrentIsVisible()
{
SceneControl.Call("ensure_current_is_visible");
if (GameController.OnGodot)
{
SceneControl.Call("ensure_current_is_visible");
}
}
public int GetItemAtPosition(Vector2 position, bool exact = false)
{
return (int)SceneControl.Call("get_item_at_position", position.Convert(), exact);
return GameController.OnGodot ? (int)SceneControl.Call("get_item_at_position", position.Convert(), exact) : default;
}
public bool IsSelected(int idx)
{
return (bool)SceneControl.Call("is_selected", idx);
return GameController.OnGodot ? (bool)SceneControl.Call("is_selected", idx) : default;
}
public void RemoveItem(int idx)
{
SceneControl.Call("remove_item", idx);
if (GameController.OnGodot)
{
SceneControl.Call("remove_item", idx);
}
}
public void Select(int idx, bool single = true)
{
SceneControl.Call("select", idx, single);
if (GameController.OnGodot)
{
SceneControl.Call("select", idx, single);
}
}
public void SetItemCustomBgColor(int idx, Color color)
{
SceneControl.Call("set_icon_custom_bg_color", idx, color.Convert());
if (GameController.OnGodot)
{
SceneControl.Call("set_icon_custom_bg_color", idx, color.Convert());
}
}
public void SetItemDisabled(int idx, bool disabled)
{
SceneControl.Call("set_item_disabled", idx, disabled);
if (GameController.OnGodot)
{
SceneControl.Call("set_item_disabled", idx, disabled);
}
}
public void SetItemIcon(int idx, Texture icon)
{
SceneControl.Call("set_item_icon", idx, icon);
if (GameController.OnGodot)
{
SceneControl.Call("set_item_icon", idx, icon);
}
}
public void SetItemIconRegion(int idx, UIBox2 region)
{
SceneControl.Call("set_item_icon_region", idx, region.Convert());
if (GameController.OnGodot)
{
SceneControl.Call("set_item_icon_region", idx, region.Convert());
}
}
public void SetItemSelectable(int idx, bool selectable)
{
SceneControl.Call("set_item_selectable", idx, selectable);
if (GameController.OnGodot)
{
SceneControl.Call("set_item_selectable", idx, selectable);
}
}
public void SetItemText(int idx, string text)
{
SceneControl.Call("set_item_text", idx, text);
if (GameController.OnGodot)
{
SceneControl.Call("set_item_text", idx, text);
}
}
public void SetItemTooltip(int idx, string tooltip)
{
SceneControl.Call("set_item_tooltip", idx, tooltip);
if (GameController.OnGodot)
{
SceneControl.Call("set_item_tooltip", idx, tooltip);
}
}
public void SetItemTooltipEnabled(int idx, bool enabled)
{
SceneControl.Call("set_item_tooltip_enabled", idx, enabled);
if (GameController.OnGodot)
{
SceneControl.Call("set_item_tooltip_enabled", idx, enabled);
}
}
public void SortItemsByText()
{
SceneControl.Call("sort_items_by_text");
if (GameController.OnGodot)
{
SceneControl.Call("sort_items_by_text");
}
}
public void Unselect(int idx)
{
SceneControl.Call("unselect", idx);
if (GameController.OnGodot)
{
SceneControl.Call("unselect", idx);
}
}
}
}

View File

@@ -1,4 +1,5 @@
using JetBrains.Annotations;
using System;
using JetBrains.Annotations;
using SS14.Client.Graphics;
using SS14.Shared.Maths;
@@ -13,29 +14,49 @@ namespace SS14.Client.UserInterface.Controls
public Label(string name) : base(name)
{
}
public Label() : base()
{
}
internal Label(Godot.Label control) : base(control)
{
}
public string Text
{
get => (string)SceneControl.Get("text");
set => SceneControl.Set("text", value);
get => GameController.OnGodot ? (string)SceneControl.Get("text") : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Set("text", value);
}
}
}
public bool AutoWrap
{
get => (bool)SceneControl.Get("autowrap");
set => SceneControl.Set("autowrap", value);
get => GameController.OnGodot ? (bool)SceneControl.Get("autowrap") : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Set("autowrap", value);
}
}
}
public AlignMode Align
{
get => (AlignMode) SceneControl.Get("align");
set => SceneControl.Set("align", (Godot.Label.AlignEnum) value);
get => GameController.OnGodot ? (AlignMode) SceneControl.Get("align") : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Set("align", (Godot.Label.AlignEnum) value);
}
}
}
private Font _fontOverride;
@@ -85,10 +106,10 @@ namespace SS14.Client.UserInterface.Controls
public enum AlignMode
{
Left = Godot.Label.AlignEnum.Left,
Center = Godot.Label.AlignEnum.Center,
Right = Godot.Label.AlignEnum.Right,
Fill = Godot.Label.AlignEnum.Fill,
Left = 0,
Center = 1,
Right = 2,
Fill = 3,
}
}
}

View File

@@ -9,9 +9,11 @@ namespace SS14.Client.UserInterface.Controls
public LineEdit() : base()
{
}
public LineEdit(string name) : base(name)
{
}
internal LineEdit(Godot.LineEdit control) : base(control)
{
}
@@ -23,26 +25,50 @@ namespace SS14.Client.UserInterface.Controls
public AlignMode TextAlign
{
get => (AlignMode)SceneControl.Get("align");
set => SceneControl.Set("align", (Godot.LineEdit.AlignEnum)value);
get => GameController.OnGodot ? (AlignMode)SceneControl.Get("align") : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Set("align", (Godot.LineEdit.AlignEnum) value);
}
}
}
public string Text
{
get => (string)SceneControl.Get("text");
set => SceneControl.Set("text", value);
get => GameController.OnGodot ? (string)SceneControl.Get("text") : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Set("text", value);
}
}
}
public bool Editable
{
get => (bool)SceneControl.Get("editable");
set => SceneControl.Set("editable", value);
get => GameController.OnGodot ? (bool)SceneControl.Get("editable") : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Set("editable", value);
}
}
}
public string PlaceHolder
{
get => (string)SceneControl.Get("placeholder_text");
set => SceneControl.Set("placeholder_text", value);
get => GameController.OnGodot ? (string)SceneControl.Get("placeholder_text") : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Set("placeholder_text", value);
}
}
}
// TODO:
@@ -50,36 +76,58 @@ namespace SS14.Client.UserInterface.Controls
// since most of it won't be used yet (if at all).
// Feel free to implement wrappers for all the other properties!
// Future me reporting, thanks past me.
// Second future me reporting, thanks again.
public void AppendAtCursor(string text)
{
SceneControl.Call("append_at_cursor", text);
if (GameController.OnGodot)
{
SceneControl.Call("append_at_cursor", text);
}
}
public void Clear()
{
SceneControl.Call("clear");
if (GameController.OnGodot)
{
SceneControl.Call("clear");
}
}
public int CursorPosition
{
get => (int)SceneControl.Get("caret_position");
set => SceneControl.Set("caret_position", value);
get => GameController.OnGodot ? (int)SceneControl.Get("caret_position") : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Set("caret_position", value);
}
}
}
public void ExecuteMenuOption(MenuOption option)
{
SceneControl.Call("menu_option", (int)option);
if (GameController.OnGodot)
{
SceneControl.Call("menu_option", (int)option);
}
}
public void Select(int from = 0, int to = -1)
{
SceneControl.Call("select", from, to);
if (GameController.OnGodot)
{
SceneControl.Call("select", from, to);
}
}
public void SelectAll()
{
SceneControl.Call("select_all");
if (GameController.OnGodot)
{
SceneControl.Call("select_all");
}
}
public event Action<LineEditEventArgs> OnTextChanged;
@@ -87,21 +135,21 @@ namespace SS14.Client.UserInterface.Controls
public enum AlignMode
{
Left = Godot.LineEdit.AlignEnum.Left,
Center = Godot.LineEdit.AlignEnum.Center,
Right = Godot.LineEdit.AlignEnum.Right,
Fill = Godot.LineEdit.AlignEnum.Fill,
Left = 0,
Center = 1,
Right = 2,
Fill = 3,
}
public enum MenuOption
{
Cut = Godot.LineEdit.MenuItems.Cut,
Copy = Godot.LineEdit.MenuItems.Copy,
Paste = Godot.LineEdit.MenuItems.Paste,
Clear = Godot.LineEdit.MenuItems.Clear,
SelectAll = Godot.LineEdit.MenuItems.SelectAll,
Undo = Godot.LineEdit.MenuItems.Undo,
Redo = Godot.LineEdit.MenuItems.Redo,
Cut = 0,
Copy = 1,
Paste = 2,
Clear = 3,
SelectAll = 4,
Undo = 5,
Redo = 6,
}
public class LineEditEventArgs : EventArgs
@@ -153,12 +201,12 @@ namespace SS14.Client.UserInterface.Controls
private void __textChangedHook(object text)
{
OnTextChanged?.Invoke(new LineEditEventArgs(this, (string)text));
OnTextChanged?.Invoke(new LineEditEventArgs(this, (string) text));
}
private void __textEnteredHook(object text)
{
OnTextEntered?.Invoke(new LineEditEventArgs(this, (string)text));
OnTextEntered?.Invoke(new LineEditEventArgs(this, (string) text));
}
}
}

View File

@@ -11,59 +11,84 @@ namespace SS14.Client.UserInterface.Controls
public int Selected
{
get => (int)SceneControl.Get("selected");
set => SceneControl.Set("selected", value);
get => GameController.OnGodot ? (int)SceneControl.Get("selected") : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Set("selected", value);
}
}
}
public void AddItem(Texture icon, string label, int id = 1)
{
SceneControl.Call("add_icon_item", icon.GodotTexture, label, id);
if (GameController.OnGodot)
{
SceneControl.Call("add_icon_item", icon.GodotTexture, label, id);
}
}
public void AddItem(string label, int id = 1)
{
SceneControl.Call("add_item", label, id);
if (GameController.OnGodot)
{
SceneControl.Call("add_item", label, id);
}
}
public void AddSeparator()
{
SceneControl.Call("add_separator");
if (GameController.OnGodot)
{
SceneControl.Call("add_separator");
}
}
public void Clear()
{
SceneControl.Call("clear");
if (GameController.OnGodot)
{
SceneControl.Call("clear");
}
}
public int ItemCount => (int)SceneControl.Call("get_item_count");
public int ItemCount => GameController.OnGodot ? (int)SceneControl.Call("get_item_count") : default;
public int GetItemId(int idx)
{
return (int)SceneControl.Call("get_item_id", idx);
return GameController.OnGodot ? (int)SceneControl.Call("get_item_id", idx) : throw new NotImplementedException();
}
public object GetItemMetadata(int idx)
{
return SceneControl.Call("get_item_metadata", idx);
return GameController.OnGodot ? SceneControl.Call("get_item_metadata", idx) : throw new NotImplementedException();
}
public int SelectedId => (int)SceneControl.Call("get_selected_id");
public int SelectedId => GameController.OnGodot ? (int)SceneControl.Call("get_selected_id") : default;
public object SelectedMetadata => SceneControl.GetSceneInstanceLoadPlaceholder();
public object SelectedMetadata =>
GameController.OnGodot ? SceneControl.GetSceneInstanceLoadPlaceholder() : default;
public bool IsItemDisabled(int idx)
{
return (bool)SceneControl.Call("is_item_disabled", idx);
return GameController.OnGodot ? (bool)SceneControl.Call("is_item_disabled", idx) : default;
}
public void RemoveItem(int idx)
{
SceneControl.Call("remove_item", idx);
if (GameController.OnGodot)
{
SceneControl.Call("remove_item", idx);
}
}
public void Select(int idx)
{
SceneControl.Call("select", idx);
if (GameController.OnGodot)
{
SceneControl.Call("select", idx);
}
}
public void SelectId(int id)
@@ -86,35 +111,52 @@ namespace SS14.Client.UserInterface.Controls
public void SetItemDisabled(int idx, bool disabled)
{
SceneControl.Call("set_item_disabled", idx, disabled);
if (GameController.OnGodot)
{
SceneControl.Call("set_item_disabled", idx, disabled);
}
}
public void SetItemIcon(int idx, Texture texture)
{
SceneControl.Call("set_item_icon", idx, texture);
if (GameController.OnGodot)
{
SceneControl.Call("set_item_icon", idx, texture);
}
}
public void SetItemId(int idx, int id)
{
SceneControl.Call("set_item_id", idx, id);
if (GameController.OnGodot)
{
SceneControl.Call("set_item_id", idx, id);
}
}
public void SetItemMetadata(int idx, object metadata)
{
SceneControl.Call("set_item_metadata", idx, metadata);
if (GameController.OnGodot)
{
SceneControl.Call("set_item_metadata", idx, metadata);
}
}
public void SetItemText(int idx, string text)
{
SceneControl.Call("set_item_text", idx, text);
if (GameController.OnGodot)
{
SceneControl.Call("set_item_text", idx, text);
}
}
public OptionButton() : base()
{
}
public OptionButton(string name) : base(name)
{
}
internal OptionButton(Godot.OptionButton button) : base(button)
{
}
@@ -165,7 +207,7 @@ namespace SS14.Client.UserInterface.Controls
private void __itemSelectedHook(object id)
{
OnItemSelected?.Invoke(new ItemSelectedEventArgs((int)id, this));
OnItemSelected?.Invoke(new ItemSelectedEventArgs((int) id, this));
}
}
}

View File

@@ -8,9 +8,11 @@ namespace SS14.Client.UserInterface.Controls
public Panel(string name) : base(name)
{
}
public Panel() : base()
{
}
internal Panel(Godot.Panel panel) : base(panel)
{
}

View File

@@ -17,6 +17,11 @@ namespace SS14.Client.UserInterface.Controls
{
}
private protected override Godot.Control SpawnSceneControl()
{
return new Godot.PanelContainer();
}
private StyleBox _panelOverride;
public StyleBox PanelOverride
@@ -24,10 +29,5 @@ namespace SS14.Client.UserInterface.Controls
get => _panelOverride ?? GetStyleBoxOverride("panel");
set => SetStyleBoxOverride("panel", _panelOverride = value);
}
private protected override Godot.Control SpawnSceneControl()
{
return new Godot.PanelContainer();
}
}
}

View File

@@ -30,17 +30,26 @@ namespace SS14.Client.UserInterface.Controls
public void Open(UIBox2? box = null)
{
SceneControl.Call("popup", box?.Convert());
if (GameController.OnGodot)
{
SceneControl.Call("popup", box?.Convert());
}
}
public void OpenCentered()
{
SceneControl.Call("popup_centered");
if (GameController.OnGodot)
{
SceneControl.Call("popup_centered");
}
}
public void OpenMinimum()
{
SceneControl.Call("popup_centered_minsize");
if (GameController.OnGodot)
{
SceneControl.Call("popup_centered_minsize");
}
}
private GodotSignalSubscriber0 __popupHideSubscriber;

View File

@@ -1,3 +1,5 @@
using System;
namespace SS14.Client.UserInterface.Controls
{
[ControlWrap(typeof(Godot.ProgressBar))]
@@ -20,8 +22,11 @@ namespace SS14.Client.UserInterface.Controls
/// </summary>
public bool PercentVisible
{
get => (bool)SceneControl.Get("percent_visible");
set => SceneControl.Set("percent_visible", value);
get => GameController.OnGodot ? (bool)SceneControl.Get("percent_visible") : default;
set
{
if (GameController.OnGodot) SceneControl.Set("percent_visible", value);
}
}
private protected override Godot.Control SpawnSceneControl()

View File

@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Godot;
namespace SS14.Client.UserInterface.Controls
{
@@ -13,40 +12,66 @@ namespace SS14.Client.UserInterface.Controls
public Range() : base()
{
}
public Range(string name) : base(name)
{
}
internal Range(Godot.Range control) : base(control)
{
}
public float GetAsRatio()
{
return (float)SceneControl.Call("get_as_ratio");
return GameController.OnGodot ? (float)SceneControl.Call("get_as_ratio") : default;
}
public float Page
{
get => (float)SceneControl.Get("page");
set => SceneControl.Set("page", value);
get => GameController.OnGodot ? (float)SceneControl.Get("page") : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Set("page", value);
}
}
}
public float MaxValue
{
get => (float)SceneControl.Get("max_value");
set => SceneControl.Set("max_value", value);
get => GameController.OnGodot ? (float)SceneControl.Get("max_value") : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Set("max_value", value);
}
}
}
public float MinValue
{
get => (float)SceneControl.Get("min_value");
set => SceneControl.Set("min_value", value);
get => GameController.OnGodot ? (float)SceneControl.Get("min_value") : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Set("min_value", value);
}
}
}
public float Value
{
get => (float)SceneControl.Get("value");
set => SceneControl.Set("value", value);
get => GameController.OnGodot ? (float)SceneControl.Get("value") : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Set("value", value);
}
}
}
}
}

View File

@@ -1,4 +1,5 @@
using SS14.Client.Utility;
using System;
using SS14.Client.Utility;
using SS14.Shared.Maths;
namespace SS14.Client.UserInterface.Controls
@@ -9,9 +10,11 @@ namespace SS14.Client.UserInterface.Controls
public RichTextLabel() : base()
{
}
public RichTextLabel(string name) : base(name)
{
}
internal RichTextLabel(Godot.RichTextLabel button) : base(button)
{
}
@@ -23,44 +26,78 @@ namespace SS14.Client.UserInterface.Controls
public bool BBCodeEnabled
{
get => (bool)SceneControl.Get("bbcode_enabled");
set => SceneControl.Set("bbcode_enabled", value);
get => GameController.OnGodot ? (bool)SceneControl.Get("bbcode_enabled") : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Set("bbcode_enabled", value);
}
}
}
public void Clear()
{
SceneControl.Call("clear");
if (GameController.OnGodot)
{
SceneControl.Call("clear");
}
}
public Godot.Error AppendBBCode(string code)
{
return (Godot.Error)SceneControl.Call("append_bbcode", code);
if (GameController.OnGodot)
{
return (Godot.Error)SceneControl.Call("append_bbcode", code);
}
else
{
return default;
}
}
public void PushColor(Color color)
{
SceneControl.Call("push_color", color.Convert());
if (GameController.OnGodot)
{
SceneControl.Call("push_color", color.Convert());
}
}
public void AddText(string text)
{
SceneControl.Call("add_text", text);
if (GameController.OnGodot)
{
SceneControl.Call("add_text", text);
}
}
public void Pop()
{
SceneControl.Call("pop");
if (GameController.OnGodot)
{
SceneControl.Call("pop");
}
}
public void NewLine()
{
SceneControl.Call("newline");
if (GameController.OnGodot)
{
SceneControl.Call("newline");
}
}
public bool ScrollFollowing
{
get => (bool)SceneControl.Call("is_scroll_following");
set => SceneControl.Call("set_scroll_following", value);
get => GameController.OnGodot ? (bool)SceneControl.Call("is_scroll_following") : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Call("set_scroll_following", value);
}
}
}
}
}

View File

@@ -12,9 +12,11 @@ namespace SS14.Client.UserInterface.Controls
public ScrollBar() : base()
{
}
public ScrollBar(string name) : base(name)
{
}
public ScrollBar(Godot.ScrollBar control) : base(control)
{
}

View File

@@ -13,7 +13,6 @@ namespace SS14.Client.UserInterface.Controls
internal ScrollContainer(Godot.ScrollContainer container) : base(container)
{
}
private protected override Godot.Control SpawnSceneControl()

View File

@@ -9,11 +9,12 @@ using SS14.Shared.Maths;
namespace SS14.Client.UserInterface.Controls
{
[ControlWrap(typeof(GodotGlue.SpriteView))]
[ControlWrap(typeof(GodotGlue.SpriteView), "res://Engine/Scenes/SpriteMirror/SpriteView.tscn")]
public class SpriteView : Control
{
ISpriteProxy Mirror;
ISpriteComponent _sprite;
public ISpriteComponent Sprite
{
get => _sprite;
@@ -37,17 +38,14 @@ namespace SS14.Client.UserInterface.Controls
public SpriteView() : base()
{
}
public SpriteView(string name) : base(name)
{
}
public SpriteView(GodotGlue.SpriteView control) : base(control)
public SpriteView(Godot.Control control) : base(control)
{
}
protected override void Initialize()

View File

@@ -24,20 +24,38 @@ namespace SS14.Client.UserInterface.Controls
public int CurrentTab
{
get => (int)SceneControl.Call("get_current_tab");
set => SceneControl.Call("set_current_tab", value);
get => GameController.OnGodot ? (int)SceneControl.Call("get_current_tab") : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Call("set_current_tab", value);
}
}
}
public TabAlignMode AlignMode
{
get => (TabAlignMode) SceneControl.Call("get_tab_align");
set => SceneControl.Call("set_tab_align", (Godot.TabContainer.TabAlignEnum) value);
get => GameController.OnGodot ? (TabAlignMode) SceneControl.Call("get_tab_align") : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Call("set_tab_align", (Godot.TabContainer.TabAlignEnum) value);
}
}
}
public bool TabsVisible
{
get => (bool)SceneControl.Get("tabs_visible");
set => SceneControl.Set("tabs_visible", value);
get => GameController.OnGodot ? (bool)SceneControl.Get("tabs_visible") : default;
set
{
if (GameController.OnGodot)
{
SceneControl.Set("tabs_visible", value);
}
}
}
public event Action<int> OnTabSelected;
@@ -45,22 +63,28 @@ namespace SS14.Client.UserInterface.Controls
public string GetTabTitle(int tab)
{
return (string)SceneControl.Call("get_tab_title", tab);
return GameController.OnGodot ? (string)SceneControl.Call("get_tab_title", tab) : default;
}
public void SetTabTitle(int tab, string title)
{
SceneControl.Call("set_tab_title", tab, title);
if (GameController.OnGodot)
{
SceneControl.Call("set_tab_title", tab, title);
}
}
public Texture GetTabIcon(int tab)
{
return new GodotTextureSource((Godot.Texture)SceneControl.Call("get_tab_icon", tab));
return GameController.OnGodot ? (Texture)new GodotTextureSource((Godot.Texture)SceneControl.Call("get_tab_icon", tab)) : new BlankTexture();
}
public void SetTabIcon(int tab, Texture icon)
{
SceneControl.Call("set_tab_icon", tab, icon);
if (GameController.OnGodot)
{
SceneControl.Call("set_tab_icon", tab, icon);
}
}
private protected override Godot.Control SpawnSceneControl()
@@ -103,9 +127,9 @@ namespace SS14.Client.UserInterface.Controls
public enum TabAlignMode
{
Left = Godot.TabContainer.TabAlignEnum.Left,
Center = Godot.TabContainer.TabAlignEnum.Center,
Right = Godot.TabContainer.TabAlignEnum.Right
Left = 0,
Center = 1,
Right = 2
}
}
}

View File

@@ -6,9 +6,11 @@
public TextureButton() : base()
{
}
public TextureButton(string name) : base(name)
{
}
internal TextureButton(Godot.TextureButton button) : base(button)
{
}

Some files were not shown because too many files have changed in this diff Show More