/// <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); }
/// <inheritdoc /> public override Task WriteAsync(TType value, IWireStreamWriterStrategyAsync dest) { byte[] bytes = SerializerStrategy.GetBytes(value); Array.Reverse(bytes); return(dest.WriteAsync(bytes)); }
/// <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); }
/// <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); }
/// <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)); }
/// <inheritdoc /> public override Task WriteAsync(bool value, [NotNull] IWireStreamWriterStrategyAsync dest) { if (dest == null) { throw new ArgumentNullException(nameof(dest)); } return(dest.WriteAsync(ConvertFromBool(value))); }
/// <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); }
/// <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)); }
/// <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); }
/// <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); } }
/// <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)); }
/// <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); } }
/// <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); }
/// <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); } }