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/>.
18 #include "ais_user_models.h"
19 #include "ai_instance.h"
20 #include "ais_actions.h"
21 #include "nel/misc/sstring.h"
22 #include "nel/misc/algo.h"
27 using namespace NLMISC
;
28 using namespace NLNET
;
29 using namespace AITYPES
;
30 using namespace CAISActionEnums
;
33 * This manager is used by the dynamic creature system, allowing leveldesigners to modify a npc's basesheet attributes,
34 * or to define custom loot tables.
35 * First, the primitive is parsed in order to find usermodels and/or custom loot tables (see primitive_parser.cpp,
36 * methods: parsePrimCustomLootTable, parsePrimUserModelList).
37 * The datas are stored in a specific class (CSCriptData for userModels, CCustomLootTableManager for clt). These classes
38 * are defined in game_share so that they can be re-used egs side.
39 * The datas are then sent to EGS, trough 2 AIActions "USR_MDL" for user models and "CUSTOMLT" for custom loot tables
40 * The real objects CDynamicSheet and CLootTables are built egs-side by the egs CDynamicSheetManager.
44 CAIUserModelManager
* CAIUserModelManager::_instance
= 0;
46 /************************************************************************/
48 /************************************************************************/
49 void stripWhitespaces(std::string
& str
)
51 if(str
.empty()) return;
53 string::size_type startIndex
= str
.find_first_not_of(" ");
54 string::size_type endIndex
= str
.find_last_not_of(" ");
55 std::string tmp
= str
;
58 str
= tmp
.substr(startIndex
, (endIndex
-startIndex
+ 1) );
62 std::string
removeComment(const std::string
&str
)
64 string::size_type newPos
= str
.find("//",0);
66 if (newPos
!= string::npos
)
71 return str
.substr(0, newPos
);
77 /************************************************************************/
79 /************************************************************************/
82 * used to send usermodels to EGS
84 DEFINE_ACTION(ContextGlobal
,USR_MDL
)
86 //not true anymore : primAlias also pushed in the vector
87 /*if (args.size() % 3 != 0)
91 std::vector
<CAIActions::CArg
>::const_iterator it
= args
.begin();
96 for (it
= args
.begin(); it
!= args
.end();++it
)
98 if (it
== args
.begin())
100 if (it
->get(primAlias
) == false)
106 modelId
= it
->toString();
107 string
sheetId((++it
)->toString());
108 string
script((++it
)->toString());
110 //will contain all script info and the base sheet id
111 TScriptContent scriptContent
;
112 //first push base sheet Id
113 scriptContent
.push_back(sheetId
);
115 //build a temporary vector. Each element of the vector is a script line
116 std::vector
<string
> tmpVector
;
117 splitString(script
, "\n", tmpVector
);
119 std::vector
<string
>::iterator tmpIt
;
120 for (tmpIt
= tmpVector
.begin(); tmpIt
!= tmpVector
.end(); ++tmpIt
)
122 //remove comment from the line and push back the line only if the line wasn't just a comment
123 std::string noComment
= removeComment(*tmpIt
);
124 stripWhitespaces(noComment
);
126 scriptContent
.push_back(noComment
);
129 //add the usermodel to the manager's map
130 CAIUserModelManager::getInstance()->addToUserModels(primAlias
, modelId
, scriptContent
);
133 CContextStack::setContext(ContextGlobal
);
135 //send msg to EGS if EGS up
136 if (EGSHasMirrorReady
)
138 if (modelId
.size() > 4 && modelId
[0] == 'A' && modelId
[1] == 'R' && modelId
[2] == 'K' && modelId
[3] == '_') // Ark user model (only one)
139 CAIUserModelManager::getInstance()->sendUserModel(primAlias
, modelId
);
141 CAIUserModelManager::getInstance()->sendUserModels();
146 * used to send custom loot tables
148 DEFINE_ACTION(ContextGlobal
,CUSTOMLT
)
150 std::vector
<CAIActions::CArg
>::const_iterator it
= args
.begin();;
153 if (it
->get(tablesNb
) == false)
155 nlwarning("<CAIUserModelManager::CUSTOMLT>Unable to retrieve number of parsed loot tables, abort.");
158 nldebug("<CAIUserModelManager::CUSTOMLT>Number of parsed loot tables: %u", tablesNb
);
163 if (it
->get(primAlias
) == false)
165 nlwarning("<CAIUserModelManager::CUSTOMLT>Unable to retrieve primitive alias, abort.");
169 TCustomLootTable customLootTables
;
171 //for each loot table
172 for (uint i
= 0; i
< tablesNb
; ++i
)
176 //gets number of loot sets in a loot table
178 if (it
->get(lootSetsNb
) == false)
183 //then gets all info relative to the loot table (id, money values)
184 std::string
lootTableId((++it
)->toString());
186 if ((++it
)->get(moneyProba
) == false)
188 nlwarning("<CAIUserModelManager::CUSTOMLT> unable to get moneyDropProbability");
191 if (moneyProba
< 0.0 || moneyProba
> 1.0)
193 nlwarning("<CAIUserModelManager::CUSTOMLT> invalid moneyDropProbability, don't send custom loot tables info to EGS");
198 if ((++it
)->get(moneyFactor
) == false)
200 nlwarning("<CAIUserModelManager::CUSTOMLT> unable to get moneyFactor");
203 if (moneyFactor
< 0.0)
205 nlwarning("<CAIUserModelManager::CUSTOMLT> invalid moneyFactor, don't send custom loot tables info to EGS");
210 if ((++it
)->get(moneyBase
) == false)
212 nlwarning("<CAIUserModelManager::CUSTOMLT> unable to get moneyBase");
217 nlwarning("<CAIUserModelManager::CUSTOMLT> invalid moneyBase, don't send custom loot tables info to EGS");
223 //for each loot set inside the current table
224 for (uint j
= 0; j
< lootSetsNb
; ++j
)
226 std::string
dropProba((++it
)->toString());
227 std::string
script((++it
)->toString());
229 TScriptContent lootSetContent
;
231 std::vector
<string
> tmpVector
;
232 splitString(script
, "\n", tmpVector
);
234 std::vector
<string
>::iterator tmpIt
;
235 for (tmpIt
= tmpVector
.begin(); tmpIt
!= tmpVector
.end(); ++tmpIt
)
237 std::string noComment
= removeComment(*tmpIt
);
238 stripWhitespaces(noComment
);
240 lootSetContent
.push_back(noComment
);
243 NLMISC::fromString(dropProba
, proba
);
244 // FIXME: test on proba value...
245 if (proba
== 0 || proba
> 100)
247 nlwarning("<CUSTOMLT> invalid drop proba value for lootset %i in custom loot table '%s', skip the lootset",
248 j
+ 1, lootTableId
.c_str() );
251 lootSets
.insert(make_pair(CCustomElementId(0, dropProba
), lootSetContent
));
254 if (lootSets
.empty())
256 nlwarning("<CUSTOMLT> Don't add empty lootsets to customloot table, skip loot table '%s'.", lootTableId
.c_str());
260 nldebug("<CAIUserModelManager> Adding table '%s' to manager with primAlias '%u'", lootTableId
.c_str(), primAlias
);
261 CAIUserModelManager::getInstance()->addCustomLootTable(primAlias
, lootTableId
,lootSets
,
262 moneyProba
, moneyFactor
, moneyBase
);
265 CContextStack::setContext(ContextGlobal
);
267 //send msg to EGS if EGS up
268 if (EGSHasMirrorReady
)
270 CAIUserModelManager::getInstance()->sendCustomLootTables();
275 CAIUserModelManager
*CAIUserModelManager::getInstance()
279 _instance
= new CAIUserModelManager();
285 void CAIUserModelManager::destroyInstance()
291 CAIUserModelManager::CAIUserModelManager()
296 CAIUserModelManager::~CAIUserModelManager()
301 void CAIUserModelManager::init()
303 nldebug("<CAIUserModelManager> Manager initialized.");
306 void CAIUserModelManager::addToUserModels(uint32 primAlias
,
307 const std::string
&userModelId
,
308 const TScriptContent
&userModel
)
310 if (userModelId
.size() > 4 && userModelId
[0] == 'A' && userModelId
[1] == 'R' && userModelId
[2] == 'K' && userModelId
[3] == '_') // Ark user model (can be updated)
312 CCustomElementId
id(primAlias
, userModelId
);
313 TScripts::iterator it
= _UserModels
.Scripts
.find(id
);
314 if (it
!= _UserModels
.Scripts
.end())
315 _UserModels
.Scripts
.erase(it
);
318 bool inserted
= _UserModels
.Scripts
.insert(make_pair(CCustomElementId(primAlias
, userModelId
), userModel
)).second
;
321 nlwarning("<AIUserModelManager::addToUserModels> tried to register twice the same user model with id: '%s'", userModelId
.c_str());
324 nldebug("<AIUserModelManager::addToUserModels> Added usermodel '%s' with alias '%u'", userModelId
.c_str(), primAlias
);
327 void CAIUserModelManager::sendUserModel(uint32 primAlias
, const std::string
&userModelId
)
329 NLNET::CMessage
msgout("USER_MODEL");
331 CCustomElementId
id(primAlias
, userModelId
);
332 TScripts::iterator it
= _UserModels
.Scripts
.find(id
);
333 if (it
== _UserModels
.Scripts
.end())
336 CScriptData scriptData
;
337 scriptData
.Scripts
.insert(make_pair(id
, it
->second
));
338 msgout
.serial(const_cast<CScriptData
&>(scriptData
));
340 nlinfo("Sending %u user models to EGS", scriptData
.Scripts
.size());
341 sendMessageViaMirror("EGS", msgout
);
344 void CAIUserModelManager::sendUserModels()
346 NLNET::CMessage
msgout("USER_MODELS");
347 const CScriptData
&scriptData
= CAIUserModelManager::getInstance()->getUserModels();
348 msgout
.serial(const_cast<CScriptData
&>(scriptData
));
350 nldebug("<CAIUserModelManager> Sending %u user models to EGS", scriptData
.Scripts
.size());
351 sendMessageViaMirror("EGS", msgout
);
354 bool CAIUserModelManager::isUserModel(uint32 primAlias
, const std::string
&userModelId
) const
356 CCustomElementId
id(primAlias
, userModelId
);
358 return _UserModels
.Scripts
.find(id
) != _UserModels
.Scripts
.end();
361 bool CAIUserModelManager::isCustomLootTable(uint32 primAlias
, const std::string
&lootTableId
) const
363 CCustomElementId
id(primAlias
, lootTableId
);
365 return _CustomLootTables
.Tables
.find(id
) != _CustomLootTables
.Tables
.end();
369 void CAIUserModelManager::sendCustomLootTables()
371 nldebug("<CAIUserModelManager> Sending custom loot tables to EGS");
372 NLNET::CMessage
msgout("CUSTOM_LOOT_TABLES");
373 CCustomLootTableManager customLootTable
= CAIUserModelManager::getInstance()->getCustomLootTables();
374 msgout
.serial(customLootTable
);
375 sendMessageViaMirror("EGS", msgout
);
378 void CAIUserModelManager::addCustomLootTable(uint32 primAlias
,
379 const std::string
&tableId
,
386 if (CAIUserModelManager::getInstance()->isCustomLootTable(primAlias
, tableId
) == true)
388 nlwarning("<CAIUserModelManager::addCustomLootTable> Table '%s' with primAlias '%u' is already present in manager. Skipping it.", tableId
.c_str(), primAlias
);
391 CScriptData tableContent
;
392 tableContent
.Scripts
= lootSets
;
393 CCustomLootTable customLootTable
;
395 customLootTable
.LootSets
= tableContent
;
396 customLootTable
.MoneyProba
= moneyProba
;
397 customLootTable
.MoneyFactor
= moneyFactor
;
398 customLootTable
.MoneyBase
= moneyBase
;
400 _CustomLootTables
.Tables
.insert(make_pair(CCustomElementId(primAlias
, tableId
), customLootTable
));
404 void CAIUserModelManager::deleteCustomDataByPrimAlias(uint32 primAlias
)
406 CCustomElementId
idLow(primAlias
, "");
407 CCustomElementId
idHigh(primAlias
+ 1, "");
408 TScripts::iterator upperBound
= _UserModels
.Scripts
.upper_bound(idLow
);
409 TScripts::iterator lowerBound
= _UserModels
.Scripts
.lower_bound(idHigh
);
410 if (upperBound
!= _UserModels
.Scripts
.end())
411 _UserModels
.Scripts
.erase(upperBound
, lowerBound
);
413 TCustomLootTable::iterator upperBoundLootTables
= _CustomLootTables
.Tables
.upper_bound(idLow
);
414 TCustomLootTable::iterator lowerBoundLootTables
= _CustomLootTables
.Tables
.lower_bound(idHigh
);
416 if (upperBoundLootTables
!= _CustomLootTables
.Tables
.end())
417 _CustomLootTables
.Tables
.erase(upperBoundLootTables
, lowerBoundLootTables
);
419 if (EGSHasMirrorReady
)
421 nldebug("<CAIUserModelManager::deleteCustomData> Sending alias '%u' to EGS for data deletion", primAlias
);
422 NLNET::CMessage
msgout("DELCUSTOM");
423 msgout
.serial(primAlias
);
425 sendMessageViaMirror("EGS", msgout
);