예제 #1
0
        public Task Enter(IFieldObjUser user)
        {
            var items = Info.Items.Values
                        .OrderBy(i => i.ID)
                        .ToList();
            var packet = new UnstructuredOutgoingPacket(PacketSendOperations.OpenShopDlg);

            packet.WriteInt(TemplateID);
            packet.WriteShort((short)items.Count);

            items.ForEach(i =>
            {
                packet.WriteInt(i.TemplateID);
                packet.WriteInt(i.Price);
                packet.WriteByte(i.DiscountRate);
                packet.WriteInt(i.TokenTemplateID);
                packet.WriteInt(i.TokenPrice);
                packet.WriteInt(i.ItemPeriod);
                packet.WriteInt(i.LevelLimited);

                if (GameConstants.IsRechargeableItem(i.TemplateID))
                {
                    packet.WriteDouble(i.UnitPrice);
                }
                else
                {
                    packet.WriteShort((short)i.Quantity);
                }

                packet.WriteShort(i.MaxPerSlot);
            });

            return(user.Dispatch(packet));
        }
예제 #2
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);
        }
예제 #3
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)
                );
        }
예제 #4
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);
        }
예제 #5
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);
        }
예제 #6
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);
        }
예제 #7
0
        protected override IPacket GetMigratePacket(byte[] address, short port)
        {
            var packet = new UnstructuredOutgoingPacket(PacketSendOperations.SelectCharacterResult);

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

            foreach (var b in address)
            {
                packet.WriteByte(b);
            }
            packet.WriteShort(port);

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

            return(packet);
        }
예제 #8
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);
            }
        }
예제 #9
0
        public override void ChannelActive(IChannelHandlerContext context)
        {
            var random    = new Random();
            var newSocket = new NettySocket(
                context.Channel,
                (uint)random.Next(),
                (uint)random.Next()
                );
            var newSession = _acceptor.SessionInitializer.Initialize(newSocket);
            var handshake  = new UnstructuredOutgoingPacket();

            handshake.WriteShort(_acceptor.Version);
            handshake.WriteString(_acceptor.Patch);
            handshake.WriteInt((int)newSocket.SeqRecv);
            handshake.WriteInt((int)newSocket.SeqSend);
            handshake.WriteByte(_acceptor.Locale);

            _ = newSocket.Dispatch(handshake);

            context.Channel.GetAttribute(NettyAttributes.SocketKey).Set(newSocket);
            context.Channel.GetAttribute(NettyAttributes.SessionKey).Set(newSession);

            lock (_acceptor) _acceptor.Sessions.Add(newSession.Socket.ID, newSession);
        }
예제 #10
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);
            }));
        }
예제 #11
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);
        }