1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "data_set_base.h"
21 #include <nel/georges/u_form_elm.h>
23 #include "ryzom_entity_id.h"
26 using namespace NLMISC
;
27 using namespace NLNET
;
28 using namespace NLGEORGES
;
31 // The following variable controls the logging of nlinfo and nldebug messages produced by the MIRROR_INFO and MIRROR_DEBUG macros
32 CVariable
<bool> VerboseMIRROR("ms","VerboseMIRROR","Enable verbose logging in Mirror operations",true,0,true);
35 #ifdef MIRROR_LIST_ROW_32BITS
36 const char *ListRowSizeString
= "L32";
38 const char *ListRowSizeString
= "L16";
45 CDataSetBase::CDataSetBase() : _MaxNbRows(INVALID_DATASET_INDEX
) //, _SizeOfRow(Row32)
54 void CDataSetBase::init( const NLMISC::CSheetId
& sheetId
, const TDataSetSheet
& properties
)
56 /*string dataSetName = "player";
57 TPropertyIndex nbProperties = 4;
58 _PropIndexToType.resize( nbProperties );
59 _PropIndexToType[0] = TypeSint32;
60 _PropIndexToType[1] = TypeSint32;
61 _PropIndexToType[2] = TypeSint32;
62 _PropIndexToType[3] = TypeSint32;
63 _DataSetName = dataSetName;*/
65 nlctassert( sizeof(TDataSetRow
) == 4 );
68 _DataSetName
= properties
.DataSetName
;
69 _MaxNbRows
= properties
.getConfigDataSetSize();
70 //_SizeOfRow = (_MaxNbRows>65534) ? Row32 : ((_MaxNbRows>254)?Row16:Row8);
71 //nlinfo( "\t Dataset %s: Rows will be transfered using %s-bit index", _DataSetName.c_str(), (_SizeOfRow==Row32)?"32":((_SizeOfRow==Row16)?"16":"8") );
72 _PropIndexToType
= properties
.PropIndexToType
;
74 _EntityTypesFilter
= properties
.EntityTypesFilter
;
75 _PropIsList
= properties
.PropIsList
;
76 _PropertyContainer
.init( properties
.NbProperties
);
82 * When the flag initValues is set:
83 * If the counts must be initialised from a remote MS, use the vector ptCountsToSet (it will be read
84 * then deleted) and timestamp, otherwise set NULL.
85 * If propName is the special entityId property, the behaviour is different (propName need not exist)
87 void CDataSetBase::setPropertyPointer( std::string
& propName
, TPropertyIndex propIndex
, void *segmentPt
, bool initValues
, uint32 dataTypeSize
, bool isReadOnly
, bool mustMonitorAssignment
, std::vector
<uint8
> *ptCountsToSet
, NLMISC::TGameCycle
/* timestamp */, uint32 segmentSize
)
89 uint8
*endPt
= (uint8
*)segmentPt
;
91 // Handle special case of _CEntityId_
92 if ( propName
.substr(0,LENGTH_OF_ENTITYID_PREFIX
) == ENTITYID_PREFIX
)
94 _PropertyContainer
.EntityIdArray
.EntityIds
= (CEntityId
*)segmentPt
;
95 _PropertyContainer
.EntityIdArray
.OnlineBitfieldPt
= (uint32
*)((uint8
*)segmentPt
+ (sizeof(CEntityId
)*maxNbRows()));
96 _PropertyContainer
.EntityIdArray
.OnlineTimestamps
= (NLMISC::TGameCycle
*)(((uint8
*)_PropertyContainer
.EntityIdArray
.OnlineBitfieldPt
) + maxNbRows()/8 + 4);
97 _PropertyContainer
.EntityIdArray
.Counts
= ((uint8
*)_PropertyContainer
.EntityIdArray
.OnlineTimestamps
) + maxNbRows()*sizeof(NLMISC::TGameCycle
);
98 _PropertyContainer
.EntityIdArray
.SpawnerServiceIds
= ((TServiceId8
*)_PropertyContainer
.EntityIdArray
.Counts
) + maxNbRows()*sizeof(TServiceId8
);
99 endPt
= ((uint8
*)_PropertyContainer
.EntityIdArray
.SpawnerServiceIds
) + maxNbRows()*sizeof(TServiceId8
);
101 // In the Mirror Service, initialize the value
104 // Set the entityid array to the default value
105 for ( TDataSetIndex i
=0; i
!=(uint32
)maxNbRows(); ++i
)
107 _PropertyContainer
.EntityIdArray
.EntityIds
[i
] = CEntityId::Unknown
;
108 _PropertyContainer
.EntityIdArray
.setOnline( i
, false );
109 if ( ptCountsToSet
!= NULL
)
110 _PropertyContainer
.EntityIdArray
.Counts
[i
] = (*ptCountsToSet
)[i
];
112 _PropertyContainer
.EntityIdArray
.Counts
[i
] = 1; // begins at 1, 0 is reserved for "no counter"
114 // Always init the online timestamps to 0 (otherwise the assert in declareEntity() will fail)
115 _PropertyContainer
.EntityIdArray
.OnlineTimestamps
[i
] = 0;
117 _PropertyContainer
.EntityIdArray
.SpawnerServiceIds
[i
] = TServiceId8(0);
119 if ( ptCountsToSet
!= NULL
)
121 delete ptCountsToSet
;
127 if ( (uint
)propIndex
< (uint
)nbProperties() )
129 _PropertyContainer
.PropertyValueArrays
[propIndex
].ChangeTimestamps
= (TGameCycle
*)segmentPt
;
130 #ifdef STORE_CHANGE_SERVICEIDS
131 _PropertyContainer
.PropertyValueArrays
[propIndex
].ChangeServiceIds
= (TServiceId8
*)((uint8
*)segmentPt
+ (sizeof(TGameCycle
)*maxNbRows()));
132 _PropertyContainer
.PropertyValueArrays
[propIndex
].Values
= (void*)((uint8
*)_PropertyContainer
.PropertyValueArrays
[propIndex
].ChangeServiceIds
+ (sizeof(TServiceId8
)*maxNbRows()));
134 _PropertyContainer
.PropertyValueArrays
[propIndex
].Values
= (void*)((uint8
*)segmentPt
+ (sizeof(TGameCycle
)*maxNbRows()));
136 _PropertyContainer
.PropertyValueArrays
[propIndex
].DataTypeSize
= dataTypeSize
;
138 _PropertyContainer
.PropertyValueArrays
[propIndex
].IsReadOnly
= isReadOnly
;
139 _PropertyContainer
.PropertyValueArrays
[propIndex
].IsMonitored
= mustMonitorAssignment
;
142 // Cell container for list properties
143 if ( _PropIsList
[ propIndex
] )
145 uint8
*ptFreeCellsFront
= ((uint8
*)(_PropertyContainer
.PropertyValueArrays
[propIndex
].Values
)) + sizeof(TSharedListRow
)*maxNbRows();
146 _PropertyContainer
.PropertyValueArrays
[propIndex
].ListCellContainer
= ptFreeCellsFront
+ sizeof(TSharedListRow
);
148 // In the Mirror Service, set up the list headers (1 per datasetrow) and container
152 TSharedListRow
*listHeaders
= (TSharedListRow
*)(_PropertyContainer
.PropertyValueArrays
[propIndex
].Values
);
153 for ( TDataSetIndex i
=0; i
!=(uint32
)maxNbRows(); ++i
)
155 listHeaders
[i
] = INVALID_SHAREDLIST_ROW
;
157 uint32 datasize
= getDataSizeOfProp( propIndex
);
159 //nldebug( "%p + %u bytes + %u", _PropertyContainer.PropertyValueArrays[propIndex].Values, sizeof(TSharedListRow)*maxNbRows(), sizeof(TSharedListRow) );
160 //nldebug( "%p", _PropertyContainer.PropertyValueArrays[propIndex].ListCellContainer );
161 //nldebug( "Segment size: %u", segmentSize );
162 nldebug( "Shared List container uses %u bytes (at %u bytes per cell)", segmentSize
- ( (uint8
*)(_PropertyContainer
.PropertyValueArrays
[propIndex
].ListCellContainer
) - (uint8
*)segmentPt
), sizeof(TSharedListRow
)+datasize
);
163 //nldebug( "End at %p", (uint8*)segmentPt + segmentSize );
165 // Init the list of free cells
166 TSharedListRow
*freeCellsFront
= (TSharedListRow
*)ptFreeCellsFront
;
169 uint8
*cellPt
= (uint8
*)(_PropertyContainer
.PropertyValueArrays
[propIndex
].ListCellContainer
);
170 for ( TSharedListRow j
=0; j
!=NB_SHAREDLIST_CELLS
-1 /*TEMP*/; ++j
)
172 TSharedListRow
*nextField
= (TSharedListRow
*)cellPt
;
174 cellPt
+= sizeof(TSharedListRow
) + datasize
; // assumes #pragma pack!
176 TSharedListRow
*nextField
= (TSharedListRow
*)cellPt
;
177 *nextField
= INVALID_SHAREDLIST_ROW
;
179 endPt
= ((uint8
*)_PropertyContainer
.PropertyValueArrays
[propIndex
].ListCellContainer
) + (NB_SHAREDLIST_CELLS
*(sizeof(TSharedListRow
) + datasize
)); // assumes #pragma pack!
184 _PropertyContainer
.PropertyValueArrays
[propIndex
].ListCellContainer
= NULL
;
188 endPt
= ((uint8
*)_PropertyContainer
.PropertyValueArrays
[propIndex
].Values
) + maxNbRows()*dataTypeSize
;
196 // Check that the total size of segment is sufficient
197 nlassert( ((uint8
*)segmentPt
) + segmentSize
>= endPt
);
203 * Fill the datasize array using the prop to type array
205 void CDataSetBase::fillDataSizeByProp()
207 _DataSizeByProp
.resize( _PropIndexToType
.size() );
208 vector
<uint32
>::iterator itd
;
209 vector
<TTypeOfProp
>::const_iterator itp
;
210 for ( itp
=_PropIndexToType
.begin(), itd
=_DataSizeByProp
.begin(); itp
!=_PropIndexToType
.end(); ++itp
, ++itd
)
214 case TypeUint8
: *itd
= 1; break;
215 case TypeSint8
: *itd
= 1; break;
216 case TypeUint16
: *itd
= 2; break;
217 case TypeSint16
: *itd
= 2; break;
218 case TypeUint32
: *itd
= 4; break;
219 case TypeSint32
: *itd
= 4; break;
220 case TypeUint64
: *itd
= 8; break;
221 case TypeSint64
: *itd
= 8; break;
222 case TypeFloat
: *itd
= 4; break;
223 case TypeDouble
: *itd
= 8; break;
224 case TypeCEntityId
: *itd
= 8; break;
225 case TypeBool
: *itd
= 1; break;
226 default: *itd
= 0; break;
233 * Check that the template argument T passed to CMirrorPropValue<T> has the right size
235 void CDataSetBase::checkTemplateSize( uint32 passedSize
, TPropertyIndex propIndex
, const TDataSetRow
& entityIndex
) const
237 nlassertex( passedSize
== _PropertyContainer
.PropertyValueArrays
[propIndex
].DataTypeSize
,
238 ("Wrong CMirrorPropValue template argument: size=%u (expected: %u) (%s/E%d/P%hd)",
239 passedSize
, _PropertyContainer
.PropertyValueArrays
[propIndex
].DataTypeSize
, name().c_str(), entityIndex
.getIndex(), propIndex
) );
246 void TDataSetSheet::readGeorges( const NLMISC::CSmartPtr
<NLGEORGES::UForm
> &form
, const NLMISC::CSheetId
&sheetId
)
250 // Get the name of the dataset
251 DataSetName
= sheetId
.toString();
252 DataSetName
.erase( DataSetName
.find_last_of( '.' ) ); // erase .dataset
253 MIRROR_INFO( "MIRROR: Reading sheet for dataset '%s'", DataSetName
.c_str() );
255 UFormElm
& root
= form
->getRootNode();
257 // Get the max number of rows (will be used only if not overriden in the .cfg)
258 if ( root
.getValueByName( MaxNbRows
, "max number of rows or entities" ) )
260 MIRROR_INFO( "MIRROR: \tMaxNbRows = %d in sheet", MaxNbRows
);
265 nlinfo( "MaxNbRows of %s not specified in sheet, expecting value in .cfg", DataSetName
.c_str() );
268 // Get property types and names
269 UFormElm
*arrayProperties
;
270 if( root
.getNodeByName( &arrayProperties
, "properties" ) && arrayProperties
)
273 nlverify( arrayProperties
->getArraySize(size
) );
274 nlassert( size
< 0x10000 );
276 PropertyNames
.resize( NbProperties
);
277 PropIndexToType
.resize( NbProperties
);
278 //Weights.resize( NbProperties );
279 PropIsList
.resize( NbProperties
);
281 for ( sint p
=0; p
!=NbProperties
; ++p
)
283 const UFormElm
*property
= NULL
;
284 if ( arrayProperties
->getArrayNode( &property
, p
) && property
)
286 // Name of the property
287 property
->getValueByName( PropertyNames
[p
], "name" );
289 // Type of the property
291 property
->getValueByName( typeStr
, "type" );
293 if ( typeStr
== "uint8" ) theType
= TypeUint8
;
294 else if ( typeStr
== "sint8" ) theType
= TypeSint8
;
295 else if ( typeStr
== "uint16" ) theType
= TypeUint16
;
296 else if ( typeStr
== "sint16" ) theType
= TypeSint16
;
297 else if ( typeStr
== "uint32" ) theType
= TypeUint32
;
298 else if ( typeStr
== "sint32" ) theType
= TypeSint32
;
299 else if ( typeStr
== "uint64" ) theType
= TypeUint64
;
300 else if ( typeStr
== "sint64" ) theType
= TypeSint64
;
301 else if ( typeStr
== "float" ) theType
= TypeFloat
;
302 else if ( typeStr
== "double" ) theType
= TypeDouble
;
303 else if ( typeStr
== "entityid" ) theType
= TypeCEntityId
;
304 else if ( typeStr
== "boolean" ) theType
= TypeBool
;
307 nlerror( "MIRROR: CDataSetBase::readGeorges: unknown data type '%s'", typeStr
.c_str() ); // not forcing to TypeUint64 anymore
308 theType
= TypeUint64
;
310 PropIndexToType
[p
] = theType
;
314 if ( ! property->getValueByName( weight, "weight" ) )
320 nlwarning( "Weights must be lower than 256" );
323 Weights[p] = (uint8)weight;
326 // List or single value?
328 if ( ! property
->getValueByName( b
, "is a list" ) )
334 MIRROR_INFO( "MIRROR: \tProperty '%s' : Type %s%s"/*", Weight %d"*/, PropertyNames
[p
].c_str(), PropIsList
[p
]?"list of ":"", typeStr
.c_str()/*, Weights[p]*/ );
337 //property->getValueByName(propElt.Persistant, "persistant");
339 //property->getValueByName(propElt.Mirror, "mirror");
345 nlwarning( "MIRROR: CDataSetBase::readGeorges: 'properties' not found" );
348 // Get entity type filter
349 UFormElm
*arrayEntityTypes
;
350 if ( root
.getNodeByName( &arrayEntityTypes
, "entity types" ) && arrayEntityTypes
)
353 nlverify( arrayEntityTypes
->getArraySize(size
) );
354 nlassert( size
< 0x10000 );
355 EntityTypesFilter
.resize( size
);
356 for ( uint et
=0; et
!=size
; ++et
)
359 arrayEntityTypes
->getArrayValue( typeName
, et
);
360 EntityTypesFilter
[et
] = RYZOMID::fromString(typeName
);
361 MIRROR_INFO( "MIRROR: \tLinking to entity type %hu", (uint16
)EntityTypesFilter
[et
] );
366 nlwarning( "MIRROR: CDataSetBase::readGeorges: 'entity types' not found" );
373 * Serial (for fast binary sheet loading)
375 void TDataSetSheet::serial( NLMISC::IStream
& s
)
377 s
.serial( DataSetName
);
378 s
.serial( MaxNbRows
);
379 s
.serial( NbProperties
);
382 PropIndexToType
.resize( NbProperties
);
383 PropertyNames
.resize( NbProperties
);
384 //Weights.resize( NbProperties );
385 PropIsList
.resize( NbProperties
);
387 for ( TPropertyIndex p
=0; p
!=NbProperties
; ++p
)
389 s
.serial( PropertyNames
[p
] );
390 s
.serialEnum( PropIndexToType
[p
] );
391 MIRROR_DEBUG( "MIRROR: Serializing %s, type %u", PropertyNames
[p
].c_str(), PropIndexToType
[p
] );
392 //s.serial( Weights[p] );
393 bool b
= PropIsList
[p
];
397 s
.serialCont( EntityTypesFilter
);
402 * Return the dataset size to use.
403 * If found in the .cfg, use the value of the property DataSetSize + DataSetName.
404 * If not found, use the value in the sheet.
406 TDataSetIndex
TDataSetSheet::getConfigDataSetSize() const
408 string cfgVarName
= "DatasetSize" + DataSetName
;
409 CConfigFile::CVar
*cfgVar
= NLNET::IService::getInstance()->ConfigFile
.getVarPtr( cfgVarName
);
410 TDataSetIndex result
;
413 result
= cfgVar
->asInt();
414 nlinfo( "\t%s: %u (from cfg)", cfgVarName
.c_str(), result
);
419 nlinfo( "\t%s: %u (from packed sheet)", cfgVarName
.c_str(), result
);