/*==LICENSE==* CyanWorlds.com Engine - MMOG client, server and tools Copyright (C) 2011 Cyan Worlds, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . You can contact Cyan Worlds, Inc. by email legal@cyan.com or by snail mail at: Cyan Worlds, Inc. 14617 N Newport Hwy Mead, WA 99021 *==LICENSE==*/ #include "plRelevanceMgr.h" #include "plRelevanceRegion.h" #include "../plIntersect/plRegionBase.h" #include "hsStream.h" #include "hsStringTokenizer.h" plRelevanceMgr* plRelevanceMgr::fInstance = nil; plRelevanceMgr::plRelevanceMgr() : fEnabled(true) { } void plRelevanceMgr::Init() { fInstance = TRACKED_NEW plRelevanceMgr; fInstance->RegisterAs(kRelevanceMgr_KEY); } void plRelevanceMgr::DeInit() { if (fInstance) { fInstance->UnRegisterAs(kRelevanceMgr_KEY); fInstance = nil; } } void plRelevanceMgr::IAddRegion(plRelevanceRegion *region) { int i; int dstIdx = fRegions.GetCount(); for (i = 0; i < fRegions.GetCount(); i++) { if (fRegions[i] == nil) { dstIdx = i; break; } } if (dstIdx == fRegions.GetCount()) fRegions.Append(region); else fRegions[i] = region; region->SetMgrIndex(dstIdx + 1); } void plRelevanceMgr::IRemoveRegion(plRelevanceRegion *region) { fRegions[region->fMgrIdx - 1] = nil; } void plRelevanceMgr::SetRegionVectors(const hsPoint3 &pos, hsBitVector ®ionsImIn, hsBitVector ®ionsICareAbout) { regionsImIn.Clear(); regionsICareAbout.Clear(); regionsICareAbout.SetBit(0, true); // Always care about region zero, the special "No region" node hsBool inAnyRegion = false; int i; for (i = 0; i < fRegions.GetCount(); i++) { if (fRegions[i] && fRegions[i]->fRegion->IsInside(pos)) { regionsImIn.SetBit(i + 1, true); regionsICareAbout |= fRegions[i]->fRegionsICareAbout; inAnyRegion = true; } } // If I'm not in any region, that means I'm in the special zero region and care about everything. if (!inAnyRegion) { regionsImIn.SetBit(0, true); regionsICareAbout.Set(fRegions.GetCount()); } } UInt32 plRelevanceMgr::GetNumRegions() const { int i; for (i = fRegions.GetCount(); i > 0 && fRegions[i - 1] == nil; i--); return i + 1; // Add 1 for the special zero-region } hsBool plRelevanceMgr::MsgReceive(plMessage* msg) { plGenRefMsg *genMsg = plGenRefMsg::ConvertNoRef(msg); if (genMsg) { plRelevanceRegion *region = plRelevanceRegion::ConvertNoRef(genMsg->GetRef()); if( genMsg->GetContext() & (plRefMsg::kOnCreate) ) { IAddRegion(region); } else if( genMsg->GetContext() & (plRefMsg::kOnDestroy|plRefMsg::kOnRemove) ) { IRemoveRegion(region); } return true; } return hsKeyedObject::MsgReceive(msg); } UInt32 plRelevanceMgr::GetIndex(char *regionName) { int i; for (i = 0; i < fRegions.GetCount(); i++) { if (fRegions[i] && !stricmp(regionName, fRegions[i]->GetKeyName())) return i + 1; } return -1; } void plRelevanceMgr::MarkRegion(UInt32 localIdx, UInt32 remoteIdx, hsBool doICare) { if (localIdx == (UInt32)-1 || remoteIdx == (UInt32)-1) return; if (localIdx - 1 >= fRegions.GetCount() || remoteIdx - 1 >= fRegions.GetCount() || fRegions[localIdx - 1] == nil) return; fRegions[localIdx - 1]->fRegionsICareAbout.SetBit(remoteIdx, doICare); } // tiny class for the function below class plRegionInfo { public: char *fName; int fIndex; plRegionInfo() : fName(nil), fIndex(-1) {} ~plRegionInfo() { delete [] fName; } }; /* * This function expects a CSV file representing the matrix * * name1 name2 name3 * name1 value value value * name2 value value value * name3 value value value * * where the value determines how much the that row's region cares about the region in the current column. * (Currently, the possible values are: * 0: Doesn't care * 1 or greater: row cares about column */ void plRelevanceMgr::ParseCsvInput(hsStream *s) { const int kBufSize = 512; char buff[kBufSize]; hsTArray regions; hsStringTokenizer toke; hsBool firstLine = true; while (!s->AtEnd()) { if (!s->ReadLn(buff, kBufSize)) break; if (firstLine) { firstLine = false; toke.Reset(buff, ","); while (toke.Next(buff, kBufSize)) { if (strcmp(buff, "") == 0) continue; // ignore the initial blank one plRegionInfo *info = TRACKED_NEW plRegionInfo; regions.Append(info); info->fName = hsStrcpy(buff); info->fIndex = GetIndex(buff); } } else // parsing actual settings. { toke.Reset(buff, ","); if (!toke.Next(buff, kBufSize)) continue; int rowIndex = GetIndex(buff); int column = 0; while (toke.Next(buff, kBufSize) && column < regions.GetCount()) { int value = atoi(buff); MarkRegion(rowIndex, regions[column]->fIndex, value != 0); column++; } } } int i; for (i = regions.GetCount() - 1; i >= 0; i--) delete regions[i]; } std::string plRelevanceMgr::GetRegionNames(hsBitVector regions) { std::string retVal = ""; if (regions.IsBitSet(0)) retVal = "-Nowhere (0)-"; for (int i = 0; i < fRegions.GetCount(); ++i) { if (regions.IsBitSet(i + 1)) { if (retVal.length() != 0) retVal += ", "; if (fRegions[i]) retVal += fRegions[i]->GetKeyName(); } } if (retVal.length() == 0) retVal = ""; return retVal; }