예제 #1
0
        public async Task ModifyStats(Action <IModifyStatContext> action = null, bool exclRequest = false)
        {
            var context = new ModifyStatContext(Character);

            action?.Invoke(context);
            await UpdateStats();

            if (!IsInstantiated)
            {
                return;
            }

            var statPacket = new UnstructuredOutgoingPacket(PacketSendOperations.StatChanged);

            statPacket.WriteBool(exclRequest);
            statPacket.Write(context);
            statPacket.WriteBool(false);
            statPacket.WriteBool(false);

            await Dispatch(statPacket);

            if (Party != null && (context.Flag.HasFlag(ModifyStatType.Job) || context.Flag.HasFlag(ModifyStatType.Level)))
            {
                _ = GameStage.PartyService.UpdateChangeLevelOrJob(new PartyUpdateChangeLevelOrJobRequest
                {
                    Character = ID,
                    Level     = context.Level,
                    Job       = context.Job
                });
            }
        }
예제 #2
0
        public override async Task Handle(LoginStageUser user, IPacketReader packet)
        {
            var worldTemplates = (await Task.WhenAll(user.Stage.Info.Worlds
                                                     .Select(w => user.Stage.WorldTemplates.Retrieve(w))))
                                 .Where(w => w != null)
                                 .OrderBy(w => w.ID)
                                 .ToList();

            foreach (var world in worldTemplates)
            {
                var response = new UnstructuredOutgoingPacket(PacketSendOperations.WorldInformation);

                response.WriteByte((byte)world.ID);
                response.WriteString(world.Name);
                response.WriteByte(world.State);
                response.WriteString(""); // WorldEventDesc
                response.WriteShort(0);   // WorldEventEXP_WSE, WorldSpecificEvent
                response.WriteShort(0);   // WorldEventDrop_WSE, WorldSpecificEvent
                response.WriteBool(world.BlockCharCreation);

                var channelServerRequest = new DescribeServerByMetadataRequest();

                channelServerRequest.Metadata.Add("Type", Enum.GetName(ServerStageType.Game));
                channelServerRequest.Metadata.Add("WorldID", world.ID.ToString());

                var channelServers = (await user.Stage.ServerRegistry.DescribeByMetadata(channelServerRequest)).Servers
                                     .OrderBy(c => c.Id)
                                     .ToList();

                response.WriteByte((byte)channelServers.Count);

                foreach (var channel in channelServers)
                {
                    response.WriteString(channel.Metadata["ID"]);
                    response.WriteInt(0); // TODO: UserNo
                    response.WriteByte(Convert.ToByte(channel.Metadata["WorldID"]));
                    response.WriteByte(Convert.ToByte(channel.Metadata["ChannelID"]));
                    response.WriteBool(false); // TODO: AdultChannel
                }

                response.WriteShort(0); // TODO: Balloon
                await user.Dispatch(response);
            }

            await user.Dispatch(
                new UnstructuredOutgoingPacket(PacketSendOperations.WorldInformation)
                .WriteByte(0xFF)
                );

            await user.Dispatch(
                new UnstructuredOutgoingPacket(PacketSendOperations.LatestConnectedWorld)
                .WriteInt(user.Account.LatestConnectedWorld ?? 0)
                );
        }
예제 #3
0
        public async Task UpdateAvatar()
        {
            var avatarPacket = new UnstructuredOutgoingPacket(PacketSendOperations.UserAvatarModified);

            avatarPacket.WriteInt(ID);
            avatarPacket.WriteByte(0x1); // Flag
            avatarPacket.WriteCharacterLook(Character);

            avatarPacket.WriteBool(false);
            avatarPacket.WriteBool(false);
            avatarPacket.WriteBool(false);
            avatarPacket.WriteInt(0);

            await FieldSplit.Dispatch(this, avatarPacket);
        }
예제 #4
0
        public async Task ModifySkills(Action <IModifySkillContext> action = null, bool exclRequest = false)
        {
            var context = new ModifySkillContext(Character);

            action?.Invoke(context);
            await UpdateStats();

            var skillPacket = new UnstructuredOutgoingPacket(PacketSendOperations.ChangeSkillRecordResult);

            skillPacket.WriteBool(exclRequest);
            skillPacket.Write(context);
            skillPacket.WriteBool(true);

            await Dispatch(skillPacket);
        }
예제 #5
0
        public override IPacket GetEnterFieldPacket()
        {
            var packet = new UnstructuredOutgoingPacket(PacketSendOperations.UserEnterField);

            packet.WriteInt(ID);

            packet.WriteByte(Character.Level);
            packet.WriteString(Character.Name);

            packet.WriteString(Guild?.Name ?? "");
            packet.WriteShort(Guild?.MarkBg ?? 0);
            packet.WriteByte(Guild?.MarkBgColor ?? 0);
            packet.WriteShort(Guild?.Mark ?? 0);
            packet.WriteByte(Guild?.MarkColor ?? 0);

            packet.WriteSecondaryStatsToRemote(SecondaryStats);

            packet.WriteShort(Character.Job);
            packet.WriteCharacterLook(Character);

            packet.WriteInt(0);
            packet.WriteInt(0);
            packet.WriteInt(0);
            packet.WriteInt(0);
            packet.WriteInt(0);
            packet.WriteInt(0);

            packet.WritePoint2D(Position);
            packet.WriteByte((byte)Action);
            packet.WriteShort((short)(Foothold?.ID ?? 0));
            packet.WriteByte(0);

            packet.WriteBool(false);
            packet.WriteBool(false);
            packet.WriteBool(false);

            packet.WriteBool(false);

            packet.WriteInt(0);
            packet.WriteInt(0);
            packet.WriteInt(0);

            packet.WriteByte(0);

            packet.WriteBool(false);

            packet.WriteBool(false);
            packet.WriteBool(false);
            packet.WriteBool(false);

            packet.WriteByte(0);

            packet.WriteByte(0);
            packet.WriteInt(0);

            return(packet);
        }
예제 #6
0
        public async Task <PartyChangeBossResponse> ChangeBoss(PartyChangeBossRequest request)
        {
            var source = new CancellationTokenSource();

            source.CancelAfter(PartyLockTimeoutDuration);

            var @lock = await _locker.AcquireAsync(PartyLockKey, cancellationToken : source.Token);

            if (@lock != null)
            {
                var result = PartyServiceResult.Ok;
                var party  = await _repository.RetrieveByMember(request.Character);

                if (party == null)
                {
                    result = PartyServiceResult.FailedNotInParty;
                }
                else if (party.Boss == request.Character)
                {
                    result = PartyServiceResult.FailedAlreadyBoss;
                }

                if (result == PartyServiceResult.Ok)
                {
                    var targets = party.Members.Select(m => m.ID).ToImmutableList();
                    var packet  = new UnstructuredOutgoingPacket(PacketSendOperations.PartyResult);

                    party.Boss = request.Character;

                    await _repository.Update(party);

                    packet.WriteByte((byte)PartyResultCode.ChangePartyBoss_Done);
                    packet.WriteInt(request.Character);
                    packet.WriteBool(request.IsDisconnect);

                    var dispatchRequest = new DispatchToCharactersRequest {
                        Data = ByteString.CopyFrom(packet.Buffer)
                    };

                    dispatchRequest.Characters.Add(targets);

                    await _dispatcher.DispatchToCharacters(dispatchRequest);

                    await _messenger.PublishAsync(new PartyUpdateEvent { Party = party });
                }

                await @lock.ReleaseAsync();

                return(new PartyChangeBossResponse {
                    Result = result
                });
            }

            return(new PartyChangeBossResponse {
                Result = PartyServiceResult.FailedTimeout
            });
        }
예제 #7
0
        public IPacket GetSetFieldPacket()
        {
            var packet = new UnstructuredOutgoingPacket(PacketSendOperations.SetField);

            packet.WriteShort(0); // ClientOpt

            packet.WriteInt(GameStage.ChannelID);
            packet.WriteInt(GameStage.WorldID);

            packet.WriteBool(true); // sNotifierMessage._m_pStr
            packet.WriteBool(!IsInstantiated);
            packet.WriteShort(0);   // nNotifierCheck, loops

            if (!IsInstantiated)
            {
                packet.WriteUInt(Damage.InitSeed1);
                packet.WriteUInt(Damage.InitSeed2);
                packet.WriteUInt(Damage.InitSeed3);

                packet.WriteCharacterData(Character);

                packet.WriteInt(0);
                for (var i = 0; i < 3; i++)
                {
                    packet.WriteInt(0);
                }
            }
            else
            {
                packet.WriteByte(0);
                packet.WriteInt(Character.FieldID);
                packet.WriteByte(Character.FieldPortal);
                packet.WriteInt(Character.HP);
                packet.WriteBool(false);
            }

            packet.WriteDateTime(DateTime.Now);

            return(packet);
        }
예제 #8
0
        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)));
        }
예제 #9
0
        protected virtual IPacket GetMigratePacket(byte[] address, short port)
        {
            var packet = new UnstructuredOutgoingPacket(PacketSendOperations.MigrateCommand);

            packet.WriteBool(true);

            foreach (var b in address)
            {
                packet.WriteByte(b);
            }
            packet.WriteShort(port);
            return(packet);
        }
        protected override async Task Handle(GameStageUser stageUser, IFieldObjUser user, IPacketReader packet)
        {
            _ = packet.ReadInt();
            var type     = (ItemInventoryType)packet.ReadByte();
            var response = new UnstructuredOutgoingPacket(PacketSendOperations.GatherItemResult);

            response.WriteBool(false);
            response.WriteByte((byte)type);

            await user.ModifyInventory(i => i[type].Gather(), true);

            await user.Dispatch(response);
        }
예제 #11
0
        protected override IPacket GetChangeControllerPacket(bool setAsController)
        {
            var packet = new UnstructuredOutgoingPacket(PacketSendOperations.NpcChangeController);

            packet.WriteBool(setAsController);
            packet.WriteInt(ID);

            if (setAsController)
            {
                WriteData(packet);
            }
            return(packet);
        }
예제 #12
0
        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);
        }
예제 #13
0
        public async Task ModifyInventory(Action <IModifyMultiInventoryContext> action = null, bool exclRequest = false)
        {
            var context = new ModifyMultiInventoryContext(Character.Inventories, GameStage.ItemTemplates);

            action?.Invoke(context);

            var inventoryPacket = new UnstructuredOutgoingPacket(PacketSendOperations.InventoryOperation);

            inventoryPacket.WriteBool(exclRequest);
            inventoryPacket.Write(context);
            inventoryPacket.WriteBool(false);

            await Dispatch(inventoryPacket);

            if (
                context.History.Any(o => o.Slot < 0) ||
                context.History.OfType <MoveModifyInventoryOperation>().Any(o => o.ToSlot < 0)
                )
            {
                await UpdateStats();
                await UpdateAvatar();
            }
        }
예제 #14
0
        public override async Task Enter(GameStageUser user)
        {
            await base.Enter(user);

            var field = await FieldRepository.Retrieve(user.Character.FieldID);

            var fieldUser = new FieldObjUser(user);

            var guildLoadResponse = await GuildService.LoadByCharacter(new GuildLoadByCharacterRequest { Character = user.Character.ID });

            var partyLoadResponse = await PartyService.LoadByCharacter(new PartyLoadByCharacterRequest { Character = user.Character.ID });

            if (guildLoadResponse.Guild != null)
            {
                fieldUser.Guild = new Guild(guildLoadResponse.Guild);
            }
            if (partyLoadResponse.Party != null)
            {
                fieldUser.Party = new Party(partyLoadResponse.Party);
            }

            user.FieldUser = fieldUser;

            await field.Enter(fieldUser);

            var functionKeyPacket  = new UnstructuredOutgoingPacket(PacketSendOperations.FuncKeyMappedInit);
            var quickSlotKeyPacket = new UnstructuredOutgoingPacket(PacketSendOperations.QuickslotMappedInit);

            functionKeyPacket.WriteBool(false);

            for (var i = 0; i < 90; i++)
            {
                var key = user.Character.FunctionKeys[i];

                functionKeyPacket.WriteByte(key?.Type ?? 0);
                functionKeyPacket.WriteInt(key?.Action ?? 0);
            }

            quickSlotKeyPacket.WriteBool(false);

            for (var i = 0; i < 8; i++)
            {
                quickSlotKeyPacket.WriteInt(user.Character.QuickSlotKeys[i].Key);
            }

            _ = user.Dispatch(functionKeyPacket);
            _ = user.Dispatch(quickSlotKeyPacket);
        }
예제 #15
0
        protected override async Task Handle(GameStageUser stageUser, IFieldObjUser user, IPacketReader packet)
        {
            var contimove = await stageUser.Stage.ContiMoveRepository.RetrieveByField(user.Field);

            if (contimove == null)
            {
                return;
            }

            var response = new UnstructuredOutgoingPacket(PacketSendOperations.CONTISTATE);

            response.WriteByte((byte)contimove.State);
            response.WriteBool(contimove.State == ContiMoveState.Event);

            await user.Dispatch(response);
        }
예제 #16
0
        protected override async Task Handle(GameStageUser stageUser, IFieldObjUser user, IPacketReader packet)
        {
            _ = packet.ReadInt();
            var targetID = packet.ReadInt();
            var target   = user.Watching
                           .SelectMany(w => w.GetObjects <IFieldObjUser>())
                           .Where(o => o.ID == targetID)
                           .FirstOrDefault();

            if (target == null)
            {
                return;
            }

            var response = new UnstructuredOutgoingPacket(PacketSendOperations.CharacterInfo);

            response.WriteInt(target.ID);
            response.WriteByte(target.Character.Level);
            response.WriteShort(target.Character.Job);
            response.WriteShort(target.Character.POP);

            response.WriteByte(0);

            response.WriteString(target?.Guild?.Name ?? "");
            response.WriteString("");  // sAlliance

            response.WriteByte(0);     // Medal?

            response.WriteBool(false); // Pets

            response.WriteByte(0);     // TamingMobInfo
            response.WriteByte(0);     // Wishlist

            response.WriteInt(0);      // MedalAchievementInfo
            response.WriteShort(0);

            var chairs = target.Character.Inventories[ItemInventoryType.Install].Items
                         .Select(kv => kv.Value)
                         .Select(i => i.TemplateID)
                         .Where(i => i / 10000 == 301)
                         .ToList();

            response.WriteInt(chairs.Count);
            chairs.ForEach(i => response.WriteInt(i));

            await user.Dispatch(response);
        }
예제 #17
0
        protected override async Task Handle(GameStageUser stageUser, IFieldObjUser user, IPacketReader packet)
        {
            var emotion      = packet.ReadInt();
            var duration     = packet.ReadInt();
            var byItemOption = packet.ReadBool();

            // TODO item option check

            var response = new UnstructuredOutgoingPacket(PacketSendOperations.UserEmotion);

            response.WriteInt(user.ID);
            response.WriteInt(emotion);
            response.WriteInt(duration);
            response.WriteBool(byItemOption);

            await user.FieldSplit.Dispatch(user, response);
        }
예제 #18
0
        public async Task ModifySecondaryStats(Action <IModifySecondaryStatContext> action = null, bool exclRequest = false)
        {
            var context = new ModifySecondaryStatContext(SecondaryStats as SecondaryStats);

            action?.Invoke(context);
            await UpdateStats();

            if (context.ResetHistory.ToDictionary().Any())
            {
                var resetLocalPacket  = new UnstructuredOutgoingPacket(PacketSendOperations.TemporaryStatReset);
                var resetRemotePacket = new UnstructuredOutgoingPacket(PacketSendOperations.UserTemporaryStatReset);

                resetLocalPacket.WriteSecondaryStatsFlag(context.ResetHistory);
                resetLocalPacket.WriteBool(false); // IsMovementAffectingStat

                resetRemotePacket.WriteInt(ID);
                resetRemotePacket.WriteSecondaryStatsFlag(context.ResetHistory);

                await Dispatch(resetLocalPacket);

                await FieldSplit.Dispatch(resetRemotePacket);
            }

            if (context.SetHistory.ToDictionary().Any())
            {
                var setLocalPacket  = new UnstructuredOutgoingPacket(PacketSendOperations.TemporaryStatSet);
                var setRemotePacket = new UnstructuredOutgoingPacket(PacketSendOperations.UserTemporaryStatSet);

                setLocalPacket.WriteSecondaryStatsToLocal(context.SetHistory);
                setLocalPacket.WriteShort(0);    // tDelay
                setLocalPacket.WriteBool(false); // IsMovementAffectingStat

                setRemotePacket.WriteInt(ID);
                setRemotePacket.WriteSecondaryStatsToLocal(context.SetHistory);
                setRemotePacket.WriteShort(0); // tDelay

                await Dispatch(setLocalPacket);

                await FieldSplit.Dispatch(setRemotePacket);
            }
        }
예제 #19
0
        public override async Task Handle(LoginStageUser user, IPacketReader packet)
        {
            var cancel = !packet.ReadBool();

            if (cancel)
            {
                await user.Disconnect();

                return;
            }

            var gender   = (byte)(packet.ReadBool() ? 1 : 0);
            var response = new UnstructuredOutgoingPacket(PacketSendOperations.SetAccountResult);

            user.Account.Gender = gender;

            response.WriteByte(gender);
            response.WriteBool(!cancel);

            await user.Dispatch(response);
        }
예제 #20
0
        public async Task <PartyWithdrawResponse> Withdraw(PartyWithdrawRequest request)
        {
            var source = new CancellationTokenSource();

            source.CancelAfter(PartyLockTimeoutDuration);

            var @lock = await _locker.AcquireAsync(PartyLockKey, cancellationToken : source.Token);

            if (@lock != null)
            {
                var result = PartyServiceResult.Ok;
                var party  = await _repository.RetrieveByMember(request.Character);

                var member = party?.Members?.FirstOrDefault(m => m.ID == request.Character);

                if (party == null || member == null)
                {
                    result = PartyServiceResult.FailedNotInParty;
                }

                if (result == PartyServiceResult.Ok)
                {
                    var targets   = party.Members.ToList();
                    var isDisband = request.Character == party.Boss;

                    if (isDisband)
                    {
                        party.Members.Clear();
                        await _repository.Delete(party);
                    }
                    else
                    {
                        party.Members.Remove(member);
                        await _repository.Update(party);
                    }

                    await Task.WhenAll(targets.Select(async m =>
                    {
                        var packet = new UnstructuredOutgoingPacket(PacketSendOperations.PartyResult);

                        packet.WriteByte((byte)PartyResultCode.WithdrawParty_Done);
                        packet.WriteInt(party.ID);
                        packet.WriteInt(request.Character);
                        packet.WriteBool(!isDisband);

                        if (!isDisband)
                        {
                            packet.WriteBool(request.IsKick);
                            packet.WriteString(member.Name);
                            packet.WritePartyData(party, m.Channel);
                        }

                        var dispatchRequest = new DispatchToCharactersRequest {
                            Data = ByteString.CopyFrom(packet.Buffer)
                        };

                        dispatchRequest.Characters.Add(m.ID);

                        await _dispatcher.DispatchToCharacters(dispatchRequest);
                    }));

                    await _messenger.PublishAsync(new PartyUpdateEvent { Party = party });
                }

                await @lock.ReleaseAsync();

                return(new PartyWithdrawResponse {
                    Result = result
                });
            }

            return(new PartyWithdrawResponse {
                Result = PartyServiceResult.FailedTimeout
            });
        }
예제 #21
0
        protected override async Task Handle(
            GameStageUser stageUser,
            IFieldObjUser controller,
            IFieldObjMob controlled,
            IPacketReader packet
            )
        {
            if (controlled.HP <= 0)
            {
                return;
            }

            var mobCtrlSN = packet.ReadShort();
            var v7        = packet.ReadByte();         //v85 = nDistance | 4 * (v184 | 2 * ((unsigned __int8)retaddr | 2 * v72)); [ CONFIRMED ]

            var oldSplit           = (v7 & 0xF0) != 0; //this is a type of CFieldSplit
            var mobMoveStartResult = (v7 & 0xF) != 0;

            var curSplit        = packet.ReadByte();
            var illegalVelocity = packet.ReadInt();
            var v8 = packet.ReadByte();

            var cheatedRandom   = (v8 & 0xF0) != 0;
            var cheatedCtrlMove = (v8 & 0xF) != 0;

            var multiTargetForBall = packet.ReadInt();

            for (var i = 0; i < multiTargetForBall; i++)
            {
                packet.ReadLong();                                          // int, int
            }
            var randTimeForAreaAttack = packet.ReadInt();

            for (var i = 0; i < randTimeForAreaAttack; i++)
            {
                packet.ReadInt();
            }

            packet.ReadInt(); // HackedCode
            packet.ReadInt(); // idk
            packet.ReadInt(); // HackedCodeCrc
            packet.ReadInt(); // idk

            var path = packet.Read(new MovePath());

            await controlled.Move(path);

            var response = new UnstructuredOutgoingPacket(PacketSendOperations.MobCtrlAck);

            response.WriteInt(controlled.ID);
            response.WriteShort(mobCtrlSN);
            response.WriteBool(mobMoveStartResult);
            response.WriteShort((short)controlled.MP); // nMP
            response.WriteByte(0);                     // SkillCommand
            response.WriteByte(0);                     // SLV

            await controller.Dispatch(response);

            var movement = new UnstructuredOutgoingPacket(PacketSendOperations.MobMove);

            movement.WriteInt(controlled.ID);
            movement.WriteBool(false); // NotForceLandingWhenDiscard
            movement.WriteBool(false); // NotChangeAction
            movement.WriteBool(false); // NextAttackPossible
            movement.WriteBool(false); // Left
            movement.WriteInt(illegalVelocity);

            movement.WriteInt(0); // MultiTargetForBall
            movement.WriteInt(0); // RandTimeForAreaAttack

            movement.Write(path);

            await controlled.Field.Dispatch(controller, movement);
        }
예제 #22
0
        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;
            }
        }
예제 #23
0
        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);
        }
예제 #24
0
        protected override async Task Handle(GameStageUser stageUser, IFieldObjUser user, IPacketReader packet)
        {
            var clientAttackInfo = packet.Read(new ClientAttackInfo());

            var skill       = (Skill)clientAttackInfo.SkillID;
            var skillLevel  = clientAttackInfo.SkillID > 0 ? user.Character.GetSkillLevel(clientAttackInfo.SkillID) : 0;
            var damageType  = Type == AttackType.Magic ? DamageType.Magic : DamageType.Physical;
            var damageApply = new List <Tuple <IFieldObjMob, int> >();

            if (Type == AttackType.Melee)
            {
                // TODO bmage blows
            }

            if (Type == AttackType.Body)
            {
                // TODO teleport mastery
            }

            var operation = (PacketSendOperations)((int)PacketSendOperations.UserMeleeAttack + (int)Type);
            var response  = new UnstructuredOutgoingPacket(operation);

            response.WriteInt(user.ID);
            response.WriteByte((byte)(clientAttackInfo.DamagePerMob | 16 * clientAttackInfo.MobCount));
            response.WriteByte(user.Character.Level);

            response.WriteByte((byte)skillLevel);
            if (skillLevel > 0)
            {
                response.WriteInt(clientAttackInfo.SkillID);
            }

            response.WriteByte((byte)(
                                   1 * Convert.ToByte(clientAttackInfo.IsFinalAfterSlashBlast) |
                                   8 * Convert.ToByte(clientAttackInfo.IsShadowPartner) |
                                   16 * 0 |
                                   32 * Convert.ToByte(clientAttackInfo.IsSerialAttack)
                                   ));
            response.WriteShort((short)(
                                    clientAttackInfo.Action & 0x7FFF |
                                    Convert.ToByte(clientAttackInfo.IsFacingLeft) << 15)
                                );

            if (clientAttackInfo.Action <= 0x110)
            {
                response.WriteByte(0); // nMastery
                response.WriteByte(0); // v82
                response.WriteInt(0);  // bMovingShoot

                clientAttackInfo.Mobs.ForEach(m =>
                {
                    var critical    = new bool[clientAttackInfo.DamagePerMob];
                    var damage      = new int[clientAttackInfo.DamagePerMob];
                    var totalDamage = m.Damage.Sum();
                    var mob         = user.Field.GetObject <IFieldObjMob>(m.MobID);

                    response.WriteInt(m.MobID);
                    response.WriteByte(m.HitAction);

                    if (mob != null)
                    {
                        var equipInventory   = user.Character.Inventories[ItemInventoryType.Equip];
                        var serverAttackInfo = new AttackInfo(user, mob)
                        {
                            WeaponID = equipInventory.Items.ContainsKey((short)BodyPart.Weapon)
                                ? equipInventory.Items[(short)BodyPart.Weapon].TemplateID
                                : 0,
                            BulletID   = 0,
                            SkillID    = clientAttackInfo.SkillID,
                            SkillLevel = skillLevel
                        };

                        var calculatedDamage = damageType == DamageType.Physical
                            ? user.Damage.CalculateCharacterPDamage(serverAttackInfo)
                            : user.Damage.CalculateCharacterMDamage(serverAttackInfo);
                        var calculatedTotalDamage = calculatedDamage.Select(d => d.Damage).Sum();

                        // TODO cheatdetector?
                        if (clientAttackInfo.DamagePerMob != calculatedDamage.Length)
                        {
                            user.Message($"Attack count mismatch: {clientAttackInfo.DamagePerMob} : {calculatedDamage.Length}");
                            return;
                        }
                        if (totalDamage != calculatedTotalDamage)
                        {
                            user.Message($"Client damage: {string.Join(" + ", m.Damage.Select(m => $"{m}"))} = {totalDamage}");
                            user.Message($"Server damage: {string.Join(" + ", calculatedDamage.Select(m => $"{m.Damage}"))} = {calculatedTotalDamage}");
                        }

                        damageApply.Add(Tuple.Create(mob, calculatedTotalDamage));

                        for (var i = 0; i < clientAttackInfo.DamagePerMob; i++)
                        {
                            critical[i] = calculatedDamage[i].IsCritical;
                            damage[i]   = calculatedDamage[i].Damage;
                        }
                    }
                    else
                    {
                        user.Damage.SkipCalculationForCharacterDamage();
                    }

                    for (var i = 0; i < clientAttackInfo.DamagePerMob; i++)
                    {
                        response.WriteBool(critical[i]);
                        response.WriteInt(damage[i]);
                    }
                });
            }

            // TODO Keydown

            await user.FieldSplit.Dispatch(user, response);

            await Task.WhenAll(damageApply.Select(async a =>
            {
                var(mob, damage) = a;

                mob.Controller = user;
                await mob.Damage(user, damage);
            }));
        }
예제 #25
0
        public override async Task Handle(LoginStageUser user, IPacketReader packet)
        {
            _ = packet.ReadByte(); // Unknown1

            var worldID   = packet.ReadByte();
            var channelID = packet.ReadByte();

            var result   = LoginResultCode.Success;
            var response = new UnstructuredOutgoingPacket(PacketSendOperations.SelectWorldResult);

            var gameServerRequest = new DescribeServerByMetadataRequest();

            gameServerRequest.Metadata.Add("Type", Enum.GetName(ServerStageType.Game));
            gameServerRequest.Metadata.Add("WorldID", worldID.ToString());

            var gameServers = (await user.Stage.ServerRegistry.DescribeByMetadata(gameServerRequest)).Servers
                              .OrderBy(g => g.Metadata["ChannelID"])
                              .ToList();

            if (channelID > gameServers.Count)
            {
                result = LoginResultCode.NotConnectableWorld;
            }

            response.WriteByte((byte)result);

            if (result == LoginResultCode.Success)
            {
                var gameServer   = gameServers[channelID];
                var accountWorld = await user.Stage.AccountWorldRepository.RetrieveByAccountAndWorld(user.Account.ID, worldID);

                if (accountWorld == null)
                {
                    accountWorld = new AccountWorld
                    {
                        AccountID = user.Account.ID,
                        WorldID   = worldID
                    };

                    await user.Stage.AccountWorldRepository.Insert(accountWorld);
                }

                user.State             = LoginState.SelectCharacter;
                user.AccountWorld      = accountWorld;
                user.SelectedWorldID   = Convert.ToByte(gameServer.Metadata["WorldID"]);
                user.SelectedChannelID = Convert.ToByte(gameServer.Metadata["ChannelID"]);

                var characters = (await user.Stage.CharacterRepository.RetrieveAllByAccountWorld(accountWorld.ID)).ToList();

                response.WriteByte((byte)characters.Count);
                characters.ForEach(c =>
                {
                    response.WriteCharacterStats(c);
                    response.WriteCharacterLook(c);

                    response.WriteBool(false);
                    response.WriteBool(false);
                });

                response.WriteBool(!string.IsNullOrEmpty(user.Account.SPW)); // bLoginOpt TODO: proper bLoginOpt stuff
                response.WriteInt(accountWorld.SlotCount);
                response.WriteInt(0);
            }

            await user.Dispatch(response);
        }