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) 2014-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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/>.
25 #include "continent_container.h"
29 #include "nel/misc/aabbox.h"
30 #include "nel/misc/path.h"
31 #include "nel/misc/file.h"
32 #include "nel/misc/command.h"
33 #include <nel/misc/algo.h>
35 #include "nel/georges/u_form_loader.h"
36 #include "nel/georges/load_form.h"
38 #include "light_ig_loader.h"
42 using namespace NLMISC
;
43 using namespace NLPACS
;
44 using namespace NLGEORGES
;
48 CContinentContainer::CContinentContainer()
53 void CContinentContainer::init(uint gridWidth
, uint gridHeight
, double primitiveMaxSize
, uint nbWorldImages
, const string
&packedSheetsDirectory
, double cellSize
, bool loadPacsPrims
)
55 _GridWidth
= gridWidth
;
56 _GridHeight
= gridHeight
;
57 _PrimitiveMaxSize
= primitiveMaxSize
;
58 _NbWorldImages
= nbWorldImages
;
60 _LoadPacsPrims
= loadPacsPrims
;
62 buildSheets(packedSheetsDirectory
);
66 void CContinentContainer::buildSheets(const string
&packedSheetsDirectory
)
68 std::vector
<std::string
> filters
;
69 filters
.push_back("continent");
71 // if the 'GeorgePaths' config file var exists then we try to perform a mini-scan for sheet files
72 if (NLNET::IService::isServiceInitialized() && (NLNET::IService::getInstance()->ConfigFile
.getVarPtr(std::string("GeorgePaths"))!=NULL
))
74 loadForm(filters
, packedSheetsDirectory
+"continents.packed_sheets", _SheetMap
, false, false);
77 // if we haven't succeeded in minimal scan (or 'GeorgePaths' wasn't found in config file) then perform standard scan
78 if (_SheetMap
.empty())
80 loadForm(filters
, packedSheetsDirectory
+"continents.packed_sheets", _SheetMap
, true);
85 void CContinentContainer::loadContinent(string name
, string file
, sint index
, bool allowAutoSpawn
)
87 nlinfo("loadContinent(\"%s\", \"%s\", %d)", name
.c_str(), file
.c_str(), index
);
89 // check if the continent is already loaded
91 TContinentContainer::iterator first(_Continents.begin()), last(_Continents.end());
92 for (; first != last; ++first)
94 if (first->Name == name)
96 nlinfo("loadContinent(\"%s\", \"%s\", %d) : continent already loaded, ignoring second load.", name.c_str(), file.c_str(), index);
102 nlassert(index
>= 0);
104 TSheetMap::iterator its
, found
= _SheetMap
.end();
106 for (its
=_SheetMap
.begin(); its
!=_SheetMap
.end(); ++its
)
108 if (NLMISC::toLowerAscii((*its
).second
.Name
) == NLMISC::toLowerAscii(name
+".continent") ||
109 NLMISC::toLowerAscii((*its
).second
.PacsRBank
) == NLMISC::toLowerAscii(name
+".rbank"))
111 if (found
== _SheetMap
.end())
117 nlinfo("Found 2 different possible continent sheets for %s: %s and %s, continent is not loaded twice", name
.c_str(), (*its
).second
.Name
.c_str(), (*found
).second
.Name
.c_str());
122 if (found
!= _SheetMap
.end())
124 name
= (*found
).second
.Name
;
125 file
= CFile::getFilenameWithoutExtension((*found
).second
.PacsRBank
);
129 nlwarning("Couldn't find continent sheet for '%s', use name instead", name
.c_str());
132 for (uint i
=0; i
<_Continents
.size(); ++i
)
134 if (_Continents
[i
].Name
== name
)
136 nlinfo("Continent '%s' already loaded, loading aborted for this new continent.", name
.c_str());
141 if ((sint
)_Continents
.size() <= index
)
142 _Continents
.resize(index
+1);
144 if (_Continents
[index
].RetrieverBank
!= NULL
||
145 _Continents
[index
].GlobalRetriever
!= NULL
||
146 _Continents
[index
].MoveContainer
!= NULL
)
148 nlwarning("Init retriever bank failed, index %d already used by continent '%s'", index
, _Continents
[index
].Name
.c_str());
152 _Continents
[index
].Name
= name
;
153 _Continents
[index
].AllowAutoSpawn
= allowAutoSpawn
;
158 filename
= file
+".rbank";
159 _Continents
[index
].RetrieverBank
= URetrieverBank::createRetrieverBank ( filename
.c_str(), true );
160 if( _Continents
[index
].RetrieverBank
== NULL
)
162 nlwarning("Init retriever bank failed, file load is %s", filename
.c_str() );
167 filename
= file
+".gr";
168 _Continents
[index
].GlobalRetriever
= UGlobalRetriever::createGlobalRetriever ( filename
.c_str(), _Continents
[index
].RetrieverBank
);
169 if( _Continents
[index
].GlobalRetriever
== NULL
)
171 nlwarning("Init global retriever failed, file load is %s", filename
.c_str() );
172 URetrieverBank::deleteRetrieverBank(_Continents
[index
].RetrieverBank
);
173 _Continents
[index
].RetrieverBank
= NULL
;
177 uint gw
= _GridWidth
;
178 uint gh
= _GridHeight
;
180 if (_CellSize
!= 0.0)
182 CAABBox cbox
= _Continents
[index
].GlobalRetriever
->getBBox();
184 gw
= (uint
)(cbox
.getHalfSize().x
*2.0 / _CellSize
) + 1;
185 gh
= (uint
)(cbox
.getHalfSize().y
*2.0 / _CellSize
) + 1;
188 // create the move container
189 /// \todo Ben : correct init for the move container cells count
190 _Continents
[index
].MoveContainer
= UMoveContainer::createMoveContainer ( _Continents
[index
].GlobalRetriever
, gw
, gh
, _PrimitiveMaxSize
, _NbWorldImages
);
192 if( _Continents
[index
].MoveContainer
== NULL
)
194 nlwarning("Init Move container failed, continent %s", name
.c_str());
195 URetrieverBank::deleteRetrieverBank(_Continents
[index
].RetrieverBank
);
196 UGlobalRetriever::deleteGlobalRetriever(_Continents
[index
].GlobalRetriever
);
197 _Continents
[index
].GlobalRetriever
= NULL
;
198 _Continents
[index
].RetrieverBank
= NULL
;
199 _Continents
[index
].MoveContainer
= NULL
;
202 _Continents
[index
].MoveContainer
->setAsStatic(0);
204 nlinfo("Loaded continent, initialized move container to %dx%d cells", gw
, gh
);
206 if (found
!= _SheetMap
.end())
207 loadPacsPrims((*found
).second
, _Continents
[index
].MoveContainer
);
212 void CContinentContainer::removeContinent(sint index
)
214 nlassert(index
>= 0);
216 if (index
>= (sint
)_Continents
.size() ||
217 (_Continents
[index
].RetrieverBank
== NULL
&&
218 _Continents
[index
].GlobalRetriever
== NULL
&&
219 _Continents
[index
].MoveContainer
== NULL
))
221 //nlwarning("Can't remove continent, index %d not used", index);
225 nlinfo("Remove continent %d '%s'... Entities shouldn't point any longer to this continent !", index
, _Continents
[index
].Name
.c_str());
227 _Continents
[index
].Name
.clear();
229 if (_Continents
[index
].MoveContainer
!= NULL
)
230 UMoveContainer::deleteMoveContainer(_Continents
[index
].MoveContainer
);
231 _Continents
[index
].MoveContainer
= NULL
;
233 if (_Continents
[index
].GlobalRetriever
!= NULL
)
234 UGlobalRetriever::deleteGlobalRetriever(_Continents
[index
].GlobalRetriever
);
235 _Continents
[index
].GlobalRetriever
= NULL
;
237 if (_Continents
[index
].RetrieverBank
!= NULL
)
238 URetrieverBank::deleteRetrieverBank(_Continents
[index
].RetrieverBank
);
239 _Continents
[index
].RetrieverBank
= NULL
;
244 void CContinentContainer::initPacsPrim(const string
&path
)
246 vector
<string
> fileNames
;
248 if (CFile::fileExists(CPath::lookup(path
, false, false)))
250 nlinfo("Peeking into '%s' file for pacs_prim files", path
.c_str());
252 if (primFile
.open(CPath::lookup(path
, false, false)))
254 char primbuffer
[1024];
255 while (!primFile
.eof())
257 primFile
.getline(primbuffer
, 1024);
258 fileNames
.push_back(CPath::lookup(primbuffer
, false, false));
263 nlwarning("Couldn't open file '%s' to load pacs_prims", path
.c_str());
266 else if (CFile::isExists(path
))
268 nlinfo("Peeking into '%s' directory for pacs_prim files", path
.c_str());
269 //CPath::getPathContent(path, true, false, true, fileNames);
270 CPath::addSearchPath(path
, true, false);
271 CPath::getFileList("pacs_prim", fileNames
);
275 nlwarning("CContinentContainer: can't initPacsPrim(), path '%s' for pacs primitives not found", path
.c_str());
279 nlinfo("%d file found at lookup", fileNames
.size());
284 for(k
=0; k
<fileNames
.size(); ++k
)
287 if (NLMISC::toLowerAscii(CFile::getExtension(fileNames
[k
])) != "pacs_prim")
289 // not a pacs primitive, skip it..
294 string ppName
= NLMISC::toLowerAscii(CFile::getFilenameWithoutExtension(fileNames
[k
]));
296 if (_PacsPrimMap
.find(ppName
) != _PacsPrimMap
.end())
299 CUniquePtr
<UPrimitiveBlock
> pb(UPrimitiveBlock::createPrimitiveBlockFromFile(CPath::lookup(fileNames
[k
], false)));
300 UPrimitiveBlock
* ptr
= pb
.release();
303 _PacsPrimMap
[ppName
] = ptr
;
308 nlwarning("Couldn't load prim block '%s'", fileNames
[k
].c_str());
311 catch (const NLMISC::EStream
&e
)
313 nlwarning("Couldn't load Pacs Primitive Block file '%s': %s", fileNames
[k
].c_str(), e
.what());
317 nlinfo("%d primitive blocs initialised", numPrims
);
322 void CContinentContainer::loadPacsPrims(const CSheet
&sheet
, NLPACS::UMoveContainer
*moveContainer
)
324 vector
<string
> igs
= sheet
.ListIG
;
326 string igFilename
= CPath::lookup(sheet
.LandscapeIG
, false);
328 if(!igFilename
.empty())
331 if (igFile
.open(igFilename
))
334 while (!igFile
.eof())
336 igFile
.getline(igbuffer
, 1024);
337 if(strlen(igbuffer
) > 0)
338 igs
.push_back(igbuffer
);
343 nlwarning("Couldn't open file '%s' to instantiate landscape pacs_prims", igFilename
.c_str());
348 nlwarning("Couldn't find file '%s' to instantiate landscape pacs_prims", sheet
.LandscapeIG
.c_str());
351 nlinfo("Loading igs for continent %s", sheet
.Name
.c_str());
353 uint numAddedPrimBlocs
= 0;
354 uint numFoundIgs
= 0;
356 for (i
=0; i
<igs
.size(); ++i
)
358 CLightIGLoader igLoader
;
362 igLoader
.loadIG(CFile::getFilenameWithoutExtension(igs
[i
])+".ig");
366 uint numInstances
= igLoader
.getNumInstance();
367 for(uint k
= 0; k
< numInstances
; ++k
)
369 TPacsPrimMap::iterator pbIt
;
371 string shapeName
= NLMISC::toLowerAscii(CFile::getFilenameWithoutExtension(igLoader
.getShapeName(k
)));
372 string instanceName
= NLMISC::toLowerAscii(CFile::getFilenameWithoutExtension(igLoader
.getInstanceName(k
)));
374 bool isTrigger
= false;
377 if ((pbIt
= _PacsPrimMap
.find(shapeName
)) != _PacsPrimMap
.end() ||
378 // nice hardcoded trick that allows graphists to spawn ghost collisions in ZC
379 // when shapename is like 'bat_zc_0?', spaw a pacs prim bloc called gen_bt_col_ext, so nice I just shit my pants
380 (isZC
= (testWildCard(shapeName
.c_str(), "bat_zc_0?") && shapeName
!= "bat_zc_00" && (pbIt
= _PacsPrimMap
.find("gen_bt_col_ext")) != _PacsPrimMap
.end())) || // the magic hack
381 (isTrigger
= ((pbIt
= _PacsPrimMap
.find(instanceName
)) != _PacsPrimMap
.end())))
383 if (_LoadPacsPrims
|| isTrigger
)
385 // compute orientation and position
386 CMatrix instanceMatrix
;
387 igLoader
.getInstanceMatrix(k
, instanceMatrix
);
390 UMoveContainer::getPACSCoordsFromMatrix(pos
, angle
, instanceMatrix
);
391 // insert the matching primitive block
392 vector
<UMovePrimitive
*> insertedPrimitives
;
393 moveContainer
->addCollisionnablePrimitiveBlock(pbIt
->second
, 0, 1, &insertedPrimitives
, angle
, pos
, true);
398 for (i
=0; i
<insertedPrimitives
.size(); ++i
)
400 UMovePrimitive
*prim
= insertedPrimitives
[i
];
401 uint64 id
= prim
->UserData
;
402 uint triggerId
= (uint
)((prim
->UserData
& 0xffff0000) >> 16);
403 _TriggerMap
[triggerId
] = prim
->getFinalPosition(0);
412 catch(const Exception
&e
)
414 nlwarning("Failed to load IG '%s': %s", igs
[i
].c_str(), e
.what());
418 nlinfo("Loaded %d IGs", numFoundIgs
);
419 nlinfo("Added %d primitive blocs", numAddedPrimBlocs
);