Linux multi-monitor fullscreen support
[ryzomcore.git] / ryzom / client / src / interface_v3 / sbrick_manager.cpp
blob6bf830ecde5466063156faf13b36c7896c1304d5
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
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>
7 //
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/>.
23 #include "stdpch.h"
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"
31 using namespace std;
32 using namespace NLMISC;
33 using namespace NLGEORGES;
36 CSBrickManager* CSBrickManager::_Instance = NULL;
38 // ***************************************************************************
39 void CSBrickManager::releaseInstance()
41 if( _Instance )
43 delete _Instance;
44 _Instance = NULL;
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();
59 _BrickVector.clear();
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)
64 // it's a brick?
65 CSBrickSheet *br = dynamic_cast<CSBrickSheet *>(it->second.EntitySheet); // TODO: Avoid dynamic_cast, depend on getSheetType
66 if (br)
68 // ok, add it
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;
77 // Process Bricks
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;
84 if (!brickSheet)
85 continue;
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
99 sint32 shidc = -1;
100 for (std::vector<CSBrickSheet *>::iterator itb(_BrickVector.begin()), endb(_BrickVector.end()); itb != endb; ++itb)
102 ++shidc;
103 CSBrickSheet *brickSheet = *itb;
104 if (!brickSheet)
105 continue;
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());
112 continue;
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.
123 checkBricks();
125 // make root list
126 makeRoots();
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
144 char buf[100];
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");
169 if(branch)
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();
195 return 0;
198 // ***************************************************************************
199 CCDBNodeLeaf* CSBrickManager::getKnownBrickBitFieldDB(uint family) const
201 if (family < _NbFamily && _FamiliesBits[family])
202 return _FamiliesBits[family];
203 return NULL;
208 // ***************************************************************************
209 void CSBrickManager::makeRoots()
211 _Roots.clear();
213 for (std::vector<CSBrickSheet *>::size_type ib = 0; ib < _BrickVector.size(); ++ib)
215 const CSBrickSheet *brickSheet = _BrickVector[ib];
216 if (!brickSheet)
217 continue;
219 // List only the Roots
220 if (!brickSheet->isRoot())
221 continue;
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)
234 return empty;
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];
244 if (!brickSheet)
245 continue;
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);
264 if(brick)
266 return brick->SabrinaCost;
268 else
270 return 0;
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);
280 if(brick)
282 return brick->SabrinaRelativeCost;
284 else
286 return 0.f;
290 // ***************************************************************************
291 sint32 CSBrickManager::CBrickContainer::getNumParameters(NLMISC::CSheetId id) const
293 CSBrickManager *pBM= CSBrickManager::getInstance();
294 CSBrickSheet *brick= pBM->getBrick(id);
295 if(brick)
297 return (sint32)brick->ParameterFamilies.size();
299 else
301 return 0;
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);
311 if(brick)
313 indexInFamily = brick->IndexInFamily;
314 return brick->BrickFamily;
316 else
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);
327 if(brick)
329 return BRICK_FAMILIES::brickType(brick->BrickFamily);
331 else
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);
342 if(brick)
344 return brick->FaberPlan.ToolType;
346 else
348 return TOOL_TYPE::Unknown;
353 // ***************************************************************************
354 void CSBrickManager::makeVisualBrickForSkill()
356 // clear
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];
366 if (!brickSheet)
367 continue;
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];
385 else
386 return CSheetId();
390 // ***************************************************************************
391 void CSBrickManager::compileBrickProperties()
393 // clear
394 _BrickPropIdMap.clear();
395 uint NumIds= 0;
397 // **** for all bricks, compile props
398 for (std::vector<CSBrickSheet *>::size_type ib = 0; ib < _BrickVector.size(); ++ib)
400 CSBrickSheet *brickSheet = _BrickVector[ib];
401 if (!brickSheet)
402 continue;
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);
413 // get key id.
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);
428 // Get usual PropIds
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
439 string textTemp;
440 textTemp.reserve(1000);
441 for (std::vector<CSBrickSheet *>::size_type ib = 0; ib < _BrickVector.size(); ++ib)
443 CSBrickSheet *brickSheet = _BrickVector[ib];
444 if (!brickSheet)
445 continue;
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];
457 textTemp.erase();
459 // Parse the text
460 uint textSize= (uint)text.size();
461 for(uint j=0;j<textSize;)
463 // Property parsing?
464 if(text[j]=='$')
466 // double $ ??
467 if(j+1<textSize && text[j+1]=='$')
469 textTemp+= '$';
470 j+= 2;
472 // else this is a key desc.
473 else
475 string key;
476 uint k= j+1;
477 bool doAbs= false;
478 uint paramId= 0;
479 // read option formating option
480 for(;;)
482 // Abs Value?
483 if(k<textSize && text[k]=='|')
485 doAbs= true;
486 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]))
491 char tp[2];
492 tp[0]= (char)text[k];
493 tp[1]= 0;
494 fromString(tp, paramId);
495 k++;
497 else
498 break;
500 // find the key end.
501 while(k<textSize && (isalpha((char)text[k]) || text[k]=='_'))
503 key+= (char)text[k];
504 k++;
506 // get the key and replace text with value
507 if (!key.empty())
509 // Parse all the brick properties if match the key
510 float value= 0.f;
511 // get the wanted prop id
512 key = toLowerAscii(key);
513 uint propId= getBrickPropId(key);
514 // if propid exist
515 if(propId)
517 for(uint p=0;p<brickSheet->Properties.size();p++)
519 const CSBrickSheet::CProperty &prop= brickSheet->Properties[p];
520 if(prop.PropId==propId)
522 if(paramId==0)
523 value= brickSheet->Properties[p].Value;
524 else
526 // must parse the initial text/ skip the identifier
527 string::size_type pos= prop.Text.find(':');
528 uint id= 0;
529 while(pos!=string::npos && id<paramId)
531 // skip the ':', and next
532 pos= prop.Text.find(':', pos+1);
533 id++;
535 if(pos!=string::npos)
537 // skip the :, and read the value
538 fromString(prop.Text.substr(pos+1), value);
541 break;
545 // abs value?
546 if(doAbs)
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);
553 else
554 textTemp+= toString("%.3f", value);
556 // skip the keyword
557 j= k;
560 // no, std letter
561 else
563 textTemp+= text[j];
564 j++;
568 // repalce with result
569 text= textTemp;
572 // reset
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())
583 return it->second;
585 return 0;
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
608 bricks= res;
611 // ***************************************************************************
612 void CSBrickManager::appendBrickLearnedCallback(IBrickLearnedCallback *cb)
614 if(cb)
615 _BrickLearnedCallbackSet.insert(cb);
618 // ***************************************************************************
619 void CSBrickManager::removeBrickLearnedCallback(IBrickLearnedCallback *cb)
621 if(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();