using System;
using System.Windows;
using Breath_of_the_Wild_Multiplayer.Source_files;
using System.Windows.Media;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Net;
using System.Net.Sockets;
using System.Diagnostics;
using System.Text;
using Newtonsoft.Json;
using Breath_of_the_Wild_Multiplayer.MVVM.Model.DTO;
using System.Threading.Tasks;
namespace Breath_of_the_Wild_Multiplayer.MVVM.Model
{
public class serverDataModel : ObservableObject
{
private static Random random = new Random();
public static int serversAdded = 0;
private string _Name;
public string Name
{
get { return _Name; }
set {
_Name = value;
OnPropertyChanged();
}
}
private string _description;
public string description
{
get { return _description; }
set {
_description = value;
OnPropertyChanged();
}
}
private string _playStyle;
public string playStyle
{
get { return _playStyle; }
set {
_playStyle = value;
OnPropertyChanged();
}
}
private int _capacity;
public int capacity
{
get { return _capacity; }
set {
_capacity = value;
OnPropertyChanged();
}
}
///
/// Get the formatted string for connected players
///
public string connectedPlayersString {
get { return this.open ? String.Format("{0}/{1} players", playerList.Count, capacity) : ""; }
set { OnPropertyChanged(); }
}
private string _questGiver;
public string questGiver
{
get { return _questGiver; }
set {
_questGiver = value;
OnPropertyChanged();
}
}
private Dictionary playerList = new Dictionary();
public List playerListWithNumber
{
get
{
List playerNamesWithPlayerNumber = new List();
foreach(KeyValuePair player in playerList)
{
playerNamesWithPlayerNumber.Add($"{player.Key + 1}. {player.Value}");
}
return playerNamesWithPlayerNumber;
}
set { OnPropertyChanged(); }
}
public bool shouldDisplayPlayersTooltip
{
get { return open && playerList.Count > 0; }
set
{
OnPropertyChanged();
}
}
public int TooltipColumnCount
{
get { return playerList.Count > 8 ? 8 : playerList.Count; }
set
{
OnPropertyChanged();
}
}
private int _ping;
public int ping
{
get {
return _ping;
}
set {
_ping = value;
OnPropertyChanged();
}
}
public string pingData
{
get {
if (this.status == ServerStatus.Pinging)
return "Pinging...";
else if (this.status == ServerStatus.Offline)
return "Server closed";
else if (this.status == ServerStatus.WrongPassword)
return "Wrong password";
else
return $"{this.ping} ms";
}
set
{
OnPropertyChanged();
}
}
public enum ServerStatus
{
Online,
Offline,
WrongPassword,
Pinging
}
private ServerStatus _status;
public ServerStatus status
{
get { return _status; }
set {
_status = value;
CallGetterUpdates();
}
}
public SolidColorBrush pingColor
{
get {
if (!this.open)
return new SolidColorBrush(Color.FromArgb(0xFF, 0x8C, 0x8C, 0x8C));
if (this.ping >= 150)
return new SolidColorBrush(Color.FromArgb(0xFF, 0xE3, 0x46, 0x46));
if (this.ping >= 100)
return new SolidColorBrush(Color.FromArgb(0xFF, 0xE3, 0xD1, 0x46));
return new SolidColorBrush(Color.FromArgb(0xFF, 0x5F, 0xE3, 0x46));
}
set
{
OnPropertyChanged();
}
}
private string _IP;
public string IP
{
get { return _IP; }
set {
_IP = value;
OnPropertyChanged();
}
}
private int _Port;
public int Port
{
get { return _Port; }
set {
_Port = value;
OnPropertyChanged();
}
}
private bool _selected;
public bool selected
{
get { return _selected; }
set {
_selected = value;
OnPropertyChanged();
}
}
private int _serverIndex;
public int serverIndex
{
get { return _serverIndex; }
set {
_serverIndex = value;
OnPropertyChanged();
}
}
private bool _favorite;
public bool favorite
{
get { return _favorite; }
set {
_favorite = value;
OnPropertyChanged();
}
}
private bool _open;
public bool open
{
get { return _open; }
set {
_open = value;
OnPropertyChanged();
}
}
public string connectMessage
{
get
{
if (!isCemuSetup)
return "BCML installation not found";
if (!open)
return "Server closed";
return "Connect";
}
set
{
OnPropertyChanged();
}
}
private Visibility _visible;
public Visibility visible
{
get { return _visible; }
set {
_visible = value;
OnPropertyChanged();
}
}
private bool isCemuSetup;
public RelayCommand changeFavoriteState { get; set; }
public string Password { get; set; }
public serverDataModel(bool isCemuSetup, string name, string ip, int port, bool favorite, string password, bool selected = false, bool async = true)
{
this.serverIndex = serversAdded;
this.Name = name;
this.description = "";
this.playStyle = "";
this.IP = ip;
this.Port = port;
this.favorite = favorite;
this.selected = selected;
this.isCemuSetup = isCemuSetup;
this.Password = password;
this.status = ServerStatus.Offline;
this.ping = 0;
this.capacity = 0;
if (!string.IsNullOrEmpty(ip))
{
visible = Visibility.Visible;
if (async)
_ = Task.Run(() => pingServer());
else
pingServer();
serversAdded++;
}
else
visible = Visibility.Hidden;
List QuestGivers = new List()
{
"Mipha",
"Revali",
"Urbosa",
"Daruk",
"Old Man",
"Zelda",
"Ganondorf",
"Impa",
"Kass"
};
this.questGiver = QuestGivers[random.Next(QuestGivers.Count)];
changeFavoriteState = new RelayCommand(o =>
{
this.favorite = !this.favorite;
SharedData.ServerBrowser.ChangeFavorite(this.serverIndex);
});
Password = password;
}
public void pingServer()
{
IPEndPoint ip = new IPEndPoint(IPAddress.Parse(this.IP), this.Port);
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
this.status = ServerStatus.Pinging;
var result = s.BeginConnect(ip, null, null);
bool success = result.AsyncWaitHandle.WaitOne(500, true);
if (!success)
{
s.Close();
setAsOffline();
this.status = ServerStatus.Offline;
return;
}
Stopwatch pingTimer = Stopwatch.StartNew();
int SIZE = 6144;
byte[] info = new byte[SIZE];
List data = new List() { 0x01 };
data.AddRange(Encoding.UTF8.GetBytes(this.Password));
while (data.Count < SIZE)
data.Add(0);
s.SendTimeout = 2500;
s.ReceiveTimeout = 2500;
try
{
s.Send(data.ToArray());
s.Receive(info, 0, info.Length, 0);
}
catch
{
setAsOffline();
this.status = ServerStatus.Offline;
s.Close();
return;
}
ServerDataDTO PingResult = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(info));
if(!PingResult.CorrectPassword)
{
setAsOffline();
this.status = ServerStatus.WrongPassword;
s.Close();
return;
}
this.description = PingResult.Description;
this.capacity = PingResult.PlayerLimit;
this.playStyle = PingResult.Gamemode;
this.playerList = PingResult.PlayerList.Names;
this.status = ServerStatus.Online;
this.open = true;
CallGetterUpdates();
s.Close();
ping = (int)pingTimer.ElapsedMilliseconds;
}
public void setAsOffline()
{
open = false;
description = "";
capacity = 0;
playStyle = "";
this.playerList = new Dictionary();
CallGetterUpdates();
}
public void CallGetterUpdates()
{
connectedPlayersString = "";
playerListWithNumber = new List();
shouldDisplayPlayersTooltip = false;
TooltipColumnCount = 0;
pingData = "";
pingColor = new SolidColorBrush();
connectMessage = "";
}
}
}