using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Brigadier.NET;
using Brigadier.NET.Exceptions;
using MinecraftClient.ChatBots;
using MinecraftClient.CommandHandler;
using MinecraftClient.CommandHandler.Patch;
using MinecraftClient.Inventory;
using MinecraftClient.Logger;
using MinecraftClient.EntityHandler;
using MinecraftClient.Mapping;
using MinecraftClient.Protocol;
using MinecraftClient.Protocol.Handlers.Forge;
using MinecraftClient.Protocol.Message;
using MinecraftClient.Protocol.ProfileKey;
using MinecraftClient.Protocol.Session;
using MinecraftClient.Proxy;
using MinecraftClient.Scripting;
using static MinecraftClient.Settings;
namespace MinecraftClient
{
///
/// The main client class, used to connect to a Minecraft server.
///
public class McClient : IMinecraftComHandler
{
public static int ReconnectionAttemptsLeft = 0;
public static CommandDispatcher dispatcher = new();
private readonly Dictionary onlinePlayers = new();
private readonly ConcurrentQueue chatQueue = new();
private DateTime nextMessageSendTime = DateTime.MinValue;
private readonly object inventoryLock = new();
private readonly Dictionary inventories = new();
private readonly List registeredServerPluginChannels = new();
private readonly Dictionary> registeredBotPluginChannels = new();
private bool terrainAndMovementsEnabled;
private bool terrainAndMovementsRequested = false;
private bool inventoryHandlingEnabled;
private bool inventoryHandlingRequested = false;
private bool entityHandlingEnabled;
private static SemaphoreSlim locationLock = new(1, 1);
private bool locationReceived = false;
private readonly World world = new();
private Queue? steps;
private Queue? path;
private Location location;
private float? _yaw; // Used for calculation ONLY!!! Doesn't reflect the client yaw
private float? _pitch; // Used for calculation ONLY!!! Doesn't reflect the client pitch
private float playerYaw;
private float playerPitch;
private double motionY;
public enum MovementType { Sneak, Walk, Sprint }
private int sequenceId; // User for player block synchronization (Aka. digging, placing blocks, etc..)
private readonly string host;
private readonly int port;
private int protocolversion;
private string username;
private Guid uuid;
private string uuidStr;
private string sessionId;
private PlayerKeyPair? playerKeyPair;
private DateTime lastKeepAlive;
private int respawnTicks = 0;
private int gamemode = 0;
private bool isSupportPreviewsChat;
private EnchantmentData? lastEnchantment = null;
private int playerEntityID;
// player health and hunger
private float playerHealth;
private int playerFoodSaturation;
private int playerLevel;
private int playerTotalExperience;
private byte CurrentSlot = 0;
// Entity handling
private readonly Dictionary entities = new();
// server TPS
private long lastAge = 0;
private DateTime lastTime;
private double serverTPS = 0;
private double averageTPS = 20;
private const int maxSamples = 5;
private readonly List tpsSamples = new(maxSamples);
private double sampleSum = 0;
// ChatBot
private ChatBot[] chatbots = Array.Empty();
private static ChatBot[] botsOnHold = Array.Empty();
private bool OldChatBotUpdateTrigger = false;
private bool networkPacketCaptureEnabled = false;
// ChatBot Async Events
private static int EventTypeCount = typeof(McClientEventType).GetFields().Length;
private static SemaphoreSlim EventCallbackWriteLock = new(1, 1);
private static Task[][] ChatbotEventTasks = new Task[EventTypeCount][];
private static Task[] WaitChatbotExecuteTask = new Task[EventTypeCount];
private static SemaphoreSlim[] ChatbotEventTaskLocks = new SemaphoreSlim[EventTypeCount];
private static Func