internal async Task SendPlayerInfoAsync() { var list = new List <PlayerInfoAction>(); foreach (Player player in this.Server.OnlinePlayers.Values) { var piaa = new PlayerInfoAddAction() { Name = player.Username, Uuid = player.Uuid, Ping = player.Ping, Gamemode = (int)Player.Gamemode, DisplayName = ChatMessage.Simple(player.Username) }; if (this.config.OnlineMode) { var uuid = player.Uuid.ToString().Replace("-", ""); var skin = await MinecraftAPI.GetUserAndSkinAsync(uuid); piaa.Properties.AddRange(skin.Properties); } list.Add(piaa); } await this.QueuePacketAsync(new PlayerInfo(0, list)); }
public static async Task <string> DetectVersion(StorageFile resourcePackFile, bool onlyReleases = true) { if (resourcePackFile == null) { throw new ArgumentNullException(nameof(resourcePackFile)); } Logger.WriteLine($"Detecting resource pack version of file {resourcePackFile.Name}."); var relations = await ResourceRelationService.GetOrCreateAsync(); if (relations?.Count == 0) { throw new InvalidOperationException("Retrieved relation set is empty."); } if (!MinecraftService.IsInitialized) { await MinecraftService.InitializeAsync(); } var versionCount = onlyReleases ? MinecraftAPI.Releases.ToDictionary(x => x.Id, x => 0) : MinecraftAPI.Versions.ToDictionary(x => x.Id, x => 0); using (var stream = await resourcePackFile.OpenStreamForReadAsync()) using (var archive = new ZipArchive(stream, ZipArchiveMode.Read)) { foreach (var entry in archive.Entries.ToList()) { var entryPath = entry.FullName.Replace("/", "\\"); foreach (var relation in relations) { foreach (var versionPathPair in relation) { if (versionPathPair.Value.Equals(entryPath) && versionCount.ContainsKey(versionPathPair.Key)) { versionCount[versionPathPair.Key]++; } } } } } var maxCount = versionCount.Max(vp => vp.Value); var mostNominatedVersions = versionCount.Where(r => r.Value == maxCount).Select(vp => vp.Key); string maxVersion = null; foreach (var nominatedVersion in mostNominatedVersions) { if (maxVersion == null) { maxVersion = nominatedVersion; } else { maxVersion = MinecraftAPI.MaxVersion(maxVersion, nominatedVersion); } } return(maxVersion); }
public static async Task InitializeAsync() { Debug.WriteLine("Initializing MinecraftService..."); var localDirectory = await ApplicationData.Current.LocalFolder.CreateFolderAsync("MinecraftApi", CreationCollisionOption.OpenIfExists); if (!MinecraftAPI.IsInitialized) { await MinecraftAPI.InitializeAsync(localDirectory.Path); } Debug.WriteLine("...MinecraftService initialized."); }
public static async Task<StorageFile> DownloadAsync(string version, DownloadOption option = DownloadOption.Default) { if (!MinecraftAPI.IsInitialized) { Debug.WriteLine($"MinecraftService is not initialized. Proceeds to initialize it."); await InitializeAsync(); } if (!MinecraftAPI.Contains(version)) { Debug.WriteLine($"Version {version} does not exist in available links."); return null; } if (await ContainsZip(version)) { Debug.WriteLine($"Version {version} is already downloaded. No further steps required."); return null; } var uri = new Uri(MinecraftAPI.Get(version)?.Downloads.Client?.Url); var root = await GetOrCreateRootFolderAsync(); var file = await root?.CreateFileAsync(version + ".zip", CreationCollisionOption.ReplaceExisting); try { BackgroundDownloader downloader = new BackgroundDownloader(); DownloadOperation download = downloader?.CreateDownload(uri, file); Debug.WriteLine($"Downloading: {uri?.AbsolutePath}..."); await download.StartAsync(); Debug.WriteLine($"...Download completed: {uri?.AbsolutePath}"); } catch (Exception e) { Debug.WriteLine($"Error when downloading {uri.AbsolutePath}:\n{e.Message}"); return null; } await CreateResourceListAsync(version); if (option == DownloadOption.ExtractFiles) await Extract(version); return file; }
/// <summary> /// 开始下载 /// </summary> public void Download(DownloadingEventHandler eve) { percent = 0; DownloadProgressRefreshed(this, new EventArgs()); if (MinecraftVersion == null) { throw new Exception("Minecraft Version Can't be NULL"); } else { MinecraftProfile profile = MinecraftProfile.GetFromVersion(MinecraftVersion, VersionName); profile.SaveToLocalPath(); profile.InstallVersion((float f) => { eve(f * (1f - ((float)APIVersions.Count / 10f))); }); if (APIVersions.Count == 0) { } else { int count = APIVersions.Values.Count; int dldd = 0; foreach (var api in APIVersions.Values) { MinecraftAPI mcapi = api.GetMinecraftAPI(); mcapi.profile = profile; profile.APIConfig.InstallAPI(mcapi, (float f) => { eve((1f - ((float)APIVersions.Count / 10f)) + (float)(f / 10f) + (float)(dldd / 10f)); }); dldd++; } } } }
public async Task StartConnectionAsync() { while (!Cancellation.IsCancellationRequested && this.tcp.Connected) { Packet packet = await this.GetNextPacketAsync(); if (this.State == ClientState.Play && packet.data.Length < 1) { this.Disconnect(); } switch (this.State) { case ClientState.Status: // Server ping/list switch (packet.id) { case 0x00: var status = new ServerStatus(Server); await this.SendPacketAsync(new RequestResponse(status)); break; case 0x01: await this.SendPacketAsync(new PingPong(packet.data)); this.Disconnect(); break; } break; case ClientState.Handshaking: if (packet.id == 0x00) { if (packet == null) { throw new InvalidOperationException(); } var handshake = await PacketSerializer.FastDeserializeAsync <Handshake>(packet.data); var nextState = handshake.NextState; if (nextState != ClientState.Status && nextState != ClientState.Login) { this.Logger.LogDebug($"Client sent unexpected state ({(int)nextState}), forcing it to disconnect"); await this.DisconnectAsync(ChatMessage.Simple("you seem suspicious")); } this.State = nextState; this.Logger.LogInformation($"Handshaking with client (protocol: {handshake.Version}, server: {handshake.ServerAddress}:{handshake.ServerPort})"); } else { // Handle legacy ping } break; case ClientState.Login: switch (packet.id) { default: this.Logger.LogError("Client in state Login tried to send an unimplemented packet. Forcing it to disconnect."); await this.DisconnectAsync("Unknown Packet Id."); break; case 0x00: var loginStart = await PacketSerializer.FastDeserializeAsync <LoginStart>(packet.data); string username = config.MulitplayerDebugMode ? $"Player{Globals.Random.Next(1, 999)}" : loginStart.Username; this.Logger.LogDebug($"Received login request from user {loginStart.Username}"); await this.Server.DisconnectIfConnectedAsync(username); if (this.config.OnlineMode) { var user = await MinecraftAPI.GetUserAsync(loginStart.Username); this.Player = new Player(Guid.Parse(user.Id), loginStart.Username, this) { World = this.Server.World }; this.packetCryptography.GenerateKeyPair(); var values = this.packetCryptography.GeneratePublicKeyAndToken(); this.randomToken = values.randomToken; await this.SendPacketAsync(new EncryptionRequest(values.publicKey, this.randomToken)); break; } this.Player = new Player(UUIDFactory.CreateUUID(3, 1, $"OfflinePlayer:{username}"), username, this) { World = this.Server.World }; //await this.SetCompression(); await this.ConnectAsync(); break; case 0x01: var encryptionResponse = PacketSerializer.FastDeserialize <EncryptionResponse>(packet.data); this.sharedKey = this.packetCryptography.Decrypt(encryptionResponse.SharedSecret); var decryptedToken = this.packetCryptography.Decrypt(encryptionResponse.VerifyToken); if (!decryptedToken.SequenceEqual(this.randomToken)) { await this.DisconnectAsync("Invalid token.."); break; } var serverId = sharedKey.Concat(this.packetCryptography.PublicKey).ToArray().MinecraftShaDigest(); JoinedResponse response = await MinecraftAPI.HasJoined(this.Player.Username, serverId); if (response is null) { this.Logger.LogWarning($"Failed to auth {this.Player.Username}"); await this.DisconnectAsync("Unable to authenticate.."); break; } this.encryptionEnabled = true; this.minecraftStream = new AesStream(this.debugStream ?? (Stream)this.tcp.GetStream(), this.sharedKey); //await this.SetCompression(); await ConnectAsync(); break; case 0x02: // Login Plugin Response break; } break; case ClientState.Play: //await this.Logger.LogDebugAsync($"Received Play packet with Packet ID 0x{packet.id.ToString("X")}"); await PacketHandler.HandlePlayPackets(packet, this); break; } //await Task.Delay(50); } Logger.LogInformation($"Disconnected client"); if (this.State == ClientState.Play) { await this.Server.Events.InvokePlayerLeaveAsync(new PlayerLeaveEventArgs(this.Player)); } if (tcp.Connected) { this.tcp.Close(); if (this.Player != null) { this.Server.OnlinePlayers.TryRemove(this.Player.Uuid, out var _); } } }
public async Task StartConnectionAsync() { while (!Cancellation.IsCancellationRequested && this.Tcp.Connected) { Packet packet = this.Compressed ? await this.GetNextCompressedPacketAsync() : await this.GetNextPacketAsync(); Packet returnPacket; if (this.State == ClientState.Play && packet.PacketData.Length < 1) { this.Disconnect(); } switch (this.State) { case ClientState.Status: //server ping/list switch (packet.PacketId) { case 0x00: var status = new ServerStatus(OriginServer); await PacketHandler.CreateAsync(new RequestResponse(status), this.MinecraftStream); break; case 0x01: await PacketHandler.CreateAsync(new PingPong(packet.PacketData), this.MinecraftStream); this.Disconnect(); break; } break; case ClientState.Handshaking: if (packet.PacketId == 0x00) { if (packet == null) { throw new InvalidOperationException(); } var handshake = await PacketHandler.CreateAsync(new Handshake(packet.PacketData)); var nextState = handshake.NextState; if (nextState != ClientState.Status && nextState != ClientState.Login) { this.Logger.LogDebug($"Client sent unexpected state ({(int)nextState}), forcing it to disconnect"); await this.DisconnectAsync(Chat.ChatMessage.Simple("you seem suspicious")); } this.State = nextState; this.Logger.LogMessage($"Handshaking with client (protocol: {handshake.Version}, server: {handshake.ServerAddress}:{handshake.ServerPort})"); } else { //Handle legacy ping stuff } break; case ClientState.Login: switch (packet.PacketId) { default: this.Logger.LogError("Client in state Login tried to send an unimplemented packet. Forcing it to disconnect."); await this.DisconnectAsync(ChatMessage.Simple("Unknown Packet Id.")); break; case 0x00: var loginStart = await PacketHandler.CreateAsync(new LoginStart(packet.PacketData)); string username = loginStart.Username; if (Config.MulitplayerDebugMode) { username = $"Player{new Random().Next(1, 999)}"; this.Logger.LogDebug($"Overriding username from {loginStart.Username} to {username}"); } this.Logger.LogDebug($"Received login request from user {loginStart.Username}"); if (this.OriginServer.CheckPlayerOnline(username)) { await this.OriginServer.Clients.FirstOrDefault(c => c.Player.Username == username).DisconnectAsync(Chat.ChatMessage.Simple("Logged in from another location")); } if (this.Config.OnlineMode) { var users = await MinecraftAPI.GetUsersAsync(new string[] { loginStart.Username }); var uid = users.FirstOrDefault(); var uuid = Guid.Parse(uid.Id); this.Player = new Player(uuid, loginStart.Username, this); PacketCryptography.GenerateKeyPair(); var pubKey = PacketCryptography.PublicKeyToAsn(); this.Token = PacketCryptography.GetRandomToken(); returnPacket = await PacketHandler.CreateAsync(new EncryptionRequest(pubKey, this.Token), this.MinecraftStream); break; } this.Player = new Player(Guid.NewGuid(), username, this); await ConnectAsync(this.Player.Uuid); break; case 0x01: var encryptionResponse = await PacketHandler.CreateAsync(new EncryptionResponse(packet.PacketData)); JoinedResponse response; this.SharedKey = PacketCryptography.Decrypt(encryptionResponse.SharedSecret); var dec2 = PacketCryptography.Decrypt(encryptionResponse.VerifyToken); var dec2Base64 = Convert.ToBase64String(dec2); var tokenBase64 = Convert.ToBase64String(this.Token); if (!dec2Base64.Equals(tokenBase64)) { await this.DisconnectAsync(Chat.ChatMessage.Simple("Invalid token..")); break; } var encodedKey = PacketCryptography.PublicKeyToAsn(); var serverId = PacketCryptography.MinecraftShaDigest(SharedKey.Concat(encodedKey).ToArray()); response = await MinecraftAPI.HasJoined(this.Player.Username, serverId); if (response is null) { this.Logger.LogWarning($"Failed to auth {this.Player.Username}"); await this.DisconnectAsync(Chat.ChatMessage.Simple("Unable to authenticate..")); break; } this.EncryptionEnabled = true; this.MinecraftStream = new AesStream(this.Tcp.GetStream(), this.SharedKey); await ConnectAsync(new Guid(response.Id)); break; case 0x02: // Login Plugin Response break; } break; case ClientState.Play: ///this.Logger.LogDebugAsync($"Received Play packet with Packet ID 0x{packet.PacketId.ToString("X")}"); await PacketHandler.HandlePlayPackets(packet, this); break; } } Logger.LogMessage($"Disconnected client"); if (this.IsPlaying) { await this.OriginServer.Events.InvokePlayerLeave(new PlayerLeaveEventArgs(this)); } this.OriginServer.Broadcast(string.Format(this.Config.LeaveMessage, this.Player.Username)); this.Player = null; if (Tcp.Connected) { this.Tcp.Close(); } }