Funkční komunikace mezi jedním clientem a serverem

This commit is contained in:
Perry 2025-12-19 17:54:50 +01:00
commit 3f235f6e04
44 changed files with 1030 additions and 0 deletions

View file

@ -0,0 +1,36 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-mgcb": {
"version": "3.8.4",
"commands": [
"mgcb"
]
},
"dotnet-mgcb-editor": {
"version": "3.8.4",
"commands": [
"mgcb-editor"
]
},
"dotnet-mgcb-editor-linux": {
"version": "3.8.4",
"commands": [
"mgcb-editor-linux"
]
},
"dotnet-mgcb-editor-windows": {
"version": "3.8.4",
"commands": [
"mgcb-editor-windows"
]
},
"dotnet-mgcb-editor-mac": {
"version": "3.8.4",
"commands": [
"mgcb-editor-mac"
]
}
}
}

14
FNAF_Clone/.vscode/launch.json vendored Normal file
View file

@ -0,0 +1,14 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "C#: FNAF_Clone Debug",
"type": "dotnet",
"request": "launch",
"projectPath": "${workspaceFolder}/FNAF_Clone.csproj"
}
],
}

View file

@ -0,0 +1,18 @@
namespace FNAF_Clone;
public class CameraSystem {
public bool Enabled { get; private set; }
public int CurrentCamera { get; private set; }
public void FlipUp() {
Enabled = true;
}
public void FlipDown() {
Enabled = false;
}
public void SetCamera(int camera) {
}
}

103
FNAF_Clone/Client.cs Normal file
View file

@ -0,0 +1,103 @@
using System;
using System.Net;
using System.Net.Sockets;
using LiteNetLib;
using LiteNetLib.Utils;
using PacketLib;
namespace FNAF_Clone;
public class Client {
private static EventBasedNetListener listener = new();
private static NetManager client;
private static NetPeer server;
private static NetDataWriter writer;
private static NetPacketProcessor processor;
public static ClientPlayer Player { get; } = new();
public static void Connect(string endPoint, int port) {
writer = new NetDataWriter();
processor = new NetPacketProcessor();
NestedTypeManager.AutoRegister(processor);
processor.SubscribeReusable<JoinAcceptPacket>(OnJoinAccept);
processor.SubscribeReusable<UpdatePlayerPacket>(OnPlayerUpdate);
client = new NetManager(listener){
AutoRecycle = true
};
client.Start();
Console.WriteLine($"Connecting to server @ {endPoint}:{port}");
listener.NetworkReceiveEvent += (peer, reader, channel, method) => {
OnNetworkReceive(peer, reader, method);
};
listener.PeerConnectedEvent += peer => {
Console.WriteLine("Connected to Server");
server = peer;
SendPacket(new JoinPacket {username = "Player1"}, DeliveryMethod.ReliableOrdered);
};
client.Connect(endPoint, port, ""); // TODO: figure out how keys work
}
public static void SendPacket<T>(T packet, DeliveryMethod deliveryMethod) where T : class, new() {
if (server != null) {
writer.Reset();
processor.Write(writer, packet);
server.Send(writer, deliveryMethod);
}
}
public static void SendCommands(PlayerCommand[] pCommands) {
SendPacket(new PlayerCommandPacket{commands = pCommands}, DeliveryMethod.ReliableOrdered);
}
public static void OnNetworkReceive(NetPeer peer, NetPacketReader reader, DeliveryMethod deliveryMethod) {
processor.ReadAllPackets(reader, peer);
}
public static void OnJoinAccept(JoinAcceptPacket packet) {
Console.WriteLine($"Accepted by server, pid: {packet.state.pid}");
Player.state = packet.state;
}
public static void Update() {
client.PollEvents();
}
public static void OnPlayerUpdate(UpdatePlayerPacket packet) {
//Player.state = Player.state.pid == 0 ? packet.stateP1 : packet.stateP2;
foreach (var e in packet.events){
switch (e.ID){
case 0: // join
Console.WriteLine("E: Player joined");
break;
case 1: // leave
Console.WriteLine("E: Player left");
break;
case 2: // switch cam
if (Player.state.pid == e.Args[0]){
Player.state.camera = e.Args[1];
}
Console.WriteLine($"E: player {e.Args[0]} switched to camera {e.Args[1]}");
break;
case 3: // toggle cam
Player.state.monitorUp = e.Args[1] == 1;
Console.WriteLine($"E: Player {e.Args[0]} toggled monitor {(e.Args[1] == 0 ? "off" : "on")}");
break;
case -1: // movement
throw new NotImplementedException();
}
}
}
}

View file

@ -0,0 +1,8 @@
using PacketLib;
namespace FNAF_Clone;
public class ClientPlayer {
public PlayerState state;
public string username;
}

View file

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework.Input;
using MonoGameLibrary.Input;
using PacketLib;
namespace FNAF_Clone;
public class CommandManager {
private static (string label, Keys key, Action action)[] keybinds = [
("Toggle Camera", Keys.S, ToggleCamera)
];
private static InputListenerHook toggleCamHook = new(true);
public static void InitInputListeners() {
Array.ForEach(keybinds, tuple => InputManager.AddListener(tuple.label, tuple.key, _ => tuple.action(), InputTiming.PRESS, toggleCamHook));
}
private static void ToggleCamera() {
Client.SendCommands([PlayerCommand.TOGGLE_MONITOR()]);
}
}

View file

@ -0,0 +1,15 @@
#----------------------------- Global Properties ----------------------------#
/outputDir:bin/$(Platform)
/intermediateDir:obj/$(Platform)
/platform:DesktopGL
/config:
/profile:Reach
/compress:False
#-------------------------------- References --------------------------------#
#---------------------------------- Content ---------------------------------#

View file

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This file contains an xml description of a font, and will be read by the XNA
Framework Content Pipeline. Follow the comments to customize the appearance
of the font in your game, and to change the characters which are available to draw
with.
-->
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
<Asset Type="Graphics:FontDescription">
<!--
Modify this string to change the font that will be imported.
-->
<FontName>Arial</FontName>
<!--
Size is a float value, measured in points. Modify this value to change
the size of the font.
-->
<Size>12</Size>
<!--
Spacing is a float value, measured in pixels. Modify this value to change
the amount of spacing in between characters.
-->
<Spacing>0</Spacing>
<!--
UseKerning controls the layout of the font. If this value is true, kerning information
will be used when placing characters.
-->
<UseKerning>true</UseKerning>
<!--
Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
and "Bold, Italic", and are case sensitive.
-->
<Style>Regular</Style>
<!--
If you uncomment this line, the default character will be substituted if you draw
or measure text that contains characters which were not included in the font.
-->
<!-- <DefaultCharacter>*</DefaultCharacter> -->
<!--
CharacterRegions control what letters are available in the font. Every
character from Start to End will be built and made available for drawing. The
default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
character set. The characters are ordered according to the Unicode standard.
See the documentation for more information.
-->
<CharacterRegions>
<CharacterRegion>
<Start>&#32;</Start>
<End>&#126;</End>
</CharacterRegion>
</CharacterRegions>
</Asset>
</XnaContent>

Binary file not shown.

View file

@ -0,0 +1,50 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<RollForward>Major</RollForward>
<PublishReadyToRun>false</PublishReadyToRun>
<TieredCompilation>false</TieredCompilation>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
<ApplicationIcon>Icon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<None Remove="Icon.ico"/>
<None Remove="Icon.bmp"/>
<None Remove="Input\**" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Icon.ico">
<LogicalName>Icon.ico</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="Icon.bmp">
<LogicalName>Icon.bmp</LogicalName>
</EmbeddedResource>
<EmbeddedResource Remove="Input\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="LiteNetLib" Version="1.3.1" />
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.*"/>
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.*"/>
</ItemGroup>
<ItemGroup>
<Folder Include="lib\" />
</ItemGroup>
<ItemGroup>
<Reference Include="MonoGameLibrary">
<HintPath>lib\MonoGameLibrary.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PacketLib\PacketLib.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Input\**" />
</ItemGroup>
<Target Name="RestoreDotnetTools" BeforeTargets="CollectPackageReferences">
<Message Text="Restoring dotnet tools (this might take a while depending on your internet speed and should only happen upon building your project for the first time, or after upgrading MonoGame, or clearing your nuget cache)" Importance="High"/>
<Exec Command="dotnet tool restore"/>
</Target>
</Project>

47
FNAF_Clone/GameMain.cs Normal file
View file

@ -0,0 +1,47 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using MonoGameLibrary;
using MonoGameLibrary.Input;
namespace FNAF_Clone;
public class GameMain() : Core("fnafkooo", 1920, 1080, false) {
private GraphicsDeviceManager _graphics;
private SpriteBatch _spriteBatch;
protected override void Initialize() {
Client.Connect("127.0.0.1", 9012);
CommandManager.InitInputListeners();
base.Initialize();
}
protected override void LoadContent() {
_spriteBatch = new SpriteBatch(GraphicsDevice);
// TODO: use this.Content to load your game content here
}
protected override void Update(GameTime gameTime) {
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed ||
Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
// TODO: Add your update logic here
InputManager.NextInputCycle();
Client.Update();
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime) {
GraphicsDevice.Clear(Color.CornflowerBlue);
// TODO: Add your drawing code here
base.Draw(gameTime);
}
}

BIN
FNAF_Clone/Icon.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

BIN
FNAF_Clone/Icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

View file

@ -0,0 +1,6 @@
namespace FNAF_Clone.Input;
public class InputListenerHook(bool enabled, bool oneTimeOnly = false) {
public bool Enabled { get; set; } = enabled;
public bool RemoveOnNextTrigger { get; set; } = oneTimeOnly;
}

View file

@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework.Input;
namespace FNAF_Clone.Input;
public static class InputManager {
private static Dictionary<Keys, List<(KeypressHandler, InputListenerHook)>> keyPressListeners = new();
private static Dictionary<Keys, List<(KeypressHandler, InputListenerHook)>> keyHoldListeners = new(); // The bool is for enabling/disabling that method
private static Dictionary<Keys, List<(KeypressHandler, InputListenerHook)>> keyReleaseListeners = new();
private static KeyboardState oldState = Keyboard.GetState();
private static KeyboardState newState;
// public static ConcurrentQueue<Action> inputEventQueue = new();
public delegate void KeypressHandler(KeyboardState state);
// public static void StartListening() {
// processInputThread.Start();
// Console.WriteLine("Started listening for input");
// }
public static void NextInputCycle() {
Queue<KeypressHandler> inputEventQueue = new();
// Read
newState = Keyboard.GetState();
Keys[] pressed = newState.GetPressedKeys();
Keys[] pressedLastFrame = oldState.GetPressedKeys();
Array.ForEach(pressed, key => {
if (oldState.IsKeyUp(key)){
if (keyPressListeners.TryGetValue(key, out var pressHandlers)){
pressHandlers.ForEach(t => {
if (t.Item2.Enabled){
inputEventQueue.Enqueue(t.Item1);
}
if (t.Item2.RemoveOnNextTrigger){
pressHandlers.Remove(t);
}
});
}
}
if (keyHoldListeners.TryGetValue(key, out var holdHandlers)){
holdHandlers.ForEach(t => {
if (t.Item2.Enabled){
inputEventQueue.Enqueue(t.Item1);
}
if (t.Item2.RemoveOnNextTrigger){
holdHandlers.Remove(t);
}
});
}
});
Array.ForEach(pressedLastFrame, key => {
if (!keyReleaseListeners.ContainsKey(key)){
return;
}
if (newState.IsKeyUp(key)){
if (keyReleaseListeners.TryGetValue(key, out var releaseHandlers))
releaseHandlers.ForEach(t => {
if (t.Item2.Enabled){
inputEventQueue.Enqueue(t.Item1);
}
if (t.Item2.RemoveOnNextTrigger){
releaseHandlers.Remove(t);
}
});
}
});
oldState = newState;
// Execute
foreach (KeypressHandler handler in inputEventQueue){
handler(newState);
}
}
// private static Thread processInputThread = new(() => {
//
// });
public static void AddListener(Keys key, KeypressHandler action, InputTiming timing, InputListenerHook hook) {
Dictionary<Keys, List<(KeypressHandler, InputListenerHook)>> workingDict;
switch (timing){
case InputTiming.PRESS:
workingDict = keyPressListeners;
break;
case InputTiming.HOLD:
workingDict = keyHoldListeners;
break;
case InputTiming.RELEASE:
workingDict = keyReleaseListeners;
break;
default:
throw new ArgumentOutOfRangeException(nameof(timing), timing, null);
}
if (!workingDict.ContainsKey(key)){
workingDict.Add(key, new());
}
workingDict[key].Add((action, hook));
}
}

View file

@ -0,0 +1,7 @@
namespace FNAF_Clone.Input;
public enum InputTiming {
PRESS,
HOLD,
RELEASE
}

2
FNAF_Clone/Program.cs Normal file
View file

@ -0,0 +1,2 @@
using var game = new FNAF_Clone.GameMain();
game.Run();

43
FNAF_Clone/app.manifest Normal file
View file

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="FNAF_Clone"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on and is
is designed to work with. Uncomment the appropriate elements and Windows will
automatically selected the most compatible environment. -->
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">permonitorv2,permonitor</dpiAwareness>
</windowsSettings>
</application>
</assembly>

View file

@ -0,0 +1 @@
../../MonoGameLibrary/MonoGameLibrary/bin/Debug/net8.0/MonoGameLibrary.dll