mirror of
https://bitbucket.org/seefoe/src.git
synced 2026-08-01 02:15:47 -04:00
1256 lines
44 KiB
C++
1256 lines
44 KiB
C++
//========================================================================
|
|
//
|
|
// RegionMaster.cpp
|
|
//
|
|
// copyright 2001 Sony Online Entertainment
|
|
//
|
|
//========================================================================
|
|
|
|
#include "serverGame/FirstServerGame.h"
|
|
#include "serverGame/RegionMaster.h"
|
|
|
|
#include "serverGame/ConfigServerGame.h"
|
|
#include "serverGame/CreatureObject.h"
|
|
#include "serverGame/GameServer.h"
|
|
#include "serverGame/PlanetObject.h"
|
|
#include "serverGame/Region.h"
|
|
#include "serverGame/RegionPvp.h"
|
|
#include "serverGame/ServerUniverse.h"
|
|
#include "serverGame/ServerWorld.h"
|
|
#include "serverGame/UniverseObject.h"
|
|
#include "serverNetworkMessages/CreateDynamicRegionCircleMessage.h"
|
|
#include "serverNetworkMessages/CreateDynamicRegionRectangleMessage.h"
|
|
#include "serverNetworkMessages/CreateDynamicSpawnRegionCircleMessage.h"
|
|
#include "sharedFoundation/CalendarTime.h"
|
|
#include "sharedFoundation/DynamicVariableList.h"
|
|
#include "sharedFoundation/FloatMath.h"
|
|
#include "sharedFoundation/ExitChain.h"
|
|
#include "sharedMath/MxCifQuadTree.h"
|
|
#include "sharedMath/MxCifQuadTreeBounds.h"
|
|
#include "serverScript/GameScriptObject.h"
|
|
#include "serverScript/ScriptParameters.h"
|
|
#include "sharedUtility/DataTable.h"
|
|
#include "sharedUtility/DataTableManager.h"
|
|
#include <unordered_set>
|
|
#include <map>
|
|
#include <vector>
|
|
|
|
|
|
// objvars for dynamic regions
|
|
const static std::string OBJVAR_DYNAMIC_REGION("dynamic_region");
|
|
const static std::string OBJVAR_DYNAMIC_REGION_PLANET("planet");
|
|
const static std::string OBJVAR_DYNAMIC_REGION_NAME("name");
|
|
const static std::string OBJVAR_DYNAMIC_REGION_GEOMETRY("geometry");
|
|
const static std::string OBJVAR_DYNAMIC_REGION_MINX("minX");
|
|
const static std::string OBJVAR_DYNAMIC_REGION_MINY("minY");
|
|
const static std::string OBJVAR_DYNAMIC_REGION_MAXX("maxX");
|
|
const static std::string OBJVAR_DYNAMIC_REGION_MAXY("maxY");
|
|
const static std::string OBJVAR_DYNAMIC_REGION_PVP("pvp");
|
|
const static std::string OBJVAR_DYNAMIC_REGION_GEOGRAPHY("geography");
|
|
const static std::string OBJVAR_DYNAMIC_REGION_MIN_DIFFICULTY("minDifficulty");
|
|
const static std::string OBJVAR_DYNAMIC_REGION_MAX_DIFFICULTY("maxDifficulty");
|
|
const static std::string OBJVAR_DYNAMIC_REGION_SPAWN("spawn");
|
|
const static std::string OBJVAR_DYNAMIC_REGION_MISSION("mission");
|
|
const static std::string OBJVAR_DYNAMIC_REGION_BUILDABLE("buildable");
|
|
const static std::string OBJVAR_DYNAMIC_REGION_MUNICIPAL("municipal");
|
|
const static std::string OBJVAR_DYNAMIC_REGION_VISIBLE("visible");
|
|
const static std::string OBJVAR_DYNAMIC_REGION_BATTLEFIELD_MARKER("_battlefield");
|
|
const static std::string OBJVAR_DYNAMIC_REGION_NOTIFY("notify");
|
|
const static std::string OBJVAR_DYNAMIC_REGION_SPAWNTABLE("spawntable");
|
|
const static std::string OBJVAR_DYNAMIC_REGION_DURATION("duration");
|
|
const static std::string OBJVAR_DYNAMIC_REGION_MAXDURATION("maxDuration");
|
|
const static std::string OBJVAR_DYNAMIC_REGION_BIRTH("birth");
|
|
const static std::string OBJVAR_DYNAMIC_REGION_READABLE_BIRTH("calendarBirth");
|
|
const static std::string OBJVAR_DYNAMIC_REGION_READABLE_DEATH("calenderDeath");
|
|
const static std::string OBJVAR_DYNAMIC_REGION_CREATURE_LIST("creatureList");
|
|
|
|
// template used to make dynamic regions
|
|
const static std::string DYNAMIC_REGION_TEMPLATE_NAME("object/universe/dynamic_region.iff");
|
|
|
|
|
|
|
|
enum RegionGeometry
|
|
{
|
|
RG_rectagle,
|
|
RG_circle
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
struct RegionMaster::RegionData
|
|
{
|
|
MxCifQuadTree * tree;
|
|
RegionsMappedByName nameMap;
|
|
|
|
RegionData() : tree(NULL), nameMap() {}
|
|
};
|
|
|
|
namespace RegionMasterNamspace
|
|
{
|
|
EnvironmentInfo convertFromStringToEnvironmentInfo(std::string const & stringList);
|
|
|
|
std::string s_environmentFlagsDataTable = "datatables/region/region_environment_flags.iff";
|
|
std::map<std::string, EnvironmentInfo> s_conversionMap;
|
|
|
|
std::string s_dynamicMasterScript = "systems.regions.dynamic_region_master";
|
|
}
|
|
|
|
using namespace RegionMasterNamspace;
|
|
//========================================================================
|
|
// static member vars
|
|
|
|
std::map<std::string, RegionMaster::RegionData> RegionMaster::ms_planetRegions;
|
|
std::vector<const Region *> RegionMaster::ms_staticRegions;
|
|
std::vector<const Region *> RegionMaster::ms_dynamicRegions;
|
|
bool RegionMaster::ms_installed = false;
|
|
|
|
//========================================================================
|
|
|
|
/**
|
|
* Called on program startup. Creates the RegionMaster.
|
|
*/
|
|
void RegionMaster::install()
|
|
{
|
|
if (!ms_installed)
|
|
{
|
|
ms_installed = true;
|
|
readRegionDataTables();
|
|
ExitChain::add(exit, "RegionMaster");
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
/**
|
|
* Called on program shutdown. Deletes the RegionMaster.
|
|
*/
|
|
void RegionMaster::exit()
|
|
{
|
|
if (ms_installed)
|
|
{
|
|
{
|
|
for (std::map<std::string, RegionData>::iterator i1 = ms_planetRegions.begin();
|
|
i1 != ms_planetRegions.end(); ++i1)
|
|
{
|
|
delete (*i1).second.tree;
|
|
(*i1).second.tree = NULL;
|
|
}
|
|
ms_planetRegions.clear();
|
|
}
|
|
|
|
{
|
|
for (std::vector<const Region *>::iterator i2 = ms_staticRegions.begin();
|
|
i2 != ms_staticRegions.end(); ++i2)
|
|
{
|
|
delete const_cast<Region *>(*i2);
|
|
*i2 = NULL;
|
|
}
|
|
ms_staticRegions.clear();
|
|
}
|
|
|
|
{
|
|
for (std::vector<const Region *>::iterator i2 = ms_dynamicRegions.begin();
|
|
i2 != ms_dynamicRegions.end(); ++i2)
|
|
{
|
|
delete const_cast<Region *>(*i2);
|
|
*i2 = NULL;
|
|
}
|
|
ms_dynamicRegions.clear();
|
|
}
|
|
|
|
ms_installed = false;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
/**
|
|
* Reads the static region info from the planets' region datatables.
|
|
*/
|
|
void RegionMaster::readRegionDataTables()
|
|
{
|
|
if (!ms_installed)
|
|
{
|
|
WARNING(true, ("RegionMaster::readRegionDataTables, not installed"));
|
|
return;
|
|
}
|
|
|
|
const char * regionFilesName = ConfigServerGame::getRegionFilesName();
|
|
|
|
DataTable * const regionFilesTable = DataTableManager::getTable(regionFilesName, true);
|
|
if (regionFilesTable == NULL)
|
|
{
|
|
WARNING(true, ("RegionMaster::readRegionDataTables could not open file %s, static regions will not be read!", regionFilesName));
|
|
return;
|
|
}
|
|
|
|
{
|
|
const int numRegionFiles = regionFilesTable->getNumRows();
|
|
for (int i = 0; i < numRegionFiles; ++i)
|
|
{
|
|
// get the region table from the filename table
|
|
const std::string & planetName = regionFilesTable->getStringValue(0, i);
|
|
const std::string & regionFileName = regionFilesTable->getStringValue(1, i);
|
|
float regionMinX = regionFilesTable->getFloatValue (2, i);
|
|
float regionMinY = regionFilesTable->getFloatValue (3, i);
|
|
float regionMaxX = regionFilesTable->getFloatValue (4, i);
|
|
float regionMaxY = regionFilesTable->getFloatValue (5, i);
|
|
|
|
DataTable * const regionTable = DataTableManager::getTable(regionFileName, true);
|
|
if (regionTable == NULL)
|
|
{
|
|
WARNING(true, ("RegionMaster::readRegionDataTables could not open region file %s.", regionFileName.c_str()));
|
|
continue;
|
|
}
|
|
|
|
RegionData & regionData = ms_planetRegions[planetName];
|
|
if (regionData.tree == NULL)
|
|
{
|
|
regionData.tree = new MxCifQuadTree(regionMinX, regionMinY, regionMaxX, regionMaxY, ConfigServerGame::getRegionTreeDepth());
|
|
}
|
|
|
|
int numRegions = regionTable->getNumRows();
|
|
for (int j = 0; j < numRegions; ++j)
|
|
{
|
|
// read the region data from the table
|
|
const Unicode::String name(Unicode::narrowToWide(regionTable->getStringValue( 0, j)));
|
|
int geometry = regionTable->getIntValue ( 1, j);
|
|
float minX = regionTable->getFloatValue ( 2, j);
|
|
float minY = regionTable->getFloatValue ( 3, j);
|
|
float maxX = regionTable->getFloatValue ( 4, j);
|
|
float maxY = regionTable->getFloatValue ( 5, j);
|
|
int pvp = regionTable->getIntValue ( 6, j);
|
|
int geography = regionTable->getIntValue ( 7, j);
|
|
int minDifficulty = regionTable->getIntValue ( 8, j);
|
|
int maxDifficulty = regionTable->getIntValue ( 9, j);
|
|
int spawn = regionTable->getIntValue (10, j);
|
|
int mission = regionTable->getIntValue (11, j);
|
|
int buildable = regionTable->getIntValue (12, j);
|
|
int municipal = regionTable->getIntValue (13, j);
|
|
int visible = regionTable->getIntValue (14, j);
|
|
int notify = regionTable->getIntValue (15, j);
|
|
EnvironmentInfo envFlags = convertFromStringToEnvironmentInfo( regionTable->getStringValue(16, j) );
|
|
|
|
// make sure the region has a unique name
|
|
if (name.empty())
|
|
{
|
|
WARNING(true, ("RegionMaster::readRegionDataTables row %d of table %s has no region name",
|
|
j, regionFileName.c_str()));
|
|
continue;
|
|
}
|
|
else if (regionData.nameMap.find(name) != regionData.nameMap.end())
|
|
{
|
|
WARNING(true, ("RegionMaster::readRegionDataTables row %d of table %s is trying to add duplicate region %s",
|
|
j, regionFileName.c_str(), Unicode::wideToNarrow(name).c_str()));
|
|
continue;
|
|
}
|
|
|
|
// create a rectangular or circular region and add it to the region tree
|
|
Region * region = NULL;
|
|
switch (geometry)
|
|
{
|
|
case RG_rectagle:
|
|
{
|
|
RegionRectangle * const rectangle = new RegionRectangle(minX, minY, maxX, maxY);
|
|
if (regionData.tree->addObject(rectangle->getBounds()))
|
|
region = rectangle;
|
|
else
|
|
delete rectangle;
|
|
}
|
|
break;
|
|
case RG_circle:
|
|
{
|
|
if (pvp == PR_battlefieldPvp || pvp == PR_battlefieldPve)
|
|
{
|
|
RegionPvp * battlefield = new RegionPvp(minX, minY, maxX);
|
|
if (regionData.tree->addObject(battlefield->getBounds()))
|
|
region = battlefield;
|
|
else
|
|
delete battlefield;
|
|
}
|
|
else
|
|
{
|
|
RegionCircle * circle = new RegionCircle(minX, minY, maxX);
|
|
if (regionData.tree->addObject(circle->getBounds()))
|
|
region = circle;
|
|
else
|
|
delete circle;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
WARNING(true, ("RegionMaster::readRegionDataTables row %d of table %s has invalid geometry parameter %d",
|
|
j, regionFileName.c_str(), geometry));
|
|
continue;
|
|
}
|
|
// set the rest of the region's data
|
|
if (region != NULL)
|
|
{
|
|
region->setName(name);
|
|
region->setPlanet(planetName);
|
|
region->setPvp(pvp);
|
|
region->setGeography(geography);
|
|
region->setMinDifficulty(minDifficulty);
|
|
region->setMaxDifficulty(maxDifficulty);
|
|
region->setSpawn(spawn);
|
|
region->setMission(mission);
|
|
region->setBuildable(buildable);
|
|
region->setMunicipal(municipal);
|
|
region->setVisible(visible);
|
|
region->setNotify(notify);
|
|
region->setEnvironmentFlags(envFlags);
|
|
ms_staticRegions.push_back(region);
|
|
regionData.nameMap[name] = region;
|
|
}
|
|
else
|
|
{
|
|
FATAL(true, ("RegionMaster::readRegionDataTables could not add row %d (%s) of table %s to region tree",
|
|
j, Unicode::wideToNarrow(name).c_str(), regionFileName.c_str()));
|
|
}
|
|
}
|
|
DataTableManager::close(regionFileName);
|
|
}
|
|
}
|
|
DataTableManager::close(regionFilesName);
|
|
} // RegionMaster::readRegionDataTables
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
/**
|
|
* Creates a new rectangular dynamic region.
|
|
*
|
|
* @param minX min x coordinate
|
|
* @param minZ min z coordinate
|
|
* @param maxX max x coordinate
|
|
* @param maxZ max z coordinate
|
|
* @param name region name
|
|
* @param planet region planet name
|
|
* @param pvp pvp state
|
|
* @param buildable buildable state
|
|
* @param municipal municipal state
|
|
* @param geography geography state
|
|
* @param minDifficulty min difficulty state
|
|
* @param maxDifficulty max difficulty state
|
|
* @param spawnable spawnable state
|
|
* @param mission mission state
|
|
* @param visible visible flag
|
|
* @param notify notify flag
|
|
*/
|
|
void RegionMaster::createNewDynamicRegion(float minX, float minZ,
|
|
float maxX, float maxZ, const Unicode::String & name, const std::string & planet,
|
|
int pvp, int buildable, int municipal, int geography, int minDifficulty,
|
|
int maxDifficulty, int spawnable, int mission, bool visible, bool notify)
|
|
{
|
|
// no creating duplicate regions
|
|
if (getRegionByName(planet, name))
|
|
return;
|
|
|
|
// only the universe process may create universe objects
|
|
if (!ServerUniverse::getInstance().isAuthoritative())
|
|
{
|
|
CreateDynamicRegionRectangleMessage const createMessage(minX, minZ, maxX, maxZ, name, planet, pvp, buildable, municipal, geography, minDifficulty, maxDifficulty, spawnable, mission, visible, notify);
|
|
GameServer::getInstance().sendToCentralServer(createMessage);
|
|
return;
|
|
}
|
|
|
|
// create a new UniverseObject that will be used to hold the region data
|
|
Transform tr;
|
|
tr.setPosition_p(Vector::xyz111);
|
|
UniverseObject *regionObject = safe_cast<UniverseObject *>(ServerWorld::createNewObject(DYNAMIC_REGION_TEMPLATE_NAME, tr, 0, false));
|
|
|
|
if (!regionObject)
|
|
return;
|
|
|
|
if (!setDynamicRegionObjectData(*regionObject, name, planet, RG_rectagle, minX,
|
|
minZ, maxX, maxZ, pvp, buildable, municipal, geography, minDifficulty,
|
|
maxDifficulty, spawnable, mission, visible, notify))
|
|
{
|
|
regionObject->permanentlyDestroy(DeleteReasons::SetupFailed);
|
|
return;
|
|
}
|
|
|
|
const Region * region = addDynamicRegion(*regionObject);
|
|
if (region)
|
|
regionObject->persist();
|
|
else
|
|
{
|
|
regionObject->removeObjVarItem(OBJVAR_DYNAMIC_REGION);
|
|
regionObject->permanentlyDestroy(DeleteReasons::SetupFailed);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
/**
|
|
* Creates a new circlular dynamic region.
|
|
*
|
|
* @param centerX x coordinate of circle center
|
|
* @param centerZ z coordinate of circle center
|
|
* @param radius circle radius
|
|
* @param name region name
|
|
* @param planet region planet name
|
|
* @param pvp pvp state
|
|
* @param buildable buildable state
|
|
* @param municipal municipal state
|
|
* @param geography geography state
|
|
* @param minDifficulty min difficulty state
|
|
* @param maxDifficulty max difficulty state
|
|
* @param spawnable spawnable state
|
|
* @param mission mission state
|
|
* @param visible visible flag
|
|
* @param notify notify flag
|
|
*
|
|
* @return the new region, or NULL on error
|
|
*/
|
|
void RegionMaster::createNewDynamicRegion(float centerX, float centerZ,
|
|
float radius, const Unicode::String & name, const std::string & planet, int pvp,
|
|
int buildable, int municipal, int geography, int minDifficulty, int maxDifficulty,
|
|
int spawnable, int mission, bool visible, bool notify)
|
|
{
|
|
// no creating duplicate regions
|
|
if (getRegionByName(planet, name))
|
|
return;
|
|
|
|
// only the universe process may create universe objects
|
|
if (!ServerUniverse::getInstance().isAuthoritative())
|
|
{
|
|
CreateDynamicRegionCircleMessage const createMessage(centerX, centerZ, radius, name, planet, pvp, buildable, municipal, geography, minDifficulty, maxDifficulty, spawnable, mission, visible, notify);
|
|
GameServer::getInstance().sendToCentralServer(createMessage);
|
|
return;
|
|
}
|
|
|
|
// create a new UniverseObject that will be used to hold the region data
|
|
Transform tr;
|
|
tr.setPosition_p(Vector::xyz111);
|
|
UniverseObject *regionObject = safe_cast<UniverseObject *>(ServerWorld::createNewObject(DYNAMIC_REGION_TEMPLATE_NAME, tr, 0, false));
|
|
|
|
if (!regionObject)
|
|
return;
|
|
|
|
if (!setDynamicRegionObjectData(*regionObject, name, planet, RG_circle, centerX,
|
|
centerZ, radius, 0, pvp, buildable, municipal, geography, minDifficulty,
|
|
maxDifficulty, spawnable, mission, visible, notify))
|
|
{
|
|
regionObject->permanentlyDestroy(DeleteReasons::SetupFailed);
|
|
return;
|
|
}
|
|
|
|
regionObject->addToWorld();
|
|
|
|
const Region * region = addDynamicRegion(*regionObject);
|
|
if (region)
|
|
regionObject->persist();
|
|
else
|
|
{
|
|
regionObject->removeObjVarItem(OBJVAR_DYNAMIC_REGION);
|
|
regionObject->permanentlyDestroy(DeleteReasons::SetupFailed);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
/**
|
|
* Sets the objvars on a universe object to turn it into a dynamic region
|
|
* object.
|
|
*
|
|
* @param object the object
|
|
* @param name region name
|
|
* @param planet region planet name
|
|
* @param geometry region geometry (rect or circle)
|
|
* @param minX min x coordinate/center x
|
|
* @param minZ min z coordinate/center z
|
|
* @param maxX max x coordinate/radius
|
|
* @param maxZ max z coordinate/ignored
|
|
* @param pvp pvp state
|
|
* @param buildable buildable state
|
|
* @param municipal municipal state
|
|
* @param geography geography state
|
|
* @param minDifficulty min difficulty state
|
|
* @param maxDifficulty max difficulty state
|
|
* @param spawnable spawnable state
|
|
* @param mission mission state
|
|
* @param visible visible flag
|
|
* @param notify notify flag
|
|
*
|
|
* @return true on success, false if there was an error
|
|
*/
|
|
bool RegionMaster::setDynamicRegionObjectData(UniverseObject & object,
|
|
const Unicode::String & name, const std::string & planet, int geometry,
|
|
float minX, float minZ, float maxX, float maxZ, int pvp, int buildable,
|
|
int municipal, int geography, int minDifficulty, int maxDifficulty, int spawnable,
|
|
int mission, bool visible, bool notify)
|
|
{
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_NAME, name);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_PLANET, Unicode::narrowToWide(planet));
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_GEOMETRY, geometry);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MINX, minX);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MINY, minZ);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MAXX, maxX);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MAXY, maxZ);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_PVP, pvp);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_GEOGRAPHY, geography);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MIN_DIFFICULTY, minDifficulty);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MAX_DIFFICULTY, maxDifficulty);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_SPAWN, spawnable);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MISSION, mission);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_BUILDABLE, buildable);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MUNICIPAL, municipal);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_VISIBLE, static_cast<int>(visible));
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_NOTIFY, static_cast<int>(notify));
|
|
return true;
|
|
} // RegionMaster::setDynamicRegionObjectData
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
/**
|
|
* Adds a dynamic region to the world.
|
|
*
|
|
* @param source the source of the region
|
|
*/
|
|
const Region * RegionMaster::addDynamicRegion(const UniverseObject & source)
|
|
{
|
|
if (!ms_installed)
|
|
{
|
|
WARNING(true, ("RegionMaster::addDynamicRegion, not installed"));
|
|
return NULL;
|
|
}
|
|
|
|
DynamicVariableList::NestedList regionObjvars(source.getObjVars(),OBJVAR_DYNAMIC_REGION);
|
|
|
|
Unicode::String planet;
|
|
if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_PLANET,planet))
|
|
{
|
|
DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no planet data", source.getNetworkId().getValueString().c_str()));
|
|
return NULL;
|
|
}
|
|
Unicode::String name;
|
|
if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_NAME,name))
|
|
{
|
|
DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no name data", source.getNetworkId().getValueString().c_str()));
|
|
return NULL;
|
|
}
|
|
if (name.empty())
|
|
{
|
|
DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has empty "
|
|
"name data", source.getNetworkId().getValueString().c_str()));
|
|
return NULL;
|
|
}
|
|
int geometry = 0;
|
|
if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_GEOMETRY,geometry))
|
|
{
|
|
DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no "
|
|
"geometry data", source.getNetworkId().getValueString().c_str()));
|
|
return NULL;
|
|
}
|
|
float minX;
|
|
if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_MINX,minX))
|
|
{
|
|
DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no "
|
|
"minX data", source.getNetworkId().getValueString().c_str()));
|
|
return NULL;
|
|
}
|
|
float minY;
|
|
if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_MINY,minY))
|
|
{
|
|
DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no "
|
|
"minY data", source.getNetworkId().getValueString().c_str()));
|
|
return NULL;
|
|
}
|
|
float maxX;
|
|
if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_MAXX,maxX))
|
|
{
|
|
DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no "
|
|
"maxX data", source.getNetworkId().getValueString().c_str()));
|
|
return NULL;
|
|
}
|
|
float maxY;
|
|
if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_MAXY,maxY))
|
|
{
|
|
DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no "
|
|
"maxY data", source.getNetworkId().getValueString().c_str()));
|
|
return NULL;
|
|
}
|
|
int pvp=0;
|
|
if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_PVP,pvp))
|
|
{
|
|
DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no "
|
|
"pvp data", source.getNetworkId().getValueString().c_str()));
|
|
return NULL;
|
|
}
|
|
int geography=0;
|
|
if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_GEOGRAPHY,geography))
|
|
{
|
|
DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no "
|
|
"geography data", source.getNetworkId().getValueString().c_str()));
|
|
return NULL;
|
|
}
|
|
int minDifficulty = 0;
|
|
if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_MIN_DIFFICULTY, minDifficulty))
|
|
{
|
|
DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no "
|
|
"min difficulty data", source.getNetworkId().getValueString().c_str()));
|
|
return NULL;
|
|
}
|
|
int maxDifficulty = 0;
|
|
if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_MAX_DIFFICULTY, maxDifficulty))
|
|
{
|
|
DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no "
|
|
"max difficulty data", source.getNetworkId().getValueString().c_str()));
|
|
return NULL;
|
|
}
|
|
int spawn = 0;
|
|
if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_SPAWN,spawn))
|
|
{
|
|
DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no "
|
|
"spawn data", source.getNetworkId().getValueString().c_str()));
|
|
return NULL;
|
|
}
|
|
int mission = 0;
|
|
if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_MISSION,mission))
|
|
{
|
|
DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no "
|
|
"mission data", source.getNetworkId().getValueString().c_str()));
|
|
return NULL;
|
|
}
|
|
int buildable = 0;
|
|
if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_BUILDABLE,buildable))
|
|
{
|
|
DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no "
|
|
"buildable data", source.getNetworkId().getValueString().c_str()));
|
|
return NULL;
|
|
}
|
|
int municipal = 0;
|
|
if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_MUNICIPAL,municipal))
|
|
{
|
|
DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no "
|
|
"municipal data", source.getNetworkId().getValueString().c_str()));
|
|
return NULL;
|
|
}
|
|
int visible = 0;
|
|
if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_VISIBLE,visible))
|
|
{
|
|
DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no "
|
|
"visible data", source.getNetworkId().getValueString().c_str()));
|
|
return NULL;
|
|
}
|
|
int notify = 0;
|
|
if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_NOTIFY,notify))
|
|
{
|
|
DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no "
|
|
"notify data", source.getNetworkId().getValueString().c_str()));
|
|
return NULL;
|
|
}
|
|
|
|
// find the appropriate region data for the planet
|
|
// note that dynamic regions cannot define new planets
|
|
std::map<std::string, RegionData>::iterator result = ms_planetRegions.find(
|
|
Unicode::wideToNarrow(planet));
|
|
if (result == ms_planetRegions.end())
|
|
{
|
|
WARNING(true, ("RegionMaster::addDynamicRegion object %s gave unknown "
|
|
"planet %s for its region", source.getNetworkId().getValueString().c_str(),
|
|
Unicode::wideToNarrow(planet).c_str()));
|
|
return NULL;
|
|
}
|
|
RegionData & regionData = (*result).second;
|
|
if (regionData.tree == NULL)
|
|
{
|
|
WARNING_STRICT_FATAL(true, ("RegionMaster::addDynamicRegion planet %s "
|
|
"has no tree defined!", Unicode::wideToNarrow(planet).c_str()));
|
|
return NULL;
|
|
}
|
|
|
|
// make sure the region name is unique
|
|
if (regionData.nameMap.find(name) != regionData.nameMap.end())
|
|
{
|
|
WARNING(true, ("RegionMaster::addDynamicRegion object %s is trying "
|
|
"to add duplicate region %s", source.getNetworkId().getValueString().c_str(),
|
|
Unicode::wideToNarrow(name).c_str()));
|
|
return NULL;
|
|
}
|
|
|
|
// create a rectangular or circular region and add it to the region tree
|
|
Region * region = NULL;
|
|
switch (geometry)
|
|
{
|
|
case RG_rectagle:
|
|
{
|
|
RegionRectangle * rectangle = new RegionRectangle(minX, minY, maxX, maxY, CachedNetworkId(source));
|
|
if (regionData.tree->addObject(rectangle->getBounds()))
|
|
region = rectangle;
|
|
else
|
|
delete rectangle;
|
|
}
|
|
break;
|
|
case RG_circle:
|
|
{
|
|
if (pvp == PR_battlefieldPvp || pvp == PR_battlefieldPve)
|
|
{
|
|
RegionPvp * battlefield = new RegionPvp(minX, minY, maxX, CachedNetworkId(source));
|
|
if (regionData.tree->addObject(battlefield->getBounds()))
|
|
region = battlefield;
|
|
else
|
|
delete battlefield;
|
|
}
|
|
else
|
|
{
|
|
RegionCircle * circle = new RegionCircle(minX, minY, maxX, CachedNetworkId(source));
|
|
if (regionData.tree->addObject(circle->getBounds()))
|
|
region = circle;
|
|
else
|
|
delete circle;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has unknown "
|
|
"geometry type", source.getNetworkId().getValueString().c_str(),
|
|
geometry));
|
|
return false;
|
|
}
|
|
if (region == NULL)
|
|
{
|
|
WARNING(true, ("RegionMaster::readRegionDataTables could "
|
|
"not add region defined by object %s to region tree",
|
|
source.getNetworkId().getValueString().c_str()));
|
|
return NULL;
|
|
}
|
|
|
|
// set the rest of the region's data
|
|
region->setName(name);
|
|
region->setPlanet(Unicode::wideToNarrow(planet));
|
|
region->setPvp(pvp);
|
|
region->setGeography(geography);
|
|
region->setMinDifficulty(minDifficulty);
|
|
region->setMaxDifficulty(maxDifficulty);
|
|
region->setSpawn(spawn);
|
|
region->setMission(mission);
|
|
region->setBuildable(buildable);
|
|
region->setMunicipal(municipal);
|
|
region->setVisible(visible);
|
|
region->setNotify(notify);
|
|
ms_dynamicRegions.push_back(region);
|
|
regionData.nameMap[name] = region;
|
|
|
|
if (region->asRegionPvp())
|
|
region->asRegionPvp()->checkBattlefieldMarker();
|
|
|
|
// if the region is a notify region, force checkNotifyRegions() to be
|
|
// called on all character creatures in the region as soon as possible so
|
|
// notifications will be sent that the creature has entered the region
|
|
if (notify)
|
|
{
|
|
std::vector<const Region *> regions;
|
|
|
|
CreatureObject::AllCreaturesSet const &creatureList = CreatureObject::getAllCreatures();
|
|
for (CreatureObject::AllCreaturesSet::const_iterator i = creatureList.begin(); i != creatureList.end(); ++i)
|
|
{
|
|
CreatureObject *creatureObj = const_cast<CreatureObject*>(*i);
|
|
if (creatureObj->isInitialized() && creatureObj->isAuthoritative() && creatureObj->isPlayerControlled() && creatureObj->isInWorld())
|
|
{
|
|
regions.clear();
|
|
getRegionsAtPoint(ServerWorld::getSceneId(), creatureObj->getPosition_w().x, creatureObj->getPosition_w().z, regions);
|
|
if (std::find(regions.begin(), regions.end(), region) != regions.end())
|
|
creatureObj->forceNotifyRegionsCheck();
|
|
}
|
|
}
|
|
}
|
|
|
|
return region;
|
|
} // RegionMaster::addDynamicRegion
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
/**
|
|
* Removes a dynamic region from the world.
|
|
*
|
|
* @param source the source of the region
|
|
*/
|
|
void RegionMaster::removeDynamicRegion(const UniverseObject & source)
|
|
{
|
|
if (!ms_installed)
|
|
{
|
|
WARNING(true, ("RegionMaster::removeDynamicRegion, not installed"));
|
|
return;
|
|
}
|
|
|
|
DynamicVariableList::NestedList regionObjvars(source.getObjVars(),OBJVAR_DYNAMIC_REGION);
|
|
|
|
Unicode::String planet;
|
|
if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_PLANET,planet))
|
|
{
|
|
DEBUG_WARNING(true, ("RegionMaster::removeDynamicRegion object %s has no "
|
|
"planet data", source.getNetworkId().getValueString().c_str()));
|
|
return;
|
|
}
|
|
Unicode::String name;
|
|
if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_NAME,name))
|
|
{
|
|
DEBUG_WARNING(true, ("RegionMaster::removeDynamicRegion object %s has no "
|
|
"name data", source.getNetworkId().getValueString().c_str()));
|
|
return;
|
|
}
|
|
|
|
// find the appropriate region data for the planet
|
|
// note that dynamic regions cannot define new planets
|
|
std::map<std::string, RegionData>::iterator dataResult = ms_planetRegions.find(
|
|
Unicode::wideToNarrow(planet));
|
|
if (dataResult == ms_planetRegions.end())
|
|
{
|
|
WARNING(true, ("RegionMaster::removeDynamicRegion object %s gave unknown "
|
|
"planet %s for its region", source.getNetworkId().getValueString().c_str(),
|
|
Unicode::wideToNarrow(planet).c_str()));
|
|
return;
|
|
}
|
|
RegionData & regionData = (*dataResult).second;
|
|
if (regionData.tree == NULL)
|
|
{
|
|
WARNING_STRICT_FATAL(true, ("RegionMaster::addDynamicRegion planet %s "
|
|
"has no tree defined!", Unicode::wideToNarrow(planet).c_str()));
|
|
return;
|
|
}
|
|
|
|
// find the region by its name
|
|
RegionsMappedByName::iterator regionResult = regionData.nameMap.find(name);
|
|
if (regionResult == regionData.nameMap.end())
|
|
{
|
|
WARNING(true, ("RegionMaster::removeDynamicRegion object %s gave unknown "
|
|
"name %s for its region", source.getNetworkId().getValueString().c_str(),
|
|
Unicode::wideToNarrow(name).c_str()));
|
|
return;
|
|
}
|
|
const Region * region = (*regionResult).second;
|
|
if (region && !region->isDynamic())
|
|
{
|
|
WARNING(true, ("RegionMaster::removeDynamicRegion object %s tried to remove static region %s",
|
|
source.getNetworkId().getValueString().c_str(), Unicode::wideToNarrow(name).c_str()));
|
|
return;
|
|
}
|
|
|
|
// if the region is a notify region, force checkNotifyRegions() to be
|
|
// called on all character creatures in the region as soon as possible so
|
|
// notifications will be sent that the creature has left the region
|
|
if (region->getNotify())
|
|
{
|
|
std::vector<const Region *> regions;
|
|
|
|
CreatureObject::AllCreaturesSet const &creatureList = CreatureObject::getAllCreatures();
|
|
for (CreatureObject::AllCreaturesSet::const_iterator i = creatureList.begin(); i != creatureList.end(); ++i)
|
|
{
|
|
CreatureObject *creatureObj = const_cast<CreatureObject*>(*i);
|
|
if (creatureObj->isInitialized() && creatureObj->isAuthoritative() && creatureObj->isPlayerControlled() && creatureObj->isInWorld())
|
|
{
|
|
regions.clear();
|
|
getRegionsAtPoint(ServerWorld::getSceneId(), creatureObj->getPosition_w().x, creatureObj->getPosition_w().z, regions);
|
|
if (std::find(regions.begin(), regions.end(), region) != regions.end())
|
|
creatureObj->forceNotifyRegionsCheck();
|
|
}
|
|
}
|
|
}
|
|
|
|
regionData.nameMap.erase(regionResult);
|
|
|
|
// remove the region from the tree
|
|
if (!regionData.tree->removeObject(region->getBounds()))
|
|
{
|
|
WARNING(true, ("RegionMaster::removeDynamicRegion error removing dynamic "
|
|
"region %s from region tree, continuing anyway",
|
|
source.getNetworkId().getValueString().c_str()));
|
|
}
|
|
|
|
// remove the region from the dynamic region list
|
|
std::vector<const Region *>::iterator removeResult = std::find(
|
|
ms_dynamicRegions.begin(), ms_dynamicRegions.end(), region);
|
|
if (removeResult != ms_dynamicRegions.end())
|
|
{
|
|
ms_dynamicRegions.erase(removeResult);
|
|
}
|
|
else
|
|
{
|
|
WARNING(true, ("RegionMaster::removeDynamicRegion dynamic region %s was "
|
|
"not in the dynamic region list, continuing anyway",
|
|
source.getNetworkId().getValueString().c_str()));
|
|
}
|
|
|
|
// remove the region
|
|
delete region;
|
|
} // RegionMaster::removeDynamicRegion
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
/**
|
|
* Returns the dynamic region associated with a UniverseObject.
|
|
*
|
|
* @param source the object to get the region from
|
|
*/
|
|
const Region * RegionMaster::getDynamicRegionFromObject(const UniverseObject & source)
|
|
{
|
|
if (!ms_installed)
|
|
{
|
|
WARNING(true, ("RegionMaster::getDynamicRegionFromObject, not installed"));
|
|
return NULL;
|
|
}
|
|
|
|
DynamicVariableList::NestedList regionObjVars(source.getObjVars(),OBJVAR_DYNAMIC_REGION);
|
|
|
|
Unicode::String planet;
|
|
if (!regionObjVars.getItem(OBJVAR_DYNAMIC_REGION_PLANET,planet))
|
|
{
|
|
DEBUG_WARNING(true, ("RegionMaster::getDynamicRegionFromObject object %s has no "
|
|
"planet data", source.getNetworkId().getValueString().c_str()));
|
|
return NULL;
|
|
}
|
|
Unicode::String name;
|
|
if (!regionObjVars.getItem(OBJVAR_DYNAMIC_REGION_NAME,name))
|
|
{
|
|
DEBUG_WARNING(true, ("RegionMaster::getDynamicRegionFromObject object %s has no "
|
|
"name data", source.getNetworkId().getValueString().c_str()));
|
|
return NULL;
|
|
}
|
|
|
|
return getRegionByName(Unicode::wideToNarrow(planet), name);
|
|
} // RegionMaster::getDynamicRegionFromObject
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
/**
|
|
* Returns the region with the given name.
|
|
*/
|
|
Region * RegionMaster::getRegionByName(const std::string & planetName, const Unicode::String & regionName)
|
|
{
|
|
if (!ms_installed)
|
|
{
|
|
WARNING(true, ("RegionMaster::getRegionByName, not installed"));
|
|
return NULL;
|
|
}
|
|
|
|
const RegionData & regionData = ms_planetRegions[planetName];
|
|
if (regionData.tree != NULL)
|
|
{
|
|
RegionsMappedByName::const_iterator result = regionData.nameMap.find(regionName);
|
|
if (result != regionData.nameMap.end())
|
|
return (*result).second;
|
|
}
|
|
return NULL;
|
|
} // RegionMaster::getRegionByName
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
/**
|
|
* Finds the region with the smallest area at a given point.
|
|
*/
|
|
const Region * RegionMaster::getSmallestRegionAtPoint(const std::string & planet, float x, float z)
|
|
{
|
|
if (!ms_installed)
|
|
{
|
|
WARNING(true, ("RegionMaster::getSmallestRegionAtPoint, not installed"));
|
|
return NULL;
|
|
}
|
|
|
|
std::vector<const Region *> regions;
|
|
getRegionsAtPoint(planet, x, z, regions);
|
|
|
|
float area = 0;
|
|
const Region * region = NULL;
|
|
for (std::vector<const Region *>::const_iterator iter = regions.begin();
|
|
iter != regions.end(); ++iter)
|
|
{
|
|
if (region == NULL)
|
|
{
|
|
region = *iter;
|
|
area = region->getArea();
|
|
}
|
|
else
|
|
{
|
|
float testArea = (*iter)->getArea();
|
|
if (testArea < area)
|
|
{
|
|
area = testArea;
|
|
region = *iter;
|
|
}
|
|
}
|
|
}
|
|
return region;
|
|
} // RegionMaster::getSmallestRegionAtPoint
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
/**
|
|
* Same as getSmallestRegionAtPoint, but the region must be marked as visible.
|
|
*/
|
|
const Region * RegionMaster::getSmallestVisibleRegionAtPoint(const std::string & planet, float x, float z)
|
|
{
|
|
if (!ms_installed)
|
|
{
|
|
WARNING(true, ("RegionMaster::getSmallestRegionAtPoint, not installed"));
|
|
return NULL;
|
|
}
|
|
|
|
std::vector<const Region *> regions;
|
|
getRegionsAtPoint(planet, x, z, regions);
|
|
|
|
float area = 0;
|
|
const Region * region = NULL;
|
|
for (std::vector<const Region *>::const_iterator iter = regions.begin(); iter != regions.end(); ++iter)
|
|
{
|
|
if ((*iter)->isVisible())
|
|
{
|
|
if (region == NULL)
|
|
{
|
|
region = *iter;
|
|
area = region->getArea();
|
|
}
|
|
else
|
|
{
|
|
float testArea = (*iter)->getArea();
|
|
if (testArea < area)
|
|
{
|
|
area = testArea;
|
|
region = *iter;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return region;
|
|
} // RegionMaster::getSmallestVisibleRegionAtPoint
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
/**
|
|
* Finds the regions at a given point.
|
|
*
|
|
* @param planet planet name of region to get
|
|
* @param x x coordinate of point
|
|
* @param z z coordinate of point
|
|
* @param regions vector to be filled in with list of regions at the point
|
|
*/
|
|
void RegionMaster::getRegionsAtPoint(const std::string & planet, float x, float z,
|
|
std::vector<const Region *> & regions)
|
|
{
|
|
regions.clear();
|
|
|
|
if (!ms_installed)
|
|
{
|
|
WARNING(true, ("RegionMaster::getRegionsAtPoint, not installed"));
|
|
return;
|
|
}
|
|
|
|
const RegionData & regionData = ms_planetRegions[planet];
|
|
if (regionData.tree != NULL)
|
|
{
|
|
std::vector<const MxCifQuadTreeBounds *> objects;
|
|
regionData.tree->getObjectsAt(x, z, objects);
|
|
for (std::vector<const MxCifQuadTreeBounds *>::const_iterator iter = objects.begin();
|
|
iter != objects.end(); ++iter)
|
|
{
|
|
regions.push_back(static_cast<Region *>((*iter)->getData()));
|
|
}
|
|
}
|
|
} // RegionMaster::getRegionsAtPoint
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
/**
|
|
* Returns all the regions for a given planet.
|
|
*/
|
|
void RegionMaster::getRegionsForPlanet(const std::string & planetName,
|
|
std::vector<const Region *> & regions)
|
|
{
|
|
regions.clear();
|
|
|
|
if (!ms_installed)
|
|
{
|
|
WARNING(true, ("RegionMaster::getRegionsForPlanet, not installed"));
|
|
return;
|
|
}
|
|
|
|
const RegionData & regionData = ms_planetRegions[planetName];
|
|
if (regionData.tree != NULL)
|
|
{
|
|
std::vector<const MxCifQuadTreeBounds *> objects;
|
|
regionData.tree->getAllObjects(objects);
|
|
for (std::vector<const MxCifQuadTreeBounds *>::const_iterator iter = objects.begin();
|
|
iter != objects.end(); ++iter)
|
|
{
|
|
regions.push_back(static_cast<Region *>((*iter)->getData()));
|
|
}
|
|
}
|
|
} // RegionMaster::getRegionsForPlanet
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void RegionMaster::registerBattlefieldMarker(const std::string ®ionName, BattlefieldMarkerObject *marker)
|
|
{
|
|
Region *region = getRegionByName(ServerWorld::getSceneId(), Unicode::narrowToWide(regionName));
|
|
if (region)
|
|
{
|
|
RegionPvp *regionPvp = region->asRegionPvp();
|
|
if (regionPvp)
|
|
regionPvp->setBattlefieldMarker(marker);
|
|
}
|
|
}
|
|
|
|
EnvironmentInfo RegionMasterNamspace::convertFromStringToEnvironmentInfo(std::string const & stringList)
|
|
{
|
|
if(stringList.empty())
|
|
return 0;
|
|
|
|
if(s_conversionMap.empty())
|
|
{
|
|
// Fill the Datatable with values from our environment flags datatable.
|
|
DataTable * const environmentFlagTable = DataTableManager::getTable(s_environmentFlagsDataTable, true);
|
|
for(int i = 0; i < environmentFlagTable->getNumRows(); ++i)
|
|
{
|
|
s_conversionMap.insert( std::pair<std::string, EnvironmentInfo>(environmentFlagTable->getStringValue(0,i), static_cast<EnvironmentInfo>(1 << i) ) );
|
|
}
|
|
}
|
|
|
|
std::string parserList = stringList;
|
|
const char delimiter = ',';
|
|
EnvironmentInfo outputValue = 0;
|
|
|
|
// Parse the input string using , as the delimiter.
|
|
std::vector<std::string> parsedStringVector;
|
|
std::string::size_type loc = parserList.find(delimiter);
|
|
|
|
if (std::string::npos != loc) // We found a comma
|
|
{
|
|
std::vector<int> locations;
|
|
locations.push_back(loc);
|
|
while (std::string::npos != (loc = parserList.find(delimiter, loc+1)))
|
|
{
|
|
locations.push_back(loc);
|
|
}
|
|
|
|
for(std::vector<int>::size_type i = 0; i < locations.size(); ++i)
|
|
{
|
|
std::string subString;
|
|
|
|
if(i == 0)
|
|
subString = parserList.substr(0, locations[i]);
|
|
else
|
|
subString = parserList.substr(locations[i - 1], locations[i]);
|
|
|
|
parsedStringVector.push_back(subString);
|
|
}
|
|
|
|
}
|
|
else
|
|
parsedStringVector.push_back(parserList); // No comma, must be one item in the list.
|
|
|
|
// Now we just search our map for the strings we just read in. If we find it, we add that flag to our output value.
|
|
for(std::vector<std::string>::size_type i = 0; i < parsedStringVector.size(); ++i)
|
|
{
|
|
std::map<std::string, EnvironmentInfo>::iterator searchIter = s_conversionMap.find(parsedStringVector[i]);
|
|
|
|
if( searchIter != s_conversionMap.end())
|
|
{
|
|
outputValue |= searchIter->second;
|
|
}
|
|
}
|
|
|
|
|
|
return outputValue;
|
|
}
|
|
|
|
NetworkId RegionMaster::createNewDynamicRegionWithSpawn(float centerX, float centerY, float centerZ,
|
|
float radius, const Unicode::String & name, const std::string & planet, int pvp,
|
|
int buildable, int municipal, int geography, int minDifficulty, int maxDifficulty,
|
|
int spawnable, int mission, bool visible, bool notify, std::string spawnDatatable, int duration)
|
|
{
|
|
// no creating duplicate regions
|
|
if (getRegionByName(planet, name))
|
|
return NetworkId();
|
|
|
|
// only the universe process may create universe objects
|
|
if (!ServerUniverse::getInstance().isAuthoritative())
|
|
{
|
|
CreateDynamicSpawnRegionCircleMessage const createMessage(centerX, centerY, centerZ, radius, name, planet, pvp, buildable, municipal, geography, minDifficulty, maxDifficulty, spawnable, mission, visible, notify, spawnDatatable, duration);
|
|
GameServer::getInstance().sendToCentralServer(createMessage);
|
|
return NetworkId();
|
|
}
|
|
|
|
// create a new UniverseObject that will be used to hold the region data
|
|
Transform tr;
|
|
tr.setPosition_p(Vector::xyz111);
|
|
UniverseObject *regionObject = safe_cast<UniverseObject *>(ServerWorld::createNewObject(DYNAMIC_REGION_TEMPLATE_NAME, tr, 0, false));
|
|
|
|
if (!regionObject || !regionObject->getScriptObject())
|
|
return NetworkId();
|
|
|
|
if (!setDynamicSpawnRegionObjectData(*regionObject, name, planet, RG_circle, centerX,
|
|
centerZ, radius, 0, pvp, buildable, municipal, geography, minDifficulty,
|
|
maxDifficulty, spawnable, mission, visible, notify, spawnDatatable, duration))
|
|
{
|
|
regionObject->permanentlyDestroy(DeleteReasons::SetupFailed);
|
|
return NetworkId();
|
|
}
|
|
|
|
regionObject->addToWorld();
|
|
|
|
const Region * region = addDynamicRegion(*regionObject);
|
|
if (region)
|
|
regionObject->persist();
|
|
else
|
|
{
|
|
regionObject->removeObjVarItem(OBJVAR_DYNAMIC_REGION);
|
|
regionObject->permanentlyDestroy(DeleteReasons::SetupFailed);
|
|
}
|
|
|
|
// Everything went okay. Add dynamic spawn script and other objvars.
|
|
regionObject->getScriptObject()->attachScript(s_dynamicMasterScript, true);
|
|
|
|
if(!spawnDatatable.empty())
|
|
{
|
|
// Creature spawning has to be done in script.
|
|
ScriptParams params;
|
|
params.addParam(regionObject->getNetworkId());
|
|
params.addParam(spawnDatatable.c_str());
|
|
params.addParam(centerX);
|
|
params.addParam(centerY);
|
|
params.addParam(centerZ);
|
|
|
|
IGNORE_RETURN(regionObject->getScriptObject()->trigAllScripts(Scripting::TRIG_ON_DYNAMIC_SPAWN_REGION_CREATED, params));
|
|
}
|
|
|
|
return regionObject->getNetworkId();
|
|
}
|
|
|
|
bool RegionMaster::setDynamicSpawnRegionObjectData(UniverseObject & object,
|
|
const Unicode::String & name, const std::string & planet, int geometry,
|
|
float minX, float minZ, float maxX, float maxZ, int pvp, int buildable,
|
|
int municipal, int geography, int minDifficulty, int maxDifficulty, int spawnable,
|
|
int mission, bool visible, bool notify, std::string spawntable, int duration)
|
|
{
|
|
time_t const birthEpoch = ::time(NULL);
|
|
time_t const endEpoch = birthEpoch + (duration * 60); // Duration is in minutes.
|
|
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_NAME, name);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_PLANET, Unicode::narrowToWide(planet));
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_GEOMETRY, geometry);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MINX, minX);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MINY, minZ);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MAXX, maxX);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MAXY, maxZ);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_PVP, pvp);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_GEOGRAPHY, geography);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MIN_DIFFICULTY, minDifficulty);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MAX_DIFFICULTY, maxDifficulty);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_SPAWN, spawnable);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MISSION, mission);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_BUILDABLE, buildable);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MUNICIPAL, municipal);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_VISIBLE, static_cast<int>(visible));
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_NOTIFY, static_cast<int>(notify));
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_SPAWNTABLE, spawntable);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_BIRTH, static_cast<int>(birthEpoch));
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_DURATION, duration);
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MAXDURATION, duration + (duration/3)); // Max duration is an extra 30% of the time.
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_READABLE_BIRTH, CalendarTime::convertEpochToTimeStringGMT_YYYYMMDDHHMMSS(birthEpoch));
|
|
object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_READABLE_DEATH, CalendarTime::convertEpochToTimeStringGMT_YYYYMMDDHHMMSS(endEpoch));
|
|
return true;
|
|
} // RegionMaster::setDynamicRegionObjectData
|
|
|
|
//----------------------------------------------------------------------
|
|
|