mirror of
https://github.com/Impostor/Impostor.git
synced 2026-10-19 15:51:42 +00:00
Possible to create / join a game
This commit is contained in:
1 parent
b65326a4a8
commit
bc028b421c
13 files changed
+341
-75
No files matched your search
@@ -10,9 +10,9 @@ namespace AmongUs.Client
|
||||
{
|
||||
var appData = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "..\\LocalLow");
|
||||
var regionFile = Path.Combine(appData, "Innersloth", "Among Us", "regionInfo.dat");
|
||||
var region = new RegionInfo("Private", "127.0.0.1", new []
|
||||
var region = new RegionInfo("Private", "192.168.1.211", new []
|
||||
{
|
||||
new ServerInfo("Private-Master-1", "127.0.0.1", 22023)
|
||||
new ServerInfo("Private-Master-1", "192.168.1.211", 22023)
|
||||
});
|
||||
|
||||
using (var file = File.Open(regionFile, FileMode.Create, FileAccess.Write))
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace AmongUs.Server.Data
|
||||
{
|
||||
public static class DisconnectMessages
|
||||
{
|
||||
public const string Error = "There was an internal server error. " +
|
||||
"Check the server console for more information. " +
|
||||
"Please report the issue on the AmongUsServer GitHub if it keeps happening.";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace AmongUs.Server.Exceptions
|
||||
{
|
||||
public class AmongUsException : Exception
|
||||
{
|
||||
public AmongUsException()
|
||||
{
|
||||
}
|
||||
|
||||
protected AmongUsException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
|
||||
public AmongUsException(string? message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public AmongUsException(string? message, Exception? innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using AmongUs.Server.Data;
|
||||
using AmongUs.Server.Exceptions;
|
||||
using AmongUs.Server.Extensions;
|
||||
using AmongUs.Server.Net.Request;
|
||||
using AmongUs.Server.Net.Response;
|
||||
@@ -17,46 +18,55 @@ namespace AmongUs.Server.Net
|
||||
|
||||
private readonly ClientManager _clientManager;
|
||||
private readonly GameManager _gameManager;
|
||||
private readonly Connection _connection;
|
||||
private readonly ClientState _state;
|
||||
private readonly int _version;
|
||||
private readonly string _name;
|
||||
|
||||
public Client(ClientManager clientManager, GameManager gameManager, Connection connection, int version, string name)
|
||||
public Client(ClientManager clientManager, GameManager gameManager, int id, string name, Connection connection)
|
||||
{
|
||||
_clientManager = clientManager;
|
||||
_gameManager = gameManager;
|
||||
_connection = connection;
|
||||
_connection.DataReceived += OnDataReceived;
|
||||
_connection.Disconnected += OnDisconnected;
|
||||
_state = new ClientState(_connection);
|
||||
_version = version;
|
||||
_name = name;
|
||||
Id = id;
|
||||
Name = name;
|
||||
Connection = connection;
|
||||
Connection.DataReceived += OnDataReceived;
|
||||
Connection.Disconnected += OnDisconnected;
|
||||
Player = new ClientPlayer(this);
|
||||
}
|
||||
|
||||
public int Id { get; }
|
||||
public string Name { get; }
|
||||
public Connection Connection { get; }
|
||||
public ClientPlayer Player { get; }
|
||||
|
||||
private void OnDataReceived(DataReceivedEventArgs e)
|
||||
{
|
||||
while (true)
|
||||
try
|
||||
{
|
||||
if (e.Message.Position >= e.Message.Length)
|
||||
while (true)
|
||||
{
|
||||
break;
|
||||
if (e.Message.Position >= e.Message.Length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
OnMessageReceived(e.Message.ReadMessage(), e.SendOption);
|
||||
}
|
||||
|
||||
OnMessageReceived(e.Message.ReadMessage());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error(ex, "Exception caught in client data handler.");
|
||||
Connection.Send(new Message1DisconnectReason(DisconnectReason.Custom, DisconnectMessages.Error));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMessageReceived(MessageReader message)
|
||||
private void OnMessageReceived(MessageReader message, SendOption sendOption)
|
||||
{
|
||||
var flag = (RequestFlag) message.Tag;
|
||||
|
||||
Logger.Verbose("[{0}] Server got {1}.", Id, flag);
|
||||
|
||||
switch (flag)
|
||||
{
|
||||
// 101A3813
|
||||
case RequestFlag.HostGame:
|
||||
Logger.Debug("Server got host game");
|
||||
|
||||
{
|
||||
// Read game settings.
|
||||
var gameInfoBytes = message.ReadBytesAndSize();
|
||||
var gameInfo = GameOptionsData.Deserialize(gameInfoBytes);
|
||||
@@ -65,69 +75,98 @@ namespace AmongUs.Server.Net
|
||||
var game = _gameManager.Create(this, gameInfo);
|
||||
if (game == null)
|
||||
{
|
||||
_connection.Send(new Message1DisconnectReason(DisconnectReason.ServerFull));
|
||||
Connection.Send(new Message1DisconnectReason(DisconnectReason.ServerFull));
|
||||
return;
|
||||
}
|
||||
|
||||
// Code (32) in the packet below will be used in JoinGame.
|
||||
// Code in the packet below will be used in JoinGame.
|
||||
using (var writer = MessageWriter.Get(SendOption.Reliable))
|
||||
{
|
||||
writer.StartMessage(0);
|
||||
writer.Write(32);
|
||||
writer.Write(game.Code);
|
||||
writer.EndMessage();
|
||||
|
||||
_connection.Send(writer);
|
||||
Connection.Send(writer);
|
||||
}
|
||||
break;
|
||||
// 101A388C
|
||||
}
|
||||
|
||||
case RequestFlag.JoinGame:
|
||||
Logger.Debug("Server got join game");
|
||||
|
||||
{
|
||||
var gameCode = message.ReadInt32();
|
||||
if (gameCode != 32)
|
||||
var unknown = message.ReadByte();
|
||||
var game = _gameManager.Find(gameCode);
|
||||
if (game == null)
|
||||
{
|
||||
Logger.Debug("- Code {0}", gameCode, GameCode.IntToGameName(gameCode));
|
||||
|
||||
_connection.Send(new Message1DisconnectReason(DisconnectReason.GameMissing));
|
||||
Connection.Send(new Message1DisconnectReason(DisconnectReason.GameMissing));
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: JoinGame
|
||||
Logger.Debug("JoinGame {0} {1}", gameCode, message.ReadByte());
|
||||
|
||||
game.HandleJoinGame(Player);
|
||||
break;
|
||||
}
|
||||
|
||||
// 101A3960
|
||||
case RequestFlag.StartGame:
|
||||
Logger.Debug("Server got StartGame");
|
||||
break;
|
||||
|
||||
// 101A39EC
|
||||
case RequestFlag.RemoveGame:
|
||||
Logger.Debug("Server got RemoveGame");
|
||||
break;
|
||||
|
||||
case RequestFlag.RemovePlayer:
|
||||
Logger.Debug("Server got RemovePlayer");
|
||||
break;
|
||||
// 101A3A15
|
||||
|
||||
case RequestFlag.GameData:
|
||||
Logger.Debug("Server got GameData");
|
||||
break;
|
||||
// 101A3AAB
|
||||
case RequestFlag.GameDataTo:
|
||||
Logger.Debug("Server got GameDataTo");
|
||||
{
|
||||
var game = Player.Game;
|
||||
if (game == null)
|
||||
{
|
||||
throw new NullReferenceException("Game was not set for the client.");
|
||||
}
|
||||
|
||||
var code = message.ReadInt32();
|
||||
if (code != game.Code)
|
||||
{
|
||||
// Packet was meant for another game.
|
||||
return;
|
||||
}
|
||||
|
||||
// Broadcast packet to all other players.
|
||||
using (var writer = MessageWriter.Get(sendOption))
|
||||
{
|
||||
if (flag == RequestFlag.GameDataTo)
|
||||
{
|
||||
var target = message.ReadPackedInt32();
|
||||
writer.CopyFrom(message);
|
||||
game.SendTo(writer, target);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.CopyFrom(message);
|
||||
game.SendToAllExcept(writer, Player);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// 101A3BA6
|
||||
case RequestFlag.JoinedGame:
|
||||
Logger.Debug("Server got JoinedGame");
|
||||
break;
|
||||
|
||||
// 101A3BD0
|
||||
case RequestFlag.EndGame:
|
||||
Logger.Debug("Server got EndGame");
|
||||
break;
|
||||
|
||||
default:
|
||||
Logger.Debug("Server received unknown {0}", flag);
|
||||
Logger.Warning("Server received unknown flag {0}.", flag);
|
||||
break;
|
||||
}
|
||||
|
||||
if (message.Position < message.Length)
|
||||
if (flag != RequestFlag.GameData &&
|
||||
flag != RequestFlag.GameDataTo &&
|
||||
message.Position < message.Length)
|
||||
{
|
||||
Logger.Warning("Server did not consume all bytes from {0} ({1} < {2}).",
|
||||
flag,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Concurrent;
|
||||
using AmongUs.Server.Exceptions;
|
||||
using Serilog;
|
||||
|
||||
namespace AmongUs.Server.Net
|
||||
@@ -7,25 +8,57 @@ namespace AmongUs.Server.Net
|
||||
{
|
||||
private static readonly ILogger Logger = Log.ForContext<ClientManager>();
|
||||
|
||||
private readonly HashSet<Client> _clients;
|
||||
private readonly ConcurrentDictionary<int, Client> _clients;
|
||||
private readonly object _idLock;
|
||||
private int _idLast;
|
||||
|
||||
public ClientManager()
|
||||
{
|
||||
_clients = new HashSet<Client>();
|
||||
_clients = new ConcurrentDictionary<int, Client>();
|
||||
_idLock = new object();
|
||||
_idLast = 0;
|
||||
}
|
||||
|
||||
// No idea what a good way for this is.
|
||||
public int NextId()
|
||||
{
|
||||
lock (_idLock)
|
||||
{
|
||||
// 3 Attempts.
|
||||
for (var i = 0; i < 3; i++)
|
||||
{
|
||||
// It is important that ids start from 1, a 0 id causes issues.
|
||||
var result = ++_idLast;
|
||||
|
||||
if (_idLast == int.MaxValue)
|
||||
{
|
||||
_idLast = 0;
|
||||
}
|
||||
|
||||
if (_clients.ContainsKey(_idLast))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
throw new AmongUsException("Unable to generate a client id.");
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(Client client)
|
||||
{
|
||||
Logger.Information("Client connected.");
|
||||
|
||||
_clients.Add(client);
|
||||
|
||||
_clients.TryAdd(client.Id, client);
|
||||
}
|
||||
|
||||
public void Remove(Client client)
|
||||
{
|
||||
Logger.Information("Client disconnected.");
|
||||
|
||||
_clients.Remove(client);
|
||||
|
||||
_clients.TryRemove(client.Id, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using AmongUs.Shared.Innersloth.Data;
|
||||
|
||||
namespace AmongUs.Server.Net
|
||||
{
|
||||
public class ClientPlayer
|
||||
{
|
||||
public ClientPlayer(Client client)
|
||||
{
|
||||
Client = client;
|
||||
}
|
||||
|
||||
public Client Client { get; }
|
||||
public Game Game { get; set; }
|
||||
public LimboStates LimboState { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using Hazel;
|
||||
|
||||
namespace AmongUs.Server.Net
|
||||
{
|
||||
public class ClientState
|
||||
{
|
||||
private readonly Connection _connection;
|
||||
|
||||
public ClientState(Connection connection)
|
||||
{
|
||||
_connection = connection;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,143 @@
|
||||
using AmongUs.Shared.Innersloth;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AmongUs.Server.Exceptions;
|
||||
using AmongUs.Server.Extensions;
|
||||
using AmongUs.Server.Net.Response;
|
||||
using AmongUs.Shared.Innersloth;
|
||||
using AmongUs.Shared.Innersloth.Data;
|
||||
using Hazel;
|
||||
using Serilog;
|
||||
using ILogger = Serilog.ILogger;
|
||||
|
||||
namespace AmongUs.Server.Net
|
||||
{
|
||||
public class Game
|
||||
{
|
||||
private static readonly ILogger Logger = Log.ForContext<Game>();
|
||||
|
||||
private readonly ConcurrentDictionary<int, ClientPlayer> _players;
|
||||
private int _hostId;
|
||||
|
||||
public Game(int code, GameOptionsData options)
|
||||
{
|
||||
Code = code;
|
||||
CodeStr = GameCode.IntToGameName(code);
|
||||
GameState = GameStates.NotStarted;
|
||||
Options = options;
|
||||
|
||||
_hostId = -1;
|
||||
_players = new ConcurrentDictionary<int, ClientPlayer>();
|
||||
}
|
||||
|
||||
public int Code { get; }
|
||||
public string CodeStr { get; }
|
||||
public GameStates GameState { get; }
|
||||
public GameOptionsData Options { get; }
|
||||
|
||||
public void SendToAllExcept(MessageWriter message, ClientPlayer sender)
|
||||
{
|
||||
foreach (var (_, player) in _players.Where(x => x.Value != sender))
|
||||
{
|
||||
player.Client.Connection.Send(message);
|
||||
}
|
||||
}
|
||||
|
||||
public void SendTo(MessageWriter message, int playerId)
|
||||
{
|
||||
if (_players.TryGetValue(playerId, out var player))
|
||||
{
|
||||
player.Client.Connection.Send(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Warning("[{0}] Sending data to {1} failed, player does not exist.", CodeStr, playerId);
|
||||
}
|
||||
}
|
||||
|
||||
public void HandleJoinGame(ClientPlayer player)
|
||||
{
|
||||
switch (GameState)
|
||||
{
|
||||
case GameStates.NotStarted:
|
||||
HandleJoinGameNew(player);
|
||||
break;
|
||||
case GameStates.Started:
|
||||
HandleJoinGameNext(player);
|
||||
break;
|
||||
case GameStates.Ended:
|
||||
case GameStates.Destroyed:
|
||||
player.Client.Connection.Send(new Message1DisconnectReason(DisconnectReason.GameStarted));
|
||||
return;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleJoinGameNew(ClientPlayer player)
|
||||
{
|
||||
Logger.Verbose("[{0}] Player joined.", CodeStr);
|
||||
|
||||
// Store player.
|
||||
if (!_players.TryAdd(player.Client.Id, player))
|
||||
{
|
||||
throw new AmongUsException("Failed to add player to game.");
|
||||
}
|
||||
|
||||
// Assign player to this game for future packets.
|
||||
player.Game = this;
|
||||
|
||||
// Assign hostId if none is set.
|
||||
if (_hostId == -1)
|
||||
{
|
||||
_hostId = player.Client.Id;
|
||||
}
|
||||
|
||||
if (_hostId == player.Client.Id)
|
||||
{
|
||||
player.LimboState = LimboStates.NotLimbo;
|
||||
}
|
||||
|
||||
using (var message = MessageWriter.Get(SendOption.Reliable))
|
||||
{
|
||||
// TODO: WriteJoinedMessage - Move to own method / class
|
||||
message.StartMessage(7);
|
||||
message.Write(Code);
|
||||
message.Write(player.Client.Id);
|
||||
message.Write(_hostId);
|
||||
message.WritePacked(_players.Count - 1);
|
||||
|
||||
foreach (var (_, p) in _players.Where(x => x.Value == player))
|
||||
{
|
||||
message.WritePacked(p.Client.Id);
|
||||
}
|
||||
|
||||
message.EndMessage();
|
||||
|
||||
message.StartMessage(10);
|
||||
message.Write(Code);
|
||||
message.Write((sbyte)1);
|
||||
message.Write(false); // Private / Public
|
||||
message.EndMessage();
|
||||
|
||||
player.Client.Connection.Send(message);
|
||||
|
||||
// TODO: BroadcastJoinMessage - Move to own method / class
|
||||
message.Clear(SendOption.Reliable);
|
||||
message.StartMessage(1);
|
||||
message.Write(Code);
|
||||
message.Write(player.Client.Id);
|
||||
message.Write(_hostId);
|
||||
message.EndMessage();
|
||||
|
||||
SendToAllExcept(message, player);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleJoinGameNext(ClientPlayer player)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,9 +28,15 @@ namespace AmongUs.Server.Net
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Remove(int key)
|
||||
public Game Find(int gameCode)
|
||||
{
|
||||
_games.TryRemove(key, out _);
|
||||
_games.TryGetValue(gameCode, out var game);
|
||||
return game;
|
||||
}
|
||||
|
||||
public void Remove(int gameCode)
|
||||
{
|
||||
_games.TryRemove(gameCode, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace AmongUs.Server.Net
|
||||
{
|
||||
public enum GameStates : byte
|
||||
{
|
||||
NotStarted = 0,
|
||||
Started = 1,
|
||||
Ended = 2,
|
||||
Destroyed = 3
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,7 @@ namespace AmongUs.Server.Net
|
||||
}
|
||||
|
||||
// Register client.
|
||||
_clientManager.Add(new Client(_clientManager, _gameManager, e.Connection, clientVersion, clientName));
|
||||
_clientManager.Add(new Client(_clientManager, _gameManager, _clientManager.NextId(), clientName, e.Connection));
|
||||
}
|
||||
|
||||
public void Start()
|
||||
|
||||
@@ -6,18 +6,25 @@ namespace AmongUs.Server.Net.Response
|
||||
public class Message1DisconnectReason : MessageBase
|
||||
{
|
||||
private readonly DisconnectReason _reason;
|
||||
private readonly string _message;
|
||||
|
||||
// Notes:
|
||||
// - Specifying no reason does something with ban minutes left.
|
||||
// - (?) You were disconnected because Among Us was suspended by another app.
|
||||
public Message1DisconnectReason(DisconnectReason reason) : base(SendOption.Reliable, MessageFlag.DisconnectReason)
|
||||
public Message1DisconnectReason(DisconnectReason reason, string message = null) : base(SendOption.Reliable, MessageFlag.DisconnectReason)
|
||||
{
|
||||
_reason = reason;
|
||||
_message = message;
|
||||
}
|
||||
|
||||
protected override void WriteMessage(MessageWriter writer)
|
||||
{
|
||||
writer.Write((int) _reason);
|
||||
|
||||
if (_reason == DisconnectReason.Custom)
|
||||
{
|
||||
writer.Write(_message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace AmongUs.Shared.Innersloth.Data
|
||||
{
|
||||
public enum LimboStates
|
||||
{
|
||||
PreSpawn,
|
||||
NotLimbo,
|
||||
WaitingForHost,
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user