Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / ryzom / common / src / game_share / ring_access.cpp
blob5c2f4d6d5ef359264d75ed98a1c572c49e621d4e
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 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 //-----------------------------------------------------------------------------
21 // includes
22 //-----------------------------------------------------------------------------
24 #include "stdpch.h"
26 #include "game_share/ring_access.h"
28 #include "game_share/scenario_entry_points.h"
29 #include "game_share/object.h"
31 #include "nel/misc/file.h"
32 #include "nel/misc/command.h"
33 #include "game_share/utils.h"
34 #include "scenario_entry_points.h"
35 #include "nel/misc/o_xml.h"
36 #include "nel/misc/i_xml.h"
37 #include "nel/misc/algo.h"
38 #include "nel/misc/xml_auto_ptr.h"
41 #ifdef DEBUG_NEW
42 #define new DEBUG_NEW
43 #endif
45 using namespace std;
46 using namespace R2;
47 using namespace NLMISC;
49 static const std::string RingAccessFilename = "r2_ring_access.xml";
51 namespace std
53 // STL port fixup
54 #ifdef NL_COMP_VC8
55 inline void bit_swap(priv::_Bit_reference __x, priv::_Bit_reference __y)
56 #else
57 inline void bit_swap(_Bit_reference __x, _Bit_reference __y)
58 #endif
60 bool __tmp = (bool)__x;
61 __x = __y;
62 __y = __tmp;
68 inline void bit_swap(bool __x, bool __y)
70 bool __tmp = __x;
71 __x = __y;
72 __y = __tmp;
76 std::string CVerfiyRightRtScenarioError::toString() const
79 const char* typeTrad[] = { "None", "InvalidData", "InvalidIslandLevel", "InvalidBotLevel" };
80 TType type = Type;
81 if ( static_cast<uint>(type) > static_cast<uint>(InvalidBotLevel) )
83 type = None;
86 std::string typeStr( typeTrad[static_cast<uint>(Type)]);
88 return NLMISC::toString("Type: '%s' '%s' : Package: '%s' needed: %d, user: %d)", typeStr.c_str(), Name.c_str(), Package.c_str(), Level, CharLevel );
92 CRingAccess::CRingAccess()
94 _Initialised = false;
97 bool CRingAccess::isPlotItemSheetId(const NLMISC::CSheetId& sheetId ) const
99 return _R2PlotItemSheetId.find(sheetId) != _R2PlotItemSheetId.end();
102 void CRingAccess::init()
107 if (_Initialised ) { return; } // no double initialisation
108 _CustomNpcSheetId.clear();
109 //CSheetId::init() must be called first
110 _CustomNpcSheetId.insert(CSheetId("basic_matis_male.creature"));
111 _CustomNpcSheetId.insert(CSheetId("basic_fyros_male.creature"));
112 _CustomNpcSheetId.insert(CSheetId("basic_tryker_male.creature"));
113 _CustomNpcSheetId.insert(CSheetId("basic_zorai_male.creature"));
115 _CustomNpcSheetId.insert(CSheetId("basic_matis_female.creature"));
116 _CustomNpcSheetId.insert(CSheetId("basic_fyros_female.creature"));
117 _CustomNpcSheetId.insert(CSheetId("basic_tryker_female.creature"));
118 _CustomNpcSheetId.insert(CSheetId("basic_zorai_female.creature"));
121 for (uint32 i = 0 ; i <= 184 ; ++i)
123 _R2PlotItemSheetId.insert( CSheetId( NLMISC::toString("r2_plot_item_%d.sitem", i)));
126 _SheetIdToAccess.clear();//only useful when manualy re init file
127 // File stream
128 CIFile file;
131 std::string pathFileName = CPath::lookup(RingAccessFilename, false, false, false);
132 // Open the file
133 if (pathFileName.empty() || !file.open(pathFileName.c_str()))
135 nlinfo("Can't open the file for reading : %s", RingAccessFilename.c_str());
136 return;
141 // Create the XML stream
142 CIXml input;
144 // Init
145 if(input.init(file))
147 xmlNodePtr entitiesAccess = input.getRootNode();
148 xmlNodePtr entityAccess = input.getFirstChildNode(entitiesAccess, "entityAccess");
150 while (entityAccess != 0)
153 // island name
154 CXMLAutoPtr namePtr( (const char*) xmlGetProp(entityAccess, (xmlChar*) "name") );
155 CXMLAutoPtr packagePtr( (const char*) xmlGetProp(entityAccess, (xmlChar*) "package") );
156 CXMLAutoPtr sheetClientPtr( (const char*) xmlGetProp(entityAccess, (xmlChar*) "sheetClient") );
157 CXMLAutoPtr sheetPtr( (const char*) xmlGetProp(entityAccess, (xmlChar*) "sheetServer") );
159 if (!namePtr.getDatas()|| !packagePtr.getDatas() || !sheetClientPtr.getDatas() || !sheetPtr.getDatas())
161 nlerror( "Syntax error in %s", pathFileName.c_str());
162 return;
165 std::string sheet( sheetPtr.getDatas() );
166 std::string package( packagePtr.getDatas() );
167 std::string sheetClient(sheetClientPtr.getDatas());
170 CSheetId sheetClientId(sheetClient);
171 CSheetId sheetId; // no sheet server
173 if (sheet.empty())
175 bool ok = _SheetIdToAccess.insert( std::make_pair(std::make_pair(sheetClientId, sheetId), package)).second;
176 if (!ok)
178 std::string previousPackage = _SheetIdToAccess[std::make_pair(sheetClientId, sheetId)];
179 // only display warning if one key has multiple package
180 if ( previousPackage != package )
182 nlwarning("%s: Entity %s sheet(%s) is defined more than once with different package definition. Previous definition is '%s', current definition is '%s'", RingAccessFilename.c_str(), namePtr.getDatas(), sheetClientPtr.getDatas(), previousPackage.c_str(), package.c_str());
187 else
191 sheetId = CSheetId(sheet);
192 if (_CustomNpcSheetId.find(sheetClientId) != _CustomNpcSheetId.end())
195 bool ok = _SheetIdToAccess.insert( std::make_pair(std::make_pair(sheetClientId, sheetId), package)).second;
196 if (!ok)
198 std::string previousPackage = _SheetIdToAccess[std::make_pair(sheetClientId, sheetId)];
199 // only display warning if one key has multiple package
200 if ( previousPackage != package )
202 nlwarning("%s: Entity %s sheet(%s) is defined more than once. Previous definition is '%s', current definition is '%s'", RingAccessFilename.c_str(), namePtr.getDatas(), sheetPtr.getDatas(), previousPackage.c_str(), package.c_str());
206 else
208 nlwarning("%s: Entity %s has invalid sheets %s %s", RingAccessFilename.c_str(), namePtr.getDatas(), sheetClientPtr.getDatas(), sheetPtr.getDatas());
213 entityAccess = input.getNextChildNode(entityAccess, "entityAccess");
217 // Close the file
218 file.close ();
220 _Initialised = true;
225 bool CRingAccess::isSheetClient(const NLMISC::CSheetId& sheet) const
228 static const std::string racesStr[] = { "matis_", "fyros_", "tryker_", "zorai_"};
229 static const uint32 racesLen[] = { 6, 6, 7 ,6 };
230 static const std::string sexsStr[] = { "male", "female"};
231 static const uint32 sexsLen[] = { 4, 6};
232 static const std::string basic = "basic_";
233 static const uint32 basicLength = 6;
236 std::string sheetStr = sheet.toString();
237 uint32 sheetLength = (uint32)sheetStr.length();
241 if (sheetLength >= basicLength && sheetStr.substr(0, basicLength) == basic)
243 // good thing is a basic_* something
244 for (uint32 i = 0; i < 4 ; ++i)
246 const uint32 raceLength = racesLen[i];
247 if ( sheetLength > basicLength + raceLength && sheetStr.substr(basicLength, raceLength) == racesStr[i])
250 // good thing is a basic_race_
251 for (uint32 j = 0; j < 2 ; ++j)
253 uint32 sexLength = sexsLen[j];
254 if (sheetLength > basicLength + raceLength + sexLength && sheetStr.substr(basicLength + raceLength, sexLength) == sexsStr[j])
256 return true;
263 return false;
266 std::string CRingAccess::getSheetIdAccessInfo(const NLMISC::CSheetId& sheetClientId, const NLMISC::CSheetId& sheetServerId) const
268 const_cast<R2::CRingAccess*>(this)->init(); //lazy initialization;
271 // We can not verify ring access based only on sheet
272 // eg a tryker level 250 whith VPA of a matis must be seen as a matis :(
273 if ( isSheetClient(sheetClientId) )
275 return "a1";
278 TSheetIdToAccess::const_iterator found(_SheetIdToAccess.find(std::make_pair(sheetClientId, sheetServerId)));
279 if (found == _SheetIdToAccess.end()) { return ""; }
280 return found->second;
284 std::string CRingAccess::getSheetAccessInfo(const std::string& sheetClient, const std::string&sheetServer) const
288 const_cast<R2::CRingAccess*>(this)->init(); //lazy initialization;
292 NLMISC::CSheetId sheetClientId(sheetClient);
293 NLMISC::CSheetId sheetServerId;
294 if (!sheetServer.empty()) { sheetServerId = NLMISC::CSheetId(sheetServer); }
298 return getSheetIdAccessInfo(sheetClientId, sheetServerId);
301 std::string CRingAccess::getIslandAccessInfo(const std::string& islandeName) const
303 CScenarioEntryPoints::CCompleteIsland* island = CScenarioEntryPoints::getInstance().getIslandFromId(islandeName);
304 if (!island) { return "";}
305 return island->Package;
308 void CRingAccess::getRingAccessAsMap(const std::string&ringAccess, std::map<std::string, int> & ringAccessAsMap) const
310 std::vector<std::string> vect;
311 NLMISC::splitString(ringAccess,":" , vect);
312 std::vector<std::string>::iterator first(vect.begin()), last(vect.end());
313 for ( ;first != last; ++first)
316 std::string::size_type f = 0;
317 std::string::size_type l = first->size();
318 const std::string &s = *first;
319 for (; f != l && (s[f] < '0' || s[f] > '9') ; ++f) {}
320 if (f != l)
322 std::string package = s.substr(0, f);
323 int level;
324 fromString(s.substr(f, l - f), level);
325 ringAccessAsMap[package] = level;
332 std::string CRingAccess::upgradeRingAccess(const std::string& defaultValue, const std::string& bonusValue) const
335 std::map<std::string, int> defaultMap;
336 std::map<std::string, int> bonusMap;
338 getRingAccessAsMap(defaultValue, defaultMap);
339 getRingAccessAsMap(bonusValue, bonusMap);
340 // get the highest value between default value and bonus Value
342 std::map<std::string, int>::const_iterator first(bonusMap.begin()), last(bonusMap.end());
343 for (; first != last; ++first)
345 std::map<std::string, int>::iterator found = defaultMap.find(first->first);
346 if (found == defaultMap.end())
348 defaultMap.insert( *first);
350 else
352 if (found->second < first->second) { found->second = first->second; }
357 // return the new value as string
358 std::string toRet;
361 std::map<std::string, int>::const_iterator first(defaultMap.begin()), last(defaultMap.end());
362 for (; first != last; ++first)
364 if (!toRet.empty()) { toRet += ":"; }
365 toRet += NLMISC::toString("%s%d", first->first.c_str(), first->second);
369 return toRet;
373 bool CRingAccess::verifyRight(const std::string& askedAccess, const std::string& allowedAccess) const
375 std::map<std::string, int> askedAccessMap;
376 std::map<std::string, int> allowedAccessMap;
377 std::string package; int neededLevel; int charLevel;
379 getRingAccessAsMap(allowedAccess, allowedAccessMap);
380 getRingAccessAsMap(askedAccess, askedAccessMap);
381 return verifyRight(askedAccessMap, allowedAccessMap, package, neededLevel, charLevel);
385 bool CRingAccess::verifyRight(const std::map<std::string, int>& askedAccessMap, const std::map<std::string, int>& allowedAccessMap, std::string& package, int& neededLevel, int& charLevel) const
387 std::map<std::string, int>::const_iterator first(askedAccessMap.begin()), last(askedAccessMap.end());
388 for ( ; first != last; ++first)
390 std::map<std::string, int>::const_iterator found( allowedAccessMap.find(first->first));
391 if (found == allowedAccessMap.end()) { package = first->first; neededLevel = first->second; charLevel = 0; return false; }
392 if ( found->second < first->second ) { package = first->first; neededLevel = first->second; charLevel = found->second; return false; }
394 return true;
400 bool CRingAccess::verifyRtScenario(CObject* rtScenario, const std::string& charRingAccess, CVerfiyRightRtScenarioError* &err) const
402 if (!rtScenario) { err= new CVerfiyRightRtScenarioError(CVerfiyRightRtScenarioError::InvalidData); return false;}
404 std::map<std::string, int> charRingAccessMap;
405 std::map<std::string, int> entityAccessMap;
408 std::string package;
409 int neededLevel;
410 int charLevel;
413 getRingAccessAsMap(charRingAccess, charRingAccessMap);
416 // verify Location
417 CObject* locations = rtScenario->getAttr("Locations");
418 if (!locations || !locations->isTable() )
420 err = new CVerfiyRightRtScenarioError(CVerfiyRightRtScenarioError::InvalidData);
421 return false;
424 uint32 firstLocation = 0;
425 uint32 lastLocation = locations->getSize();
428 for ( ;firstLocation != lastLocation; ++firstLocation)
430 CObject* location = locations->getValueAtPos(firstLocation);
431 if (!location || !location->isString("Island"))
433 err = new CVerfiyRightRtScenarioError(CVerfiyRightRtScenarioError::InvalidData);
434 return false;
436 std::string islandName = location->toString("Island");
437 std::string access = getIslandAccessInfo(islandName);
438 getRingAccessAsMap(access, entityAccessMap);
439 if (!verifyRight(entityAccessMap, charRingAccessMap, package, neededLevel, charLevel))
441 err = new CVerfiyRightRtScenarioError(CVerfiyRightRtScenarioError::InvalidIslandLevel, islandName, package, neededLevel, charLevel);
442 return false;
446 // verify npcs
447 CObject* acts = rtScenario->getAttr("Acts");
448 if (!acts || !acts->isTable()) { return false; }
450 uint32 firstActIndex = 0;
451 uint32 lastActIndex = acts->getSize();
452 for ( ;firstActIndex != lastActIndex; ++firstActIndex)
454 CObject* act = acts->getValueAtPos(firstActIndex);
455 if (!act || !act->isTable() || !act->isTable("Npcs"))
457 err = new CVerfiyRightRtScenarioError(CVerfiyRightRtScenarioError::InvalidData);
458 return false;
461 CObject* npcs = act->getAttr("Npcs");
462 uint32 firstNpcIndex = 0;
463 uint32 lastNpcIndex = npcs->getSize();
464 for (; firstNpcIndex != lastNpcIndex; ++firstNpcIndex)
466 CObject* npc = npcs->getValueAtPos(firstNpcIndex);
467 if (npc && npc->isTable() && npc->isString("SheetClient") && npc->isString("Sheet"))
469 std::string botName;
470 if ( npc->isString("Name"))
472 botName = npc->toString("Name");
474 std::string sheetClient = npc->toString("SheetClient");
475 std::string sheet = npc->toString("Sheet");
476 std::string access = getSheetAccessInfo(sheetClient, sheet);
477 getRingAccessAsMap(access, entityAccessMap);
478 if (!verifyRight(entityAccessMap, charRingAccessMap, package, neededLevel, charLevel))
480 err = new CVerfiyRightRtScenarioError(CVerfiyRightRtScenarioError::InvalidBotLevel, botName, package, neededLevel, charLevel);
481 return false;
488 return true;
492 uint32 CRingAccess::cypherCharId(uint32 id)
494 std::vector<bool> v(32);
495 std::vector<bool> v2(32);
497 static uint32 mask=0x7ce3b52d;
498 id ^= mask;
499 uint32 i;
500 for (i=0; i != 32; ++i)
502 v[i] = (id &( 1 << i)) != 0;
505 v2[ 0] = v[ 5]; v2[ 1] = v[ 8]; v2[ 2] = v[16]; v2[ 3] = v[23];
506 v2[ 4] = v[ 2]; v2[ 5] = v[31]; v2[ 6] = v[27]; v2[ 7] = v[12];
507 v2[ 8] = v[ 6]; v2[ 9] = v[24]; v2[10] = v[30]; v2[11] = v[21];
508 v2[12] = v[17]; v2[13] = v[14]; v2[14] = v[20]; v2[15] = v[18];
510 v2[16] = v[ 4]; v2[17] = v[29]; v2[18] = v[22]; v2[19] = v[10];
511 v2[20] = v[ 0]; v2[21] = v[26]; v2[22] = v[ 9]; v2[23] = v[28];
512 v2[24] = v[15]; v2[25] = v[ 3]; v2[26] = v[11]; v2[27] = v[19];
513 v2[28] = v[ 7]; v2[29] = v[ 1]; v2[30] = v[25]; v2[31] = v[13];
515 uint32 id2=0;
516 for (i=0; i != 32; ++i)
518 id2 |= (v2[i] << i);
520 return id2;
523 uint32 CRingAccess::uncypherCharId(uint32 id)
525 std::vector<bool> v(32);
526 std::vector<bool> v2(32);
527 static uint32 mask=0x7ce3b52d;
529 uint32 i;
530 for (i=0; i != 32; ++i)
532 v2[i] = (id &( 1 << i)) != 0;
535 v[ 5] = v2[ 0]; v[ 8] = v2[ 1]; v[16] = v2[ 2]; v[23] = v2[ 3];
536 v[ 2] = v2[ 4]; v[31] = v2[ 5]; v[27] = v2[ 6]; v[12] = v2[ 7];
537 v[ 6] = v2[ 8]; v[24] = v2[ 9]; v[30] = v2[10]; v[21] = v2[11];
538 v[17] = v2[12]; v[14] = v2[13]; v[20] = v2[14]; v[18] = v2[15];
540 v[ 4] = v2[16]; v[29] = v2[17]; v[22] = v2[18]; v[10] = v2[19];
541 v[ 0] = v2[20]; v[26] = v2[21]; v[ 9] = v2[22]; v[28] = v2[23];
542 v[15] = v2[24]; v[ 3] = v2[25]; v[11] = v2[26]; v[19] = v2[27];
543 v[ 7] = v2[28]; v[ 1] = v2[29]; v[25] = v2[30]; v[13] = v2[31];
545 uint32 id2=0;
546 for (i=0; i != 32; ++i)
548 id2 |= (v[i] << i);
551 id2 ^= mask;
552 return id2;