2
2
using Google . ProtocolBuffers ;
3
3
using MHServerEmu . Core . Extensions ;
4
4
using MHServerEmu . Core . Logging ;
5
+ using MHServerEmu . Core . Serialization ;
5
6
using MHServerEmu . Core . VectorMath ;
7
+ using MHServerEmu . Games . Common ;
6
8
using MHServerEmu . Games . GameData ;
7
9
using MHServerEmu . Games . GameData . Calligraphy ;
8
10
using MHServerEmu . Games . GameData . Prototypes ;
@@ -12,7 +14,7 @@ namespace MHServerEmu.Games.Properties
12
14
/// <summary>
13
15
/// An aggregatable collection of key/value pairs of <see cref="PropertyId"/> and <see cref="PropertyValue"/>.
14
16
/// </summary>
15
- public class PropertyCollection : IEnumerable < KeyValuePair < PropertyId , PropertyValue > >
17
+ public class PropertyCollection : IEnumerable < KeyValuePair < PropertyId , PropertyValue > > , ISerialize
16
18
{
17
19
// TODO: Eval
18
20
// TODO: PropertyChangeWatcher API: AttachWatcher(), RemoveWatcher(), RemoveAllWatchers()
@@ -25,7 +27,7 @@ public class PropertyCollection : IEnumerable<KeyValuePair<PropertyId, PropertyV
25
27
private readonly Dictionary < PropertyId , CurveProperty > _curveList = new ( ) ;
26
28
27
29
// Parent and child collections
28
- // NOTE: The client uses a tabletree structure to store those with PropertyCollection as key and an empty struct called EmptyDummyValue as value.
30
+ // NOTE: The client uses a tabletree structure to store these with PropertyCollection as key and an empty struct called EmptyDummyValue as value.
29
31
// I'm not sure what the intention there was, but it makes zero sense for us to do it the same way.
30
32
private readonly HashSet < PropertyCollection > _parentCollections = new ( ) ;
31
33
private readonly HashSet < PropertyCollection > _childCollections = new ( ) ;
@@ -399,7 +401,52 @@ public bool RemoveFromParent(PropertyCollection parentCollection)
399
401
400
402
#endregion
401
403
402
- // TODO: PropertyCollection::serializeWithDefault
404
+ public virtual bool Serialize ( Archive archive )
405
+ {
406
+ return SerializeWithDefault ( archive , null ) ;
407
+ }
408
+
409
+ public virtual bool SerializeWithDefault ( Archive archive , PropertyCollection defaultCollection )
410
+ {
411
+ bool success = true ;
412
+
413
+ // TODO: skip properties that match the default collection
414
+
415
+ if ( archive . IsPacking )
416
+ {
417
+ // NOTE: PropertyCollection::serializeWithDefault() does a weird thing where it manipulates the archive buffer directly.
418
+ // First it allocates 4 bytes for the number of properties, than it writes all the properties, and then it goes back
419
+ // and updates the number. This is most likely a side effect of not all properties being saved to the database in the
420
+ // original implementation.
421
+ archive . WriteUnencodedStream ( ( uint ) _baseList . Count ) ;
422
+
423
+ foreach ( var kvp in _baseList )
424
+ success &= SerializePropertyForPacking ( kvp , archive , defaultCollection ) ;
425
+ }
426
+ else
427
+ {
428
+ uint numProperties = 0 ;
429
+ success &= archive . ReadUnencodedStream ( ref numProperties ) ;
430
+
431
+ for ( uint i = 0 ; i < numProperties ; i ++ )
432
+ {
433
+ PropertyId id = new ( ) ;
434
+ success &= Serializer . Transfer ( archive , ref id ) ;
435
+
436
+ PropertyInfo info = GameDatabase . PropertyInfoTable . LookupPropertyInfo ( id . Enum ) ;
437
+
438
+ ulong bits = 0 ;
439
+ success &= Serializer . Transfer ( archive , ref bits ) ;
440
+
441
+ if ( success )
442
+ SetPropertyValue ( id , ConvertBitsToValue ( bits , info . DataType ) ) ;
443
+ }
444
+ }
445
+
446
+ return success ;
447
+ }
448
+
449
+ #region REMOVEME: Old Serialization
403
450
404
451
/// <summary>
405
452
/// Decodes <see cref="PropertyCollection"/> data from a <see cref="CodedInputStream"/>.
@@ -423,9 +470,24 @@ public virtual void Encode(CodedOutputStream stream)
423
470
{
424
471
stream . WriteRawUInt32 ( ( uint ) _baseList . Count ) ;
425
472
foreach ( var kvp in _baseList )
426
- SerializePropertyForPacking ( kvp , stream ) ;
473
+ OLD_SerializePropertyForPacking ( kvp , stream ) ;
474
+ }
475
+
476
+ /// <summary>
477
+ /// Serializes a key/value pair of <see cref="PropertyId"/> and <see cref="PropertyValue"/> to a <see cref="CodedOutputStream"/>.
478
+ /// </summary>
479
+ protected static bool OLD_SerializePropertyForPacking ( KeyValuePair < PropertyId , PropertyValue > kvp , CodedOutputStream stream )
480
+ {
481
+ // TODO: Serialize only properties that are different from the base collection for replication
482
+ PropertyInfo info = GameDatabase . PropertyInfoTable . LookupPropertyInfo ( kvp . Key . Enum ) ;
483
+ ulong valueBits = ConvertValueToBits ( kvp . Value , info . DataType ) ;
484
+ stream . WriteRawVarint64 ( kvp . Key . Raw . ReverseBytes ( ) ) ;
485
+ stream . WriteRawVarint64 ( valueBits ) ;
486
+ return true ;
427
487
}
428
488
489
+ #endregion
490
+
429
491
/// <summary>
430
492
/// Returns the <see cref="PropertyValue"/> with the specified <see cref="PropertyId"/>.
431
493
/// Falls back to the default value for the property if this <see cref="PropertyCollection"/> does not contain it.
@@ -474,17 +536,19 @@ protected bool SetPropertyValue(PropertyId id, PropertyValue value, SetPropertyF
474
536
return hasChanged || flags . HasFlag ( SetPropertyFlags . Flag2 ) ; // Some kind of flag that forces property value update
475
537
}
476
538
477
- /// <summary>
478
- /// Serializes a key/value pair of <see cref="PropertyId"/> and <see cref="PropertyValue"/> to a <see cref="CodedOutputStream"/>.
479
- /// </summary>
480
- protected static bool SerializePropertyForPacking ( KeyValuePair < PropertyId , PropertyValue > kvp , CodedOutputStream stream )
539
+ protected static bool SerializePropertyForPacking ( KeyValuePair < PropertyId , PropertyValue > kvp , Archive archive , PropertyCollection defaultCollection )
481
540
{
541
+ bool success = true ;
542
+
482
543
// TODO: Serialize only properties that are different from the base collection for replication
483
544
PropertyInfo info = GameDatabase . PropertyInfoTable . LookupPropertyInfo ( kvp . Key . Enum ) ;
484
- ulong valueBits = ConvertValueToBits ( kvp . Value , info . DataType ) ;
485
- stream . WriteRawVarint64 ( kvp . Key . Raw . ReverseBytes ( ) ) ; // Id is reversed so that it can be efficiently encoded into varint when all params are 0
486
- stream . WriteRawVarint64 ( valueBits ) ;
487
- return true ;
545
+
546
+ ulong id = kvp . Key . Raw . ReverseBytes ( ) ; // Id is reversed so that it can be efficiently encoded into varint when all params are 0
547
+ ulong value = ConvertValueToBits ( kvp . Value , info . DataType ) ;
548
+ success &= Serializer . Transfer ( archive , ref id ) ;
549
+ success &= Serializer . Transfer ( archive , ref value ) ;
550
+
551
+ return success ;
488
552
}
489
553
490
554
// TODO: make value <-> bits conversion protected once we no longer need it for hacks
0 commit comments