From 03580bfc8da7bd6e32f4127cc1292f754a12e41c Mon Sep 17 00:00:00 2001 From: Roddie Kieley Date: Fri, 31 Mar 2023 10:53:02 -0230 Subject: [PATCH 01/18] issue67: First successful build and run after 3 to 4 migration updates. --- AMQPserver.cs | 332 ++-- Assets/Fonts/RedHatDisplay-Bold.ttf.import | 33 + Assets/Fonts/RedHatText-Italic.ttf.import | 33 + Assets/Fonts/RedHatText-Regular.ttf.import | 33 + CSLogger.cs | 2 +- Player.tscn | 58 +- PlayerShip.cs | 415 ++--- Sector.cs | 2 +- Sector.tscn | 12 +- Server.cs | 1544 +++++++++-------- Server.tscn | 86 +- SpaceMissile.cs | 146 +- SpaceMissile.tscn | 4 +- StarFieldRadius.cs | 2 +- addons/carmel4a97.RTS_Camera2D/Plugin.gd | 2 +- .../carmel4a97.RTS_Camera2D/RTS-Camera2D.gd | 38 +- .../node_icon.png.import | 31 +- debug_stack.tres | 20 +- default_env.tres | 6 +- icon.svg.import | 37 + images/missle.png.import | 31 +- images/ship.png.import | 31 +- project.godot | 92 +- sector.tres | 4 +- srt-godot-test.csproj | 7 +- 25 files changed, 1543 insertions(+), 1458 deletions(-) create mode 100644 Assets/Fonts/RedHatDisplay-Bold.ttf.import create mode 100644 Assets/Fonts/RedHatText-Italic.ttf.import create mode 100644 Assets/Fonts/RedHatText-Regular.ttf.import create mode 100644 icon.svg.import diff --git a/AMQPserver.cs b/AMQPserver.cs index 43e0a2c..ca7e5af 100644 --- a/AMQPserver.cs +++ b/AMQPserver.cs @@ -7,7 +7,7 @@ using ProtoBuf; using redhatgamedev.srt.v1; -public class AMQPserver : Node +public partial class AMQPserver : Node { public Serilog.Core.Logger _serilogger; @@ -39,237 +39,237 @@ public class AMQPserver : Node void CommandReceived(IReceiverLink receiver, Message message) { - _serilogger.Verbose("AMQPserver.cs: Client game event received!"); - // accept the message so that it gets removed from the queue - receiver.Accept(message); + _serilogger.Verbose("AMQPserver.cs: Client game event received!"); + // accept the message so that it gets removed from the queue + receiver.Accept(message); - byte[] binaryBody = (byte[])message.Body; + byte[] binaryBody = (byte[])message.Body; - MemoryStream st = new MemoryStream(binaryBody, false); + MemoryStream st = new MemoryStream(binaryBody, false); - // prep a command buffer for processing the message - Command commandBuffer; - commandBuffer = Serializer.Deserialize(st); + // prep a command buffer for processing the message + Command commandBuffer; + commandBuffer = Serializer.Deserialize(st); - MyServer.GameEventQueue.Enqueue(commandBuffer); + MyServer.GameEventQueue.Enqueue(commandBuffer); } void SecurityReceived(IReceiverLink receiver, Message message) { - _serilogger.Debug("AMQPserver.cs: Client security event received!"); - // accept the message so that it gets removed from the queue - receiver.Accept(message); + _serilogger.Debug("AMQPserver.cs: Client security event received!"); + // accept the message so that it gets removed from the queue + receiver.Accept(message); - byte[] binaryBody = (byte[])message.Body; + byte[] binaryBody = (byte[])message.Body; - MemoryStream st = new MemoryStream(binaryBody, false); + MemoryStream st = new MemoryStream(binaryBody, false); - // prep a command buffer for processing the message - Security securityBuffer; - securityBuffer = Serializer.Deserialize(st); + // prep a command buffer for processing the message + Security securityBuffer; + securityBuffer = Serializer.Deserialize(st); - MyServer.SecurityEventQueue.Enqueue(securityBuffer); + MyServer.SecurityEventQueue.Enqueue(securityBuffer); } public void SendGameEvent(GameEvent gameEvent) { - _serilogger.Verbose("AMQPserver.cs: Sending game event"); - // serialize it into a byte stream - MemoryStream st = new MemoryStream(); - Serializer.Serialize(st, gameEvent); + _serilogger.Verbose("AMQPserver.cs: Sending game event"); + // serialize it into a byte stream + MemoryStream st = new MemoryStream(); + Serializer.Serialize(st, gameEvent); - byte[] msgBytes = st.ToArray(); + byte[] msgBytes = st.ToArray(); - Message msg = new Message(msgBytes); + Message msg = new Message(msgBytes); - // create and destroy messages are mega important, so don't set a TTL for those - // updates are not as important, so set a low TTL for those - if (!(gameEvent.game_event_type == GameEvent.GameEventType.GameEventTypeCreate - | gameEvent.game_event_type == GameEvent.GameEventType.GameEventTypeDestroy)) - { msg.Header = new Header() { Ttl = 250 }; } + // create and destroy messages are mega important, so don't set a TTL for those + // updates are not as important, so set a low TTL for those + if (!(gameEvent.game_event_type == GameEvent.GameEventType.GameEventTypeCreate + | gameEvent.game_event_type == GameEvent.GameEventType.GameEventTypeDestroy)) + { msg.Header = new Header() { Ttl = 250 }; } - // don't care about the ack on our message being received - gameEventOutSender.Send(msg, null, null); + // don't care about the ack on our message being received + gameEventOutSender.Send(msg, null, null); - // this should work but there's something weird and it blows up the - // connection - //gameEventOutSender.Send(msg); + // this should work but there's something weird and it blows up the + // connection + //gameEventOutSender.Send(msg); } // only used for debug public void SendCommand(Command CommandBuffer) { - _serilogger.Verbose("AMQPServer.cs: Sending command"); + _serilogger.Verbose("AMQPServer.cs: Sending command"); - // serialize it into a byte stream - MemoryStream st = new MemoryStream(); - Serializer.Serialize(st, CommandBuffer); + // serialize it into a byte stream + MemoryStream st = new MemoryStream(); + Serializer.Serialize(st, CommandBuffer); - byte[] msgBytes = st.ToArray(); + byte[] msgBytes = st.ToArray(); - Message msg = new Message(msgBytes); + Message msg = new Message(msgBytes); - // don't care about the ack on our message being received - commandInSender.Send(msg, null, null); + // don't care about the ack on our message being received + commandInSender.Send(msg, null, null); - // this should work but there's something weird and it blows up the - // connection - //commandInSender.Send(msg); + // this should work but there's something weird and it blows up the + // connection + //commandInSender.Send(msg); } public void SendSecurity(Security security) { - _serilogger.Debug("AMQPServer.cs: Sending security command"); + _serilogger.Debug("AMQPServer.cs: Sending security command"); - // serialize it into a byte stream - MemoryStream st = new MemoryStream(); - Serializer.Serialize(st, security); + // serialize it into a byte stream + MemoryStream st = new MemoryStream(); + Serializer.Serialize(st, security); - byte[] msgBytes = st.ToArray(); + byte[] msgBytes = st.ToArray(); - Message msg = new Message(msgBytes); + Message msg = new Message(msgBytes); - // don't care about the ack on our message being received - securityOutSender.Send(msg, null, null); - // this should work but there's something weird and it blows up the - // connection - //commandInSender.Send(msg); + // don't care about the ack on our message being received + securityOutSender.Send(msg, null, null); + // this should work but there's something weird and it blows up the + // connection + //commandInSender.Send(msg); } // used for the debug client parts of the server public void SendSecurityDebug(Security security) { - _serilogger.Debug("AMQPServer.cs: Sending security command"); + _serilogger.Debug("AMQPServer.cs: Sending security command"); - // serialize it into a byte stream - MemoryStream st = new MemoryStream(); - Serializer.Serialize(st, security); + // serialize it into a byte stream + MemoryStream st = new MemoryStream(); + Serializer.Serialize(st, security); - byte[] msgBytes = st.ToArray(); + byte[] msgBytes = st.ToArray(); - Message msg = new Message(msgBytes); + Message msg = new Message(msgBytes); - // don't care about the ack on our message being received - securityInSender.Send(msg, null, null); - // this should work but there's something weird and it blows up the - // connection - //commandInSender.Send(msg); + // don't care about the ack on our message being received + securityInSender.Send(msg, null, null); + // this should work but there's something weird and it blows up the + // connection + //commandInSender.Send(msg); } async void InitializeAMQP() { - // TODO: should probably wrap in some kind of try and catch failure to connect? - // is this even async? - // TODO: include connection details - _serilogger.Information("AMQPserver.cs: Initializing AMQP connection"); - Connection.DisableServerCertValidation = true; - - try - { - //Trace.TraceLevel = TraceLevel.Frame; - //Trace.TraceListener = (l, f, a) => Console.WriteLine(DateTime.Now.ToString("[hh:mm:ss.fff]") + " " + string.Format(f, a)); - factory = new ConnectionFactory(); - Address address = new Address(url); - amqpConnection = await factory.CreateAsync(address); - amqpSession = new Session(amqpConnection); - } - catch (Exception ex) - { - _serilogger.Error("ServerConnection.cs: AMQP connection/session failed for " + url); - _serilogger.Error($"ServerConnection.cs: {ex.Message}"); - // TODO: let player know - return; - } - - // set up queues and topics //////////////////////////////////////////////// - // topics are multicast - // queues are anycast - // https://stackoverflow.com/a/51595195 - - // output to clients /////////////////////////////////////////////////////// - // multicast topic for the server to send game event updates to clients - Target gameEventOutTarget = new Target - { - Address = gameEventOutQueue, - Capabilities = new Symbol[] { new Symbol("topic") } - }; - gameEventOutSender = new SenderLink(amqpSession, "srt-game-server-command-sender", gameEventOutTarget, null); - - // multicast topic for the server to send security updates to clients - Target securityOutTarget = new Target - { - Address = securityOutQueue, - Capabilities = new Symbol[] { new Symbol("topic") } - }; - securityOutSender = new SenderLink(amqpSession, "srt-game-server-security-sender", securityOutTarget, null); - - // inputs from clients ///////////////////////////////////////////////////// - // anycast queue for the server to receive command events from clients - Source commandInSource = new Source - { - Address = commandInQueue, - Capabilities = new Symbol[] { new Symbol("queue") } - }; - commandInReceiver = new ReceiverLink(amqpSession, "srt-game-server-command-receiver", commandInSource, null); - commandInReceiver.Start(10, CommandReceived); - - // anycast queue for the server to receive security events from clients - Source securityInSource = new Source - { - Address = securityInQueue, - Capabilities = new Symbol[] { new Symbol("queue") } - }; - securityInReceiver = new ReceiverLink(amqpSession, "srt-game-server-security-receiver", securityInSource, null); - securityInReceiver.Start(10, SecurityReceived); - - - // DEBUG stuff ///////////////////////////////////////////////////////////// - // we send commands to the COMMAND.IN from the debug UI - Target commandInTarget = new Target - { - Address = commandInQueue, - Capabilities = new Symbol[] { new Symbol("queue") } - }; - commandInSender = new SenderLink(amqpSession, "srt-game-server-debug-command-sender", commandInTarget, null); - - // we send security messages to SECURITY.IN from the debug UI - Target securityInTarget = new Target - { - Address = securityInQueue, - Capabilities = new Symbol[] { new Symbol("queue") } - }; - securityInSender = new SenderLink(amqpSession, "srt-game-server-debug-security-sender", securityInTarget, null); - - _serilogger.Information("AMQPserver.cs: Finished initializing AMQP connection"); + // TODO: should probably wrap in some kind of try and catch failure to connect? + // is this even async? + // TODO: include connection details + _serilogger.Information("AMQPserver.cs: Initializing AMQP connection"); + Connection.DisableServerCertValidation = true; + + try + { + //Trace.TraceLevel = TraceLevel.Frame; + //Trace.TraceListener = (l, f, a) => Console.WriteLine(DateTime.Now.ToString("[hh:mm:ss.fff]") + " " + string.Format(f, a)); + factory = new ConnectionFactory(); + Address address = new Address(url); + amqpConnection = await factory.CreateAsync(address); + amqpSession = new Session(amqpConnection); + } + catch (Exception ex) + { + _serilogger.Error("ServerConnection.cs: AMQP connection/session failed for " + url); + _serilogger.Error($"ServerConnection.cs: {ex.Message}"); + // TODO: let player know + return; + } + + // set up queues and topics //////////////////////////////////////////////// + // topics are multicast + // queues are anycast + // https://stackoverflow.com/a/51595195 + + // output to clients /////////////////////////////////////////////////////// + // multicast topic for the server to send game event updates to clients + Target gameEventOutTarget = new Target + { + Address = gameEventOutQueue, + Capabilities = new Symbol[] { new Symbol("topic") } + }; + gameEventOutSender = new SenderLink(amqpSession, "srt-game-server-command-sender", gameEventOutTarget, null); + + // multicast topic for the server to send security updates to clients + Target securityOutTarget = new Target + { + Address = securityOutQueue, + Capabilities = new Symbol[] { new Symbol("topic") } + }; + securityOutSender = new SenderLink(amqpSession, "srt-game-server-security-sender", securityOutTarget, null); + + // inputs from clients ///////////////////////////////////////////////////// + // anycast queue for the server to receive command events from clients + Source commandInSource = new Source + { + Address = commandInQueue, + Capabilities = new Symbol[] { new Symbol("queue") } + }; + commandInReceiver = new ReceiverLink(amqpSession, "srt-game-server-command-receiver", commandInSource, null); + commandInReceiver.Start(10, CommandReceived); + + // anycast queue for the server to receive security events from clients + Source securityInSource = new Source + { + Address = securityInQueue, + Capabilities = new Symbol[] { new Symbol("queue") } + }; + securityInReceiver = new ReceiverLink(amqpSession, "srt-game-server-security-receiver", securityInSource, null); + securityInReceiver.Start(10, SecurityReceived); + + + // DEBUG stuff ///////////////////////////////////////////////////////////// + // we send commands to the COMMAND.IN from the debug UI + Target commandInTarget = new Target + { + Address = commandInQueue, + Capabilities = new Symbol[] { new Symbol("queue") } + }; + commandInSender = new SenderLink(amqpSession, "srt-game-server-debug-command-sender", commandInTarget, null); + + // we send security messages to SECURITY.IN from the debug UI + Target securityInTarget = new Target + { + Address = securityInQueue, + Capabilities = new Symbol[] { new Symbol("queue") } + }; + securityInSender = new SenderLink(amqpSession, "srt-game-server-debug-security-sender", securityInTarget, null); + + _serilogger.Information("AMQPserver.cs: Finished initializing AMQP connection"); } public void LoadConfig() { - var serverConfig = new ConfigFile(); - Godot.Error err = serverConfig.Load("Config/server.cfg"); + var serverConfig = new ConfigFile(); + Godot.Error err = serverConfig.Load("Config/server.cfg"); - // if the file was loaded successfully, read the vars - if (err == Godot.Error.Ok) - { - url = (String) serverConfig.GetValue("amqp","server_string"); - } - // pull values from env -- will get nulls if any vars are not set - String envAMQPUrl = System.Environment.GetEnvironmentVariable("SRT_AMQP_URL"); + // if the file was loaded successfully, read the vars + if (err == Godot.Error.Ok) + { + url = (String) serverConfig.GetValue("amqp","server_string"); + } + // pull values from env -- will get nulls if any vars are not set + String envAMQPUrl = System.Environment.GetEnvironmentVariable("SRT_AMQP_URL"); - if (envAMQPUrl != null) url = envAMQPUrl; + if (envAMQPUrl != null) url = envAMQPUrl; - _serilogger.Information($"AMQPServer.cs: AMQP url is {url}"); + _serilogger.Information($"AMQPServer.cs: AMQP url is {url}"); } // Called when the node enters the scene tree for the first time. public override void _Ready() { - MyServer = GetNode("/root/Server"); - _serilogger = MyServer._serilogger; - LoadConfig(); - InitializeAMQP(); + MyServer = GetNode("/root/Server"); + _serilogger = MyServer._serilogger; + LoadConfig(); + InitializeAMQP(); } // // Called every frame. 'delta' is the elapsed time since the previous frame. diff --git a/Assets/Fonts/RedHatDisplay-Bold.ttf.import b/Assets/Fonts/RedHatDisplay-Bold.ttf.import new file mode 100644 index 0000000..76fb01c --- /dev/null +++ b/Assets/Fonts/RedHatDisplay-Bold.ttf.import @@ -0,0 +1,33 @@ +[remap] + +importer="font_data_dynamic" +type="FontFile" +uid="uid://ddlj3n66imcl8" +path="res://.godot/imported/RedHatDisplay-Bold.ttf-e1dcbec6b90d2c43121204c0d1c08eca.fontdata" + +[deps] + +source_file="res://Assets/Fonts/RedHatDisplay-Bold.ttf" +dest_files=["res://.godot/imported/RedHatDisplay-Bold.ttf-e1dcbec6b90d2c43121204c0d1c08eca.fontdata"] + +[params] + +Rendering=null +antialiasing=1 +generate_mipmaps=false +multichannel_signed_distance_field=false +msdf_pixel_range=8 +msdf_size=48 +allow_system_fallback=true +force_autohinter=false +hinting=1 +subpixel_positioning=1 +oversampling=0.0 +Fallbacks=null +fallbacks=[] +Compress=null +compress=true +preload=[] +language_support={} +script_support={} +opentype_features={} diff --git a/Assets/Fonts/RedHatText-Italic.ttf.import b/Assets/Fonts/RedHatText-Italic.ttf.import new file mode 100644 index 0000000..0df7536 --- /dev/null +++ b/Assets/Fonts/RedHatText-Italic.ttf.import @@ -0,0 +1,33 @@ +[remap] + +importer="font_data_dynamic" +type="FontFile" +uid="uid://bjs422uhj0nlv" +path="res://.godot/imported/RedHatText-Italic.ttf-5442a7b92e90f81dfa98b0f90cbbf3fd.fontdata" + +[deps] + +source_file="res://Assets/Fonts/RedHatText-Italic.ttf" +dest_files=["res://.godot/imported/RedHatText-Italic.ttf-5442a7b92e90f81dfa98b0f90cbbf3fd.fontdata"] + +[params] + +Rendering=null +antialiasing=1 +generate_mipmaps=false +multichannel_signed_distance_field=false +msdf_pixel_range=8 +msdf_size=48 +allow_system_fallback=true +force_autohinter=false +hinting=1 +subpixel_positioning=1 +oversampling=0.0 +Fallbacks=null +fallbacks=[] +Compress=null +compress=true +preload=[] +language_support={} +script_support={} +opentype_features={} diff --git a/Assets/Fonts/RedHatText-Regular.ttf.import b/Assets/Fonts/RedHatText-Regular.ttf.import new file mode 100644 index 0000000..1e2c7de --- /dev/null +++ b/Assets/Fonts/RedHatText-Regular.ttf.import @@ -0,0 +1,33 @@ +[remap] + +importer="font_data_dynamic" +type="FontFile" +uid="uid://c4x2m5t0ax0nk" +path="res://.godot/imported/RedHatText-Regular.ttf-26d51c6f384dae5a588f82cd577f5d85.fontdata" + +[deps] + +source_file="res://Assets/Fonts/RedHatText-Regular.ttf" +dest_files=["res://.godot/imported/RedHatText-Regular.ttf-26d51c6f384dae5a588f82cd577f5d85.fontdata"] + +[params] + +Rendering=null +antialiasing=1 +generate_mipmaps=false +multichannel_signed_distance_field=false +msdf_pixel_range=8 +msdf_size=48 +allow_system_fallback=true +force_autohinter=false +hinting=1 +subpixel_positioning=1 +oversampling=0.0 +Fallbacks=null +fallbacks=[] +Compress=null +compress=true +preload=[] +language_support={} +script_support={} +opentype_features={} diff --git a/CSLogger.cs b/CSLogger.cs index 8117a6c..f76495e 100644 --- a/CSLogger.cs +++ b/CSLogger.cs @@ -2,7 +2,7 @@ using Godot; using System; -public class CSLogger : Node +public partial class CSLogger : Node { Node gdlogger; diff --git a/Player.tscn b/Player.tscn index c2f6c4c..8f06a23 100644 --- a/Player.tscn +++ b/Player.tscn @@ -1,10 +1,10 @@ [gd_scene load_steps=4 format=2] -[ext_resource path="res://images/ship.png" type="Texture" id=1] +[ext_resource path="res://images/ship.png" type="Texture2D" id=1] [ext_resource path="res://PlayerShip.cs" type="Script" id=2] [sub_resource type="RectangleShape2D" id=1] -extents = Vector2( 39.5, 41.5 ) +size = Vector2( 39.5, 41.5 ) [node name="ShipThings" type="Area2D"] @@ -15,10 +15,10 @@ shape = SubResource( 1 ) [node name="Stat" type="Node2D" parent="."] [node name="IDLabel" type="Label" parent="Stat"] -margin_left = -35.0 -margin_top = 28.0 -margin_right = 35.0 -margin_bottom = 42.0 +offset_left = -35.0 +offset_top = 28.0 +offset_right = 35.0 +offset_bottom = 42.0 grow_horizontal = 2 text = "UUIDUUID" align = 1 @@ -27,10 +27,10 @@ __meta__ = { } [node name="LinearVelocity" type="Label" parent="Stat"] -margin_left = -33.0 -margin_top = 41.0 -margin_right = 33.0 -margin_bottom = 55.0 +offset_left = -33.0 +offset_top = 41.0 +offset_right = 33.0 +offset_bottom = 55.0 text = "LinVel" align = 1 __meta__ = { @@ -38,10 +38,10 @@ __meta__ = { } [node name="AngularVelocity" type="Label" parent="Stat"] -margin_left = -33.0 -margin_top = 53.0 -margin_right = 33.0 -margin_bottom = 67.0 +offset_left = -33.0 +offset_top = 53.0 +offset_right = 33.0 +offset_bottom = 67.0 text = "AngVel" align = 1 __meta__ = { @@ -49,10 +49,10 @@ __meta__ = { } [node name="HitPoints" type="Label" parent="Stat"] -margin_left = -33.0 -margin_top = 68.0 -margin_right = 33.0 -margin_bottom = 82.0 +offset_left = -33.0 +offset_top = 68.0 +offset_right = 33.0 +offset_bottom = 82.0 text = "HP" align = 1 __meta__ = { @@ -60,10 +60,10 @@ __meta__ = { } [node name="Position" type="Label" parent="Stat"] -margin_left = -33.0 -margin_top = 81.0 -margin_right = 33.0 -margin_bottom = 95.0 +offset_left = -33.0 +offset_top = 81.0 +offset_right = 33.0 +offset_bottom = 95.0 text = "Position" align = 1 __meta__ = { @@ -71,25 +71,25 @@ __meta__ = { } [node name="Hex" type="Label" parent="Stat"] -margin_left = -33.0 -margin_top = 93.0 -margin_right = 33.0 -margin_bottom = 107.0 +offset_left = -33.0 +offset_top = 93.0 +offset_right = 33.0 +offset_bottom = 107.0 text = "MyHex" align = 1 __meta__ = { "_edit_use_anchors_": false } -[node name="PlayerShip" type="KinematicBody2D" parent="."] +[node name="PlayerShip" type="CharacterBody2D" parent="."] script = ExtResource( 2 ) -[node name="Sprite" type="Sprite" parent="PlayerShip"] +[node name="Sprite2D" type="Sprite2D" parent="PlayerShip"] scale = Vector2( 0.25, 0.25 ) texture = ExtResource( 1 ) [node name="ShipHitBox" type="CollisionPolygon2D" parent="PlayerShip"] -polygon = PoolVector2Array( -5, -31, 5, -31, 11, -10, 16, 5, 26, 10, 29, 28, -17, 28, -28, 28, -28, 15, -25, 10, -16, 4 ) +polygon = PackedVector2Array( -5, -31, 5, -31, 11, -10, 16, 5, 26, 10, 29, 28, -17, 28, -28, 28, -28, 15, -25, 10, -16, 4 ) [node name="RemoteTransform2D" type="RemoteTransform2D" parent="PlayerShip"] remote_path = NodePath("../../Stat") diff --git a/PlayerShip.cs b/PlayerShip.cs index 172644f..278d7c6 100644 --- a/PlayerShip.cs +++ b/PlayerShip.cs @@ -3,23 +3,23 @@ using System.Collections; using redhatgamedev.srt.v1; -public class PlayerShip : KinematicBody2D +public partial class PlayerShip : CharacterBody2D { public Serilog.Core.Logger _serilogger; - public float Thrust = 1f; // effective acceleration + public double Thrust = 1f; // effective acceleration - public float MaxSpeed = 5; + public double MaxSpeed = 5; - public float StopThreshold = 10f; + public double StopThreshold = 10f; - public float GoThreshold = 90f; + public double GoThreshold = 90f; - public float CurrentVelocity = 0; + public double CurrentVelocity = 0; - public float RotationThrust = 1.5f; + public double RotationThrust = 1.5f; - public float CurrentRotation = 0; + public double CurrentRotation = 0; public int HitPoints = 100; @@ -41,7 +41,7 @@ public class PlayerShip : KinematicBody2D // relevant when two players are very close to one another and // prevents missile spamming float MissileReloadTime = 2; - float MissileReloadCountdown; + double MissileReloadCountdown; bool MissileReady = true; public int MissileDamage = 25; @@ -65,256 +65,261 @@ public class PlayerShip : KinematicBody2D // used by the debug UI to show which player has the camera focus public bool isFocused = false; - Sprite shipSprite; + Sprite2D shipSprite; public GameEvent CreatePlayerGameEventBuffer(GameEvent.GameEventType eventType) { - //EntityGameEventBuffer egeb = new EntityGameEventBuffer(); - GameEvent gameEvent = new GameEvent(); + //EntityGameEventBuffer egeb = new EntityGameEventBuffer(); + GameEvent gameEvent = new GameEvent(); - //egeb.Type = BufferType; - gameEvent.game_event_type = eventType; + //egeb.Type = BufferType; + gameEvent.game_event_type = eventType; - //egeb.objectType = EntityGameEventBuffer.EntityGameEventBufferObjectType.Player; - gameEvent.game_object_type = GameEvent.GameObjectType.GameObjectTypePlayer; + //egeb.objectType = EntityGameEventBuffer.EntityGameEventBufferObjectType.Player; + gameEvent.game_object_type = GameEvent.GameObjectType.GameObjectTypePlayer; - //egeb.Uuid = uuid; - gameEvent.Uuid = uuid; + //egeb.Uuid = uuid; + gameEvent.Uuid = uuid; - //Box2d.PbBody body = new Box2d.PbBody(); - //body.Type = Box2d.PbBodyType.Kinematic; // not sure if this should maybe be static + //Box2d.PbBody body = new Box2d.PbBody(); + //body.Type = Box2d.PbBodyType.Kinematic; // not sure if this should maybe be static - // need to use the GlobalPosition because the ship node ends up being offset - // from the parent Node2D - //body.Position = new Box2d.PbVec2 - // { - // X = GlobalPosition.x, - // Y = GlobalPosition.y - // }; - gameEvent.PositionX = (int)GlobalPosition.x; - gameEvent.PositionY = (int)GlobalPosition.y; + // need to use the GlobalPosition because the ship node ends up being offset + // from the parent Node2D + //body.Position = new Box2d.PbVec2 + // { + // X = GlobalPosition.x, + // Y = GlobalPosition.y + // }; + gameEvent.PositionX = (int)GlobalPosition.X; + gameEvent.PositionY = (int)GlobalPosition.Y; - //body.Angle = RotationDegrees; - gameEvent.Angle = RotationDegrees; + //body.Angle = RotationDegrees; + gameEvent.Angle = RotationDegrees; - //body.AbsoluteVelocity = CurrentVelocity; - gameEvent.AbsoluteVelocity = CurrentVelocity; - - gameEvent.HitPoints = HitPoints; + //body.AbsoluteVelocity = CurrentVelocity; + gameEvent.AbsoluteVelocity = (float)CurrentVelocity; + + gameEvent.HitPoints = HitPoints; - return gameEvent; + return gameEvent; } public void ExpireMissile() { - _serilogger.Verbose($"PlayerShip.cs: removing missile {MyMissile.uuid} belongs to {MyMissile.MyPlayer.uuid}"); - MyServer.RemoveMissile(MyMissile); - MyMissile = null; + _serilogger.Verbose($"PlayerShip.cs: removing missile {MyMissile.uuid} belongs to {MyMissile.MyPlayer.uuid}"); + MyServer.RemoveMissile(MyMissile); + MyMissile = null; } public void FireMissile(string missileUUID = null) { - // only one missile allowed for now - if (MyMissile != null) - { - _serilogger.Debug($"PlayerShip.cs: Missile for player {uuid} exists - skipping"); - return; - } - - // check if reload complete - if (MissileReady == false) - { - _serilogger.Debug($"PlayerShip.cs: player {uuid} not done with reload - skipping"); - return; - } - - MyMissile = (SpaceMissile)MissileScene.Instance(); - - // TODO: need to check for UUID collision - _serilogger.Debug($"PlayerShip.cs: Supplied UUID is {missileUUID}"); - if (missileUUID != null) - // use the suggested UUID - { MyMissile.uuid = missileUUID; } - else - { MyMissile.uuid = Guid.NewGuid().ToString(); } - - _serilogger.Debug($"PlayerShip.cs: Missile UUID is {MyMissile.uuid}"); - - // missile should point in the same direction as the ship - MyMissile.Rotation = Rotation; - - // TODO: need to offset this to the front of the ship - // start at our position - MyMissile.Position = GlobalPosition; - - // negative direction is "up" - Vector2 offset = new Vector2(0, -60); - - // rotate the offset to match the current ship heading - offset = offset.Rotated(Rotation); - MyMissile.Position = MyMissile.Position + offset; - - // set missile's parameters based on current modifiers - MyMissile.MissileSpeed = MissileSpeed; - MyMissile.MissileLife = MissileLife; - MyMissile.MissileDamage = MissileDamage; - - // this is a poop way to do this - MyMissile.MyPlayer = this; - - // send the missile creation message - _serilogger.Debug($"PlayerShip.cs: creating missile {MyMissile.uuid} belongs to {MyMissile.MyPlayer.uuid}"); - Node rootNode = GetNode("/root"); - rootNode.AddChild(MyMissile); - MyServer.InstantiateMissile(MyMissile); - - // set the reload countdown - MissileReloadCountdown = MissileReloadTime; - MissileReady = false; + // only one missile allowed for now + if (MyMissile != null) + { + _serilogger.Debug($"PlayerShip.cs: Missile for player {uuid} exists - skipping"); + return; + } + + // check if reload complete + if (MissileReady == false) + { + _serilogger.Debug($"PlayerShip.cs: player {uuid} not done with reload - skipping"); + return; + } + + //MyMissile = (SpaceMissile)MissileScene.Instance(); + //3to4 + ulong iid = MissileScene.GetInstanceId(); + GodotObject go = PackedScene.InstanceFromId(iid); + MyMissile = (SpaceMissile)go; + + // TODO: need to check for UUID collision + _serilogger.Debug($"PlayerShip.cs: Supplied UUID is {missileUUID}"); + if (missileUUID != null) + // use the suggested UUID + { MyMissile.uuid = missileUUID; } + else + { MyMissile.uuid = Guid.NewGuid().ToString(); } + + _serilogger.Debug($"PlayerShip.cs: Missile UUID is {MyMissile.uuid}"); + + // missile should point in the same direction as the ship + MyMissile.Rotation = Rotation; + + // TODO: need to offset this to the front of the ship + // start at our position + MyMissile.Position = GlobalPosition; + + // negative direction is "up" + Vector2 offset = new Vector2(0, -60); + + // rotate the offset to match the current ship heading + offset = offset.Rotated(Rotation); + MyMissile.Position = MyMissile.Position + offset; + + // set missile's parameters based on current modifiers + MyMissile.MissileSpeed = MissileSpeed; + MyMissile.MissileLife = MissileLife; + MyMissile.MissileDamage = MissileDamage; + + // this is a poop way to do this + MyMissile.MyPlayer = this; + + // send the missile creation message + _serilogger.Debug($"PlayerShip.cs: creating missile {MyMissile.uuid} belongs to {MyMissile.MyPlayer.uuid}"); + Node rootNode = GetNode("/root"); + rootNode.AddChild(MyMissile); + MyServer.InstantiateMissile(MyMissile); + + // set the reload countdown + MissileReloadCountdown = MissileReloadTime; + MissileReady = false; } // Called when the node enters the scene tree for the first time. public override void _Ready() { - // initialize the logging configuration - MyServer = GetNode("/root/Server"); - _serilogger = MyServer._serilogger; + // initialize the logging configuration + MyServer = GetNode("/root/Server"); + _serilogger = MyServer._serilogger; - Node2D shipThing = (Node2D)GetParent(); - Label playerIDLabel = (Label)shipThing.GetNode("Stat/IDLabel"); + Node2D shipThing = (Node2D)GetParent(); + Label playerIDLabel = (Label)shipThing.GetNode("Stat/IDLabel"); - // TODO: deal with really long UUIDs - playerIDLabel.Text = uuid; + // TODO: deal with really long UUIDs + playerIDLabel.Text = uuid; - myCamera = GetNode("Camera2D"); - shipSprite = GetNode("Sprite"); + myCamera = GetNode("Camera2D"); + shipSprite = GetNode("Sprite2D"); - // TODO: we are doing instant rotation so probably should rename this - angularVelocityLabel = (Label)shipThing.GetNode("Stat/AngularVelocity"); - linearVelocityLabel = (Label)shipThing.GetNode("Stat/LinearVelocity"); - hitPointsLabel = (Label)shipThing.GetNode("Stat/HitPoints"); - positionLabel = (Label)shipThing.GetNode("Stat/Position"); - hexLabel = (Label)shipThing.GetNode("Stat/Hex"); + // TODO: we are doing instant rotation so probably should rename this + angularVelocityLabel = (Label)shipThing.GetNode("Stat/AngularVelocity"); + linearVelocityLabel = (Label)shipThing.GetNode("Stat/LinearVelocity"); + hitPointsLabel = (Label)shipThing.GetNode("Stat/HitPoints"); + positionLabel = (Label)shipThing.GetNode("Stat/Position"); + hexLabel = (Label)shipThing.GetNode("Stat/Hex"); - theLayout = MyServer.HexLayout; + theLayout = MyServer.HexLayout; } public void TakeDamage(int Damage) { - _serilogger.Debug($"PlayerShip.cs: {uuid}: Taking damage: {Damage}"); - HitPoints -= Damage; - _serilogger.Debug($"PlayerShip.cs: {uuid}: Hitpoints: {HitPoints}"); - - if (HitPoints <= 0) - { - _serilogger.Debug($"PlayerShip.cs: Hitpoints zeroed for {uuid}! Remove the player!"); - QueuedForRemoval = true; - RemovePlayer(); - } + _serilogger.Debug($"PlayerShip.cs: {uuid}: Taking damage: {Damage}"); + HitPoints -= Damage; + _serilogger.Debug($"PlayerShip.cs: {uuid}: Hitpoints: {HitPoints}"); + + if (HitPoints <= 0) + { + _serilogger.Debug($"PlayerShip.cs: Hitpoints zeroed for {uuid}! Remove the player!"); + QueuedForRemoval = true; + RemovePlayer(); + } } void RemovePlayer() { - _serilogger.Debug($"PlayerShip.cs: Enqueuing player removal: {uuid}"); - MyServer.PlayerRemoveQueue.Enqueue(uuid); + _serilogger.Debug($"PlayerShip.cs: Enqueuing player removal: {uuid}"); + MyServer.PlayerRemoveQueue.Enqueue(uuid); } - void CheckMissileReload(float delta) + void CheckMissileReload(double delta) { - // nothing to check if we are already reloaded - if (MissileReady == true) { return; } - - MissileReloadCountdown -= delta; - if (MissileReloadCountdown <= 0) - { - _serilogger.Debug($"PlayerShip.cs: player {uuid} missile reload countdown complete"); - MissileReady = true; - } + // nothing to check if we are already reloaded + if (MissileReady == true) { return; } + + MissileReloadCountdown -= delta; + if (MissileReloadCountdown <= 0) + { + _serilogger.Debug($"PlayerShip.cs: player {uuid} missile reload countdown complete"); + MissileReady = true; + } } public void UpdateFocused() { - if (isFocused) shipSprite.Modulate = new Color(4,4,4,1); - else shipSprite.Modulate = new Color(1,1,1,1); + if (isFocused) shipSprite.Modulate = new Color(4,4,4,1); + else shipSprite.Modulate = new Color(1,1,1,1); } - public override void _Process(float delta) + public override void _Process(double delta) { - if (QueuedForRemoval) return; + if (QueuedForRemoval) return; - if (shipThing == null) shipThing = (Node2D)GetParent(); + if (shipThing == null) shipThing = (Node2D)GetParent(); - // figure out the hex from the pixel position - FractionalHex theHex = theLayout.PixelToHex(new Point(GlobalPosition.x, GlobalPosition.y)); - hexLabel.Text = $"q: {theHex.HexRound().q}, r: {theHex.HexRound().r}, s: {theHex.HexRound().s}"; + // figure out the hex from the pixel position + FractionalHex theHex = theLayout.PixelToHex(new Point(GlobalPosition.X, GlobalPosition.Y)); + hexLabel.Text = $"q: {theHex.HexRound().q}, r: {theHex.HexRound().r}, s: {theHex.HexRound().s}"; - angularVelocityLabel.Text = $"Rot: {RotationDegrees}"; - linearVelocityLabel.Text = $"Vel: {CurrentVelocity}"; - hitPointsLabel.Text = $"HP: {HitPoints}"; - positionLabel.Text = $"X: {GlobalPosition.x} Y: {GlobalPosition.y}"; + angularVelocityLabel.Text = $"Rot: {RotationDegrees}"; + linearVelocityLabel.Text = $"Vel: {CurrentVelocity}"; + hitPointsLabel.Text = $"HP: {HitPoints}"; + positionLabel.Text = $"X: {GlobalPosition.X} Y: {GlobalPosition.Y}"; - CheckMissileReload(delta); - UpdateFocused(); + CheckMissileReload(delta); + UpdateFocused(); } - public override void _PhysicsProcess(float delta) + public override void _PhysicsProcess(double delta) { - if (shipThing == null) shipThing = (Node2D)GetParent(); - - // somewhat based on: https://kidscancode.org/godot_recipes/2d/topdown_movement/ - // "rotate and move" / asteroids-style-ish - - float rotation_dir = 0; // in case we need it - - _serilogger.Verbose($"{uuid}: handling physics"); - if (MovementQueue.Count > 0) - { - Vector2 thisMovement = (Vector2)MovementQueue.Dequeue(); - _serilogger.Verbose($"UUID: {uuid} X: {thisMovement.x} Y: {thisMovement.y}"); - - if (thisMovement.y > 0) - { - CurrentVelocity = Mathf.Lerp(CurrentVelocity, MaxSpeed, Thrust * delta); - - // max out speed when velocity gets above threshold for same reason - if (CurrentVelocity > MaxSpeed * (GoThreshold/100)) { CurrentVelocity = MaxSpeed; } - } - - if (thisMovement.y < 0) - { - CurrentVelocity = Mathf.Lerp(CurrentVelocity, 0, Thrust * delta); - - // cut speed when velocity gets below threshold, otherwise LERPing - // results in never actually stopping. - if (CurrentVelocity < MaxSpeed * (StopThreshold/100)) { CurrentVelocity = 0; } - } - - if (thisMovement.x != 0) - { - rotation_dir = thisMovement.x; - } - - _serilogger.Verbose($"UUID: {uuid} Velocity: {CurrentVelocity}"); - - } - Vector2 velocity = -(Transform.y * CurrentVelocity); - _serilogger.Verbose($"UUID: {uuid} Vector X: {velocity.x} Y: {velocity.y} "); - Rotation += rotation_dir * RotationThrust * delta; - - // TODO: implement collision mechanics - MoveAndCollide(velocity); - - // TODO: need to adust the clamp when the starfield is lopsided in the early - // game - - // clamp the player to the starfield radius - Int32 starFieldRadiusPixels = MyServer.StarFieldRadiusPixels; - Vector2 currentGlobalPosition = GlobalPosition; - if (currentGlobalPosition.Length() > starFieldRadiusPixels) - { - Vector2 newPosition = starFieldRadiusPixels * currentGlobalPosition.Normalized(); - GlobalPosition = newPosition; - } + if (shipThing == null) shipThing = (Node2D)GetParent(); + + // somewhat based on: https://kidscancode.org/godot_recipes/2d/topdown_movement/ + // "rotate and move" / asteroids-style-ish + + double rotation_dir = 0; // in case we need it + + _serilogger.Verbose($"{uuid}: handling physics"); + if (MovementQueue.Count > 0) + { + Vector2 thisMovement = (Vector2)MovementQueue.Dequeue(); + _serilogger.Verbose($"UUID: {uuid} X: {thisMovement.X} Y: {thisMovement.Y}"); + + if (thisMovement.Y > 0) + { + CurrentVelocity = Mathf.Lerp(CurrentVelocity, MaxSpeed, Thrust * delta); + + // max out speed when velocity gets above threshold for same reason + if (CurrentVelocity > MaxSpeed * (GoThreshold/100)) { CurrentVelocity = MaxSpeed; } + } + + if (thisMovement.Y < 0) + { + CurrentVelocity = Mathf.Lerp(CurrentVelocity, 0, Thrust * delta); + + // cut speed when velocity gets below threshold, otherwise LERPing + // results in never actually stopping. + if (CurrentVelocity < MaxSpeed * (StopThreshold/100)) { CurrentVelocity = 0; } + } + + if (thisMovement.Y != 0) + { + rotation_dir = thisMovement.Y; + } + + _serilogger.Verbose($"UUID: {uuid} Velocity: {CurrentVelocity}"); + + } + + Vector2 velocity = -(Transform2D.Identity.Y * (float)CurrentVelocity); + _serilogger.Verbose($"UUID: {uuid} Vector X: {velocity.X} Y: {velocity.Y} "); + Rotation += (float)(rotation_dir * RotationThrust * delta); + + // TODO: implement collision mechanics + MoveAndCollide(velocity); + + // TODO: need to adust the clamp when the starfield is lopsided in the early + // game + + // clamp the player to the starfield radius + Int32 starFieldRadiusPixels = MyServer.StarFieldRadiusPixels; + Vector2 currentGlobalPosition = GlobalPosition; + if (currentGlobalPosition.Length() > starFieldRadiusPixels) + { + Vector2 newPosition = starFieldRadiusPixels * currentGlobalPosition.Normalized(); + GlobalPosition = newPosition; + } } } diff --git a/Sector.cs b/Sector.cs index bb0ae3b..8435e57 100644 --- a/Sector.cs +++ b/Sector.cs @@ -1,7 +1,7 @@ using Godot; using System; -public class Sector : Node2D +public partial class Sector : Node2D { public string SectorLabel = "x,x"; diff --git a/Sector.tscn b/Sector.tscn index 6cdf2c7..8f21ab9 100644 --- a/Sector.tscn +++ b/Sector.tscn @@ -8,14 +8,14 @@ script = ExtResource( 1 ) [node name="SectorPolygon" type="Polygon2D" parent="."] color = Color( 1, 1, 1, 0.27451 ) -polygon = PoolVector2Array( -12.5, 21.6506, 12.5, 21.6506, 25, 0, 12.5, -21.6506, -12.5, -21.6506, -25, 0 ) +polygon = PackedVector2Array( -12.5, 21.6506, 12.5, 21.6506, 25, 0, 12.5, -21.6506, -12.5, -21.6506, -25, 0 ) [node name="SectorLabel" type="Label" parent="."] -margin_left = -16.0 -margin_top = -18.0 -margin_right = 64.0 -margin_bottom = 63.0 -rect_scale = Vector2( 0.4, 0.4 ) +offset_left = -16.0 +offset_top = -18.0 +offset_right = 64.0 +offset_bottom = 63.0 +scale = Vector2( 0.4, 0.4 ) theme = ExtResource( 2 ) text = "x,x" align = 1 diff --git a/Server.cs b/Server.cs index e4451bb..4910eea 100644 --- a/Server.cs +++ b/Server.cs @@ -4,10 +4,10 @@ using redhatgamedev.srt.v1; using Serilog; -public class Server : Node +public partial class Server : Node { int DebugUIRefreshTime = 1; // 1000ms = 1sec - float DebugUIRefreshTimer = 0; + double DebugUIRefreshTimer = 0.0f; Random rnd = new Random(); @@ -17,7 +17,8 @@ public class Server : Node AMQPserver MessageInterface; - [Export] + //[Export] + //3to4 Dictionary playerObjects = new Dictionary(); // the "width" of a hex is 2 * size @@ -34,10 +35,12 @@ public class Server : Node // the sector map will only store the number of players in each sector // it only gets updated when a new player joins - [Export] + //[Export] + //3to4 Dictionary sectorMap = new Dictionary(); - [Export] + //[Export] + //3to4 Dictionary sectorNodes = new Dictionary(); [Export] @@ -99,29 +102,29 @@ public class Server : Node void SendGameUpdates() { - _serilogger.Verbose("Server.cs: Sending updates about game state to clients"); - - Godot.Collections.Array players = _GetNodesFromGroup("player_ships"); - foreach (PlayerShip player in players) - { - _serilogger.Verbose($"Server.cs: Sending update for player: {player.uuid}"); - // create the buffer for the specific player - GameEvent gameEvent = player.CreatePlayerGameEventBuffer(GameEvent.GameEventType.GameEventTypeUpdate); - - // send the event for the player - MessageInterface.SendGameEvent(gameEvent); - } - - // TODO: we never send a create message for the missile - foreach (SpaceMissile missile in GetTree().GetNodesInGroup("missiles")) - { - _serilogger.Verbose($"Server.cs: Processing missile: {missile.uuid}"); - // create the buffer for the missile - GameEvent gameEvent = missile.CreateMissileGameEventBuffer(GameEvent.GameEventType.GameEventTypeUpdate, missile.MyPlayer.uuid); - - // send the buffer for the missile - MessageInterface.SendGameEvent(gameEvent); - } + _serilogger.Verbose("Server.cs: Sending updates about game state to clients"); + + Godot.Collections.Array players = _GetNodesFromGroup("player_ships"); + foreach (PlayerShip player in players) + { + _serilogger.Verbose($"Server.cs: Sending update for player: {player.uuid}"); + // create the buffer for the specific player + GameEvent gameEvent = player.CreatePlayerGameEventBuffer(GameEvent.GameEventType.GameEventTypeUpdate); + + // send the event for the player + MessageInterface.SendGameEvent(gameEvent); + } + + // TODO: we never send a create message for the missile + foreach (SpaceMissile missile in GetTree().GetNodesInGroup("missiles")) + { + _serilogger.Verbose($"Server.cs: Processing missile: {missile.uuid}"); + // create the buffer for the missile + GameEvent gameEvent = missile.CreateMissileGameEventBuffer(GameEvent.GameEventType.GameEventTypeUpdate, missile.MyPlayer.uuid); + + // send the buffer for the missile + MessageInterface.SendGameEvent(gameEvent); + } } // called from the player model @@ -130,465 +133,476 @@ void SendGameUpdates() // TODO: this seems to assume all removes are destroys, but what about simple leaves? public void RemovePlayer(String UUID) { - _serilogger.Debug($"Server.cs: Removing player: {UUID}"); - Node2D thePlayerToRemove = playerObjects[UUID]; - PlayerShip thePlayer = thePlayerToRemove.GetNode("PlayerShip"); + _serilogger.Debug($"Server.cs: Removing player: {UUID}"); + Node2D thePlayerToRemove = playerObjects[UUID]; + PlayerShip thePlayer = thePlayerToRemove.GetNode("PlayerShip"); - // create the buffer for the specific player and send it - GameEvent gameEvent = thePlayer.CreatePlayerGameEventBuffer(GameEvent.GameEventType.GameEventTypeDestroy); + // create the buffer for the specific player and send it + GameEvent gameEvent = thePlayer.CreatePlayerGameEventBuffer(GameEvent.GameEventType.GameEventTypeDestroy); - // TODO: should this get wrapped with a try or something? - playerObjects.Remove(UUID); - thePlayerToRemove.QueueFree(); + // TODO: should this get wrapped with a try or something? + playerObjects.Remove(UUID); + thePlayerToRemove.QueueFree(); - // send the player create event message - MessageInterface.SendGameEvent(gameEvent); + // send the player create event message + MessageInterface.SendGameEvent(gameEvent); } public void RemoveMissile(SpaceMissile missile) { - _serilogger.Debug($"Server.cs: Removing missile: {missile.uuid}"); + _serilogger.Debug($"Server.cs: Removing missile: {missile.uuid}"); - // TODO: should this get wrapped with a try or something? - missile.QueueFree(); + // TODO: should this get wrapped with a try or something? + missile.QueueFree(); - // create the buffer for the specific player and send it - GameEvent gameEvent = missile.CreateMissileGameEventBuffer(GameEvent.GameEventType.GameEventTypeDestroy, missile.MyPlayer.uuid); + // create the buffer for the specific player and send it + GameEvent gameEvent = missile.CreateMissileGameEventBuffer(GameEvent.GameEventType.GameEventTypeDestroy, missile.MyPlayer.uuid); - // send the player create event message - MessageInterface.SendGameEvent(gameEvent); + // send the player create event message + MessageInterface.SendGameEvent(gameEvent); } Hex TraverseSectors() { - Hex theCenter = new Hex(0, 0, 0); - _serilogger.Debug($"Server.cs: Traversing the sectors"); - - // based around the function from - // https://www.redblobgames.com/grids/hexagons/#rings - - // need to iterate over all the rings - for (int currentRing = 1; currentRing <= RingRadius; currentRing++) - { - _serilogger.Debug($"Server.cs: Traversing ring {currentRing}"); - // pick the 0th sector in a ring - Hex theSector = theCenter.Add(Hex.directions[4].Scale(currentRing)); - _serilogger.Debug($"Server.cs: starting with sector {theSector.q},{theSector.r}"); - - // traverse the ring - for (int i = 0; i < 6; i++) - { - for (int j = 0; j < currentRing; j++) - { - string theKey = $"{theSector.q},{theSector.r}"; - _serilogger.Debug($"Server.cs: Checking sector {theKey}"); - if (sectorMap.ContainsKey(theKey)) - { - // the sector map has the sector we're looking at, so verify how many - // players are in it. if there are less than two players, use it. - if (sectorMap[theKey] < 2) - { - _serilogger.Debug($"Server.cs: Less than two players ({sectorMap[theKey]}) in {theKey}, so choosing this one"); - return theSector; - } - } - else - { - // the sector map doesn't have the key for the sector we're looking - // at. this means the sector definitely has zero players in it. - _serilogger.Debug($"Server.cs: {theKey} not found in sectorMap, so choosing this one"); - return theSector; - } - - // if we get here, it means that the current sector is full, so move - // to the next neighbor - _serilogger.Debug($"Server.cs: {theKey} is full with {sectorMap[theKey]} players, moving on"); - theSector = theSector.Neighbor(i); - } - } - } - - // we got to the end of the rings without finding a sector, so make a new - // ring and return that ring's first sector - - _serilogger.Debug($"Server.cs: Completed traversing ring {RingRadius}, incrementing and returning 0th sector of new ring"); - RingRadius++; - _serilogger.Debug($"Server.cs: New ringradius is {RingRadius}"); - Hex hexToReturn = theCenter.Add(Hex.directions[4].Scale(RingRadius)); - _serilogger.Debug($"Server.cs: 0th sector of new ring is {hexToReturn.q},{hexToReturn.r}"); - return hexToReturn; + Hex theCenter = new Hex(0, 0, 0); + _serilogger.Debug($"Server.cs: Traversing the sectors"); + + // based around the function from + // https://www.redblobgames.com/grids/hexagons/#rings + + // need to iterate over all the rings + for (int currentRing = 1; currentRing <= RingRadius; currentRing++) + { + _serilogger.Debug($"Server.cs: Traversing ring {currentRing}"); + // pick the 0th sector in a ring + Hex theSector = theCenter.Add(Hex.directions[4].Scale(currentRing)); + _serilogger.Debug($"Server.cs: starting with sector {theSector.q},{theSector.r}"); + + // traverse the ring + for (int i = 0; i < 6; i++) + { + for (int j = 0; j < currentRing; j++) + { + string theKey = $"{theSector.q},{theSector.r}"; + _serilogger.Debug($"Server.cs: Checking sector {theKey}"); + if (sectorMap.ContainsKey(theKey)) + { + // the sector map has the sector we're looking at, so verify how many + // players are in it. if there are less than two players, use it. + if (sectorMap[theKey] < 2) + { + _serilogger.Debug($"Server.cs: Less than two players ({sectorMap[theKey]}) in {theKey}, so choosing this one"); + return theSector; + } + } + else + { + // the sector map doesn't have the key for the sector we're looking + // at. this means the sector definitely has zero players in it. + _serilogger.Debug($"Server.cs: {theKey} not found in sectorMap, so choosing this one"); + return theSector; + } + + // if we get here, it means that the current sector is full, so move + // to the next neighbor + _serilogger.Debug($"Server.cs: {theKey} is full with {sectorMap[theKey]} players, moving on"); + theSector = theSector.Neighbor(i); + } + } + } + + // we got to the end of the rings without finding a sector, so make a new + // ring and return that ring's first sector + + _serilogger.Debug($"Server.cs: Completed traversing ring {RingRadius}, incrementing and returning 0th sector of new ring"); + RingRadius++; + _serilogger.Debug($"Server.cs: New ringradius is {RingRadius}"); + Hex hexToReturn = theCenter.Add(Hex.directions[4].Scale(RingRadius)); + _serilogger.Debug($"Server.cs: 0th sector of new ring is {hexToReturn.q},{hexToReturn.r}"); + return hexToReturn; } void UpdateSectorMap() { - // re-initilize the sector map - // clear the dictionary for rebuild - sectorMap.Clear(); - _serilogger.Debug($"Server.cs: Updating sector map"); - - // delete all of the drawn sectors unless there's no players - Godot.Collections.Array players = _GetNodesFromGroup("player_ships"); - if (players.Count != 0) { - _serilogger.Debug($"Server.cs: There are players in the player_ships group, so clearing the sector nodes"); - sectorNodes.Clear(); - foreach (Node sector in _GetNodesFromGroup("sectors")) - { - sector.QueueFree(); - } - } - - _serilogger.Debug($"Server.cs: Currently {players.Count} players in 'player_ships' group"); - foreach (PlayerShip player in players) - { - _serilogger.Debug($"Server.cs: Checking where {player.uuid} is in sector map"); - FractionalHex theHex = HexLayout.PixelToHex(new Point(player.GlobalPosition.x, player.GlobalPosition.y)); - Hex theRoundedHex = theHex.HexRound(); - - // the key can be axial coordinates - String theSectorKey = $"{theRoundedHex.q},{theRoundedHex.r}"; - _serilogger.Debug($"Server.cs: player {player.uuid} sector is {theSectorKey}"); - - // check if the key exists in the dict - if (sectorMap.ContainsKey(theSectorKey)) - { - // increment it if it does - sectorMap[theSectorKey] += 1; - _serilogger.Debug($"Server.cs: {theSectorKey}: {sectorMap[theSectorKey]}"); - } - else - { - // initialize it to 1 if it doesn't - _serilogger.Debug($"Server.cs: {theSectorKey} didn't exist, initializing to 1"); - sectorMap[theSectorKey] = 1; - _serilogger.Debug($"Server.cs: {theSectorKey}: {sectorMap[theSectorKey]}"); - } - } + // re-initilize the sector map + // clear the dictionary for rebuild + sectorMap.Clear(); + _serilogger.Debug($"Server.cs: Updating sector map"); + + // delete all of the drawn sectors unless there's no players + Godot.Collections.Array players = _GetNodesFromGroup("player_ships"); + if (players.Count != 0) { + _serilogger.Debug($"Server.cs: There are players in the player_ships group, so clearing the sector nodes"); + sectorNodes.Clear(); + foreach (Node sector in _GetNodesFromGroup("sectors")) + { + sector.QueueFree(); + } + } + + _serilogger.Debug($"Server.cs: Currently {players.Count} players in 'player_ships' group"); + foreach (PlayerShip player in players) + { + _serilogger.Debug($"Server.cs: Checking where {player.uuid} is in sector map"); + FractionalHex theHex = HexLayout.PixelToHex(new Point(player.GlobalPosition.X, player.GlobalPosition.Y)); + Hex theRoundedHex = theHex.HexRound(); + + // the key can be axial coordinates + String theSectorKey = $"{theRoundedHex.q},{theRoundedHex.r}"; + _serilogger.Debug($"Server.cs: player {player.uuid} sector is {theSectorKey}"); + + // check if the key exists in the dict + if (sectorMap.ContainsKey(theSectorKey)) + { + // increment it if it does + sectorMap[theSectorKey] += 1; + _serilogger.Debug($"Server.cs: {theSectorKey}: {sectorMap[theSectorKey]}"); + } + else + { + // initialize it to 1 if it doesn't + _serilogger.Debug($"Server.cs: {theSectorKey} didn't exist, initializing to 1"); + sectorMap[theSectorKey] = 1; + _serilogger.Debug($"Server.cs: {theSectorKey}: {sectorMap[theSectorKey]}"); + } + } } void DrawSectorMap() { - // recreate the sector nodes for all the present keys - _serilogger.Debug($"Server.cs: Iterating over sectormap's keys to place sector nodes"); - foreach (string sector in sectorMap.Keys) - { - _serilogger.Debug($"Server.cs: Current sector is {sector}"); - String[] sector_parts = sector.Split(','); - - // q + r + s must equal zero - int q = sector_parts[0].ToInt(); - int r = sector_parts[1].ToInt(); - int s = 0 - q - r; - _CreateSector(new Hex(q,r,s)); - } + // recreate the sector nodes for all the present keys + _serilogger.Debug($"Server.cs: Iterating over sectormap's keys to place sector nodes"); + foreach (string sector in sectorMap.Keys) + { + _serilogger.Debug($"Server.cs: Current sector is {sector}"); + String[] sector_parts = sector.Split(','); + + // q + r + s must equal zero + int q = sector_parts[0].ToInt(); + int r = sector_parts[1].ToInt(); + int s = 0 - q - r; + _CreateSector(new Hex(q,r,s)); + } } void DrawStarFieldRing() { - StarFieldRing.radius = StarFieldRadiusPixels; - StarFieldRing.Update(); + StarFieldRing.radius = StarFieldRadiusPixels; + //StarFieldRing.Update(); + //3to4 ? } public void InstantiateMissile(SpaceMissile missile) { - // this only sends the missile creation event buffer + // this only sends the missile creation event buffer - _serilogger.Debug($"Server.cs: Sending missile creation message for missile {missile.uuid} player {missile.MyPlayer.uuid}"); + _serilogger.Debug($"Server.cs: Sending missile creation message for missile {missile.uuid} player {missile.MyPlayer.uuid}"); - // create the protobuf for the player joining - GameEvent egeb = missile.CreateMissileGameEventBuffer(GameEvent.GameEventType.GameEventTypeCreate, missile.MyPlayer.uuid); + // create the protobuf for the player joining + GameEvent egeb = missile.CreateMissileGameEventBuffer(GameEvent.GameEventType.GameEventTypeCreate, missile.MyPlayer.uuid); - // send the missile create event message - MessageInterface.SendGameEvent(egeb); + // send the missile create event message + MessageInterface.SendGameEvent(egeb); } void InstantiatePlayer(String UUID) { - // Update the sector map in preparation for traversing the rings, expanding - // the radius, and etc. need to do this before adding the new player object - // because we don't know where that player will go until we traverse the - // existing sectors, and because the physics process will kick in as soon - // as the node is created - _serilogger.Debug($"Server.cs: Instantiating player {UUID}"); - UpdateSectorMap(); - - // start with the center - Hex theSector = new Hex(0, 0, 0); - - Area2D playerShipThingInstance = (Area2D)PlayerShipThing.Instance(); - PlayerShip newPlayer = playerShipThingInstance.GetNode("PlayerShip"); - newPlayer.uuid = UUID; - - // assign the configured values - newPlayer.Thrust = PlayerDefaultThrust; - newPlayer.MaxSpeed = PlayerDefaultMaxSpeed; - newPlayer.RotationThrust = PlayerDefaultRotationThrust; - newPlayer.HitPoints = PlayerDefaultHitPoints; - newPlayer.MissileSpeed = PlayerDefaultMissileSpeed; - newPlayer.MissileLife = PlayerDefaultMissileLife; - newPlayer.MissileDamage = PlayerDefaultMissileDamage; - - _serilogger.Debug($"Server.cs: Adding {UUID} to playerObjects"); - playerObjects.Add(UUID, playerShipThingInstance); - newPlayer.AddToGroup("player_ships"); - - _serilogger.Debug($"Server.cs: Current count of playerObjects: {playerObjects.Count}"); - - // if there are more than two players, it means we are now at the point - // where we have to start calculating ring things - if (playerObjects.Count > 2) - { - - // if the ring radius is zero, and we have more than two players, we need - // to increase it, otherwise things will already blow up - if (RingRadius == 0) - { - _serilogger.Debug($"Server.cs: playerObjects count > 2 and ringradius == 0 so incrementing"); - RingRadius++; - } - - // it's possible that we have insufficient players in sector 0,0,0, so - // check that first for funzos - - int qty; - if (sectorMap.TryGetValue("0,0", out qty)) - { - if (qty < 2) - { - // do nothing since we already assigned the sector to use to 0,0,0 - _serilogger.Debug($"Server.cs: Insufficient players in sector 0 so will add player there"); - } - else - { - theSector = TraverseSectors(); - } - } - } - - _serilogger.Debug($"Server.cs: Selected sector for player {UUID} is {theSector.q},{theSector.r}"); - - // increment whatever sector this new player is going into - string sector_key = theSector.q + "," + theSector.r; - - if (sectorMap.ContainsKey(sector_key)) - { - sectorMap[sector_key] += 1; - } - else - { - sectorMap[sector_key] = 1; - } - _serilogger.Debug($"Server.cs: Sector {theSector.q},{theSector.r} now has {sectorMap[sector_key]}"); - - // reset the starfield radius - should also move the center - _CalcStarFieldRadius(); - DrawStarFieldRing(); - - // now that the sector to insert the player has been selected, find its - // pixel center - Point theSectorCenter = HexLayout.HexToPixel(theSector); - _serilogger.Debug($"Server.cs: Center of selected sector: {theSectorCenter.x},{theSectorCenter.y}"); - - // TODO: need to ensure players are not on top of one another for real. we - // will spawn two players into a sector to start, so we should check if - // there's already a player in the sector first. if there is, we should - // place the new player equidistant from the already present player - - // badly randomize start position - int theMin = (int)(SectorSize * 0.3); - int xOffset = rnd.Next(-1 * theMin, theMin); - int yOffset = rnd.Next(-1 * theMin, theMin); - int finalX = (Int32)theSectorCenter.x + xOffset; - int finalY = (Int32)theSectorCenter.y + yOffset; - _serilogger.Debug($"Server.cs: Placing player at {finalX},{finalY}"); - - playerShipThingInstance.GlobalPosition = new Vector2(x: (Int32)theSectorCenter.x + xOffset, - y: (Int32)theSectorCenter.y + yOffset); - - // connect the ship thing input signal so that we can catch when a ship was clicked in the debug UI - playerShipThingInstance.Connect("input_event", this, "_on_ShipThings_input_event", new Godot.Collections.Array {newPlayer}); - - Players.AddChild(playerShipThingInstance); - _serilogger.Information($"Server.cs: Added player {UUID} instance!"); - - // create the protobuf for the player joining - GameEvent egeb = newPlayer.CreatePlayerGameEventBuffer(GameEvent.GameEventType.GameEventTypeCreate); - - // send the player create event message - MessageInterface.SendGameEvent(egeb); - DrawSectorMap(); + // Update the sector map in preparation for traversing the rings, expanding + // the radius, and etc. need to do this before adding the new player object + // because we don't know where that player will go until we traverse the + // existing sectors, and because the physics process will kick in as soon + // as the node is created + _serilogger.Debug($"Server.cs: Instantiating player {UUID}"); + UpdateSectorMap(); + + // start with the center + Hex theSector = new Hex(0, 0, 0); + + //Area2D playerShipThingInstance = (Area2D)PlayerShipThing.Instance(); + //3to4 + ulong iid = PlayerShipThing.GetInstanceId(); + GodotObject go = PackedScene.InstanceFromId(iid); + Area2D playerShipThingInstance = (Area2D)go; + PlayerShip newPlayer = playerShipThingInstance.GetNode("PlayerShip"); + newPlayer.uuid = UUID; + + // assign the configured values + newPlayer.Thrust = PlayerDefaultThrust; + newPlayer.MaxSpeed = PlayerDefaultMaxSpeed; + newPlayer.RotationThrust = PlayerDefaultRotationThrust; + newPlayer.HitPoints = PlayerDefaultHitPoints; + newPlayer.MissileSpeed = PlayerDefaultMissileSpeed; + newPlayer.MissileLife = PlayerDefaultMissileLife; + newPlayer.MissileDamage = PlayerDefaultMissileDamage; + + _serilogger.Debug($"Server.cs: Adding {UUID} to playerObjects"); + playerObjects.Add(UUID, playerShipThingInstance); + newPlayer.AddToGroup("player_ships"); + + _serilogger.Debug($"Server.cs: Current count of playerObjects: {playerObjects.Count}"); + + // if there are more than two players, it means we are now at the point + // where we have to start calculating ring things + if (playerObjects.Count > 2) + { + + // if the ring radius is zero, and we have more than two players, we need + // to increase it, otherwise things will already blow up + if (RingRadius == 0) + { + _serilogger.Debug($"Server.cs: playerObjects count > 2 and ringradius == 0 so incrementing"); + RingRadius++; + } + + // it's possible that we have insufficient players in sector 0,0,0, so + // check that first for funzos + + int qty; + if (sectorMap.TryGetValue("0,0", out qty)) + { + if (qty < 2) + { + // do nothing since we already assigned the sector to use to 0,0,0 + _serilogger.Debug($"Server.cs: Insufficient players in sector 0 so will add player there"); + } + else + { + theSector = TraverseSectors(); + } + } + } + + _serilogger.Debug($"Server.cs: Selected sector for player {UUID} is {theSector.q},{theSector.r}"); + + // increment whatever sector this new player is going into + string sector_key = theSector.q + "," + theSector.r; + + if (sectorMap.ContainsKey(sector_key)) + { + sectorMap[sector_key] += 1; + } + else + { + sectorMap[sector_key] = 1; + } + + _serilogger.Debug($"Server.cs: Sector {theSector.q},{theSector.r} now has {sectorMap[sector_key]}"); + + // reset the starfield radius - should also move the center + _CalcStarFieldRadius(); + DrawStarFieldRing(); + + // now that the sector to insert the player has been selected, find its + // pixel center + Point theSectorCenter = HexLayout.HexToPixel(theSector); + _serilogger.Debug($"Server.cs: Center of selected sector: {theSectorCenter.x},{theSectorCenter.y}"); + + // TODO: need to ensure players are not on top of one another for real. we + // will spawn two players into a sector to start, so we should check if + // there's already a player in the sector first. if there is, we should + // place the new player equidistant from the already present player + + // badly randomize start position + int theMin = (int)(SectorSize * 0.3); + int xOffset = rnd.Next(-1 * theMin, theMin); + int yOffset = rnd.Next(-1 * theMin, theMin); + int finalX = (Int32)theSectorCenter.x + xOffset; + int finalY = (Int32)theSectorCenter.y + yOffset; + _serilogger.Debug($"Server.cs: Placing player at {finalX},{finalY}"); + + playerShipThingInstance.GlobalPosition = new Vector2(x: (Int32)theSectorCenter.x + xOffset, + y: (Int32)theSectorCenter.y + yOffset); + + // connect the ship thing input signal so that we can catch when a ship was clicked in the debug UI + //3to4 + //playerShipThingInstance.Connect("input_event", new Callable(this, "_on_ShipThings_input_event"), new Godot.Collections.Array {newPlayer}); + //Godot.Collections.Array gca = new Godot.Collections.Array{ newPlayer }; + playerShipThingInstance.Connect("input_event", + new Callable(this, "_on_ShipThings_input_event"), + 0); // no GodotObject.ConnectFlags? + + Players.AddChild(playerShipThingInstance); + _serilogger.Information($"Server.cs: Added player {UUID} instance!"); + + // create the protobuf for the player joining + GameEvent egeb = newPlayer.CreatePlayerGameEventBuffer(GameEvent.GameEventType.GameEventTypeCreate); + + // send the player create event message + MessageInterface.SendGameEvent(egeb); + DrawSectorMap(); } void ProcessMoveCommand(Command cb) { - _serilogger.Verbose("Server.cs: Processing move command!"); + _serilogger.Verbose("Server.cs: Processing move command!"); - String uuid = cb.Uuid; - Node2D playerRoot; - if (playerObjects.TryGetValue(uuid, out playerRoot)) - { - // find the PlayerShip - PlayerShip movePlayer = playerRoot.GetNode("PlayerShip"); + String uuid = cb.Uuid; + Node2D playerRoot; + if (playerObjects.TryGetValue(uuid, out playerRoot)) + { + // find the PlayerShip + PlayerShip movePlayer = playerRoot.GetNode("PlayerShip"); - // process thrust and rotation - Vector2 thrust = new Vector2(cb.InputX, cb.InputY); + // process thrust and rotation + Vector2 thrust = new Vector2(cb.InputX, cb.InputY); - // push the thrust input onto the player's array - movePlayer.MovementQueue.Enqueue(thrust); - } + // push the thrust input onto the player's array + movePlayer.MovementQueue.Enqueue(thrust); + } } void ProcessShootCommand(Command cb) { - _serilogger.Debug("Server.cs: Processing shoot command!"); - - // find the PlayerShip - String playerUUID = cb.Uuid; - Node2D playerRoot = playerObjects[playerUUID]; - PlayerShip movePlayer = playerRoot.GetNode("PlayerShip"); - // TODO: should we perform a check here to see if we should bother firing - // the missile, or leave that to the playership.firemissile method alone? - - String missileUUID; - // check if a missile uuid was suggested and, if not, generate one - if (cb.MissileUuid == "") - { - _serilogger.Debug("supplied missileUUID was null - generating"); - missileUUID = System.Guid.NewGuid().ToString(); - } - else - { - missileUUID = cb.MissileUuid; - } - _serilogger.Debug($"missile uuid is: {missileUUID}"); - - movePlayer.FireMissile(missileUUID); + _serilogger.Debug("Server.cs: Processing shoot command!"); + + // find the PlayerShip + String playerUUID = cb.Uuid; + Node2D playerRoot = playerObjects[playerUUID]; + PlayerShip movePlayer = playerRoot.GetNode("PlayerShip"); + // TODO: should we perform a check here to see if we should bother firing + // the missile, or leave that to the playership.firemissile method alone? + + String missileUUID; + // check if a missile uuid was suggested and, if not, generate one + if (cb.MissileUuid == "") + { + _serilogger.Debug("supplied missileUUID was null - generating"); + missileUUID = System.Guid.NewGuid().ToString(); + } + else + { + missileUUID = cb.MissileUuid; + } + _serilogger.Debug($"missile uuid is: {missileUUID}"); + + movePlayer.FireMissile(missileUUID); } void ProcessPlayerLeave(Security securityBuffer) { - // find the player object - Node2D playerShip; - if (playerObjects.TryGetValue(securityBuffer.Uuid, out playerShip)) - { - // we were able to find an object, so do the leave - _serilogger.Debug($"Server.cs: Leaving player with UUID: {securityBuffer.Uuid}"); + // find the player object + Node2D playerShip; + if (playerObjects.TryGetValue(securityBuffer.Uuid, out playerShip)) + { + // we were able to find an object, so do the leave + _serilogger.Debug($"Server.cs: Leaving player with UUID: {securityBuffer.Uuid}"); - // TODO: should this be a specific leave instead of destroying a player? - RemovePlayer(securityBuffer.Uuid); - } + // TODO: should this be a specific leave instead of destroying a player? + RemovePlayer(securityBuffer.Uuid); + } } void ProcessPlayerJoins() { - while (PlayerJoinQueue.Count > 0) - { - Security scb = PlayerJoinQueue.Dequeue(); - InstantiatePlayer(scb.Uuid); - } + while (PlayerJoinQueue.Count > 0) + { + Security scb = PlayerJoinQueue.Dequeue(); + InstantiatePlayer(scb.Uuid); + } } void ProcessPlayerRemoval() { - while (PlayerRemoveQueue.Count > 0) - { - RemovePlayer(PlayerRemoveQueue.Dequeue()); - } + while (PlayerRemoveQueue.Count > 0) + { + RemovePlayer(PlayerRemoveQueue.Dequeue()); + } } void ProcessGameEvents() { - while (GameEventQueue.Count > 0) - { - Command commandBuffer = GameEventQueue.Dequeue(); - switch (commandBuffer.command_type) - { - case Command.CommandType.CommandTypeMove: - _serilogger.Verbose("Server.cs: Move command received"); - ProcessMoveCommand(commandBuffer); - break; - case Command.CommandType.CommandTypeShoot: - _serilogger.Verbose("Server.cs: Shoot command received"); - ProcessShootCommand(commandBuffer); - break; - case Command.CommandType.CommandTypeUnspecified: - _serilogger.Error("Server.cs: Unspecified command received"); - break; - } - } + while (GameEventQueue.Count > 0) + { + Command commandBuffer = GameEventQueue.Dequeue(); + switch (commandBuffer.command_type) + { + case Command.CommandType.CommandTypeMove: + _serilogger.Verbose("Server.cs: Move command received"); + ProcessMoveCommand(commandBuffer); + break; + case Command.CommandType.CommandTypeShoot: + _serilogger.Verbose("Server.cs: Shoot command received"); + ProcessShootCommand(commandBuffer); + break; + case Command.CommandType.CommandTypeUnspecified: + _serilogger.Error("Server.cs: Unspecified command received"); + break; + } + } } void ProcessSecurityEvents() { - while (SecurityEventQueue.Count >0) - { - Security securityBuffer = SecurityEventQueue.Dequeue(); - switch (securityBuffer.security_type) - { - case Security.SecurityType.SecurityTypeUnspecified: - _serilogger.Error("Server.cs: Received an unspecified security event"); - break; - case Security.SecurityType.SecurityTypeAnnounce: - _serilogger.Debug($"Server.cs: Received a client announce request from {securityBuffer.Uuid}"); - SendAnnounceDetails(securityBuffer.Uuid); - break; - case Security.SecurityType.SecurityTypeJoin: - _serilogger.Debug($"Server.cs: Got player join for UUID: {securityBuffer.Uuid}"); - // TODO: buffer this because sometimes it collides with sending game - // updates and an exception is fired because the player collection is - // modified during looping over it - PlayerJoinQueue.Enqueue(securityBuffer); - break; - case Security.SecurityType.SecurityTypeLeave: - _serilogger.Debug($"Server.cs: Got player leave for UUID: {securityBuffer.Uuid}"); - ProcessPlayerLeave(securityBuffer); - break; - } - } + while (SecurityEventQueue.Count >0) + { + Security securityBuffer = SecurityEventQueue.Dequeue(); + switch (securityBuffer.security_type) + { + case Security.SecurityType.SecurityTypeUnspecified: + _serilogger.Error("Server.cs: Received an unspecified security event"); + break; + case Security.SecurityType.SecurityTypeAnnounce: + _serilogger.Debug($"Server.cs: Received a client announce request from {securityBuffer.Uuid}"); + SendAnnounceDetails(securityBuffer.Uuid); + break; + case Security.SecurityType.SecurityTypeJoin: + _serilogger.Debug($"Server.cs: Got player join for UUID: {securityBuffer.Uuid}"); + // TODO: buffer this because sometimes it collides with sending game + // updates and an exception is fired because the player collection is + // modified during looping over it + PlayerJoinQueue.Enqueue(securityBuffer); + break; + case Security.SecurityType.SecurityTypeLeave: + _serilogger.Debug($"Server.cs: Got player leave for UUID: {securityBuffer.Uuid}"); + ProcessPlayerLeave(securityBuffer); + break; + } + } } void ProcessInputEvent(Vector2 velocity, Vector2 shoot) { - // if there is no player in the dictionary, do nothing - // this catches accidental keyboard hits - if (!playerObjects.ContainsKey(playerID.Text)) { return; } - - // there was some kind of input, so construct a message to send to the server - //CommandBuffer cb = new CommandBuffer(); - //cb.Type = CommandBuffer.CommandBufferType.Rawinput; - - //RawInputCommandBuffer ricb = new RawInputCommandBuffer(); - //ricb.Type = RawInputCommandBuffer.RawInputCommandBufferType.Dualstick; - //ricb.Uuid = textField.Text; - - //DualStickRawInputCommandBuffer dsricb = new DualStickRawInputCommandBuffer(); - //if ( (velocity.Length() > 0) || (shoot.Length() > 0) ) - - if (velocity.Length() > 0) - { - _serilogger.Verbose("Server.cs: velocity length is greater than zero - move"); - Command cb = new Command(); - cb.command_type = Command.CommandType.CommandTypeMove; - cb.Uuid = playerID.Text; - - cb.InputX = (int)velocity.x; - cb.InputY = (int)velocity.y; - MessageInterface.SendCommand(cb); - } - - if (shoot.Length() > 0) - { - _serilogger.Verbose("Server.cs: shoot length is greater than zero - shoot"); - Command cb = new Command(); - cb.command_type = Command.CommandType.CommandTypeShoot; - cb.Uuid = playerID.Text; - - cb.InputX = (int)shoot.x; - cb.InputY = (int)shoot.y; - MessageInterface.SendCommand(cb); - } + // if there is no player in the dictionary, do nothing + // this catches accidental keyboard hits + if (!playerObjects.ContainsKey(playerID.Text)) { return; } + + // there was some kind of input, so construct a message to send to the server + //CommandBuffer cb = new CommandBuffer(); + //cb.Type = CommandBuffer.CommandBufferType.Rawinput; + + //RawInputCommandBuffer ricb = new RawInputCommandBuffer(); + //ricb.Type = RawInputCommandBuffer.RawInputCommandBufferType.Dualstick; + //ricb.Uuid = textField.Text; + + //DualStickRawInputCommandBuffer dsricb = new DualStickRawInputCommandBuffer(); + //if ( (velocity.Length() > 0) || (shoot.Length() > 0) ) + + if (velocity.Length() > 0) + { + _serilogger.Verbose("Server.cs: velocity length is greater than zero - move"); + Command cb = new Command(); + cb.command_type = Command.CommandType.CommandTypeMove; + cb.Uuid = playerID.Text; + + cb.InputX = (int)velocity.X; + cb.InputY = (int)velocity.Y; + MessageInterface.SendCommand(cb); + } + + if (shoot.Length() > 0) + { + _serilogger.Verbose("Server.cs: shoot length is greater than zero - shoot"); + Command cb = new Command(); + cb.command_type = Command.CommandType.CommandTypeShoot; + cb.Uuid = playerID.Text; + + cb.InputX = (int)shoot.X; + cb.InputY = (int)shoot.Y; + MessageInterface.SendCommand(cb); + } } @@ -596,133 +610,133 @@ void ProcessInputEvent(Vector2 velocity, Vector2 shoot) public void SendAnnounceDetails(String UUID) { - // create the announce message - Security announceMessage = new Security(); - announceMessage.security_type = Security.SecurityType.SecurityTypeAnnounce; - announceMessage.Uuid = UUID; - announceMessage.ShipThrust = PlayerDefaultThrust; - announceMessage.MaxSpeed = PlayerDefaultMaxSpeed; - announceMessage.RotationThrust = PlayerDefaultRotationThrust; - announceMessage.HitPoints = PlayerDefaultHitPoints; - announceMessage.MissileSpeed = PlayerDefaultMissileSpeed; - announceMessage.MissileLife = PlayerDefaultMissileLife; - announceMessage.MissileDamage = PlayerDefaultMissileDamage; - announceMessage.MissileReload = PlayerDefaultMissileReloadTime; - - _serilogger.Debug($"Server.cs: Sending announce details to client {UUID}"); - MessageInterface.SendSecurity(announceMessage); + // create the announce message + Security announceMessage = new Security(); + announceMessage.security_type = Security.SecurityType.SecurityTypeAnnounce; + announceMessage.Uuid = UUID; + announceMessage.ShipThrust = PlayerDefaultThrust; + announceMessage.MaxSpeed = PlayerDefaultMaxSpeed; + announceMessage.RotationThrust = PlayerDefaultRotationThrust; + announceMessage.HitPoints = PlayerDefaultHitPoints; + announceMessage.MissileSpeed = PlayerDefaultMissileSpeed; + announceMessage.MissileLife = PlayerDefaultMissileLife; + announceMessage.MissileDamage = PlayerDefaultMissileDamage; + announceMessage.MissileReload = PlayerDefaultMissileReloadTime; + + _serilogger.Debug($"Server.cs: Sending announce details to client {UUID}"); + MessageInterface.SendSecurity(announceMessage); } public void LoadConfig() { - _serilogger.Information("Server.cs: Configuring"); - - var serverConfig = new ConfigFile(); - // save the config file load status to err to check which value to use (config or env) later - Error err = serverConfig.Load("Config/server.cfg"); - - int DesiredLogLevel = 3; - - // if the file was loaded successfully, read the vars - if (err == Error.Ok) - { - SectorSize = (Int32)serverConfig.GetValue("game", "sector_size"); - // player settings - // https://stackoverflow.com/questions/24447387/cast-object-containing-int-to-float-results-in-invalidcastexception - PlayerDefaultThrust = Convert.ToSingle(serverConfig.GetValue("player", "thrust")); - PlayerDefaultMaxSpeed = Convert.ToSingle(serverConfig.GetValue("player", "max_speed")); - PlayerDefaultRotationThrust = Convert.ToSingle(serverConfig.GetValue("player", "rotation_thrust")); - PlayerDefaultHitPoints = (int)serverConfig.GetValue("player", "hit_points"); - PlayerDefaultMissileSpeed = (int)serverConfig.GetValue("player", "missile_speed"); - PlayerDefaultMissileLife = Convert.ToSingle(serverConfig.GetValue("player", "missile_life")); - PlayerDefaultMissileDamage = (int)serverConfig.GetValue("player", "missile_damage"); - PlayerDefaultMissileReloadTime = (int)serverConfig.GetValue("player", "missile_reload"); - DesiredLogLevel = (int)serverConfig.GetValue("game", "log_level"); - } - - // pull values from env -- will get nulls if any vars are not set - String envSectorSize = System.Environment.GetEnvironmentVariable("SRT_SECTOR_SIZE"); - String envPlayerThrust = System.Environment.GetEnvironmentVariable("SRT_PLAYER_THRUST"); - String envPlayerSpeed = System.Environment.GetEnvironmentVariable("SRT_PLAYER_SPEED"); - String envPlayerRotation = System.Environment.GetEnvironmentVariable("SRT_PLAYER_ROTATION"); - String envPlayerHealth = System.Environment.GetEnvironmentVariable("SRT_PLAYER_HEALTH"); - String envMissileSpeed = System.Environment.GetEnvironmentVariable("SRT_MISSILE_SPEED"); - String envMissileLife = System.Environment.GetEnvironmentVariable("SRT_MISSILE_LIFE"); - String envMissileDamage = System.Environment.GetEnvironmentVariable("SRT_MISSILE_DAMAGE"); - String envMissileReloadTime = System.Environment.GetEnvironmentVariable("SRT_MISSILE_RELOAD_TIME"); - String envLogLevel = System.Environment.GetEnvironmentVariable("SRT_LOG_LEVEL"); - - // override any loaded config with env - if (envSectorSize != null) SectorSize = Int32.Parse(envSectorSize); - if (envPlayerThrust != null) PlayerDefaultThrust = float.Parse(envPlayerThrust); - if (envPlayerSpeed != null) PlayerDefaultMaxSpeed = float.Parse(envPlayerSpeed); - if (envPlayerRotation != null) PlayerDefaultRotationThrust = float.Parse(envPlayerSpeed); - if (envPlayerHealth != null) PlayerDefaultHitPoints = int.Parse(envPlayerHealth); - if (envMissileSpeed != null) PlayerDefaultMissileSpeed = int.Parse(envMissileSpeed); - if (envMissileLife != null) PlayerDefaultMissileLife = float.Parse(envMissileLife); - if (envMissileDamage != null) PlayerDefaultMissileDamage = int.Parse(envMissileDamage); - if (envMissileReloadTime != null) PlayerDefaultMissileReloadTime = int.Parse(envMissileReloadTime); - if (envLogLevel != null) DesiredLogLevel = int.Parse(envLogLevel); - - switch (DesiredLogLevel) - { - case 0: - _serilogger.Information("Server.cs: Setting minimum log level to: Fatal"); - levelSwitch.MinimumLevel = Serilog.Events.LogEventLevel.Fatal; - break; - case 1: - _serilogger.Information("Server.cs: Setting minimum log level to: Error"); - levelSwitch.MinimumLevel = Serilog.Events.LogEventLevel.Error; - break; - case 2: - _serilogger.Information("Server.cs: Setting minimum log level to: Warning"); - levelSwitch.MinimumLevel = Serilog.Events.LogEventLevel.Warning; - break; - case 3: - _serilogger.Information("Server.cs: Setting minimum log level to: Information"); - levelSwitch.MinimumLevel = Serilog.Events.LogEventLevel.Information; - break; - case 4: - _serilogger.Information("Server.cs: Setting minimum log level to: Debug"); - levelSwitch.MinimumLevel = Serilog.Events.LogEventLevel.Debug; - break; - case 5: - _serilogger.Information("Server.cs: Setting minimum log level to: Verbose"); - levelSwitch.MinimumLevel = Serilog.Events.LogEventLevel.Verbose; - break; - default: - _serilogger.Information("Server.cs: Unknown log level specified, defaulting to: Information"); - levelSwitch.MinimumLevel = Serilog.Events.LogEventLevel.Debug; - break; - } - - // output the config state - _serilogger.Information($"Server.cs: Sector Size: {SectorSize}"); - _serilogger.Information($"Server.cs: Player Thrust: {PlayerDefaultThrust}"); - _serilogger.Information($"Server.cs: Player Speed: {PlayerDefaultMaxSpeed}"); - _serilogger.Information($"Server.cs: Player Rotation: {PlayerDefaultRotationThrust}"); - _serilogger.Information($"Server.cs: Player HP: {PlayerDefaultHitPoints}"); - _serilogger.Information($"Server.cs: Missile Speed: {PlayerDefaultMissileSpeed}"); - _serilogger.Information($"Server.cs: Missile Life: {PlayerDefaultMissileLife}"); - _serilogger.Information($"Server.cs: Missile Damage: {PlayerDefaultMissileDamage}"); - _serilogger.Information($"Server.cs: Missile Reload Time: {PlayerDefaultMissileReloadTime}"); + _serilogger.Information("Server.cs: Configuring"); + + var serverConfig = new ConfigFile(); + // save the config file load status to err to check which value to use (config or env) later + Error err = serverConfig.Load("Config/server.cfg"); + + int DesiredLogLevel = 3; + + // if the file was loaded successfully, read the vars + if (err == Error.Ok) + { + SectorSize = (Int32)serverConfig.GetValue("game", "sector_size"); + // player settings + // https://stackoverflow.com/questions/24447387/cast-object-containing-int-to-float-results-in-invalidcastexception + PlayerDefaultThrust = Convert.ToSingle(serverConfig.GetValue("player", "thrust")); + PlayerDefaultMaxSpeed = Convert.ToSingle(serverConfig.GetValue("player", "max_speed")); + PlayerDefaultRotationThrust = Convert.ToSingle(serverConfig.GetValue("player", "rotation_thrust")); + PlayerDefaultHitPoints = (int)serverConfig.GetValue("player", "hit_points"); + PlayerDefaultMissileSpeed = (int)serverConfig.GetValue("player", "missile_speed"); + PlayerDefaultMissileLife = Convert.ToSingle(serverConfig.GetValue("player", "missile_life")); + PlayerDefaultMissileDamage = (int)serverConfig.GetValue("player", "missile_damage"); + PlayerDefaultMissileReloadTime = (int)serverConfig.GetValue("player", "missile_reload"); + DesiredLogLevel = (int)serverConfig.GetValue("game", "log_level"); + } + + // pull values from env -- will get nulls if any vars are not set + String envSectorSize = System.Environment.GetEnvironmentVariable("SRT_SECTOR_SIZE"); + String envPlayerThrust = System.Environment.GetEnvironmentVariable("SRT_PLAYER_THRUST"); + String envPlayerSpeed = System.Environment.GetEnvironmentVariable("SRT_PLAYER_SPEED"); + String envPlayerRotation = System.Environment.GetEnvironmentVariable("SRT_PLAYER_ROTATION"); + String envPlayerHealth = System.Environment.GetEnvironmentVariable("SRT_PLAYER_HEALTH"); + String envMissileSpeed = System.Environment.GetEnvironmentVariable("SRT_MISSILE_SPEED"); + String envMissileLife = System.Environment.GetEnvironmentVariable("SRT_MISSILE_LIFE"); + String envMissileDamage = System.Environment.GetEnvironmentVariable("SRT_MISSILE_DAMAGE"); + String envMissileReloadTime = System.Environment.GetEnvironmentVariable("SRT_MISSILE_RELOAD_TIME"); + String envLogLevel = System.Environment.GetEnvironmentVariable("SRT_LOG_LEVEL"); + + // override any loaded config with env + if (envSectorSize != null) SectorSize = Int32.Parse(envSectorSize); + if (envPlayerThrust != null) PlayerDefaultThrust = float.Parse(envPlayerThrust); + if (envPlayerSpeed != null) PlayerDefaultMaxSpeed = float.Parse(envPlayerSpeed); + if (envPlayerRotation != null) PlayerDefaultRotationThrust = float.Parse(envPlayerSpeed); + if (envPlayerHealth != null) PlayerDefaultHitPoints = int.Parse(envPlayerHealth); + if (envMissileSpeed != null) PlayerDefaultMissileSpeed = int.Parse(envMissileSpeed); + if (envMissileLife != null) PlayerDefaultMissileLife = float.Parse(envMissileLife); + if (envMissileDamage != null) PlayerDefaultMissileDamage = int.Parse(envMissileDamage); + if (envMissileReloadTime != null) PlayerDefaultMissileReloadTime = int.Parse(envMissileReloadTime); + if (envLogLevel != null) DesiredLogLevel = int.Parse(envLogLevel); + + switch (DesiredLogLevel) + { + case 0: + _serilogger.Information("Server.cs: Setting minimum log level to: Fatal"); + levelSwitch.MinimumLevel = Serilog.Events.LogEventLevel.Fatal; + break; + case 1: + _serilogger.Information("Server.cs: Setting minimum log level to: Error"); + levelSwitch.MinimumLevel = Serilog.Events.LogEventLevel.Error; + break; + case 2: + _serilogger.Information("Server.cs: Setting minimum log level to: Warning"); + levelSwitch.MinimumLevel = Serilog.Events.LogEventLevel.Warning; + break; + case 3: + _serilogger.Information("Server.cs: Setting minimum log level to: Information"); + levelSwitch.MinimumLevel = Serilog.Events.LogEventLevel.Information; + break; + case 4: + _serilogger.Information("Server.cs: Setting minimum log level to: Debug"); + levelSwitch.MinimumLevel = Serilog.Events.LogEventLevel.Debug; + break; + case 5: + _serilogger.Information("Server.cs: Setting minimum log level to: Verbose"); + levelSwitch.MinimumLevel = Serilog.Events.LogEventLevel.Verbose; + break; + default: + _serilogger.Information("Server.cs: Unknown log level specified, defaulting to: Information"); + levelSwitch.MinimumLevel = Serilog.Events.LogEventLevel.Debug; + break; + } + + // output the config state + _serilogger.Information($"Server.cs: Sector Size: {SectorSize}"); + _serilogger.Information($"Server.cs: Player Thrust: {PlayerDefaultThrust}"); + _serilogger.Information($"Server.cs: Player Speed: {PlayerDefaultMaxSpeed}"); + _serilogger.Information($"Server.cs: Player Rotation: {PlayerDefaultRotationThrust}"); + _serilogger.Information($"Server.cs: Player HP: {PlayerDefaultHitPoints}"); + _serilogger.Information($"Server.cs: Missile Speed: {PlayerDefaultMissileSpeed}"); + _serilogger.Information($"Server.cs: Missile Life: {PlayerDefaultMissileLife}"); + _serilogger.Information($"Server.cs: Missile Damage: {PlayerDefaultMissileDamage}"); + _serilogger.Information($"Server.cs: Missile Reload Time: {PlayerDefaultMissileReloadTime}"); } void UpdateDebugUI() { - // clear the list and then iterate over all players to rebuild it - uiPlayerTree.Clear(); - TreeItem UIPlayerTreeRoot = uiPlayerTree.CreateItem(); - - Godot.Collections.Array players = _GetNodesFromGroup("player_ships"); - foreach (PlayerShip player in players) - { - TreeItem playerTreeItem = uiPlayerTree.CreateItem(UIPlayerTreeRoot); - playerTreeItem.SetText(0, player.uuid); - } - - RingSize.Text = RingRadius.ToString(); - StarFieldRadiusSize.Text = StarFieldRadiusPixels.ToString(); + // clear the list and then iterate over all players to rebuild it + uiPlayerTree.Clear(); + TreeItem UIPlayerTreeRoot = uiPlayerTree.CreateItem(); + + Godot.Collections.Array players = _GetNodesFromGroup("player_ships"); + foreach (PlayerShip player in players) + { + TreeItem playerTreeItem = uiPlayerTree.CreateItem(UIPlayerTreeRoot); + playerTreeItem.SetText(0, player.uuid); + } + + RingSize.Text = RingRadius.ToString(); + StarFieldRadiusSize.Text = StarFieldRadiusPixels.ToString(); } // Godot Builtins @@ -730,296 +744,306 @@ void UpdateDebugUI() // Called when the node enters the scene tree for the first time. public override void _Ready() { - levelSwitch.MinimumLevel = Serilog.Events.LogEventLevel.Information; - _serilogger = new LoggerConfiguration().MinimumLevel.ControlledBy(levelSwitch).WriteTo.Console().CreateLogger(); - _serilogger.Information("Server.cs: Space Ring Things (SRT) Game Server"); - _serilogger.Information("Server.cs: Attempting AMQP initialization"); - - MessageInterface = new AMQPserver(); - MessageInterface.Name = "AMQP_Server"; - AddChild(MessageInterface); - - _serilogger.Information("Server.cs: Beginning game server"); - - LoadConfig(); - - // initialize the starfield size to the initial sector size - // the play area is clamped - StarFieldRadiusPixels = SectorSize; - - // initialize the hexboard layout - HexLayout = new Layout(Layout.flat, new Point(SectorSize, SectorSize), new Point(0, 0)); - - // grab needed elements for later - rtsCamera = GetNode("RTS-Camera2D"); - theCanvas = GetNode("DebugUI/DebugStack"); - playerID = theCanvas.GetNode("PlayerID"); - uiPlayerTree = theCanvas.GetNode("CurrentPlayerTree"); - RingSize = theCanvas.GetNode