Skip to content

Commit

Permalink
Basic multiplayer infrastructure
Browse files Browse the repository at this point in the history
  • Loading branch information
BlueStaggo committed Dec 23, 2024
1 parent b707b0a commit 5f860bd
Show file tree
Hide file tree
Showing 19 changed files with 681 additions and 8 deletions.
4 changes: 2 additions & 2 deletions PDS/src/CompoundItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ public CompoundItem Put(string key, object? value)
public object? Deserialize(Type type)
{
if (!RuntimeFeature.IsDynamicCodeCompiled
|| type.GetCustomAttribute<PdsAutoSerializableAttribute>() is null) return default;
|| type.GetCustomAttribute<PdsAutoSerializableAttribute>() is null) return null;

ConstructorInfo? constructor = type.GetConstructor([]);
if (constructor is null) return default;
if (constructor is null) return null;

object obj = constructor.Invoke(null);
foreach (FieldInfo field in type.GetFields(BindingFlags.Public | BindingFlags.Instance))
Expand Down
49 changes: 49 additions & 0 deletions VoxelThing.Client/src/Game.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Collections.ObjectModel;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using OpenTK.Graphics.OpenGL;
Expand All @@ -17,6 +19,7 @@
using VoxelThing.Game;
using VoxelThing.Game.Blocks;
using VoxelThing.Game.Entities;
using VoxelThing.Game.Networking;
using VoxelThing.Game.Utils;
using VoxelThing.Game.Worlds;
using VoxelThing.Game.Worlds.Chunks;
Expand Down Expand Up @@ -65,6 +68,8 @@ public class Game : GameWindow
public MainRenderer MainRenderer { get; private set; }
public readonly SettingsManager Settings;

public Connection? Connection { get; private set; }

public World? World;
public Player? Player;
public IPlayerController? PlayerController;
Expand Down Expand Up @@ -226,6 +231,9 @@ protected override void OnUpdateFrame(FrameEventArgs args)
}
}
Profiler.Pop();

while (Connection is not null && Connection.PendingPackets.TryDequeue(out IPacket? packet))
HandlePacket(packet);
}

if (!paused)
Expand Down Expand Up @@ -438,6 +446,47 @@ public void ExitWorld()
GC.Collect();
}

public async Task<bool> ConnectToServer(string ip)
{
int port = 8577;
int colonIndex = ip.LastIndexOf(':');
if (colonIndex > 0)
{
string portString = ip[(colonIndex + 1)..^1];
if (!int.TryParse(portString, out port))
port = 8577;
ip = ip[..colonIndex];
}

if (ip is "127.0.0.1" or "localhost")
ip = Dns.GetHostName();

IPHostEntry ipHostEntry = await Dns.GetHostEntryAsync(ip);
IPAddress ipAddress = ipHostEntry.AddressList[0];
IPEndPoint ipEndPoint = new(ipAddress, port);

TcpClient client = new();
await client.ConnectAsync(ipEndPoint);
DisconnectFromServer();

Connection = new(client, ipEndPoint, PacketSide.Server);
Connection.Disconnected += (_, _) => DisconnectFromServer();
Connection.StartListening();
return true;
}

public void DisconnectFromServer()
{
Connection?.Dispose();
Connection = null;
}

public void HandlePacket(IPacket packet)
{
if (CurrentScreen is MultiplayerTestScreen multiplayerTestScreen)
multiplayerTestScreen.HandlePacket(packet);
}

public static void Main()
{
using Game game = new();
Expand Down
2 changes: 1 addition & 1 deletion VoxelThing.Client/src/Gui/Controls/Control.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,5 @@ public virtual void CheckMouseClicked(PositionalMouseButtonEventArgs args)
OnClick?.Invoke(this, args);
}

public bool IsInContainer(Container container) => this.Container == container;
public bool IsInContainer(Container container) => Container == container;
}
4 changes: 2 additions & 2 deletions VoxelThing.Client/src/Gui/Font.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public void Print(string text, float x, float y, float r = 1.0f, float g = 1.0f,
for (int i = 0; i < text.Length; i++)
{
char c = text[i];
if (c == '\u00a7' && i < text.Length + 1)
if (c == '\u00a7' && text.Length - i > 1)
{
c = char.ToLower(text[++i]);
if (c == 'c' && text.Length - i > 6)
Expand Down Expand Up @@ -168,7 +168,7 @@ public int GetStringLength(string text) {
for (int i = 0; i < text.Length; i++)
{
char c = text[i];
if (c == '\u00a7' && i < text.Length + 1)
if (c == '\u00a7' && text.Length - i > 1)
{
c = char.ToLower(text[++i]);
if (c == 'c' && text.Length - i > 6)
Expand Down
26 changes: 23 additions & 3 deletions VoxelThing.Client/src/Gui/Screens/MainMenuScreen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,42 @@ public MainMenuScreen(Game game) : base(game)
var playButton = AddControl(new Label(this)
{
Text = "Singleplayer",
Position = (-75, 0),
Position = (-75, -15),
Size = (150, 20),
AlignPosition = (0.5f, 0.5f),
HasBackground = true
});
playButton.OnClick += (_, _) => Game.CurrentScreen = new SaveSelectScreen(Game);

var multiplayerButton = AddControl(new Label(this)
{
Text = "Multiplayer",
Position = (-75, 10),
Size = (150, 20),
AlignPosition = (0.5f, 0.5f),
HasBackground = true
});
multiplayerButton.OnClick += (_, _) => Game.CurrentScreen = new MultiplayerConnectionScreen(Game);

var settingsButton = AddControl(new Label(this)
{
Text = "Settings",
Position = (-75, 30),
Position = (-75, 35),
Size = (150, 20),
AlignPosition = (0.5f, 0.5f),
HasBackground = true
});
settingsButton.OnClick += (_, _) => Game.CurrentScreen = new SettingsScreen(Game);

var quitButton = AddControl(new Label(this)
{
Text = "Exit Game",
Position = (-75, 60),
Size = (150, 20),
AlignPosition = (0.5f, 0.5f),
HasBackground = true
});
quitButton.OnClick += (_, _) => Game.Close();
}

protected override void OnKeyPressed(KeyboardKeyEventArgs args) { }
Expand All @@ -69,7 +89,7 @@ public override void Draw()
renderer.Fonts.Outlined.Print(
"VOXEL THING",
renderer.ScreenDimensions.IntWidth / 2.0f,
40.0f + hover * 2.0f,
35.0f + hover * 2.0f,
0.0f, 1.0f, 1.0f, 4.0f,
align: 0.5f
);
Expand Down
93 changes: 93 additions & 0 deletions VoxelThing.Client/src/Gui/Screens/MultiplayerConnectionScreen.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
using VoxelThing.Client.Gui.Controls;
using VoxelThing.Client.Rendering;
using VoxelThing.Game.Networking;

namespace VoxelThing.Client.Gui.Screens;

public class MultiplayerConnectionScreen : Screen
{
private readonly TextBox nameBox;
private Task<bool>? connectionTask;

public MultiplayerConnectionScreen(Game game) : base(game)
{
AddControl(new Label(this)
{
Text = "Enter IP",
Position = (0, -40),
AlignPosition = (0.5f, 0.5f)
});

var ipBox = AddControl(new TextBox(this)
{
Text = "127.0.0.1",
Position = (-100, -30),
Size = (200, 20),
AlignPosition = (0.5f, 0.5f)
});

nameBox = AddControl(new TextBox(this)
{
Text = "BlueStaggo",
Position = (-100, -10),
Size = (200, 20),
AlignPosition = (0.5f, 0.5f)
});

var backButton = AddControl(new Label(this)
{
Text = "Back",
Position = (-105, 20),
Size = (100, 20),
AlignPosition = (0.5f, 0.5f),
HasBackground = true
});
backButton.OnClick += (_, _) => Game.CurrentScreen = Parent;

var playButton = AddControl(new Label(this)
{
Text = "Play",
Position = (5, 20),
Size = (100, 20),
AlignPosition = (0.5f, 0.5f),
HasBackground = true
});
playButton.OnClick += (_, _) =>
{
if (connectionTask is null || connectionTask.IsCompleted)
connectionTask = Game.ConnectToServer(ipBox.Text);
};
}

public override void Tick()
{
if (connectionTask?.IsCompletedSuccessfully ?? false)
{
Game.Connection?.SendPacket(new CUpdateDisplayName(nameBox.Text));
Game.CurrentScreen = new MultiplayerTestScreen(Game, nameBox.Text);
}
}

public override void Draw()
{
base.Draw();
if (connectionTask is not null)
{
string displayString = "§cffff00Waiting...";
if (connectionTask.IsCompletedSuccessfully)
displayString = "§c00ff00Success!";
else if (connectionTask.IsFaulted)
{
displayString = "§cff0000Failure!";
}

MainRenderer renderer = Game.MainRenderer;
ScreenDimensions dimensions = renderer.ScreenDimensions;
renderer.Fonts.Outlined.Print(
displayString,
dimensions.IntWidth / 2, dimensions.IntHeight / 2 + 50,
align: 0.5f
);
}
}
}
99 changes: 99 additions & 0 deletions VoxelThing.Client/src/Gui/Screens/MultiplayerTestScreen.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
using OpenTK.Mathematics;
using OpenTK.Windowing.GraphicsLibraryFramework;
using VoxelThing.Client.Gui.Controls;
using VoxelThing.Game.Networking;

namespace VoxelThing.Client.Gui.Screens;

public class MultiplayerTestScreen : Screen
{
private readonly List<string> messages = [];

public MultiplayerTestScreen(Game game, string name) : base(game)
{
AddControl(new Label(this)
{
Text = $"You are {name}",
Font = game.MainRenderer.Fonts.Outlined,
Position = (2, 2),
AlignText = (0.0f, 0.0f)
});

var messageBox = AddControl(new TextBox(this)
{
Position = (0, -20),
Size = (-100, 20),
AlignPosition = (0.0f, 1.0f),
AlignSize = (1.0f, 0.0f)
});
messageBox.OnKeyPressed += (_, args) =>
{
if (args.Key != Keys.Enter)
return;
Game.Connection?.SendPacket(new CSendMessagePacket(messageBox.Text));
messageBox.Text = string.Empty;
};

var sendButton = AddControl(new Label(this)
{
Text = "Send",
Position = (-100, -20),
Size = (100, 20),
AlignPosition = (1.0f, 1.0f),
HasBackground = true
});
sendButton.OnClick += (_, _) =>
{
Game.Connection?.SendPacket(new CSendMessagePacket(messageBox.Text));
messageBox.Text = string.Empty;
};

var exitButton = AddControl(new IconButton(this)
{
Icon = Icons.Delete,
Position = (-20, 0),
Size = (20, 20),
AlignPosition = (1.0f, 0.0f),
});
exitButton.OnClick += (_, _) =>
{
Game.DisconnectFromServer();
Game.CurrentScreen = null;
};
}

public override void Tick()
{
if (Game.Connection is null)
Game.CurrentScreen = null;
}

public override void Draw()
{
ScreenDimensions dimensions = Game.MainRenderer.ScreenDimensions;
Game.MainRenderer.Draw2D.DrawQuad(new()
{
Color = (Vector4)Color4.Black,
Size = dimensions.IntSize
});
for (int i = 0; i < messages.Count; i++)
{
int y = dimensions.IntHeight - 30 - i * 10;
Game.MainRenderer.Fonts.Normal.Print(messages[i], 2, y);
}
base.Draw();
}

public void HandlePacket(IPacket packet)
{
if (packet is SSendMessagePacket sendMessage)
{
string fullMessage = $"{sendMessage.Author}: {sendMessage.Message}";
string fullMessageColored = $"{sendMessage.Author}: §cffffff{sendMessage.Message}";
Console.WriteLine(fullMessage);
messages.Insert(0, fullMessageColored);
if (messages.Count > 50)
messages.RemoveAt(50);
}
}
}
1 change: 1 addition & 0 deletions VoxelThing.Game/VoxelThing.Game.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="MemoryPack" Version="1.21.3" />
<PackageReference Include="OpenTK.Mathematics" Version="4.8.2" />
</ItemGroup>

Expand Down
Loading

0 comments on commit 5f860bd

Please sign in to comment.