/// <inheritdoc />
        public override async Task WriteAsync(string value, IWireStreamWriterStrategyAsync dest)
        {
            if (dest == null)
            {
                throw new ArgumentNullException(nameof(dest));
            }

            //We should check this so we don't try to decode
            //or write null. Null should be considered empty.
            if (!String.IsNullOrEmpty(value))
            {
                //See sync method for doc
                byte[] stringBytes = EncodingStrategy.GetBytes(value);

                await dest.WriteAsync(stringBytes)
                .ConfigureAwait(false);
            }

            //TODO: Make this more efficient instead of multiple wrtie calls
            //Write the null terminator; Client expects it.
            for (int i = 0; i < CharacterSize; i++)
            {
                await dest.WriteAsync(0)
                .ConfigureAwait(false);
            }
        }
        /// <inheritdoc />
        public override async Task WriteAsync([NotNull] BitArray value, IWireStreamWriterStrategyAsync dest)
        {
            if (value == null)
            {
                throw new ArgumentNullException(nameof(value));
            }
            if (dest == null)
            {
                throw new ArgumentNullException(nameof(dest));
            }

            //The size must be equal to the length divided by 8 bits (1 byte) but we do not include the
            //remainder from a modular division. The reason for this is it's always sent as 4 byte chunks from
            //Trinitycore and the size is always in terms of an int array
            byte[] bitmask = new byte[(value.Length / 8)];

            ((ICollection)value).CopyTo(bitmask, 0);

            //Write the size as if it were an int array first
            await dest.WriteAsync((byte)(bitmask.Length / 4))
            .ConfigureAwait(false);

            await dest.WriteAsync(bitmask)
            .ConfigureAwait(false);
        }
예제 #3
0
        /// <inheritdoc />
        public override Task WriteAsync(TType value, IWireStreamWriterStrategyAsync dest)
        {
            byte[] bytes = SerializerStrategy.GetBytes(value);
            Array.Reverse(bytes);

            return(dest.WriteAsync(bytes));
        }
예제 #4
0
        /// <inheritdoc />
        public override async Task WriteAsync(PackedGuid value, IWireStreamWriterStrategyAsync dest)
        {
            //TODO: Can we use span or stackalloc? Or maybe shared buffer?
            byte[] packGuid = GeneratePackedGuid(value, out int size);

            await dest.WriteAsync(packGuid, 0, size);
        }
예제 #5
0
        /// <inheritdoc />
        public override async Task WriteAsync(TBaseType value, IWireStreamWriterStrategyAsync dest)
        {
            if (dest == null)
            {
                throw new ArgumentNullException(nameof(dest));
            }

            Type childType = value.GetType();

            //If the actual type is just this type then we should handle serialization as if we
            //were a regular complex type
            if (childType == typeof(TBaseType))
            {
                //We know the complex serializer won't be null because it HAS to be non-abstract for this to
                //have been true
                keyStrategy.WriteDefault(dest);
                await InternallyManagedComplexSerializer.WriteAsync(value, dest)
                .ConfigureAwait(false);

                return;
            }

            ITypeSerializerStrategy serializer = GetWriteSerializer(value, ref childType);

            //TODO: Oh man, this is a disaster. How do we handle the default? How do we tell consumers to use the default?
            //Defer key writing to the key writing strategy
            await keyStrategy.WriteAsync(typeToKeyLookup[childType], dest)
            .ConfigureAwait(false);

            await serializer.WriteAsync(value, dest)
            .ConfigureAwait(false);
        }
        /// <inheritdoc />
        public override async Task WriteAsync(TComplexType value, IWireStreamWriterStrategyAsync dest)
        {
            if (dest == null)
            {
                throw new ArgumentNullException(nameof(dest));
            }

            //invoke before serialization if it's available
            (value as ISerializationEventListener)?.OnBeforeSerialization();

            //Writes base members first and goes down the inheritance line
            //WARNING: This caused HUGE perf probleems. Several orders of magnitude slower than Protobuf
            //We MUST not check if the serializer exists and we must precache the gets.
            if (reversedInheritanceHierarchy.Count() != 0)
            {
                foreach (Type t in reversedInheritanceHierarchy)
                {
                    if (serializerProviderService.HasSerializerFor(t))                     //TODO: Should we remove this check for perf?
                    {
                        await serializerProviderService.Get(t).ObjectIntoWriterAsync(value, dest)
                        .ConfigureAwait(false);
                    }
                }
            }

            //Write our own members now.
            await WriteMemberDataAsync(value, dest)
            .ConfigureAwait(false);
        }
예제 #7
0
 /// <inheritdoc />
 public override async Task WriteAsync(TObjectType[] value, IWireStreamWriterStrategyAsync dest)
 {
     for (int i = 0; i < value.Length; i++)
     {
         await ElementSerializer.WriteAsync(value[i], dest)
         .ConfigureAwait(false);
     }
 }
        /// <inheritdoc />
        public override Task WriteAsync(TEnumType value, IWireStreamWriterStrategyAsync dest)
        {
            if (dest == null)
            {
                throw new ArgumentNullException(nameof(dest));
            }

            return(serializerStrategy.WriteAsync(GenericMath.Convert <TEnumType, TBaseType>(value), dest));
        }
예제 #9
0
        /// <inheritdoc />
        public override Task WriteAsync(bool value, [NotNull] IWireStreamWriterStrategyAsync dest)
        {
            if (dest == null)
            {
                throw new ArgumentNullException(nameof(dest));
            }

            return(dest.WriteAsync(ConvertFromBool(value)));
        }
예제 #10
0
        /// <inheritdoc />
        public override Task WriteAsync(string value, IWireStreamWriterStrategyAsync dest)
        {
            if (dest == null)
            {
                throw new ArgumentNullException(nameof(dest));
            }

            return(decoratedSerializer.WriteAsync(new string(value.Reverse().ToArray()), dest));
        }
        /// <inheritdoc />
        public override async Task WriteMemberAsync(object obj, IWireStreamWriterStrategyAsync dest)
        {
            if (dest == null)
            {
                throw new ArgumentNullException(nameof(dest));
            }

            await WriteMemberAsync((TContainingType)obj, dest)
            .ConfigureAwait(false);
        }
예제 #12
0
        /// <inheritdoc />
        public override Task WriteAsync(TEnumType value, IWireStreamWriterStrategyAsync dest)
        {
            if (dest == null)
            {
                throw new ArgumentNullException(nameof(dest));
            }

            //Just write the string to the stream
            return(decoratedSerializer.WriteAsync(value.ToString(), dest));
        }
예제 #13
0
        /// <inheritdoc />
        public async Task WriteMemberAsync(TContainingType obj, IWireStreamWriterStrategyAsync dest)
        {
            //Check if we should read
            if (!(bool)isReadWriteEnabledGetter.Getter(obj))
            {
                return;
            }

            await DecoratedMediator.WriteMemberAsync(obj, dest)
            .ConfigureAwait(false);
        }
예제 #14
0
        /// <inheritdoc />
        public virtual Task ObjectIntoWriterAsync(TType obj, IWireStreamWriterStrategyAsync dest)
        {
            if (dest == null)
            {
                throw new ArgumentNullException(nameof(dest));
            }

            //We can't really write or read into an object on a simple type.

            return(WriteAsync(obj, dest));
        }
        /// <inheritdoc />
        public override async Task WriteAsync(LinearPathMoveInfo value, IWireStreamWriterStrategyAsync dest)
        {
            await dest.WriteAsync(value.LastIndex.Reinterpret());

            await dest.WriteAsync(value.FinalPosition.X.Reinterpret());

            await dest.WriteAsync(value.FinalPosition.Y.Reinterpret());

            await dest.WriteAsync(value.FinalPosition.Z.Reinterpret());

            await dest.WriteAsync(value.SplineMiddlePoints);
        }
        /// <inheritdoc />
        public override Task WriteAsync(string value, IWireStreamWriterStrategyAsync dest)
        {
            if (dest == null)
            {
                throw new ArgumentNullException(nameof(dest));
            }

            //TODO: Pointer hack for speed
            byte[] stringBytes = EncodingStrategy.GetBytes(value);

            return(dest.WriteAsync(stringBytes));            //Just don't write terminator. Very simple.
        }
        /// <inheritdoc />
        public override Task WriteAsync(byte[] value, IWireStreamWriterStrategyAsync dest)
        {
            if (dest == null)
            {
                throw new ArgumentNullException(nameof(dest));
            }

            //MUST copy or it will modify the external objects
            byte[] bytes = value.ToArray();
            Array.Reverse(bytes);
            return(dest.WriteAsync(bytes));
        }
        /// <inheritdoc />
        public override Task WriteAsync(TType value, [NotNull] IWireStreamWriterStrategyAsync dest)
        {
            if (dest == null)
            {
                throw new ArgumentNullException(nameof(dest));
            }

            //TODO: Figure out a way to make this safely async
            //We cannot lock to protect the shared buffer in an async context
            Write(value, dest);

            return(Task.CompletedTask);
        }
        /// <inheritdoc />
        public SkipSomeBytesWireStreamWriterStrategyDecoratorAsync([NotNull] IWireStreamWriterStrategyAsync decoratedWriter, int byteNumberToSkip)
        {
            if (decoratedWriter == null)
            {
                throw new ArgumentNullException(nameof(decoratedWriter));
            }
            if (byteNumberToSkip < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(byteNumberToSkip));
            }

            DecoratedWriter  = decoratedWriter;
            ByteNumberToSkip = byteNumberToSkip;
        }
        protected async Task WriteMemberDataAsync(TType obj, [NotNull] IWireStreamWriterStrategyAsync dest)
        {
            if (dest == null)
            {
                throw new ArgumentNullException(nameof(dest));
            }

            // Tested, does not yield better perf
            // ReSharper disable once ForCanBeConvertedToForeach
            for (int i = 0; i < orderedMemberInfos.Length; i++)
            {
                await orderedMemberInfos[i].WriteMemberAsync(obj, dest)
                .ConfigureAwait(false);
            }
        }
예제 #21
0
        /// <inheritdoc />
        public override async Task WriteAsync(TType[] value, IWireStreamWriterStrategyAsync dest)
        {
            if (dest == null)
            {
                throw new ArgumentNullException(nameof(dest));
            }

            int size = await SizeStrategyService.SizeAsync <TType[], TType>(value, dest)
                       .ConfigureAwait(false);

            //We no longer verify size thanks to PHANTASY STAR ONLINE. Thanks Sega. Sometimes we have to fake the size

            await dest.WriteAsync(value.Reinterpret())
            .ConfigureAwait(false);
        }
        /// <inheritdoc />
        public async Task WriteAsync(int value, IWireStreamWriterStrategyAsync dest)
        {
            if (dest == null)
            {
                throw new ArgumentNullException(nameof(dest));
            }

            //If the key shouldn't be written then we avoid writing it
            //It may be that the data is needed to be left in the stream to indicate
            //something about the type later down the line.
            if (!typeHandlingFlags.HasFlag(InformationHandlingFlags.DontWrite))
            {
                await KeyTypeSerializerStrategy.WriteAsync(GenericMath.Convert <int, TKeyType>(value), dest)
                .ConfigureAwait(false);
            }
        }
        //TODO: Implement once we have write and read async
        /// <inheritdoc />
        public override Task ObjectIntoWriterAsync(TType obj, IWireStreamWriterStrategyAsync dest)
        {
            if (obj == null)
            {
                throw new ArgumentNullException(nameof(obj));
            }
            if (dest == null)
            {
                throw new ArgumentNullException(nameof(dest));
            }

            //This method is only responsible for writing the members
            //Even if we're suppose to write type data for this type we don't
            //Just members
            return(WriteMemberDataAsync(obj, dest));
        }
예제 #24
0
        /// <inheritdoc />
        public override async Task WriteAsync(TObjectType[] value, IWireStreamWriterStrategyAsync dest)
        {
            if (dest == null)
            {
                throw new ArgumentNullException(nameof(dest));
            }

            int size = await sizeStrategyService.SizeAsync <TObjectType[], TObjectType>(value, dest)
                       .ConfigureAwait(false);

            //We no longer verify size thanks to PHANTASY STAR ONLINE. Thanks Sega. Sometimes we have to fake the size

            for (int i = 0; i < size; i++)
            {
                await decoratedSerializer.WriteAsync(value[i], dest)
                .ConfigureAwait(false);
            }
        }
예제 #25
0
        /// <inheritdoc />
        public override async Task WriteAsync(UpdateFieldValueCollection value, IWireStreamWriterStrategyAsync dest)
        {
            //TODO: Major performance gains if we can avoid allocations here. MAJOR!!
            //The size must be equal to the length divided by 8 bits (1 byte) but we do not include the
            //remainder from a modular division. The reason for this is it's always sent as 4 byte chunks from
            //Trinitycore and the size is always in terms of an int array
            byte[] bitmask = new byte[value.UpdateMask.Count / 8];

            ((ICollection)value.UpdateMask).CopyTo(bitmask, 0);

            byte size = (byte)(bitmask.Length / sizeof(int));

            //Write the size as if it were an int array first
            await dest.WriteAsync(size);

            await dest.WriteAsync(bitmask);

            //We must also write the update values
            await dest.WriteAsync(value.UpdateDiffValues);
        }
예제 #26
0
        /// <inheritdoc />
        public override async Task WriteAsync(TObjectType[] value, IWireStreamWriterStrategyAsync dest)
        {
            if (dest == null)
            {
                throw new ArgumentNullException(nameof(dest));
            }

            int size = await sizeStrategyService.SizeAsync <TObjectType[], TObjectType>(value, dest)
                       .ConfigureAwait(false);

            //We no longer verify size thanks to PHANTASY STAR ONLINE. Thanks Sega. Sometimes we have to fake the size

            //Don't use size to know how many to write, since it may have larger size than is in the array now since
            //negative offset values are possible.
            for (int i = 0; i < value.Length; i++)
            {
                await decoratedSerializer.WriteAsync(value[i], dest)
                .ConfigureAwait(false);
            }
        }
        /// <inheritdoc />
        public async Task <int> SizeAsync(string stringValue, IWireStreamWriterStrategyAsync writer)
        {
            if (stringValue == null)
            {
                throw new ArgumentNullException(nameof(stringValue));
            }
            if (writer == null)
            {
                throw new ArgumentNullException(nameof(writer));
            }

            int size = stringValue.Length - AddedSize;

            //add one for null terminator
            //Using JonSkeets MiscUtils we can convert objects efficently
            await sizeSerializer.WriteAsync(GenericMath <int, TSizeType> .Convert(size + (includeNullTerminatorInSizeCalculation ? 1 : 0)), writer)
            .ConfigureAwait(false);

            return(size);
        }
        /// <inheritdoc />
        public override async Task WriteAsync(TBaseType value, IWireStreamWriterStrategyAsync dest)
        {
            if (dest == null)
            {
                throw new ArgumentNullException(nameof(dest));
            }

            //TODO: Test perf
            //Defer key writing to the key writing strategy
            foreach (ChildKeyPair childKey in serializers)
            {
                if (childKey.Serializer.SerializerType == value.GetType())
                {
                    //Well, what do we do? Do we just write the flag?
                    //It's the best we can do I think. Otherwise they should use NoConsume
                    //to better define the flag written themselves
                    await keyStrategy.WriteAsync(childKey.Flags, dest)
                    .ConfigureAwait(false);

                    //Now write
                    await childKey.Serializer.WriteAsync(value, dest)
                    .ConfigureAwait(false);

                    return;
                }
            }

            //TODO: We can now write default types but this ONLY works if it uses DontConsumeRead semantics.
            //TODO: Better default type handling so that it can be handle better
            //This will NOT work if there is a value that must be written.
            //We can't write default types.
            if (DefaultSerializer == null)
            {
                throw new InvalidOperationException($"Failed to serialize Type: {value.GetType().FullName}. No prepared serializer could be found. Make sure to properly setup child mapping.");
            }
            else
            {
                await DefaultSerializer.WriteAsync(value, dest)
                .ConfigureAwait(false);
            }
        }
        /// <inheritdoc />
        public override Task WriteMemberAsync(TContainingType obj, IWireStreamWriterStrategyAsync dest)
        {
            if (obj == null)
            {
                throw new ArgumentNullException(nameof(obj));
            }
            if (dest == null)
            {
                throw new ArgumentNullException(nameof(dest));
            }

            //TODO: Check how TC handles optionals or nulls.
            //Do we write nothing? Do we write 0?
            //object memberValue = value.TryGetValue(serializerInfo.MemberInformation.Name);
            object memberValue = MemberGetter.Getter(obj);             //instead of fasterflect we use delegate to getter

            //We used to do a null check here. It was kind of pointless to do and it was slightly expensive since they weren't all
            //reference types. No reason to check nullness; it's just a perf issue

            return(TypeSerializer.WriteAsync(memberValue, dest));
        }
        /// <inheritdoc />
        public override async Task WriteAsync(string value, IWireStreamWriterStrategyAsync dest)
        {
            if (value == null)
            {
                throw new ArgumentNullException(nameof(value));
            }
            if (dest == null)
            {
                throw new ArgumentNullException(nameof(dest));
            }

            int size = await sizeProvider.SizeAsync(value, dest)
                       .ConfigureAwait(false);

            await decoratedSerializer.WriteAsync(value, dest)
            .ConfigureAwait(false);

            if (value.Length < size)
            {
                await dest.WriteAsync(new byte[(CharacterSize * (size - value.Length))])
                .ConfigureAwait(false);
            }
        }