public void Read(IPacketReader reader) { ProtocolVersion = reader.ReadVarInt(); ServerAddress = reader.ReadString().ToString(); Port = reader.ReadInt16(); NextStage = (MCConnectionStage)reader.ReadVarInt(); }
public static void WriteAddonInfo(this IAuthHandler authHandler, IPacketReader inPacket, IPacketWriter outPacket, int size) { int count = 0x100; // arbitrary number if (Authenticator.ClientBuild >= 9464) { count = inPacket.ReadInt32(); // addon count } int i = 0; while (inPacket.Position < size && i < count) { string addonName = inPacket.ReadString(); bool enabled = inPacket.ReadBool(); uint filecrc = inPacket.ReadUInt32(); uint urlcrc = inPacket.ReadUInt32(); bool requireskey = filecrc != 0x1C776D01u && filecrc != 0x4C1C776Du; // offical crcs outPacket.WriteUInt8(2); // blizzard outPacket.WriteBool(true); // enabled outPacket.WriteBool(requireskey); if (requireskey) { outPacket.Write(AddonPublicKey); } outPacket.WriteUInt32(0); // use addon url file outPacket.WriteUInt8(0); // addon url filename, cstring i++; } outPacket.WriteUInt32(0); // banned addon count }
public void HandleAuthSession(ref IPacketReader packet, ref IWorldManager manager) { Authenticator.PacketCrypt.Initialised = true; packet.Position += 8; // client version, session id string name = packet.ReadString().ToUpper(); packet.Position += 4 + 4 + 20 + 4 + 4; // realm type, salt, encrypted password int addonsize = packet.ReadInt32(); Account account = new Account(name); account.Load <Character>(); manager.Account = account; // enable addons var addonPacketInfo = new PacketReader(this.GetAddonInfo(packet), false); var addonPacketResponse = new PacketWriter(Sandbox.Instance.Opcodes[global::Opcodes.SMSG_ADDON_INFO], "SMSG_ADDON_INFO"); this.WriteAddonInfo(addonPacketInfo, addonPacketResponse, addonsize); manager.Send(addonPacketResponse); PacketWriter writer = new PacketWriter(Sandbox.Instance.Opcodes[global::Opcodes.SMSG_AUTH_RESPONSE], "SMSG_AUTH_RESPONSE"); writer.WriteUInt8(0x0C); // AUTH_OK writer.WriteUInt32(0); writer.WriteUInt8(0); writer.WriteUInt32(0); writer.WriteUInt8(Authenticator.ExpansionLevel.Clamp(1, 2)); // Expansion level manager.Send(writer); }
public void Read(IPacketReader reader) { Identifier = reader.ReadString().ToString(); var data = reader.ReadBytes((int)reader.Buffer.Length); Data = new Memory <byte>(new byte[data.Length]); data.CopyTo(Data.Span); }
public void Read(IPacketReader reader) { Locale = reader.ReadString().ToString(); RenderDistance = reader.ReadUInt8(); ChatMode = reader.ReadVarInt(); ChatColors = reader.ReadBoolean(); SkinParts = reader.ReadUInt8(); MainHand = reader.ReadVarInt(); }
public void HandleAuthSession(ref IPacketReader packet, ref IWorldManager manager) { Authenticator.PacketCrypt.Initialised = true; packet.Position = 58; int addonsize = packet.ReadInt32(); int decompressedSize = packet.ReadInt32(); byte[] addonData = this.GetAddonInfo(packet); // get account name packet.Position = 62 + addonsize; var bitUnpack = new BitUnpacker(packet); int nameLen = bitUnpack.GetBits <int>(12); string name = packet.ReadString(nameLen).ToUpper(); Account account = new Account(name); account.Load <Character>(); manager.Account = account; PacketWriter writer = new PacketWriter(Sandbox.Instance.Opcodes[global::Opcodes.SMSG_AUTH_RESPONSE], "SMSG_AUTH_RESPONSE"); var bitPack = new BitPacker(writer); bitPack.Write(0); // IsInQueue bitPack.Write(1); // HasAccountData bitPack.Flush(); writer.WriteUInt8(0); writer.WriteUInt8(4); writer.WriteUInt32(0); writer.WriteUInt32(0); writer.WriteUInt8(4); writer.WriteUInt32(0); writer.WriteUInt8(0xC); manager.Send(writer); // create addoninfo packet var addonPacketInfo = new PacketReader(addonData, false); var addonPacketResponse = new PacketWriter(Sandbox.Instance.Opcodes[global::Opcodes.SMSG_ADDON_INFO], "SMSG_ADDON_INFO"); this.WriteAddonInfo(addonPacketInfo, addonPacketResponse, decompressedSize); manager.Send(addonPacketResponse); // Tutorial Flags : REQUIRED PacketWriter tutorial = new PacketWriter(Sandbox.Instance.Opcodes[global::Opcodes.SMSG_TUTORIAL_FLAGS], "SMSG_TUTORIAL_FLAGS"); for (int i = 0; i < 8; i++) { tutorial.WriteUInt32(0); } manager.Send(tutorial); }
public override async Task Handle(LoginStageUser user, IPacketReader packet) { var name = packet.ReadString(); var result = await user.Stage.CharacterRepository.CheckExistsByName(name); var response = new UnstructuredOutgoingPacket(PacketSendOperations.CheckDuplicatedIDResult); response.WriteString(name); response.WriteBool(result); await user.Dispatch(response); }
protected override async Task Handle(GameStageUser stageUser, IFieldObjUser user, IPacketReader packet) { _ = packet.ReadInt(); var type = (GroupMessageType)packet.ReadByte(); var recipientCount = packet.ReadByte(); var recipients = new int[recipientCount]; for (var i = 0; i < recipientCount; i++) { recipients[i] = packet.ReadInt(); } var text = packet.ReadString(); switch (type) { case GroupMessageType.Party: { if (user.Party == null) { return; } var partyChat = new UnstructuredOutgoingPacket(PacketSendOperations.GroupMessage); partyChat.WriteByte((byte)GroupMessageType.Party); partyChat.WriteString(user.Character.Name); partyChat.WriteString(text); var dispatchRequest = new DispatchToCharactersRequest { Data = ByteString.CopyFrom(partyChat.Buffer) }; dispatchRequest.Characters.Add(user.Party.Members .Select(m => m.ID) .Where(m => m != user.ID) ); await stageUser.Stage.DispatchService.DispatchToCharacters(dispatchRequest); break; } default: stageUser.Stage.Logger.LogWarning($"Unhandled group message type: {type}"); break; } }
public void HandleAuthSession(ref IPacketReader packet, ref IWorldManager manager) { packet.ReadUInt64(); string name = packet.ReadString().ToUpper(); Account account = new Account(name); account.Load <Character>(); manager.Account = account; PacketWriter writer = new PacketWriter(Sandbox.Instance.Opcodes[global::Opcodes.SMSG_AUTH_RESPONSE], "SMSG_AUTH_RESPONSE"); writer.WriteUInt8(0x0C); //AUTH_OK manager.Send(writer); }
/// <inheritdoc /> public override CtfFieldValue Read(IPacketReader reader, CtfFieldValue parent = null) { Guard.NotNull(reader, nameof(reader)); reader.Align((uint)this.Align); byte[] value = reader.ReadString(); if (this.Encoding == EncodingTypes.Ascii) { return(new CtfStringValue(System.Text.Encoding.ASCII.GetString(value, 0, value.Length - 1))); } return(new CtfStringValue(System.Text.Encoding.UTF8.GetString(value, 0, value.Length - 1))); }
public void HandleCharCreate(ref IPacketReader packet, ref IWorldManager manager) { string name = packet.ReadString(); Character cha = new Character() { Name = name.ToUpperFirst(), Race = packet.ReadByte(), Class = packet.ReadByte(), Gender = packet.ReadByte(), Skin = packet.ReadByte(), Face = packet.ReadByte(), HairStyle = packet.ReadByte(), HairColor = packet.ReadByte(), FacialHair = packet.ReadByte() }; // HACK neutral panda faction template doesn't work if (cha.Race == (byte)Races.PANDAREN_NEUTRAL) { cha.Race = (byte)Races.PANDAREN_ALLI; } var result = manager.Account.Characters.Where(x => x.Build == Sandbox.Instance.Build); PacketWriter writer = new PacketWriter(Sandbox.Instance.Opcodes[global::Opcodes.SMSG_CHAR_CREATE], "SMSG_CHAR_CREATE"); if (result.Any(x => x.Name.Equals(cha.Name, StringComparison.CurrentCultureIgnoreCase))) { writer.WriteUInt8(0x32); // Duplicate name manager.Send(writer); return; } cha.Guid = (ulong)(manager.Account.Characters.Count + 1); cha.Location = new Location(-8949.95f, -132.493f, 83.5312f, 0, 0); cha.RestedState = (byte)new Random().Next(1, 2); cha.SetDefaultValues(); manager.Account.Characters.Add(cha); manager.Account.Save(); // Success writer.WriteUInt8(0x2F); manager.Send(writer); }
public void HandleAuthSession(ref IPacketReader packet, ref IWorldManager manager) { Common.Cryptography.Authenticator.ClientBuild = packet.ReadUInt16(); packet.Position = 14; string login = packet.ReadString(); string username = login.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries)[0]; Account account = new Account(username.ToUpper()); account.Load <Character>(); manager.Account = account; PacketWriter writer = new PacketWriter(Sandbox.Instance.Opcodes[global::Opcodes.SMSG_AUTH_RESPONSE], "SMSG_AUTH_RESPONSE"); writer.WriteUInt8(0x0C); // AUTH_OK manager.Send(writer); }
public override async Task Handle(LoginStageUser user, IPacketReader packet) { var spw = packet.ReadString(); var characterID = packet.ReadInt(); var result = LoginResultCode.Success; var response = new UnstructuredOutgoingPacket(PacketSendOperations.DeleteCharacterResult); var character = await user.Stage.CharacterRepository.Retrieve(characterID); if (!BCrypt.Net.BCrypt.EnhancedVerify(spw, user.Account.SPW)) { result = LoginResultCode.IncorrectSPW; } if (character == null || character.AccountWorldID != user.AccountWorld.ID) { result = LoginResultCode.DBFail; } var guild = (await user.Stage.GuildService.LoadByCharacter(new GuildLoadByCharacterRequest { Character = characterID })).Guild; var party = (await user.Stage.PartyService.LoadByCharacter(new PartyLoadByCharacterRequest { Character = characterID })).Party; if (result == LoginResultCode.Success) { // TODO: guild withdraw if not master if (party != null) { _ = user.Stage.PartyService.Withdraw(new PartyWithdrawRequest { Character = characterID }); } await user.Stage.CharacterRepository.Delete(characterID); } response.WriteInt(characterID); response.WriteByte((byte)result); await user.Dispatch(response); }
public void HandleMessageChat(ref IPacketReader packet, ref IWorldManager manager) { PacketWriter writer = new PacketWriter(Sandbox.Instance.Opcodes[global::Opcodes.SMSG_MESSAGECHAT], "SMSG_MESSAGECHAT"); writer.WriteUInt8((byte)packet.ReadInt32()); //System Message packet.ReadUInt32(); writer.WriteUInt32(0); //Language: General writer.WriteUInt64(manager.Account.ActiveCharacter.Guid); string message = packet.ReadString(); writer.WriteString(message); writer.WriteUInt8(0); if (!CommandManager.InvokeHandler(message, manager)) { manager.Send(writer); } }
public void HandleAuthSession(ref IPacketReader packet, ref IWorldManager manager) { Authenticator.PacketCrypt.Initialised = true; Authenticator.PacketCrypt.DigestSize = 40; packet.ReadUInt64(); string name = packet.ReadString().ToUpper(); Account account = new Account(name); account.Load <Character>(); manager.Account = account; PacketWriter writer = new PacketWriter(Sandbox.Instance.Opcodes[global::Opcodes.SMSG_AUTH_RESPONSE], "SMSG_AUTH_RESPONSE"); writer.WriteUInt8(0x0C); // AUTH_OK writer.WriteUInt32(0); writer.WriteUInt8(0); writer.WriteUInt32(0); manager.Send(writer); }
protected override async Task Handle(GameStageUser stageUser, IFieldObjUser user, IPacketReader packet) { _ = packet.ReadInt(); var message = packet.ReadString(); var onlyBalloon = packet.ReadBool(); if (message.StartsWith("!") || message.StartsWith("@")) // TODO: config? { await stageUser.Stage.CommandProcessor.Process(user, message.Substring(1)); return; } var chatPacket1 = new UnstructuredOutgoingPacket(PacketSendOperations.UserChat); chatPacket1.WriteInt(user.ID); chatPacket1.WriteBool(user.Account.GradeCode > 0 || user.Account.SubGradeCode > 0); // TODO: proper gm chat checks chatPacket1.WriteString(message); chatPacket1.WriteBool(onlyBalloon); await user.FieldSplit.Dispatch(chatPacket1); if (onlyBalloon) { return; } var chatPacket2 = new UnstructuredOutgoingPacket(PacketSendOperations.UserChatNLCPQ); chatPacket2.WriteInt(user.ID); chatPacket2.WriteBool(user.Account.GradeCode > 0 || user.Account.SubGradeCode > 0); // TODO: proper gm chat checks chatPacket2.WriteString(message); chatPacket2.WriteBool(onlyBalloon); chatPacket2.WriteString(user.Character.Name); await Task.WhenAll(user.Field .GetUsers() .Except(user.FieldSplit.GetWatchers()) .Select(u => u.Dispatch(chatPacket2))); }
public void HandleMessageChat(ref IPacketReader packet, ref IWorldManager manager) { var character = manager.Account.ActiveCharacter; var bitunpack = new BitUnpacker(packet); var language = packet.ReadUInt32(); var message = packet.ReadString(bitunpack.GetBits <int>(9)); PacketWriter writer = new PacketWriter(Sandbox.Instance.Opcodes[global::Opcodes.SMSG_MESSAGECHAT], "SMSG_MESSAGECHAT"); writer.WriteUInt8(1); // System Message writer.WriteUInt32(0); // Language: General writer.WriteUInt64(character.Guid); writer.WriteUInt32(0); writer.WriteUInt64(0); writer.WriteInt32(message.Length + 1); writer.WriteString(message); writer.WriteUInt8(0); if (!CommandManager.InvokeHandler(message, manager)) { manager.Send(writer); } }
protected override async Task Handle(GameStageUser stageUser, IFieldObjUser user, IPacketReader packet) { var type = (ConversationRequestType)packet.ReadByte(); if (!user.IsConversing) { return; } var context = user.CurrentConversation.Context; if (type == ConversationRequestType.AskQuiz || type == ConversationRequestType.AskSpeedQuiz) { await context.Respond( new ConversationResponse <string>(type, packet.ReadString()) ); return; } var answer = packet.ReadByte(); if ( type != ConversationRequestType.Say && type != ConversationRequestType.AskYesNo && type != ConversationRequestType.AskAccept && answer == byte.MinValue || (type == ConversationRequestType.Say || type == ConversationRequestType.AskYesNo || type == ConversationRequestType.AskAccept) && answer == byte.MaxValue ) { await user.EndConversation(); return; } switch (type) { case ConversationRequestType.AskText: case ConversationRequestType.AskBoxText: await context.Respond( new ConversationResponse <string>(type, packet.ReadString()) ); break; case ConversationRequestType.AskNumber: case ConversationRequestType.AskMenu: case ConversationRequestType.AskSlideMenu: await context.Respond( new ConversationResponse <int>(type, packet.ReadInt()) ); break; case ConversationRequestType.AskAvatar: case ConversationRequestType.AskMemberShopAvatar: await context.Respond( new ConversationResponse <byte>(type, packet.ReadByte()) ); break; case ConversationRequestType.AskYesNo: case ConversationRequestType.AskAccept: await context.Respond( new ConversationResponse <bool>(type, Convert.ToBoolean(answer)) ); break; default: await context.Respond( new ConversationResponse <byte>(type, answer) ); break; } }
protected override async Task Handle(GameStageUser stageUser, IFieldObjUser user, IPacketReader packet) { var stage = stageUser.Stage; var flag = (WhisperFlags)packet.ReadByte(); switch (flag) { case WhisperFlags.Whisper | WhisperFlags.Request: { _ = packet.ReadInt(); var name = packet.ReadString(); var text = packet.ReadString(); if (name.Equals(user.Character.Name, StringComparison.CurrentCultureIgnoreCase)) { return; } var allowed = false; var target = await stage.CharacterRepository.RetrieveByName(name); var response = new UnstructuredOutgoingPacket(PacketSendOperations.Whisper); if (target != null) { var sessionRequest = new DescribeSessionByCharacterRequest { Character = target.ID }; var sessionResponse = await stage.SessionRegistry.DescribeByCharacter(sessionRequest); if (sessionResponse.Session.State == SessionState.LoggedIn) { allowed = true; } } response.WriteByte((byte)(WhisperFlags.Whisper | WhisperFlags.Result)); response.WriteString(allowed ? target.Name : name); response.WriteBool(allowed); if (allowed) { var whisper = new UnstructuredOutgoingPacket(PacketSendOperations.Whisper) .WriteByte((byte)(WhisperFlags.Whisper | WhisperFlags.Receive)) .WriteString(user.Character.Name) .WriteByte((byte)stage.ChannelID) .WriteBool(false) // bFromAdmin .WriteString(text); var whisperRequest = new DispatchToCharactersRequest { Data = ByteString.CopyFrom(whisper.Buffer) }; whisperRequest.Characters.Add(target.ID); await stage.DispatchService.DispatchToCharacters(whisperRequest); } await user.Dispatch(response); break; } default: stage.Logger.LogWarning($"Unhandled whisper flag: {flag}"); break; } }
public void Read(IPacketReader reader) { Username = reader.ReadString().ToString(); }
protected override async Task Handle(GameStageUser stageUser, IFieldObjUser user, IPacketReader packet) { var stage = stageUser.Stage; var service = stage.PartyService; var type = (PartyRequestCode)packet.ReadByte(); switch (type) { case PartyRequestCode.CreateNewParty: { if (user.Party != null) { return; } var result = PartyResultCode.CreateNewParty_Done; var response = new UnstructuredOutgoingPacket(PacketSendOperations.PartyResult); var contract = new PartyCreateRequest { Member = new PartyMemberContract { Id = user.ID, Name = user.Character.Name, Job = user.Character.Job, Level = user.Character.Level, Channel = stage.ChannelID, Field = user.Field.ID } }; var serviceResponse = await service.Create(contract); var serviceResult = serviceResponse.Result; if (serviceResult == PartyServiceResult.FailedAlreadyInParty) { result = PartyResultCode.CreateNewParty_AlreadyJoined; } else if (serviceResult != PartyServiceResult.Ok) { result = PartyResultCode.CreateNewParty_Unknown; } response.WriteByte((byte)result); if (result == PartyResultCode.CreateNewParty_Done) { response.WriteInt(serviceResponse.Party.Id); response.WriteInt(0); // TownPortal-TownID response.WriteInt(0); // TownPortal-FieldID response.WriteInt(0); // TownPortal-SkillID response.WritePoint2D(new Point2D(0, 0)); //TownPortal-Position } await user.Dispatch(response); break; } case PartyRequestCode.WithdrawParty: { if (user.Party == null) { return; } var result = PartyResultCode.WithdrawParty_Done; var response = new UnstructuredOutgoingPacket(PacketSendOperations.PartyResult); var contract = new PartyWithdrawRequest { Character = user.ID, IsKick = false }; var serviceResponse = await service.Withdraw(contract); var serviceResult = serviceResponse.Result; if (serviceResult == PartyServiceResult.FailedNotInParty) { result = PartyResultCode.WithdrawParty_NotJoined; } else if (serviceResult != PartyServiceResult.Ok) { result = PartyResultCode.WithdrawParty_Unknown; } response.WriteByte((byte)result); if (result == PartyResultCode.WithdrawParty_Done) { return; } await user.Dispatch(response); break; } case PartyRequestCode.InviteParty: { if (user.Party == null) { var contract = new PartyCreateRequest { Member = new PartyMemberContract { Id = user.ID, Name = user.Character.Name, Job = user.Character.Job, Level = user.Character.Level, Channel = stage.ChannelID, Field = user.Field.ID } }; var serviceResponse = await service.Create(contract); var serviceResult = serviceResponse.Result; if (serviceResult != PartyServiceResult.Ok) { return; } var createResponse = new UnstructuredOutgoingPacket(PacketSendOperations.PartyResult); createResponse.WriteByte((byte)PartyResultCode.CreateNewParty_Done); createResponse.WriteInt(serviceResponse.Party.Id); createResponse.WriteInt(0); // TownPortal-TownID createResponse.WriteInt(0); // TownPortal-FieldID createResponse.WriteInt(0); // TownPortal-SkillID createResponse.WritePoint2D(new Point2D(0, 0)); //TownPortal-Position await user.Dispatch(createResponse); } if (user?.Party?.Boss != user.ID) { return; } var name = packet.ReadString(); var result = PartyResultCode.InviteParty_Sent; var response = new UnstructuredOutgoingPacket(PacketSendOperations.PartyResult); var character = await stage.CharacterRepository.RetrieveByName(name); if (character == null || user.Character.ID == character.ID) { result = PartyResultCode.InviteParty_BlockedUser; } if ((await service.LoadByCharacter(new PartyLoadByCharacterRequest { Character = character.ID })).Party != null) { result = PartyResultCode.JoinParty_AlreadyJoined; } else { var serviceResponse = await stage.InviteService.Register(new InviteRegisterRequest { Invite = new InviteContract { Type = InviteType.Party, Invited = character.ID, Inviter = user.ID } }); if (serviceResponse.Result != InviteServiceResult.Ok) { result = PartyResultCode.InviteParty_AlreadyInvited; } } response.WriteByte((byte)result); if (result == PartyResultCode.InviteParty_Sent) { var invitation = new UnstructuredOutgoingPacket(PacketSendOperations.PartyResult); var invitationRequest = new DispatchToCharactersRequest(); invitation.WriteByte((byte)PartyRequestCode.InviteParty); invitation.WriteInt(user.Character.ID); invitation.WriteString(user.Character.Name); invitation.WriteInt(user.Character.Level); invitation.WriteInt(user.Character.Job); invitation.WriteByte(0); // PartyOpt invitationRequest.Data = ByteString.CopyFrom(invitation.Buffer); invitationRequest.Characters.Add(character.ID); await stage.DispatchService.DispatchToCharacters(invitationRequest); response.WriteString(character.Name); } await user.Dispatch(response); break; } case PartyRequestCode.KickParty: { if (user.Party == null) { return; } if (user.Party.Boss != user.ID) { return; } var id = packet.ReadInt(); if (!user.Party.Members.Any(m => m.ID == id)) { return; } if (id == user.ID) { return; } var result = PartyResultCode.WithdrawParty_Done; var response = new UnstructuredOutgoingPacket(PacketSendOperations.PartyResult); var contract = new PartyWithdrawRequest { Character = id, IsKick = true }; var serviceResponse = await service.Withdraw(contract); var serviceResult = serviceResponse.Result; if (serviceResult == PartyServiceResult.FailedNotInParty) { result = PartyResultCode.WithdrawParty_NotJoined; } else if (serviceResult != PartyServiceResult.Ok) { result = PartyResultCode.WithdrawParty_Unknown; } response.WriteByte((byte)result); if (result == PartyResultCode.WithdrawParty_Done) { return; } await user.Dispatch(response); break; } case PartyRequestCode.ChangePartyBoss: { if (user.Party == null || user.Party.Boss != user.ID) { return; } var id = packet.ReadInt(); if (!user.Party.Members.Any(m => m.ID == id)) { return; } if (id == user.ID) { return; } var result = PartyResultCode.ChangePartyBoss_Done; var response = new UnstructuredOutgoingPacket(PacketSendOperations.PartyResult); var contract = new PartyChangeBossRequest { Character = id }; var serviceResponse = await service.ChangeBoss(contract); var serviceResult = serviceResponse.Result; if (serviceResult != PartyServiceResult.Ok) { result = PartyResultCode.WithdrawParty_Unknown; } response.WriteByte((byte)result); if (result == PartyResultCode.ChangePartyBoss_Done) { return; } await user.Dispatch(response); break; } default: stage.Logger.LogWarning($"Unhandled party request type: {type}"); break; } }
public override async Task Handle(LoginStageUser user, IPacketReader packet) { var name = packet.ReadString(); var race = packet.ReadInt(); var subJob = packet.ReadShort(); var face = packet.ReadInt(); var hair = packet.ReadInt(); var hairColor = packet.ReadInt(); var skin = packet.ReadInt(); var coat = packet.ReadInt(); var pants = packet.ReadInt(); var shoes = packet.ReadInt(); var weapon = packet.ReadInt(); var gender = packet.ReadByte(); var result = LoginResultCode.Success; var response = new UnstructuredOutgoingPacket(PacketSendOperations.CreateNewCharacterResult); var world = await user.Stage.WorldTemplates.Retrieve((int)user.SelectedWorldID); if (world.BlockCharCreation) { result = LoginResultCode.NotConnectableWorld; } var serverRequest = new DescribeServerByMetadataRequest(); serverRequest.Metadata.Add("Type", Enum.GetName(ServerStageType.Game)); serverRequest.Metadata.Add("WorldID", user.SelectedWorldID.ToString()); serverRequest.Metadata.Add("ChannelID", user.SelectedChannelID.ToString()); var server = (await user.Stage.ServerRegistry.DescribeByMetadata(serverRequest)).Servers.FirstOrDefault(); if (server == null) { result = LoginResultCode.NotConnectableWorld; } response.WriteByte((byte)result); if (result == LoginResultCode.Success) { var character = new Character { AccountWorldID = user.AccountWorld.ID, Name = name, Job = 0, // TODO: race -> job Face = face, Hair = hair + hairColor, Skin = (byte)skin, Gender = gender, FieldID = 310000000, // TODO: start maps FieldPortal = 0, SubJob = 0 // TODO: race -> subjob }; var context = new ModifyMultiInventoryContext(character.Inventories, user.Stage.ItemTemplates); context.Set(BodyPart.Clothes, coat); context.Set(BodyPart.Shoes, shoes); context.Set(BodyPart.Weapon, weapon); if (pants > 0) { context.Set(BodyPart.Pants, pants); } await user.Stage.CharacterRepository.Insert(character); user.Character = character; user.Stage.Logger.LogDebug($"Created new {race} character: {name} (ID: {character.ID})"); response.WriteCharacterStats(character); response.WriteCharacterLook(character); response.WriteBool(false); response.WriteBool(false); } else { response.WriteInt(0); } await user.Dispatch(response); }