Exemple #1
0
        protected PacketSerializer(Region region, GameMessageTable gameMessages,
                                   SystemMessageTable systemMessages)
        {
            Region         = region.CheckValidity(nameof(region));
            GameMessages   = gameMessages ?? throw new ArgumentNullException(nameof(gameMessages));
            SystemMessages = systemMessages ?? throw new ArgumentNullException(nameof(systemMessages));

            var byType = new Dictionary <Type, PacketInfo>();
            var byName = new Dictionary <string, PacketInfo>();
            var byCode = new Dictionary <ushort, PacketInfo>();

            void RegisterType(Type type, PacketAttribute attribute, ushort?code)
            {
                var info = new PacketInfo(type, attribute,
                                          (from prop in type.GetProperties()
                                           let opts = prop.GetCustomAttribute <PacketFieldOptionsAttribute>()
                                                      where opts == null || (!opts.Skip && (opts.Regions.Length == 0 || opts.Regions.Contains(region)))
                                                      orderby prop.MetadataToken
                                                      select CreateFieldInfo(prop, opts)).ToArray());

                byType.Add(type, info);

                if (code is ushort c)
                {
                    byName.Add(attribute.Name, info);
                    byCode.Add(c, info);
                }

                foreach (var field in info.Fields.Where(x => x.IsArray))
                {
                    RegisterType(field.Property.PropertyType.GetGenericArguments()[0], null, null);
                }
            }

            foreach (var type in Assembly.GetExecutingAssembly().DefinedTypes)
            {
                var attr = type.GetCustomAttribute <PacketAttribute>();

                if (attr == null)
                {
                    continue;
                }

                if (!gameMessages.NameToCode.TryGetValue(attr.Name, out var code))
                {
                    _log.Warning("Game message {0} not mapped to a code; ignoring definition", attr.Name);
                    continue;
                }

                RegisterType(type, attr, code);
            }

            _byType = byType;
            _byName = byName;
            _byCode = byCode;
        }
 protected override SerializablePacket OnCreate(PacketInfo info)
 {
     return(_creators[info]());
 }
        Action <GameBinaryReader, object> CompileDeserializer(PacketInfo info)
        {
            if (_deserializers.TryGetValue(info, out var d))
            {
                return(d);
            }

            var reader = typeof(GameBinaryReader).Parameter("reader");
            var target = typeof(object).Parameter("target");
            var packet = info.Type.Variable("packet");

            BlockExpression CompileByteArray(CompilerPacketFieldInfo info)
            {
                var prop = info.Property;

                var offset   = typeof(int).Variable("offset");
                var count    = typeof(ushort).Variable("count");
                var property = prop.PropertyType.Variable("property");
                var position = typeof(int).Variable("position");

                var read = Expression.Block(new[] { position },
                                            position.Assign(reader.Property(PositionName)),
                                            reader.Property(PositionName).Assign(offset),
                                            property.Call(AddRangeName, null, new[] { reader.Call(ReadBytesName, null, new[] { count.Convert(typeof(int)) }) }),
                                            reader.Property(PositionName).Assign(position));

                return(Expression.Block(new[] { offset, count, property },
                                        offset.Assign(reader.Call(ReadOffsetName, null, null)),
                                        count.Assign(reader.Call(ReadUInt16Name, null, null)),
                                        property.Assign(packet.Property(prop)),
                                        property.Call(ClearName, null, null),
                                        count.NotEqual(((ushort)0).Constant())
                                        .IfThen(read)));
            }

            BlockExpression CompileArray(CompilerPacketFieldInfo info)
            {
                var prop     = info.Property;
                var ftype    = prop.PropertyType;
                var elemInfo = GetPacketInfo(ftype.GetGenericArguments()[0]);

                var offset   = typeof(int).Variable("offset");
                var count    = typeof(ushort).Variable("count");
                var position = typeof(int).Variable("position");
                var property = ftype.Variable("property");
                var next     = typeof(int).Variable("next");
                var i        = typeof(int).Variable("i");
                var elem     = elemInfo.Type.Variable("elem");

                var loop = CustomExpression.For(
                    i, 0.Constant(),
                    i.LessThan(count.Convert(typeof(int))),
                    i.PreIncrementAssign(),
                    Expression.Block(
                        reader.Property(PositionName).Assign(next),
                        reader.Call(ReadOffsetName, null, null),
                        next.Assign(reader.Call(ReadOffsetName, null, null)),
                        elem.Assign(elemInfo.Type.New()),
                        CompileDeserializer(elemInfo).Constant().Invoke(reader, elem),
                        property.Call(AddName, null, new[] { elem })));

                var read = Expression.Block(new[] { position, next, elem },
                                            position.Assign(reader.Property(PositionName)),
                                            next.Assign(offset),
                                            loop,
                                            reader.Property(PositionName).Assign(position));

                return(Expression.Block(new[] { offset, count, property },
                                        count.Assign(reader.Call(ReadUInt16Name, null, null)),
                                        offset.Assign(reader.Call(ReadOffsetName, null, null)),
                                        property.Assign(packet.Property(prop)),
                                        property.Call(ClearName, null, null),
                                        count.NotEqual(((ushort)0).Constant())
                                        .IfThen(read)));
            }

            BlockExpression CompileString(CompilerPacketFieldInfo info)
            {
                var offset   = typeof(int).Variable("offset");
                var position = typeof(int).Variable("position");

                return(Expression.Block(new[] { offset, position },
                                        offset.Assign(reader.Call(ReadOffsetName, null, null)),
                                        position.Assign(reader.Property(PositionName)),
                                        reader.Property(PositionName).Assign(offset),
                                        packet.Property(info.Property).Assign(reader.Call(ReadStringName, null, null)),
                                        reader.Property(PositionName).Assign(position)));
            }

            BlockExpression CompilePrimitive(CompilerPacketFieldInfo info)
            {
                var prop   = info.Property;
                var ftype  = prop.PropertyType;
                var etype  = ftype.IsEnum ? ftype.GetEnumUnderlyingType() : ftype;
                var prefix = (info.Attribute?.IsSimpleSkill ?? false) ? SimpleName : string.Empty;

                Expression read = reader.Call(ReadName + prefix + etype.Name, null, null);

                if (ftype.IsEnum)
                {
                    read = read.Convert(ftype);
                }

                return(Expression.Block(packet.Property(prop).Assign(read)));
            }

            var exprs = new List <Expression>()
            {
                packet.Assign(target.Convert(info.Type)),
            };

            foreach (var field in info.Fields.Cast <CompilerPacketFieldInfo>())
            {
                exprs.Add(
                    field.IsByteArray ? CompileByteArray(field) :
                    field.IsArray ? CompileArray(field) :
                    field.IsString ? CompileString(field) :
                    CompilePrimitive(field));
            }

            return(Expression.Lambda <Action <GameBinaryReader, object> >(
                       Expression.Block(new[] { packet }, exprs), reader, target).Compile());
        }
 protected override void OnDeserialize(GameBinaryReader reader, PacketInfo info,
                                       SerializablePacket packet)
 {
     _deserializers[info](reader, packet);
 }
        Action <GameBinaryWriter, object> CompileSerializer(PacketInfo info)
        {
            if (_serializers.TryGetValue(info, out var s))
            {
                return(s);
            }

            var writer = typeof(GameBinaryWriter).Parameter("writer");
            var source = typeof(object).Parameter("source");
            var packet = info.Type.Variable("packet2");

            var offsets = new List <(CompilerPacketFieldInfo, ParameterExpression)>();

            BlockExpression CompileByteArray1(CompilerPacketFieldInfo info)
            {
                var prop = info.Property;

                var offset = typeof(int).Variable($"offset{prop.Name}");

                offsets.Add((info, offset));

                var property = packet.Property(prop);

                return(Expression.Block(
                           offset.Assign(writer.Property(PositionName)),
                           writer.Call(WriteUInt16Name, null, new[] { ((ushort)0).Constant() }),
                           writer.Call(WriteUInt16Name, null, new[] { property.Property(CountName).Convert(typeof(ushort)) })));
            }

            BlockExpression CompileArray1(CompilerPacketFieldInfo info)
            {
                var prop = info.Property;

                var offset = typeof(int).Variable($"offset{prop.Name}");

                offsets.Add((info, offset));

                var property = packet.Property(prop);

                return(Expression.Block(
                           writer.Call(WriteUInt16Name, null, new[] { property.Property(CountName).Convert(typeof(ushort)) }),
                           offset.Assign(writer.Property(PositionName)),
                           writer.Call(WriteUInt16Name, null, new[] { ((ushort)0).Constant() })));
            }

            BlockExpression CompileString1(CompilerPacketFieldInfo info)
            {
                var offset = typeof(int).Variable($"offset{info.Property.Name}");

                offsets.Add((info, offset));

                return(Expression.Block(
                           offset.Assign(writer.Property(PositionName)),
                           writer.Call(WriteUInt16Name, null, new[] { ((ushort)0).Constant() })));
            }

            BlockExpression CompilePrimitive(CompilerPacketFieldInfo info)
            {
                var prop   = info.Property;
                var ftype  = prop.PropertyType;
                var etype  = ftype.IsEnum ? ftype.GetEnumUnderlyingType() : ftype;
                var prefix = (info.Attribute?.IsSimpleSkill ?? false) ? SimpleName : string.Empty;

                Expression property;

                if (ftype == typeof(ushort) && (info.Attribute?.IsUnknownArray ?? false))
                {
                    property = ((ushort)0).Constant();
                }
                else
                {
                    property = packet.Property(prop);

                    if (ftype.IsEnum)
                    {
                        property = property.Convert(etype);
                    }
                }

                return(Expression.Block(
                           writer.Call(WriteName + prefix + etype.Name, null, new[] { property })));
            }

            var exprs = new List <Expression>()
            {
                packet.Assign(source.Convert(info.Type)),
            };

            foreach (var field in info.Fields.Cast <CompilerPacketFieldInfo>())
            {
                exprs.Add(
                    field.IsByteArray ? CompileByteArray1(field) :
                    field.IsArray ? CompileArray1(field) :
                    field.IsString ? CompileString1(field) :
                    CompilePrimitive(field));
            }

            BlockExpression CompileByteArray2(CompilerPacketFieldInfo info, ParameterExpression offset)
            {
                var property = info.Property.PropertyType.Variable("property");
                var position = typeof(int).Variable("position");

                var write = Expression.Block(new[] { position },
                                             position.Assign(writer.Property(PositionName)),
                                             writer.Property(PositionName).Assign(offset),
                                             writer.Call(WriteOffsetName, null, new[] { position }),
                                             writer.Property(PositionName).Assign(position),
                                             writer.Call(WriteBytesName, null, new[] { property.Call(ToArrayName, null, null).Convert(typeof(ReadOnlySpan <byte>)) }));

                return(Expression.Block(new[] { property },
                                        property.Assign(packet.Property(info.Property)),
                                        property.Property(CountName).NotEqual(0.Constant())
                                        .IfThen(write)));
            }

            BlockExpression CompileArray2(CompilerPacketFieldInfo info, ParameterExpression offset)
            {
                var prop     = info.Property;
                var ftype    = prop.PropertyType;
                var elemInfo = GetPacketInfo(ftype.GetGenericArguments()[0]);

                var property  = ftype.Variable("property");
                var count     = typeof(int).Variable("count");
                var position  = typeof(int).Variable("position");
                var i         = typeof(int).Variable("i");
                var position2 = typeof(int).Variable("position2");
                var position3 = typeof(int).Variable("position3");

                var writeNext = Expression.Block(new[] { position3 },
                                                 position3.Assign(writer.Property(PositionName)),
                                                 writer.Property(PositionName).Assign(position2.Add(sizeof(ushort).Constant())),
                                                 writer.Call(WriteOffsetName, null, new[] { position3 }),
                                                 writer.Property(PositionName).Assign(position3));

                var loop = CustomExpression.For(
                    i, 0.Constant(),
                    i.LessThan(count),
                    i.PreIncrementAssign(),
                    Expression.Block(new[] { position2 },
                                     position2.Assign(writer.Property(PositionName)),
                                     writer.Call(WriteOffsetName, null, new[] { position2 }),
                                     writer.Call(WriteUInt16Name, null, new[] { ((ushort)0).Constant() }),
                                     CompileSerializer(elemInfo).Constant().Invoke(writer, property.Property(ItemName, i)),
                                     i.NotEqual(count.Subtract(1.Constant()))
                                     .IfThen(writeNext)));

                var write = Expression.Block(new[] { position, i },
                                             position.Assign(writer.Property(PositionName)),
                                             writer.Property(PositionName).Assign(offset),
                                             writer.Call(WriteOffsetName, null, new[] { position }),
                                             writer.Property(PositionName).Assign(position),
                                             loop);

                return(Expression.Block(new[] { property, count },
                                        property.Assign(packet.Property(prop)),
                                        count.Assign(property.Property(CountName)),
                                        count.NotEqual(0.Constant())
                                        .IfThen(write)));
            }

            BlockExpression CompileString2(CompilerPacketFieldInfo info, ParameterExpression offset)
            {
                var position = typeof(int).Variable("position");

                return(Expression.Block(new[] { position },
                                        position.Assign(writer.Property(PositionName)),
                                        writer.Property(PositionName).Assign(offset),
                                        writer.Call(WriteOffsetName, null, new[] { position }),
                                        writer.Property(PositionName).Assign(position),
                                        writer.Call(WriteStringName, null, new[] { packet.Property(info.Property) })));
            }

            foreach (var(field, offset) in offsets)
            {
                exprs.Add(
                    field.IsByteArray ? CompileByteArray2(field, offset) :
                    field.IsArray ? CompileArray2(field, offset) :
                    CompileString2(field, offset));
            }

            var vars = new[] { packet }.Concat(offsets.Select(tup => tup.Item2));

            return(Expression.Lambda <Action <GameBinaryWriter, object> >(
                       Expression.Block(vars, exprs), writer, source).Compile());
        }
 protected override void OnSerialize(GameBinaryWriter writer, PacketInfo info,
                                     SerializablePacket packet)
 {
     _serializers[info](writer, packet);
 }
 Func <SerializablePacket> CompileCreator(PacketInfo info)
 {
     return(_creators.TryGetValue(info, out var c) ? c :
            Expression.Lambda <Func <SerializablePacket> >(info.Type.New()).Compile());
 }
Exemple #8
0
 protected abstract void OnDeserialize(GameBinaryReader reader, PacketInfo info,
                                       SerializablePacket packet);
Exemple #9
0
 protected abstract void OnSerialize(GameBinaryWriter writer, PacketInfo info,
                                     SerializablePacket packet);
Exemple #10
0
 protected abstract SerializablePacket OnCreate(PacketInfo info);
 protected override void OnSerialize(GameBinaryWriter writer, PacketInfo info,
                                     SerializablePacket packet)
 {
     SerializeObject(writer, packet);
 }
 protected override SerializablePacket OnCreate(PacketInfo info)
 {
     return((SerializablePacket)Activator.CreateInstance(info.Type));
 }