Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / ryzom / common / src / game_share / data_set_base.cpp
blobf657315eab33c29eff9cc9070bc3deb4ddf8d9c5
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
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.
8 //
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/>.
19 #include "stdpch.h"
20 #include "data_set_base.h"
21 #include <nel/georges/u_form_elm.h>
23 #include "ryzom_entity_id.h"
25 using namespace std;
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";
37 #else
38 const char *ListRowSizeString = "L16";
39 #endif
43 * Constructor
45 CDataSetBase::CDataSetBase() : _MaxNbRows(INVALID_DATASET_INDEX) //, _SizeOfRow(Row32)
52 * Initialize
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 );
67 _SheetId = sheetId;
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;
73 fillDataSizeByProp();
74 _EntityTypesFilter = properties.EntityTypesFilter;
75 _PropIsList = properties.PropIsList;
76 _PropertyContainer.init( properties.NbProperties );
81 * Fill property info.
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
102 if ( initValues )
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];
111 else
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;
125 else
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()));
133 #else
134 _PropertyContainer.PropertyValueArrays[propIndex].Values = (void*)((uint8*)segmentPt + (sizeof(TGameCycle)*maxNbRows()));
135 #endif
136 _PropertyContainer.PropertyValueArrays[propIndex].DataTypeSize = dataTypeSize;
137 #ifdef NL_DEBUG
138 _PropertyContainer.PropertyValueArrays[propIndex].IsReadOnly = isReadOnly;
139 _PropertyContainer.PropertyValueArrays[propIndex].IsMonitored = mustMonitorAssignment;
140 #endif
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
149 if ( initValues )
151 // Init the headers
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;
167 freeCellsFront = 0;
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;
173 *nextField = j+1;
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!
182 else
184 _PropertyContainer.PropertyValueArrays[propIndex].ListCellContainer = NULL;
186 if ( initValues )
188 endPt = ((uint8*)_PropertyContainer.PropertyValueArrays[propIndex].Values) + maxNbRows()*dataTypeSize;
194 if ( initValues )
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 )
212 switch ( *itp )
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 ) );
244 * Read the sheet
246 void TDataSetSheet::readGeorges( const NLMISC::CSmartPtr<NLGEORGES::UForm> &form, const NLMISC::CSheetId &sheetId )
248 if( (UForm*)form )
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 );
262 else
264 MaxNbRows = 0;
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 )
272 uint size;
273 nlverify( arrayProperties->getArraySize(size) );
274 nlassert( size < 0x10000 );
275 NbProperties = size;
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
290 string typeStr;
291 property->getValueByName( typeStr, "type" );
292 TTypeOfProp theType;
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;
305 else
307 nlerror( "MIRROR: CDataSetBase::readGeorges: unknown data type '%s'", typeStr.c_str() ); // not forcing to TypeUint64 anymore
308 theType = TypeUint64;
310 PropIndexToType[p] = theType;
312 // Weight
313 /*sint32 weight;
314 if ( ! property->getValueByName( weight, "weight" ) )
316 weight = 1;
318 if ( weight > 255 )
320 nlwarning( "Weights must be lower than 256" );
321 weight = 255;
323 Weights[p] = (uint8)weight;
326 // List or single value?
327 bool b;
328 if ( ! property->getValueByName( b, "is a list" ) )
330 b = false;
332 PropIsList[p] = b;
334 MIRROR_INFO( "MIRROR: \tProperty '%s' : Type %s%s"/*", Weight %d"*/, PropertyNames[p].c_str(), PropIsList[p]?"list of ":"", typeStr.c_str()/*, Weights[p]*/ );
336 // persistant
337 //property->getValueByName(propElt.Persistant, "persistant");
338 // mirror
339 //property->getValueByName(propElt.Mirror, "mirror");
343 else
345 nlwarning( "MIRROR: CDataSetBase::readGeorges: 'properties' not found" );
348 // Get entity type filter
349 UFormElm *arrayEntityTypes;
350 if ( root.getNodeByName( &arrayEntityTypes, "entity types" ) && arrayEntityTypes )
352 uint size;
353 nlverify( arrayEntityTypes->getArraySize(size) );
354 nlassert( size < 0x10000 );
355 EntityTypesFilter.resize( size );
356 for ( uint et=0; et!=size; ++et )
358 string typeName;
359 arrayEntityTypes->getArrayValue( typeName, et );
360 EntityTypesFilter[et] = RYZOMID::fromString(typeName);
361 MIRROR_INFO( "MIRROR: \tLinking to entity type %hu", (uint16)EntityTypesFilter[et] );
364 else
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 );
380 if ( s.isReading() )
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];
394 s.serial( b );
395 PropIsList[p] = b;
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;
411 if ( cfgVar )
413 result = cfgVar->asInt();
414 nlinfo( "\t%s: %u (from cfg)", cfgVarName.c_str(), result );
416 else
418 result = MaxNbRows;
419 nlinfo( "\t%s: %u (from packed sheet)", cfgVarName.c_str(), result );
421 return result;