ab44d7e809
--HG-- branch : develop
419 lines
12 KiB
C++
419 lines
12 KiB
C++
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
|
// Copyright (C) 2010 Winch Gate Property Limited
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
#include "stdpch.h"
|
|
#include <memory>
|
|
|
|
#include "continent_container.h"
|
|
|
|
#include <memory>
|
|
|
|
#include "nel/misc/aabbox.h"
|
|
#include "nel/misc/path.h"
|
|
#include "nel/misc/file.h"
|
|
#include "nel/misc/command.h"
|
|
#include <nel/misc/algo.h>
|
|
|
|
#include "nel/georges/u_form_loader.h"
|
|
#include "nel/georges/load_form.h"
|
|
|
|
#include "light_ig_loader.h"
|
|
|
|
|
|
using namespace std;
|
|
using namespace NLMISC;
|
|
using namespace NLPACS;
|
|
using namespace NLGEORGES;
|
|
|
|
|
|
// Constructor
|
|
CContinentContainer::CContinentContainer()
|
|
{
|
|
}
|
|
|
|
//
|
|
void CContinentContainer::init(uint gridWidth, uint gridHeight, double primitiveMaxSize, uint nbWorldImages, const string &packedSheetsDirectory, double cellSize, bool loadPacsPrims)
|
|
{
|
|
_GridWidth = gridWidth;
|
|
_GridHeight = gridHeight;
|
|
_PrimitiveMaxSize = primitiveMaxSize;
|
|
_NbWorldImages = nbWorldImages;
|
|
_CellSize = cellSize;
|
|
_LoadPacsPrims = loadPacsPrims;
|
|
|
|
buildSheets(packedSheetsDirectory);
|
|
}
|
|
|
|
//
|
|
void CContinentContainer::buildSheets(const string &packedSheetsDirectory)
|
|
{
|
|
std::vector<std::string> filters;
|
|
filters.push_back("continent");
|
|
|
|
// if the 'GeorgePaths' config file var exists then we try to perform a mini-scan for sheet files
|
|
if (NLNET::IService::isServiceInitialized() && (NLNET::IService::getInstance()->ConfigFile.getVarPtr(std::string("GeorgePaths"))!=NULL))
|
|
{
|
|
loadForm(filters, packedSheetsDirectory+"continents.packed_sheets", _SheetMap, false, false);
|
|
}
|
|
|
|
// if we haven't succeeded in minimal scan (or 'GeorgePaths' wasn't found in config file) then perform standard scan
|
|
if (_SheetMap.empty())
|
|
{
|
|
loadForm(filters, packedSheetsDirectory+"continents.packed_sheets", _SheetMap, true);
|
|
}
|
|
}
|
|
|
|
//
|
|
void CContinentContainer::loadContinent(string name, string file, sint index, bool allowAutoSpawn)
|
|
{
|
|
nlinfo("loadContinent(\"%s\", \"%s\", %d)", name.c_str(), file.c_str(), index);
|
|
|
|
// check if the continent is already loaded
|
|
/* {
|
|
TContinentContainer::iterator first(_Continents.begin()), last(_Continents.end());
|
|
for (; first != last; ++first)
|
|
{
|
|
if (first->Name == name)
|
|
{
|
|
nlinfo("loadContinent(\"%s\", \"%s\", %d) : continent already loaded, ignoring second load.", name.c_str(), file.c_str(), index);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
nlassert(index >= 0);
|
|
|
|
TSheetMap::iterator its, found = _SheetMap.end();
|
|
|
|
for (its=_SheetMap.begin(); its!=_SheetMap.end(); ++its)
|
|
{
|
|
if (NLMISC::toLower((*its).second.Name) == NLMISC::toLower(name+".continent") ||
|
|
NLMISC::toLower((*its).second.PacsRBank) == NLMISC::toLower(name+".rbank"))
|
|
{
|
|
if (found == _SheetMap.end())
|
|
{
|
|
found = its;
|
|
}
|
|
else
|
|
{
|
|
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());
|
|
}
|
|
}
|
|
}
|
|
|
|
if (found != _SheetMap.end())
|
|
{
|
|
name = (*found).second.Name;
|
|
file = CFile::getFilenameWithoutExtension((*found).second.PacsRBank);
|
|
}
|
|
else
|
|
{
|
|
nlwarning("Couldn't find continent sheet for '%s', use name instead", name.c_str());
|
|
}
|
|
|
|
for (uint i=0; i<_Continents.size(); ++i)
|
|
{
|
|
if (_Continents[i].Name == name)
|
|
{
|
|
nlinfo("Continent '%s' already loaded, loading aborted for this new continent.", name.c_str());
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ((sint)_Continents.size() <= index)
|
|
_Continents.resize(index+1);
|
|
|
|
if (_Continents[index].RetrieverBank != NULL ||
|
|
_Continents[index].GlobalRetriever != NULL ||
|
|
_Continents[index].MoveContainer != NULL)
|
|
{
|
|
nlwarning("Init retriever bank failed, index %d already used by continent '%s'", index, _Continents[index].Name.c_str());
|
|
return;
|
|
}
|
|
|
|
_Continents[index].Name = name;
|
|
_Continents[index].AllowAutoSpawn = allowAutoSpawn;
|
|
|
|
string filename;
|
|
|
|
// load the rbank
|
|
filename = file+".rbank";
|
|
_Continents[index].RetrieverBank = URetrieverBank::createRetrieverBank ( filename.c_str(), true );
|
|
if( _Continents[index].RetrieverBank == NULL )
|
|
{
|
|
nlwarning("Init retriever bank failed, file load is %s", filename.c_str() );
|
|
return;
|
|
}
|
|
|
|
// load the gr
|
|
filename = file+".gr";
|
|
_Continents[index].GlobalRetriever = UGlobalRetriever::createGlobalRetriever ( filename.c_str(), _Continents[index].RetrieverBank );
|
|
if( _Continents[index].GlobalRetriever == NULL )
|
|
{
|
|
nlwarning("Init global retriever failed, file load is %s", filename.c_str() );
|
|
URetrieverBank::deleteRetrieverBank(_Continents[index].RetrieverBank);
|
|
_Continents[index].RetrieverBank = NULL;
|
|
return;
|
|
}
|
|
|
|
uint gw = _GridWidth;
|
|
uint gh = _GridHeight;
|
|
|
|
if (_CellSize != 0.0)
|
|
{
|
|
CAABBox cbox = _Continents[index].GlobalRetriever->getBBox();
|
|
|
|
gw = (uint)(cbox.getHalfSize().x*2.0 / _CellSize) + 1;
|
|
gh = (uint)(cbox.getHalfSize().y*2.0 / _CellSize) + 1;
|
|
}
|
|
|
|
// create the move container
|
|
/// \todo Ben : correct init for the move container cells count
|
|
_Continents[index].MoveContainer = UMoveContainer::createMoveContainer ( _Continents[index].GlobalRetriever, gw, gh, _PrimitiveMaxSize, _NbWorldImages);
|
|
|
|
if( _Continents[index].MoveContainer == NULL )
|
|
{
|
|
nlwarning("Init Move container failed, continent %s", name.c_str());
|
|
URetrieverBank::deleteRetrieverBank(_Continents[index].RetrieverBank);
|
|
UGlobalRetriever::deleteGlobalRetriever(_Continents[index].GlobalRetriever);
|
|
_Continents[index].GlobalRetriever = NULL;
|
|
_Continents[index].RetrieverBank = NULL;
|
|
_Continents[index].MoveContainer = NULL;
|
|
}
|
|
|
|
_Continents[index].MoveContainer->setAsStatic(0);
|
|
|
|
nlinfo("Loaded continent, initialized move container to %dx%d cells", gw, gh);
|
|
|
|
if (found != _SheetMap.end())
|
|
loadPacsPrims((*found).second, _Continents[index].MoveContainer);
|
|
}
|
|
|
|
|
|
//
|
|
void CContinentContainer::removeContinent(sint index)
|
|
{
|
|
nlassert(index >= 0);
|
|
|
|
if (index >= (sint)_Continents.size() ||
|
|
(_Continents[index].RetrieverBank == NULL &&
|
|
_Continents[index].GlobalRetriever == NULL &&
|
|
_Continents[index].MoveContainer == NULL))
|
|
{
|
|
//nlwarning("Can't remove continent, index %d not used", index);
|
|
return;
|
|
}
|
|
|
|
nlinfo("Remove continent %d '%s'... Entities shouldn't point any longer to this continent !", index, _Continents[index].Name.c_str());
|
|
|
|
_Continents[index].Name.clear();
|
|
|
|
if (_Continents[index].MoveContainer != NULL)
|
|
UMoveContainer::deleteMoveContainer(_Continents[index].MoveContainer);
|
|
_Continents[index].MoveContainer = NULL;
|
|
|
|
if (_Continents[index].GlobalRetriever != NULL)
|
|
UGlobalRetriever::deleteGlobalRetriever(_Continents[index].GlobalRetriever);
|
|
_Continents[index].GlobalRetriever = NULL;
|
|
|
|
if (_Continents[index].RetrieverBank != NULL)
|
|
URetrieverBank::deleteRetrieverBank(_Continents[index].RetrieverBank);
|
|
_Continents[index].RetrieverBank = NULL;
|
|
}
|
|
|
|
|
|
//
|
|
void CContinentContainer::initPacsPrim(const string &path)
|
|
{
|
|
vector<string> fileNames;
|
|
|
|
if (CFile::fileExists(CPath::lookup(path, false, false)))
|
|
{
|
|
nlinfo("Peeking into '%s' file for pacs_prim files", path.c_str());
|
|
CIFile primFile;
|
|
if (primFile.open(CPath::lookup(path, false, false)))
|
|
{
|
|
char primbuffer[1024];
|
|
while (!primFile.eof())
|
|
{
|
|
primFile.getline(primbuffer, 1024);
|
|
fileNames.push_back(CPath::lookup(primbuffer, false, false));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nlwarning("Couldn't open file '%s' to load pacs_prims", path.c_str());
|
|
}
|
|
}
|
|
else if (CFile::isExists(path))
|
|
{
|
|
nlinfo("Peeking into '%s' directory for pacs_prim files", path.c_str());
|
|
//CPath::getPathContent(path, true, false, true, fileNames);
|
|
CPath::addSearchPath(path, true, false);
|
|
CPath::getFileList("pacs_prim", fileNames);
|
|
}
|
|
else
|
|
{
|
|
nlwarning("CContinentContainer: can't initPacsPrim(), path '%s' for pacs primitives not found", path.c_str());
|
|
return;
|
|
}
|
|
|
|
nlinfo("%d file found at lookup", fileNames.size());
|
|
|
|
//
|
|
uint k;
|
|
uint numPrims = 0;
|
|
for(k=0; k<fileNames.size(); ++k)
|
|
{
|
|
// check extension
|
|
if (NLMISC::toLower(CFile::getExtension(fileNames[k])) != "pacs_prim")
|
|
{
|
|
// not a pacs primitive, skip it..
|
|
continue;
|
|
}
|
|
try
|
|
{
|
|
string ppName = NLMISC::toLower(CFile::getFilenameWithoutExtension(fileNames[k]));
|
|
|
|
if (_PacsPrimMap.find(ppName) != _PacsPrimMap.end())
|
|
continue;
|
|
|
|
CUniquePtr<UPrimitiveBlock> pb(UPrimitiveBlock::createPrimitiveBlockFromFile(CPath::lookup(fileNames[k], false)));
|
|
UPrimitiveBlock* ptr = pb.release();
|
|
if (ptr != NULL)
|
|
{
|
|
_PacsPrimMap[ppName] = ptr;
|
|
++numPrims;
|
|
}
|
|
else
|
|
{
|
|
nlwarning("Couldn't load prim block '%s'", fileNames[k].c_str());
|
|
}
|
|
}
|
|
catch (const NLMISC::EStream &e)
|
|
{
|
|
nlwarning("Couldn't load Pacs Primitive Block file '%s': %s", fileNames[k].c_str(), e.what());
|
|
}
|
|
}
|
|
|
|
nlinfo("%d primitive blocs initialised", numPrims);
|
|
}
|
|
|
|
|
|
//
|
|
void CContinentContainer::loadPacsPrims(const CSheet &sheet, NLPACS::UMoveContainer *moveContainer)
|
|
{
|
|
vector<string> igs = sheet.ListIG;
|
|
|
|
string igFilename = CPath::lookup(sheet.LandscapeIG, false);
|
|
|
|
if(!igFilename.empty())
|
|
{
|
|
CIFile igFile;
|
|
if (igFile.open(igFilename))
|
|
{
|
|
char igbuffer[1024];
|
|
while (!igFile.eof())
|
|
{
|
|
igFile.getline(igbuffer, 1024);
|
|
if(strlen(igbuffer) > 0)
|
|
igs.push_back(igbuffer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nlwarning("Couldn't open file '%s' to instantiate landscape pacs_prims", igFilename.c_str());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nlwarning("Couldn't find file '%s' to instantiate landscape pacs_prims", sheet.LandscapeIG.c_str());
|
|
}
|
|
|
|
nlinfo("Loading igs for continent %s", sheet.Name.c_str());
|
|
|
|
uint numAddedPrimBlocs = 0;
|
|
uint numFoundIgs = 0;
|
|
uint i;
|
|
for (i=0; i<igs.size(); ++i)
|
|
{
|
|
CLightIGLoader igLoader;
|
|
|
|
try
|
|
{
|
|
igLoader.loadIG(CFile::getFilenameWithoutExtension(igs[i])+".ig");
|
|
|
|
++numFoundIgs;
|
|
|
|
uint numInstances = igLoader.getNumInstance();
|
|
for(uint k = 0; k < numInstances; ++k)
|
|
{
|
|
TPacsPrimMap::iterator pbIt;
|
|
|
|
string shapeName = NLMISC::toLower(CFile::getFilenameWithoutExtension(igLoader.getShapeName(k)));
|
|
string instanceName = NLMISC::toLower(CFile::getFilenameWithoutExtension(igLoader.getInstanceName(k)));
|
|
|
|
bool isTrigger = false;
|
|
bool isZC = false;
|
|
|
|
if ((pbIt = _PacsPrimMap.find(shapeName)) != _PacsPrimMap.end() ||
|
|
// nice hardcoded trick that allows graphists to spawn ghost collisions in ZC
|
|
// when shapename is like 'bat_zc_0?', spaw a pacs prim bloc called gen_bt_col_ext, so nice I just shit my pants
|
|
(isZC = (testWildCard(shapeName.c_str(), "bat_zc_0?") && shapeName != "bat_zc_00" && (pbIt = _PacsPrimMap.find("gen_bt_col_ext")) != _PacsPrimMap.end())) || // the magic hack
|
|
(isTrigger = ((pbIt = _PacsPrimMap.find(instanceName)) != _PacsPrimMap.end())))
|
|
{
|
|
if (_LoadPacsPrims || isTrigger)
|
|
{
|
|
// compute orientation and position
|
|
CMatrix instanceMatrix;
|
|
igLoader.getInstanceMatrix(k, instanceMatrix);
|
|
CVector pos;
|
|
float angle;
|
|
UMoveContainer::getPACSCoordsFromMatrix(pos, angle, instanceMatrix);
|
|
// insert the matching primitive block
|
|
vector<UMovePrimitive*> insertedPrimitives;
|
|
moveContainer->addCollisionnablePrimitiveBlock(pbIt->second, 0, 1, &insertedPrimitives, angle, pos, true);
|
|
|
|
if (isTrigger)
|
|
{
|
|
uint i;
|
|
for (i=0; i<insertedPrimitives.size(); ++i)
|
|
{
|
|
UMovePrimitive *prim = insertedPrimitives[i];
|
|
uint64 id = prim->UserData;
|
|
uint triggerId = (uint)((prim->UserData & 0xffff0000) >> 16);
|
|
_TriggerMap[triggerId] = prim->getFinalPosition(0);
|
|
}
|
|
}
|
|
|
|
++numAddedPrimBlocs;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch(const Exception &e)
|
|
{
|
|
nlwarning("Failed to load IG '%s': %s", igs[i].c_str(), e.what());
|
|
}
|
|
}
|
|
|
|
nlinfo("Loaded %d IGs", numFoundIgs);
|
|
nlinfo("Added %d primitive blocs", numAddedPrimBlocs);
|
|
}
|
|
|
|
|