4
4
5
5
namespace MHServerEmu . Games . GameData . Calligraphy
6
6
{
7
+ /// <summary>
8
+ /// A <see cref="PropertyCollection"/> that stores properties deserialized from Calligraphy prototype mixin field groups.
9
+ /// </summary>
7
10
public class PrototypePropertyCollection : PropertyCollection
8
11
{
9
12
private static readonly Logger Logger = LogManager . CreateLogger ( ) ;
10
13
11
- private readonly Dictionary < ulong , PropertyId > _mixinPropertyLookup ; // See SetKeyToPropertyId() for details on this
14
+ // Child prototypes may override params of properties of their parents, so PrototypePropertyCollection has to
15
+ // keep track of how contained property ids correspond to blueprints. For that purpose it uses a dictionary with
16
+ // composite values made from blueprint copy number and property enum as keys.
17
+ private readonly Dictionary < ulong , PropertyId > _mixinPropertyLookup ;
12
18
19
+ /// <summary>
20
+ /// Constructs a new blank <see cref="PrototypePropertyCollection"/> instance.
21
+ /// </summary>
13
22
public PrototypePropertyCollection ( )
14
23
{
15
24
_mixinPropertyLookup = new ( ) ;
16
25
}
17
26
27
+ /// <summary>
28
+ /// Constructs a new <see cref="PrototypePropertyCollection"/> instance and copies mixin property lookups from another collection.
29
+ /// </summary>
18
30
public PrototypePropertyCollection ( Dictionary < ulong , PropertyId > mixinPropertyLookup )
19
31
{
20
32
_mixinPropertyLookup = new ( mixinPropertyLookup ) ; // Copy mixin lookups
21
33
}
22
34
35
+ /// <summary>
36
+ /// Clones this <see cref="PrototypePropertyCollection"/>.
37
+ /// </summary>
23
38
public PrototypePropertyCollection ShallowCopy ( )
24
39
{
25
40
PrototypePropertyCollection newCollection = new ( _mixinPropertyLookup ) ;
26
41
newCollection . FlattenCopyFrom ( this , true ) ;
27
42
return newCollection ;
28
43
}
29
44
30
- // The ugliness going on here is an attempt to imitate passing struct pointers C++ style.
31
- // TODO: Clean this mess up .
32
-
45
+ /// <summary>
46
+ /// Sets a <see cref="PropertyValue"/> for a <see cref="PropertyId"/> from a mixin field group .
47
+ /// </summary>
33
48
public void SetPropertyFromMixin ( PropertyValue value , PropertyId propertyId , byte blueprintCopyNum , byte paramsSetMask )
34
49
{
35
50
PropertyValue ? existingValueRef = null ;
36
- CurveProperty ? curveProperty = null ;
37
- PropertyId ? curveIndex = null ;
38
51
39
- SetKeyToPropertyId ( ref propertyId , blueprintCopyNum , paramsSetMask , ref existingValueRef , ref curveProperty , ref curveIndex ) ;
52
+ SetKeyToPropertyId ( ref propertyId , blueprintCopyNum , paramsSetMask , ref existingValueRef ) ;
40
53
SetPropertyValue ( propertyId , value ) ;
41
54
}
42
55
56
+ /// <summary>
57
+ /// Updates the <see cref="PropertyId"/> of an existing <see cref="PropertyValue"/> set from a mixin field group.
58
+ /// </summary>
43
59
public void ReplacePropertyIdFromMixin ( PropertyId newPropertyId , byte blueprintCopyNum , byte paramsSetMask )
44
60
{
45
61
PropertyValue ? existingValueRef = new ( ) ;
46
- CurveProperty ? curveProperty = null ;
47
- PropertyId ? curveIndex = null ;
48
62
49
- if ( SetKeyToPropertyId ( ref newPropertyId , blueprintCopyNum , paramsSetMask , ref existingValueRef , ref curveProperty , ref curveIndex ) )
50
- SetPropertyValue ( newPropertyId , ( PropertyValue ) existingValueRef ) ; // Set property value only if there is something to replace
63
+ // If the id got updated we need to reassign the existing value to the new id
64
+ if ( SetKeyToPropertyId ( ref newPropertyId , blueprintCopyNum , paramsSetMask , ref existingValueRef ) )
65
+ SetPropertyValue ( newPropertyId , ( PropertyValue ) existingValueRef ) ;
51
66
}
52
67
68
+ /// <summary>
69
+ /// Sets a curve property for a <see cref="PropertyId"/> from a mixin field group.
70
+ /// </summary>
53
71
public void SetCurvePropertyFromMixin ( PropertyId propertyId , CurveId curveId , PropertyId indexProperty , PropertyInfo info , byte blueprintCopyNum )
54
72
{
55
- PropertyValue ? existingValueRef = null ;
56
- CurveProperty ? nullableOldCurve = new ( ) ;
57
- PropertyId ? nullableIndexProperty = indexProperty ;
73
+ CurveProperty oldCurve = new ( ) ;
58
74
59
- bool replaced = SetKeyToPropertyId ( ref propertyId , blueprintCopyNum , 0xff , ref existingValueRef , ref nullableOldCurve , ref nullableIndexProperty ) ;
60
-
61
- var oldCurve = ( CurveProperty ) nullableOldCurve ;
62
- indexProperty = ( PropertyId ) nullableIndexProperty ;
75
+ bool replaced = SetKeyToPropertyId ( ref propertyId , blueprintCopyNum , 0xff , ref oldCurve , ( PropertyId ? ) indexProperty ) ;
63
76
77
+ // There must be a valid index property
64
78
if ( indexProperty == PropertyId . Invalid )
65
79
{
66
- // If the prototype contained an invalid curve index, fall back to the old curve or default curve index from the property info
67
80
if ( replaced )
68
81
{
69
82
if ( oldCurve . IndexPropertyId == PropertyId . Invalid )
70
83
{
71
- Logger . Warn ( "Prototype property read error: trying to replace a curve property that has an invalid curve index" ) ;
84
+ // Nothing to fall back on
85
+ Logger . Error ( "Prototype property read error: trying to replace a curve property that has an invalid curve index" ) ;
72
86
return ;
73
87
}
74
88
89
+ // If we are replacing a valid existing curve property, get the index property from it
75
90
indexProperty = oldCurve . IndexPropertyId ;
76
91
}
77
92
else
78
93
{
94
+ // If we are adding a new property fall back to the default curve defined in property info
79
95
indexProperty = info . DefaultCurveIndex ;
80
96
}
81
97
}
82
98
83
99
SetCurveProperty ( propertyId , curveId , indexProperty , info , UInt32Flags . None , true ) ;
84
100
}
85
101
102
+ /// <summary>
103
+ /// Updates the <see cref="PropertyId"/> and the curve index property for an existing curve property added from a mixin field group.
104
+ /// </summary>
86
105
public void ReplaceCurvePropertyIdFromMixin ( PropertyId propertyId , PropertyId indexProperty , PropertyInfo info , byte blueprintCopyNum , byte paramsSetMask )
87
106
{
88
- PropertyValue ? existingValueRef = null ;
89
- CurveProperty ? nullableOldCurve = new ( ) ;
90
- PropertyId ? nullableIndexProperty = indexProperty ;
107
+ CurveProperty oldCurve = new ( ) ;
91
108
92
- if ( SetKeyToPropertyId ( ref propertyId , blueprintCopyNum , paramsSetMask , ref existingValueRef , ref nullableOldCurve , ref nullableIndexProperty ) )
93
- SetCurveProperty ( propertyId , ( ( CurveProperty ) nullableOldCurve ) . CurveId , ( PropertyId ) nullableIndexProperty , info , UInt32Flags . None , true ) ;
109
+ if ( SetKeyToPropertyId ( ref propertyId , blueprintCopyNum , paramsSetMask , ref oldCurve , ( PropertyId ? ) indexProperty ) )
110
+ SetCurveProperty ( propertyId , oldCurve . CurveId , indexProperty , info , UInt32Flags . None , true ) ;
94
111
}
95
112
113
+ /// <summary>
114
+ /// Updates the <see cref="PropertyId"/> for an existing curve property added from a mixin field group.
115
+ /// </summary>
96
116
public void ReplaceCurvePropertyIdFromMixin ( PropertyId propertyId , PropertyInfo info , byte blueprintCopyNum , byte paramsSetMask )
97
117
{
98
- PropertyValue ? existingValueRef = null ;
99
- CurveProperty ? nullableOldCurve = new ( ) ;
100
- PropertyId ? nullableIndexProperty = null ;
118
+ CurveProperty oldCurve = new ( ) ;
101
119
102
- if ( SetKeyToPropertyId ( ref propertyId , blueprintCopyNum , paramsSetMask , ref existingValueRef , ref nullableOldCurve , ref nullableIndexProperty ) )
103
- {
104
- CurveProperty oldCurve = ( CurveProperty ) nullableOldCurve ;
120
+ if ( SetKeyToPropertyId ( ref propertyId , blueprintCopyNum , paramsSetMask , ref oldCurve , null ) )
105
121
SetCurveProperty ( propertyId , oldCurve . CurveId , oldCurve . IndexPropertyId , info , UInt32Flags . None , true ) ;
106
- }
107
122
}
108
123
109
- private bool SetKeyToPropertyId ( ref PropertyId propertyIdRef , byte blueprintCopyNum , byte paramsSetMask ,
110
- ref PropertyValue ? existingValueRef , ref CurveProperty ? curveProp , ref PropertyId ? curveIndex )
124
+ /// <summary>
125
+ /// Updates the <see cref="PropertyId"/> corresponding to a <see cref="PropertyEnum"/> / blueprint copy number pair. For use with non-curve properties.
126
+ /// </summary>
127
+ private bool SetKeyToPropertyId ( ref PropertyId propertyIdRef , byte blueprintCopyNum , byte paramsSetMask , ref PropertyValue ? existingValueRef )
111
128
{
112
- // TODO: Make an overload of this method for handling curve properties
113
129
bool valueIsReplaced = false ;
114
-
115
- // Child prototypes may override params of properties of their parents, so PrototypePropertyCollection has to
116
- // keep track of how contained property ids correspond to blueprints. For that purpose it uses a dictionary with
117
- // composite values made from blueprint copy number and property enum as keys.
118
130
ulong key = ( ( ulong ) blueprintCopyNum << 32 ) | ( ulong ) propertyIdRef . Enum ;
119
131
120
132
// If the lookup dict already has this key it means we are modifying an existing property rather than adding a new one
121
133
if ( _mixinPropertyLookup . TryGetValue ( key , out PropertyId existingPropertyId ) )
122
134
{
123
- if ( HasMatchingParams ( propertyIdRef , existingPropertyId , 0xff ) == false || curveIndex != null )
135
+ if ( HasMatchingParams ( propertyIdRef , existingPropertyId , 0xff ) == false )
124
136
{
125
137
valueIsReplaced = true ;
126
138
127
- // We need to cast null to one of the supported value types for this check because of all the implicit casting we are doing
139
+ // If existingValueRef is not a null ref it means we are replacing an existing property id,
140
+ // and we need to output existing PropertyValue to this ref so it can be reassigned to the new id.
141
+ //
142
+ // For null comparison we need to cast null to one of the supported PropertyValue types
143
+ // for this check because of all the implicit casting we are doing.
128
144
if ( existingValueRef != ( bool ? ) null )
129
145
existingValueRef = GetPropertyValue ( existingPropertyId ) ;
130
146
131
- if ( curveProp != null )
147
+ SetOverridenParams ( ref propertyIdRef , existingPropertyId , paramsSetMask ) ;
148
+ RemoveProperty ( existingPropertyId ) ;
149
+ }
150
+ }
151
+
152
+ _mixinPropertyLookup [ key ] = propertyIdRef ;
153
+ return valueIsReplaced ;
154
+ }
155
+
156
+ /// <summary>
157
+ /// Updates the <see cref="PropertyId"/> corresponding to a <see cref="PropertyEnum"/> / blueprint copy number pair. For use with curve properties.
158
+ /// </summary>
159
+ private bool SetKeyToPropertyId ( ref PropertyId propertyIdRef , byte blueprintCopyNum , byte paramsSetMask , ref CurveProperty oldCurve , PropertyId ? curveIndex )
160
+ {
161
+ bool valueIsReplaced = false ;
162
+ ulong key = ( ( ulong ) blueprintCopyNum << 32 ) | ( ulong ) propertyIdRef . Enum ;
163
+
164
+ // If the lookup dict already has this key it means we are modifying an existing property rather than adding a new one
165
+ if ( _mixinPropertyLookup . TryGetValue ( key , out PropertyId existingPropertyId ) )
166
+ {
167
+ if ( HasMatchingParams ( propertyIdRef , existingPropertyId , 0xff ) == false || curveIndex != null )
168
+ {
169
+ // If there is an existing CurveProperty assigned to this id and we are actually making changes,
170
+ // we need to output this CurveProperty to be reassigned to the new id.
171
+ CurveProperty ? nullableExistingCurveProp = GetCurveProperty ( existingPropertyId ) ;
172
+ if ( nullableExistingCurveProp != null )
132
173
{
133
- CurveProperty ? nullableExistingCurveProp = GetCurveProperty ( existingPropertyId ) ;
134
- if ( nullableExistingCurveProp != null )
135
- {
136
- var existingCurveProp = ( CurveProperty ) nullableExistingCurveProp ;
137
-
138
- if ( curveIndex != null && propertyIdRef == existingPropertyId && existingCurveProp . IndexPropertyId == curveIndex )
139
- return false ;
140
-
141
- curveProp = existingCurveProp ;
142
- }
143
- else
144
- {
145
- valueIsReplaced = false ;
146
- }
174
+ var existingCurveProp = ( CurveProperty ) nullableExistingCurveProp ;
175
+
176
+ if ( curveIndex != null && propertyIdRef == existingPropertyId && existingCurveProp . IndexPropertyId == curveIndex )
177
+ return false ; // No need to change anything
178
+
179
+ oldCurve = existingCurveProp ;
180
+ valueIsReplaced = true ;
147
181
}
148
182
149
183
SetOverridenParams ( ref propertyIdRef , existingPropertyId , paramsSetMask ) ;
@@ -155,6 +189,9 @@ private bool SetKeyToPropertyId(ref PropertyId propertyIdRef, byte blueprintCopy
155
189
return valueIsReplaced ;
156
190
}
157
191
192
+ /// <summary>
193
+ /// Compares parameters of two <see cref="PropertyId"/> values. The provided mask defines params that need to be compared.
194
+ /// </summary>
158
195
private bool HasMatchingParams ( PropertyId left , PropertyId right , byte paramsSetMask )
159
196
{
160
197
if ( paramsSetMask == 0xff ) return left == right ;
@@ -174,6 +211,9 @@ private bool HasMatchingParams(PropertyId left, PropertyId right, byte paramsSet
174
211
return true ;
175
212
}
176
213
214
+ /// <summary>
215
+ /// Overrides <see cref="PropertyParam"/> values of a <see cref="PropertyId"/>. The provided mask defines params that need to be overriden.
216
+ /// </summary>
177
217
private void SetOverridenParams ( ref PropertyId destId , PropertyId sourceId , byte paramsSetMask )
178
218
{
179
219
if ( paramsSetMask == 0xff ) return ;
0 commit comments