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>
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 //-----------------------------------------------------------------------------
22 //-----------------------------------------------------------------------------
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"
47 using namespace NLMISC
;
49 static const std::string RingAccessFilename
= "r2_ring_access.xml";
55 inline void bit_swap(priv::_Bit_reference __x, priv::_Bit_reference __y)
57 inline void bit_swap(_Bit_reference __x, _Bit_reference __y)
60 bool __tmp = (bool)__x;
68 inline void bit_swap(bool __x
, bool __y
)
76 std::string
CVerfiyRightRtScenarioError::toString() const
79 const char* typeTrad
[] = { "None", "InvalidData", "InvalidIslandLevel", "InvalidBotLevel" };
81 if ( static_cast<uint
>(type
) > static_cast<uint
>(InvalidBotLevel
) )
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()
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
131 std::string pathFileName
= CPath::lookup(RingAccessFilename
, false, false, false);
133 if (pathFileName
.empty() || !file
.open(pathFileName
.c_str()))
135 nlinfo("Can't open the file for reading : %s", RingAccessFilename
.c_str());
141 // Create the XML stream
147 xmlNodePtr entitiesAccess
= input
.getRootNode();
148 xmlNodePtr entityAccess
= input
.getFirstChildNode(entitiesAccess
, "entityAccess");
150 while (entityAccess
!= 0)
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());
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
175 bool ok
= _SheetIdToAccess
.insert( std::make_pair(std::make_pair(sheetClientId
, sheetId
), package
)).second
;
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());
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
;
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());
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");
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
])
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
) )
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
) {}
322 std::string package
= s
.substr(0, f
);
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
);
352 if (found
->second
< first
->second
) { found
->second
= first
->second
; }
357 // return the new value as string
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
);
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; }
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
;
413 getRingAccessAsMap(charRingAccess
, charRingAccessMap
);
417 CObject
* locations
= rtScenario
->getAttr("Locations");
418 if (!locations
|| !locations
->isTable() )
420 err
= new CVerfiyRightRtScenarioError(CVerfiyRightRtScenarioError::InvalidData
);
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
);
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
);
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
);
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"))
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
);
492 uint32
CRingAccess::cypherCharId(uint32 id
)
494 std::vector
<bool> v(32);
495 std::vector
<bool> v2(32);
497 static uint32 mask
=0x7ce3b52d;
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];
516 for (i
=0; i
!= 32; ++i
)
523 uint32
CRingAccess::uncypherCharId(uint32 id
)
525 std::vector
<bool> v(32);
526 std::vector
<bool> v2(32);
527 static uint32 mask
=0x7ce3b52d;
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];
546 for (i
=0; i
!= 32; ++i
)