1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2014-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "sbrick_manager.h"
25 #include "interface_manager.h"
26 #include "../sheet_manager.h"
27 #include "dbgroup_build_phrase.h"
28 #include "skill_manager.h"
32 using namespace NLMISC
;
33 using namespace NLGEORGES
;
36 CSBrickManager
* CSBrickManager::_Instance
= NULL
;
38 // ***************************************************************************
39 void CSBrickManager::releaseInstance()
48 // ***************************************************************************
49 CSBrickManager::CSBrickManager() : _NbFamily(0), _SabrinaCom(&_BrickContainer
)
51 _BrickFamilyObs
.Owner
= this;
54 // ***************************************************************************
55 void CSBrickManager::init()
57 // Read the Bricks from the SheetMngr.
58 const CSheetManager::TEntitySheetMap
&sheetMap
= SheetMngr
.getSheets();
60 _BrickVector
.reserve(16 * 1024);
61 uint32 shtype
= CSheetId::typeFromFileExtension("sbrick");
62 for (CSheetManager::TEntitySheetMap::const_iterator
it(sheetMap
.begin()), end(sheetMap
.end()); it
!= end
; ++it
)
65 CSBrickSheet
*br
= dynamic_cast<CSBrickSheet
*>(it
->second
.EntitySheet
); // TODO: Avoid dynamic_cast, depend on getSheetType
69 uint32 shid
= it
->first
.getShortId();
70 nlassert(shtype
== it
->first
.getSheetType());
71 if (shid
>= _BrickVector
.size())
72 _BrickVector
.resize(shid
+ 1);
73 _BrickVector
[shid
] = br
;
78 if (_BrickVector
.empty()) return;
80 // Build the vector of family bit fields, and the vector of existing bricks
81 for (std::vector
<CSBrickSheet
*>::iterator
itb(_BrickVector
.begin()), endb(_BrickVector
.end()); itb
!= endb
; ++itb
)
83 CSBrickSheet
*brickSheet
= *itb
;
87 // Resize our vectors if necessary
88 if (brickSheet
->BrickFamily
>= (sint32
)_NbFamily
)
90 _SheetsByFamilies
.resize(brickSheet
->BrickFamily
+ 1);
91 _FamiliesBits
.resize(brickSheet
->BrickFamily
+ 1, 0);
92 _NbBricksPerFamily
.resize(brickSheet
->BrickFamily
+ 1, 0);
94 _NbFamily
= brickSheet
->BrickFamily
+ 1;
98 // Since _SheetsByFamilies is a vector of vector, avoid long reallocation by building it in 2 pass
100 for (std::vector
<CSBrickSheet
*>::iterator
itb(_BrickVector
.begin()), endb(_BrickVector
.end()); itb
!= endb
; ++itb
)
103 CSBrickSheet
*brickSheet
= *itb
;
107 // Resize our vectors if necessary
108 // The index in familly must be decremented because the values start at 1 in the sheets
109 if (brickSheet
->IndexInFamily
< 1)
111 nlwarning("CSBrickManager::CSBrickManager(): Reading file: %s: IndexInFamily==0 but should be >=1 - entry ignored", brickSheet
->Id
.toString().c_str());
114 if (_NbBricksPerFamily
[brickSheet
->BrickFamily
] < (uint
)(brickSheet
->IndexInFamily
))
116 _SheetsByFamilies
[brickSheet
->BrickFamily
].resize(brickSheet
->IndexInFamily
);
117 _NbBricksPerFamily
[brickSheet
->BrickFamily
] = brickSheet
->IndexInFamily
;
119 _SheetsByFamilies
[brickSheet
->BrickFamily
][brickSheet
->IndexInFamily
- 1] = brickSheet
->Id
;
122 // check brick content for client.
128 // Make interface bricks
129 makeVisualBrickForSkill();
131 // compile brick properties
132 compileBrickProperties();
134 // see getInterfaceRemoveBrick
135 _InterfaceRemoveBrick
.buildSheetId("big_remove.sbrick");
138 // ***************************************************************************
139 void CSBrickManager::initInGame()
141 CInterfaceManager
* pIM
= CInterfaceManager::getInstance();
143 // shortcut to the node
145 for(uint i
=0;i
<_FamiliesBits
.size();i
++)
147 //get the known brick entries in the database
148 sprintf(buf
,"SERVER:BRICK_FAMILY:%d:BRICKS",i
);
149 _FamiliesBits
[i
] = NLGUI::CDBManager::getInstance()->getDbProp(buf
);
152 // Add a branch observer on brick family
153 NLGUI::CDBManager::getInstance()->addBranchObserver( "SERVER:BRICK_FAMILY", &_BrickFamilyObs
);
156 // ***************************************************************************
157 void CSBrickManager::uninitInGame()
159 CInterfaceManager
* pIM
= CInterfaceManager::getInstance();
161 // remove shortcuts to the node
162 for(uint i
=0;i
<_FamiliesBits
.size();i
++)
164 _FamiliesBits
[i
] = NULL
;
167 // remove branch observer on brick family
168 CCDBNodeBranch
*branch
= NLGUI::CDBManager::getInstance()->getDbBranch("SERVER:BRICK_FAMILY");
170 branch
->removeBranchObserver(&_BrickFamilyObs
);
173 // ***************************************************************************
174 CSBrickManager::~CSBrickManager()
179 // ***************************************************************************
180 CSheetId
CSBrickManager::getBrickSheet(uint family
, uint index
) const
182 if (family
>= _NbFamily
)
183 return NLMISC::CSheetId(0);
184 if ( index
>= _NbBricksPerFamily
[family
] )
185 return NLMISC::CSheetId(0);
186 return _SheetsByFamilies
[family
][index
];
190 // ***************************************************************************
191 sint64
CSBrickManager::getKnownBrickBitField(uint family
) const
193 if (family
< _NbFamily
&& _FamiliesBits
[family
])
194 return _FamiliesBits
[family
]->getValue64();
198 // ***************************************************************************
199 CCDBNodeLeaf
* CSBrickManager::getKnownBrickBitFieldDB(uint family
) const
201 if (family
< _NbFamily
&& _FamiliesBits
[family
])
202 return _FamiliesBits
[family
];
208 // ***************************************************************************
209 void CSBrickManager::makeRoots()
213 for (std::vector
<CSBrickSheet
*>::size_type ib
= 0; ib
< _BrickVector
.size(); ++ib
)
215 const CSBrickSheet
*brickSheet
= _BrickVector
[ib
];
219 // List only the Roots
220 if (!brickSheet
->isRoot())
223 _Roots
.push_back(brickSheet
->Id
);
228 // ***************************************************************************
229 const std::vector
<NLMISC::CSheetId
> &CSBrickManager::getFamilyBricks(uint family
) const
231 static std::vector
<NLMISC::CSheetId
> empty
;
233 if (family
>= _NbFamily
)
235 return _SheetsByFamilies
[family
];
238 // ***************************************************************************
239 void CSBrickManager::checkBricks()
241 for (std::vector
<CSBrickSheet
*>::size_type ib
= 0; ib
< _BrickVector
.size(); ++ib
)
243 CSBrickSheet
*brickSheet
= _BrickVector
[ib
];
247 if (brickSheet
->ParameterFamilies
.size() > CDBGroupBuildPhrase::MaxParam
)
249 nlwarning("The Sheet %s has too many parameters for Client Composition: %d/%d",
250 brickSheet
->Id
.toString().c_str(), brickSheet
->ParameterFamilies
.size(), CDBGroupBuildPhrase::MaxParam
);
252 // reset them... don't crahs client, but won't work.
253 brickSheet
->ParameterFamilies
.clear();
258 // ***************************************************************************
259 sint32
CSBrickManager::CBrickContainer::getSabrinaCost(NLMISC::CSheetId id
) const
261 // get the true container
262 CSBrickManager
*pBM
= CSBrickManager::getInstance();
263 CSBrickSheet
*brick
= pBM
->getBrick(id
);
266 return brick
->SabrinaCost
;
274 // ***************************************************************************
275 float CSBrickManager::CBrickContainer::getSabrinaRelativeCost(NLMISC::CSheetId id
) const
277 // get the true container
278 CSBrickManager
*pBM
= CSBrickManager::getInstance();
279 CSBrickSheet
*brick
= pBM
->getBrick(id
);
282 return brick
->SabrinaRelativeCost
;
290 // ***************************************************************************
291 sint32
CSBrickManager::CBrickContainer::getNumParameters(NLMISC::CSheetId id
) const
293 CSBrickManager
*pBM
= CSBrickManager::getInstance();
294 CSBrickSheet
*brick
= pBM
->getBrick(id
);
297 return (sint32
)brick
->ParameterFamilies
.size();
306 // ***************************************************************************
307 BRICK_FAMILIES::TBrickFamily
CSBrickManager::CBrickContainer::getBrickFamily(NLMISC::CSheetId id
, uint
& indexInFamily
) const
309 CSBrickManager
*pBM
= CSBrickManager::getInstance();
310 CSBrickSheet
*brick
= pBM
->getBrick(id
);
313 indexInFamily
= brick
->IndexInFamily
;
314 return brick
->BrickFamily
;
318 return BRICK_FAMILIES::Unknown
;
322 // ***************************************************************************
323 BRICK_TYPE::EBrickType
CSBrickManager::CBrickContainer::getBrickType(NLMISC::CSheetId id
) const
325 CSBrickManager
*pBM
= CSBrickManager::getInstance();
326 CSBrickSheet
*brick
= pBM
->getBrick(id
);
329 return BRICK_FAMILIES::brickType(brick
->BrickFamily
);
333 return BRICK_TYPE::UNKNOWN
;
337 // ***************************************************************************
338 TOOL_TYPE::TCraftingToolType
CSBrickManager::CBrickContainer::getFaberPlanToolType(NLMISC::CSheetId id
) const
340 CSBrickManager
*pBM
= CSBrickManager::getInstance();
341 CSBrickSheet
*brick
= pBM
->getBrick(id
);
344 return brick
->FaberPlan
.ToolType
;
348 return TOOL_TYPE::Unknown
;
353 // ***************************************************************************
354 void CSBrickManager::makeVisualBrickForSkill()
357 for (uint i
= 0; i
< SKILLS::NUM_SKILLS
; ++i
)
359 _VisualBrickForSkill
[i
] = CSheetId();
362 // fill with interface bricks
363 for (std::vector
<CSBrickSheet
*>::size_type ib
= 0; ib
< _BrickVector
.size(); ++ib
)
365 const CSBrickSheet
*brickSheet
= _BrickVector
[ib
];
369 // List only bricks with family == BIF
370 if (brickSheet
->BrickFamily
== BRICK_FAMILIES::BIF
)
372 if (brickSheet
->getSkill() < SKILLS::NUM_SKILLS
)
374 _VisualBrickForSkill
[brickSheet
->getSkill()] = brickSheet
->Id
;
380 // ***************************************************************************
381 CSheetId
CSBrickManager::getVisualBrickForSkill(SKILLS::ESkills s
)
383 if(s
<SKILLS::NUM_SKILLS
)
384 return _VisualBrickForSkill
[s
];
390 // ***************************************************************************
391 void CSBrickManager::compileBrickProperties()
394 _BrickPropIdMap
.clear();
397 // **** for all bricks, compile props
398 for (std::vector
<CSBrickSheet
*>::size_type ib
= 0; ib
< _BrickVector
.size(); ++ib
)
400 CSBrickSheet
*brickSheet
= _BrickVector
[ib
];
404 // For all properties of this brick, compile
405 for (uint i
= 0; i
< brickSheet
->Properties
.size(); ++i
)
407 CSBrickSheet::CProperty
&prop
= brickSheet
->Properties
[i
];
408 string::size_type pos
= prop
.Text
.find(':');
409 if (pos
!= string::npos
)
411 string key
= toLowerAscii(prop
.Text
.substr(0, pos
));
412 string value
= prop
.Text
.substr(pos
+ 1);
414 if (_BrickPropIdMap
.find(key
) == _BrickPropIdMap
.end())
416 // Inc before to leave 0 as "undefined"
417 _BrickPropIdMap
[key
] = ++NumIds
;
419 prop
.PropId
= _BrickPropIdMap
[key
];
420 fromString(value
, prop
.Value
);
421 pos
= value
.find(':');
422 if (pos
!= string::npos
)
423 fromString(value
.substr(pos
+ 1), prop
.Value2
);
429 HpPropId
= getBrickPropId("hp");
430 SapPropId
= getBrickPropId("sap");
431 StaPropId
= getBrickPropId("sta");
432 StaWeightFactorId
= getBrickPropId("sta_weight_factor");
433 FocusPropId
= getBrickPropId("focus");
434 CastTimePropId
= getBrickPropId("ma_casting_time");
435 RangePropId
= getBrickPropId("ma_range");
438 // **** for all bricks, recompute localized text with formated version
440 textTemp
.reserve(1000);
441 for (std::vector
<CSBrickSheet
*>::size_type ib
= 0; ib
< _BrickVector
.size(); ++ib
)
443 CSBrickSheet
*brickSheet
= _BrickVector
[ib
];
447 // Get the Brick texts
448 std::string texts
[3];
449 texts
[0]= STRING_MANAGER::CStringManagerClient::getSBrickLocalizedName(brickSheet
->Id
);
450 texts
[1]= STRING_MANAGER::CStringManagerClient::getSBrickLocalizedDescription(brickSheet
->Id
);
451 texts
[2]= STRING_MANAGER::CStringManagerClient::getSBrickLocalizedCompositionDescription(brickSheet
->Id
);
453 // For alls texts, parse format
454 for(uint i
=0;i
<3;i
++)
456 string
&text
= texts
[i
];
460 uint textSize
= (uint
)text
.size();
461 for(uint j
=0;j
<textSize
;)
467 if(j
+1<textSize
&& text
[j
+1]=='$')
472 // else this is a key desc.
479 // read option formating option
483 if(k
<textSize
&& text
[k
]=='|')
488 // Param Id modifier? (ie read not the 0th value, but the 1th etc... up to 9)
489 else if(k
<textSize
&& (uint8
)text
[k
] < (uint8
)'\x80' && isdigit(text
[k
]))
492 tp
[0]= (char)text
[k
];
494 fromString(tp
, paramId
);
501 while(k
<textSize
&& (isalpha((char)text
[k
]) || text
[k
]=='_'))
506 // get the key and replace text with value
509 // Parse all the brick properties if match the key
511 // get the wanted prop id
512 key
= toLowerAscii(key
);
513 uint propId
= getBrickPropId(key
);
517 for(uint p
=0;p
<brickSheet
->Properties
.size();p
++)
519 const CSBrickSheet::CProperty
&prop
= brickSheet
->Properties
[p
];
520 if(prop
.PropId
==propId
)
523 value
= brickSheet
->Properties
[p
].Value
;
526 // must parse the initial text/ skip the identifier
527 string::size_type pos
= prop
.Text
.find(':');
529 while(pos
!=string::npos
&& id
<paramId
)
531 // skip the ':', and next
532 pos
= prop
.Text
.find(':', pos
+1);
535 if(pos
!=string::npos
)
537 // skip the :, and read the value
538 fromString(prop
.Text
.substr(pos
+1), value
);
547 value
= (float)fabs(value
);
549 // append to text wisely
550 sint32 floorVal
= (sint32
)floorf(value
);
551 if( floorVal
==value
)
552 textTemp
+= toString("%d", floorVal
);
554 textTemp
+= toString("%.3f", value
);
568 // repalce with result
573 STRING_MANAGER::CStringManagerClient::replaceSBrickName(brickSheet
->Id
, texts
[0], texts
[1], texts
[2]);
577 // ***************************************************************************
578 uint
CSBrickManager::getBrickPropId(const std::string
&name
)
580 std::map
<std::string
, uint
>::const_iterator it
;
581 it
= _BrickPropIdMap
.find(name
);
582 if(it
!=_BrickPropIdMap
.end())
588 // ***************************************************************************
589 NLMISC::CSheetId
CSBrickManager::getInterfaceRemoveBrick()
591 return _InterfaceRemoveBrick
;
594 // ***************************************************************************
595 void CSBrickManager::filterKnownBricks(std::vector
<CSheetId
> &bricks
)
597 std::vector
<CSheetId
> res
;
598 res
.reserve(bricks
.size());
600 // keep only known ones
601 for(uint i
=0;i
<bricks
.size();i
++)
603 if(isBrickKnown(bricks
[i
]))
604 res
.push_back(bricks
[i
]);
607 // replace with filtered one
611 // ***************************************************************************
612 void CSBrickManager::appendBrickLearnedCallback(IBrickLearnedCallback
*cb
)
615 _BrickLearnedCallbackSet
.insert(cb
);
618 // ***************************************************************************
619 void CSBrickManager::removeBrickLearnedCallback(IBrickLearnedCallback
*cb
)
622 _BrickLearnedCallbackSet
.erase(cb
);
625 // ***************************************************************************
626 void CSBrickManager::CBrickFamilyObs::update(ICDBNode
* /* node */)
628 CSBrickManager::TBLCBSet::iterator it
;
629 for(it
=Owner
->_BrickLearnedCallbackSet
.begin();it
!=Owner
->_BrickLearnedCallbackSet
.end();it
++)
631 (*it
)->onBrickLearned();