diff --git a/CMakeLists.txt b/CMakeLists.txt index 830b23e0..b5b60f31 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,7 @@ find_package(Perl REQUIRED) find_package(STLPort REQUIRED) find_package(ZLib REQUIRED) -#include_directories(${STLPORT_INCLUDE_DIR}) +include_directories(${STLPORT_INCLUDE_DIR}) add_subdirectory(external) add_subdirectory(engine) diff --git a/engine/server/library/CMakeLists.txt b/engine/server/library/CMakeLists.txt index 843c0131..35775a7c 100644 --- a/engine/server/library/CMakeLists.txt +++ b/engine/server/library/CMakeLists.txt @@ -3,5 +3,6 @@ add_subdirectory(serverGame) add_subdirectory(serverKeyShare) add_subdirectory(serverMetrics) add_subdirectory(serverNetworkMessages) +add_subdirectory(serverPathfinding) add_subdirectory(serverScript) add_subdirectory(serverUtility) diff --git a/engine/server/library/serverGame/src/CMakeLists.txt b/engine/server/library/serverGame/src/CMakeLists.txt index 2cc5a96b..bc854643 100644 --- a/engine/server/library/serverGame/src/CMakeLists.txt +++ b/engine/server/library/serverGame/src/CMakeLists.txt @@ -714,32 +714,41 @@ endif() include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/shared ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedCollision/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedCommandParser/include/public ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedDebug/include/public ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFile/include/public ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundation/include/public ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundationTypes/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFractal/include/public ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedGame/include/public ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedLog/include/public ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMath/include/public ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMathArchive/include/public ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMemoryManager/include/public ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMessageDispatch/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedNetwork/include/public ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedNetworkMessages/include/public ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedObject/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedPathfinding/include/public ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedRandom/include/public ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedSkillSystem/include/public ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedTerrain/include/public ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedUtility/include/public + ${SWG_ENGINE_SOURCE_DIR}/server/library/serverMetrics/include/public ${SWG_ENGINE_SOURCE_DIR}/server/library/serverNetworkMessages/include/public + ${SWG_ENGINE_SOURCE_DIR}/server/library/serverPathfinding/include/public + ${SWG_ENGINE_SOURCE_DIR}/server/library/serverScript/include/public ${SWG_ENGINE_SOURCE_DIR}/server/library/serverUtility/include/public ${SWG_GAME_SOURCE_DIR}/shared/library/swgSharedUtility/include/public ${SWG_EXTERNALS_SOURCE_DIR}/ours/library/archive/include + ${SWG_EXTERNALS_SOURCE_DIR}/ours/library/fileInterface/include/public ${SWG_EXTERNALS_SOURCE_DIR}/ours/library/localization/include ${SWG_EXTERNALS_SOURCE_DIR}/ours/library/localizationArchive/include/public ${SWG_EXTERNALS_SOURCE_DIR}/ours/library/singleton/include ${SWG_EXTERNALS_SOURCE_DIR}/ours/library/unicode/include ${SWG_EXTERNALS_SOURCE_DIR}/ours/library/unicodeArchive/include/public ${Boost_INCLUDE_DIR} + ${JNI_INCLUDE_DIRS} ) add_custom_command( diff --git a/engine/server/library/serverPathfinding/CMakeLists.txt b/engine/server/library/serverPathfinding/CMakeLists.txt new file mode 100644 index 00000000..4b074b1c --- /dev/null +++ b/engine/server/library/serverPathfinding/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 2.8) + +project(serverPathfinding) + +if(WIN32) + add_definitions(/D_CRT_SECURE_NO_WARNINGS) +endif() + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/public) + +add_subdirectory(src) diff --git a/engine/server/library/serverPathfinding/include/public/serverPathfinding/CityPathGraph.h b/engine/server/library/serverPathfinding/include/public/serverPathfinding/CityPathGraph.h new file mode 100644 index 00000000..e0fa49fd --- /dev/null +++ b/engine/server/library/serverPathfinding/include/public/serverPathfinding/CityPathGraph.h @@ -0,0 +1 @@ +#include "../../src/shared/CityPathGraph.h" diff --git a/engine/server/library/serverPathfinding/include/public/serverPathfinding/CityPathGraphManager.h b/engine/server/library/serverPathfinding/include/public/serverPathfinding/CityPathGraphManager.h new file mode 100644 index 00000000..ba9d3b12 --- /dev/null +++ b/engine/server/library/serverPathfinding/include/public/serverPathfinding/CityPathGraphManager.h @@ -0,0 +1 @@ +#include "../../src/shared/CityPathGraphManager.h" diff --git a/engine/server/library/serverPathfinding/include/public/serverPathfinding/CityPathNode.h b/engine/server/library/serverPathfinding/include/public/serverPathfinding/CityPathNode.h new file mode 100644 index 00000000..75b02ccf --- /dev/null +++ b/engine/server/library/serverPathfinding/include/public/serverPathfinding/CityPathNode.h @@ -0,0 +1 @@ +#include "../../src/shared/CityPathNode.h" diff --git a/engine/server/library/serverPathfinding/include/public/serverPathfinding/FirstServerPathfinding.h b/engine/server/library/serverPathfinding/include/public/serverPathfinding/FirstServerPathfinding.h new file mode 100644 index 00000000..a8f38141 --- /dev/null +++ b/engine/server/library/serverPathfinding/include/public/serverPathfinding/FirstServerPathfinding.h @@ -0,0 +1 @@ +#include "../../src/shared/FirstServerPathfinding.h" diff --git a/engine/server/library/serverPathfinding/include/public/serverPathfinding/PathAutoGenerator.h b/engine/server/library/serverPathfinding/include/public/serverPathfinding/PathAutoGenerator.h new file mode 100644 index 00000000..16320cbd --- /dev/null +++ b/engine/server/library/serverPathfinding/include/public/serverPathfinding/PathAutoGenerator.h @@ -0,0 +1 @@ +#include "../../src/shared/PathAutoGenerator.h" diff --git a/engine/server/library/serverPathfinding/include/public/serverPathfinding/ServerPathBuildManager.h b/engine/server/library/serverPathfinding/include/public/serverPathfinding/ServerPathBuildManager.h new file mode 100644 index 00000000..7398dde0 --- /dev/null +++ b/engine/server/library/serverPathfinding/include/public/serverPathfinding/ServerPathBuildManager.h @@ -0,0 +1 @@ +#include "../../src/shared/ServerPathBuildManager.h" diff --git a/engine/server/library/serverPathfinding/include/public/serverPathfinding/ServerPathBuilder.h b/engine/server/library/serverPathfinding/include/public/serverPathfinding/ServerPathBuilder.h new file mode 100644 index 00000000..f1355cbd --- /dev/null +++ b/engine/server/library/serverPathfinding/include/public/serverPathfinding/ServerPathBuilder.h @@ -0,0 +1 @@ +#include "../../src/shared/ServerPathBuilder.h" diff --git a/engine/server/library/serverPathfinding/include/public/serverPathfinding/ServerPathfinding.h b/engine/server/library/serverPathfinding/include/public/serverPathfinding/ServerPathfinding.h new file mode 100644 index 00000000..b34e1dde --- /dev/null +++ b/engine/server/library/serverPathfinding/include/public/serverPathfinding/ServerPathfinding.h @@ -0,0 +1 @@ +#include "../../src/shared/ServerPathfinding.h" diff --git a/engine/server/library/serverPathfinding/include/public/serverPathfinding/ServerPathfindingConstants.h b/engine/server/library/serverPathfinding/include/public/serverPathfinding/ServerPathfindingConstants.h new file mode 100644 index 00000000..76f88c9d --- /dev/null +++ b/engine/server/library/serverPathfinding/include/public/serverPathfinding/ServerPathfindingConstants.h @@ -0,0 +1 @@ +#include "../../src/shared/ServerPathfindingConstants.h" diff --git a/engine/server/library/serverPathfinding/include/public/serverPathfinding/ServerPathfindingMessaging.h b/engine/server/library/serverPathfinding/include/public/serverPathfinding/ServerPathfindingMessaging.h new file mode 100644 index 00000000..eadfe3fd --- /dev/null +++ b/engine/server/library/serverPathfinding/include/public/serverPathfinding/ServerPathfindingMessaging.h @@ -0,0 +1 @@ +#include "../../src/shared/ServerPathfindingMessaging.h" diff --git a/engine/server/library/serverPathfinding/include/public/serverPathfinding/ServerPathfindingNotification.h b/engine/server/library/serverPathfinding/include/public/serverPathfinding/ServerPathfindingNotification.h new file mode 100644 index 00000000..4b813fe9 --- /dev/null +++ b/engine/server/library/serverPathfinding/include/public/serverPathfinding/ServerPathfindingNotification.h @@ -0,0 +1 @@ +#include "../../src/shared/ServerPathfindingNotification.h" diff --git a/engine/server/library/serverPathfinding/include/public/serverPathfinding/SetupServerPathfinding.h b/engine/server/library/serverPathfinding/include/public/serverPathfinding/SetupServerPathfinding.h new file mode 100644 index 00000000..9f0e2c82 --- /dev/null +++ b/engine/server/library/serverPathfinding/include/public/serverPathfinding/SetupServerPathfinding.h @@ -0,0 +1 @@ +#include "../../src/shared/SetupServerPathfinding.h" diff --git a/engine/server/library/serverPathfinding/src/CMakeLists.txt b/engine/server/library/serverPathfinding/src/CMakeLists.txt new file mode 100644 index 00000000..f1127c72 --- /dev/null +++ b/engine/server/library/serverPathfinding/src/CMakeLists.txt @@ -0,0 +1,71 @@ + +set(SHARED_SOURCES + shared/CityPathGraph.cpp + shared/CityPathGraph.h + shared/CityPathGraphManager.cpp + shared/CityPathGraphManager.h + shared/CityPathNode.cpp + shared/CityPathNode.h + shared/FirstServerPathfinding.h + shared/PathAutoGenerator.cpp + shared/PathAutoGenerator.h + shared/ServerPathBuilder.cpp + shared/ServerPathBuilder.h + shared/ServerPathBuildManager.cpp + shared/ServerPathBuildManager.h + shared/ServerPathfindingConstants.cpp + shared/ServerPathfindingConstants.h + shared/ServerPathfinding.cpp + shared/ServerPathfinding.h + shared/ServerPathfindingMessaging.cpp + shared/ServerPathfindingMessaging.h + shared/ServerPathfindingNotification.cpp + shared/ServerPathfindingNotification.h + shared/SetupServerPathfinding.cpp + shared/SetupServerPathfinding.h +) + +if(WIN32) + set(PLATFORM_SOURCES + win32/FirstServerPathfinding.cpp + ) +else() + set(PLATFORM_SOURCES "") +endif() + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/shared + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedCollision/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedDebug/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFile/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundation/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundationTypes/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedGame/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMath/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMathArchive/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMemoryManager/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMessageDispatch/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedNetworkMessages/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedObject/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedPathfinding/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedRandom/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedSkillSystem/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedTerrain/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedUtility/include/public + ${SWG_ENGINE_SOURCE_DIR}/server/library/serverGame/include/public + ${SWG_ENGINE_SOURCE_DIR}/server/library/serverNetworkMessages/include/public + ${SWG_ENGINE_SOURCE_DIR}/server/library/serverScript/include/public + ${SWG_ENGINE_SOURCE_DIR}/server/library/serverUtility/include/public + ${SWG_GAME_SOURCE_DIR}/shared/library/swgSharedUtility/include/public + ${SWG_EXTERNALS_SOURCE_DIR}/ours/library/archive/include + ${SWG_EXTERNALS_SOURCE_DIR}/ours/library/localization/include + ${SWG_EXTERNALS_SOURCE_DIR}/ours/library/localizationArchive/include/public + ${SWG_EXTERNALS_SOURCE_DIR}/ours/library/unicode/include + ${SWG_EXTERNALS_SOURCE_DIR}/ours/library/unicodeArchive/include/public + ${Boost_INCLUDE_DIR} +) + +add_library(serverPathfinding STATIC + ${SHARED_SOURCES} + ${PLATFORM_SOURCES} +) diff --git a/engine/server/library/serverPathfinding/src/shared/CityPathGraph.cpp b/engine/server/library/serverPathfinding/src/shared/CityPathGraph.cpp new file mode 100644 index 00000000..2f14d0ac --- /dev/null +++ b/engine/server/library/serverPathfinding/src/shared/CityPathGraph.cpp @@ -0,0 +1,740 @@ +// ====================================================================== +// +// CityPathGraph.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "serverPathfinding/FirstServerPathfinding.h" +#include "serverPathfinding/CityPathGraph.h" + +#include "serverPathfinding/CityPathNode.h" +#include "serverPathfinding/ServerPathfindingConstants.h" + +#include "sharedCollision/CollisionWorld.h" +#include "sharedCollision/Containment2d.h" + +#include "sharedFoundation/DynamicVariableList.h" + +#include "sharedMath/AxialBox.h" +#include "sharedMath/SphereTree.h" + +#include "sharedObject/CellProperty.h" + +#include "sharedPathfinding/ConfigSharedPathfinding.h" + +#include "Unicode.h" +#include "UnicodeUtils.h" + +#include +#include + +class PathNodeSphereAccessor; + +typedef SphereTree PathNodeTree; + +float g_linkDistance = 40.0f; + +// ---------- + +class PathNodeSphereAccessor: public BaseSphereTreeAccessor +{ +public: + + static Sphere const getExtent(PathNode const * const node) + { + return Sphere(node->getPosition_p(), 0.5f); + } + + static char const *getDebugName(PathNode const * const node) + { + //@todo - make this return the path node name if there is one + + UNREF(node); + + return "pathNode"; + } + +}; + + +// ====================================================================== + +CityPathGraph::CityPathGraph ( int cityToken ) +: DynamicPathGraph(PGT_City), + m_nodeTree( new PathNodeTree ), + m_namedNodes( new std::map >), + m_token(cityToken), + m_dirtyBoxes( new BoxList() ) +{ +} + +CityPathGraph::~CityPathGraph() +{ + delete m_namedNodes; + m_namedNodes = NULL; + + delete m_nodeTree; + m_nodeTree = NULL; + + delete m_dirtyBoxes; + m_dirtyBoxes = NULL; +} + +// ---------------------------------------------------------------------- + +int CityPathGraph::addNode ( DynamicPathNode * newNode ) +{ + CityPathNode * cityNode = dynamic_cast(newNode); + + NOT_NULL(cityNode); + + int index = DynamicPathGraph::addNode(newNode); + + SpatialHandle * handle = m_nodeTree->addObject( cityNode ); + if (handle != NULL) + { + if (cityNode->getName() != Unicode::emptyString) + { + std::map >::iterator found = m_namedNodes->find(cityNode->getName()); + if (found == m_namedNodes->end()) + found = m_namedNodes->insert(std::make_pair(cityNode->getName(), std::set())).first; + found->second.insert(cityNode); + } + } + + cityNode->setSpatialHandle( handle ); + + // ---------- + + bool dirty = ConfigSharedPathfinding::getEnableDirtyBoxes() && isDirty(cityNode->getPosition_p()); + + ServerObject const * source = cityNode->getSourceObject(); + + if(source && source->getObjVars().hasItem(OBJVAR_PATHFINDING_WAYPOINT_EDGES) && !dirty) + { + cityNode->loadEdgesFromObjvars(); + } + else + { + relinkNode(cityNode->getIndex()); + + cityNode->saveAllData(); + } + + return index; +} + +// ---------------------------------------------------------------------- + +void CityPathGraph::removeNode ( int nodeIndex ) +{ + CityPathNode * cityNode = _getNode(nodeIndex); + NOT_NULL(cityNode); + + SpatialHandle * handle = cityNode->getSpatialHandle(); + + if (m_namedNodes != NULL) + { + std::map >::iterator found = m_namedNodes->find(cityNode->getName()); + if (found != m_namedNodes->end()) + { + found->second.erase(cityNode); + if (found->second.empty()) + m_namedNodes->erase(found); + } + } + m_nodeTree->removeObject( handle ); + + cityNode->setSpatialHandle(NULL); + + DynamicPathGraph::removeNode(nodeIndex); +} + +// ---------------------------------------------------------------------- +// When a waypoint is permanently destroyed from a city graph, we need to +// make sure that all neighboring nodes are relinked and thatthe edge +// lists on the objvars are updated as well. + +void CityPathGraph::destroyNode ( int nodeIndex ) +{ + CityPathNode * cityNode = _getNode(nodeIndex); + + if(cityNode == NULL) return; + + // ---------- + // Remember which nodes were adjacent to the node we're removing + + std::vector neighborList; + + int edgeCount = cityNode->getEdgeCount(); + + int i; + + for(i = 0; i < edgeCount; i++) + { + int neighborIndex = cityNode->getNeighbor(i); + + neighborList.push_back( neighborIndex ); + } + + // ---------- + // Update the sphere tree + + SpatialHandle * handle = cityNode->getSpatialHandle(); + + m_nodeTree->removeObject( handle ); + + cityNode->setSpatialHandle(NULL); + + // ---------- + // Remove the node + + removeNode( nodeIndex ); + + // ---------- + // Relink the neighbors and store their new edge lists back into + // the objvars. Do this in two passes to ensure that the edges + // aren't corrupted (relinking a node can change the edge lists + // of other nodes) + + for(i = 0; i < edgeCount; i++) + { + relinkNode(neighborList[i]); + } + + for(i = 0; i < edgeCount; i++) + { + CityPathNode * neighborNode = _getNode(neighborList[i]); + + if(neighborNode) neighborNode->saveEdgesToObjvars(); + } +} + +// ---------------------------------------------------------------------- + +void CityPathGraph::moveNode ( int nodeIndex, Vector const & newPosition ) +{ + CityPathNode * cityNode = _getNode(nodeIndex); + + if(cityNode == NULL) return; + + // ---------- + // Remember which nodes were adjacent to the node we're removing + + std::vector oldNeighborList; + + int oldEdgeCount = cityNode->getEdgeCount(); + + int i; + + for(i = 0; i < oldEdgeCount; i++) + { + int neighborIndex = cityNode->getNeighbor(i); + + oldNeighborList.push_back( neighborIndex ); + } + + // ---------- + // Update the sphere tree + + m_nodeTree->move(cityNode->getSpatialHandle()); + + // ---------- + // Move the node + + DynamicPathGraph::moveNode(nodeIndex,newPosition); + + // ---------- + // Relink the old neighbors and store their new edge lists back into + // the objvars. Do this in two passes to ensure that the edges + // aren't corrupted (relinking a node can change the edge lists + // of other nodes) + + for(i = 0; i < oldEdgeCount; i++) + { + relinkNode(oldNeighborList[i]); + } + + for(i = 0; i < oldEdgeCount; i++) + { + CityPathNode * oldNeighborNode = _getNode(oldNeighborList[i]); + + if(oldNeighborNode) oldNeighborNode->saveEdgesToObjvars(); + } + + cityNode->saveAllData(); +} + +// ---------------------------------------------------------------------- + +void CityPathGraph::relinkNode ( int nodeIndex ) +{ + CityPathNode * nodeA = _getNode(nodeIndex); + + if(nodeA == NULL) return; + + // ---------- + + //int oldNeighborCode = getNeighborCode(nodeIndex); + + unlinkNode(nodeIndex); + + PathNodeType typeA = nodeA->getType(); + + // ---------- + // Building nodes always connect only to their entrances + + if(typeA == PNT_CityBuilding) + { + int listSize = getNodeCount(); + + for(int i = 0; i < listSize; i++) + { + CityPathNode * nodeB = _getNode(i); + + if(nodeB == NULL) continue; + if(nodeA == nodeB) continue; + + PathNodeType typeB = nodeB->getType(); + + if(typeB != PNT_CityBuildingEntrance) continue; + + if(nodeA->getCreatorObject() == NULL) continue; + + if(nodeB->getCreatorObject() == NULL) continue; + + if(nodeA->getCreatorObject() != nodeB->getCreatorObject()) continue; + + // ---------- + // A is a building, B is an entrance, and they have the same creator + + nodeA->addEdge( nodeB->getIndex() ); + nodeB->addEdge( nodeA->getIndex() ); + } + + // return so we don't try and connect to any other nodes + + return; + } + + // ---------- + // Building entrances _must_ connect to their building, and may connect + // to other nodes as well + + if(typeA == PNT_CityBuildingEntrance) + { + int listSize = getNodeCount(); + + for(int i = 0; i < listSize; i++) + { + CityPathNode * nodeB = _getNode(i); + + if(nodeB == NULL) continue; + if(nodeA == nodeB) continue; + + PathNodeType typeB = nodeB->getType(); + + if(typeB != PNT_CityBuilding) continue; + + if(nodeA->getCreatorObject() == NULL) continue; + + if(nodeB->getCreatorObject() == NULL) continue; + + if(nodeA->getCreatorObject() != nodeB->getCreatorObject()) continue; + + // ---------- + // A is an entrance, B is a building, and they have the same creator + + nodeA->addEdge( nodeB->getIndex() ); + nodeB->addEdge( nodeA->getIndex() ); + } + } + + // ---------- + + static std::vector results; + + results.clear(); + + m_nodeTree->findInRange( nodeA->getPosition_p(), g_linkDistance, results ); + + int resultCount = results.size(); + + int i; + + for(i = 0; i < resultCount; i++) + { + CityPathNode * nodeB = static_cast(results[i]); + + if(nodeB == NULL) continue; + if(nodeA == nodeB) continue; + + PathNodeType typeB = nodeB->getType(); + + if(typeB == PNT_CityBuilding) continue; + + Vector posA = nodeA->getPosition_p(); + Vector posB = nodeB->getPosition_p(); + + if(posA.magnitudeBetweenSquared(posB) < (g_linkDistance * g_linkDistance)) + { + bool moveAB = (CollisionWorld::canMove( CellProperty::getWorldCellProperty(), posA, posB, 0.5f, true, true, false ) == CMR_MoveOK); + bool moveBA = (CollisionWorld::canMove( CellProperty::getWorldCellProperty(), posB, posA, 0.5f, true, true, false ) == CMR_MoveOK); + + if(moveAB && moveBA) + { + nodeA->addEdge( nodeB->getIndex() ); + nodeB->addEdge( nodeA->getIndex() ); + } + else + { + // nodes can't be connected + + continue; + } + } + } + + // ---------- + // Linking done, prune redundant edges + + IGNORE_RETURN( nodeA->markRedundantEdges() ); + IGNORE_RETURN( nodeA->removeMarkedEdges() ); + + // this has to be done in two passes, otherwise node A's neighbor list could be changing + // as we prune edges. + + static std::vector neighborList; + + neighborList.clear(); + + int edgeCount = nodeA->getEdgeCount(); + + for(i = 0; i < edgeCount; i++) + { + neighborList.push_back( nodeA->getNeighbor(i) ); + } + + for(i = 0; i < edgeCount; i++) + { + CityPathNode * neighborNode = _getNode(neighborList[i]); + + if(neighborNode != NULL) + { + neighborNode->markRedundantEdges(); + neighborNode->removeMarkedEdges(); + } + } + + // ---------- + + /* + int newNeighborCode = getNeighborCode(nodeIndex); + + if(oldNeighborCode == newNeighborCode) + { + DEBUG_REPORT_LOG(true,("neighbors were the same\n")); + } + else + { + DEBUG_REPORT_LOG(true,("neighbors were different\n")); + } + */ +} + +// ---------------------------------------------------------------------- + +CityPathNode * CityPathGraph::_getNode ( int whichNode ) +{ + return safe_cast(getNode(whichNode)); +} + +// ---------- + +CityPathNode const * CityPathGraph::_getNode ( int whichNode ) const +{ + return safe_cast(getNode(whichNode)); +} + +// ---------------------------------------------------------------------- + +CityPathNode * CityPathGraph::findNodeForObject ( ServerObject const & object ) +{ + int nodeCount = getNodeCount(); + + for (int i = 0; i < nodeCount; i++) + { + CityPathNode * node = _getNode(i); + + if(node == NULL) continue; + + ServerObject const * source = node->getSourceObject(); + + if(source == NULL) continue; + + if(source == &object) + { + return node; + } + } + + return NULL; +} + +// ---------------------------------------------------------------------- + +CityPathNode const * CityPathGraph::findNodeForObject ( ServerObject const & object ) const +{ + int nodeCount = getNodeCount(); + + for(int i = 0; i < nodeCount; i++) + { + CityPathNode const * node = _getNode(i); + + if(node == NULL) continue; + + ServerObject const * source = node->getSourceObject(); + + if(source == NULL) continue; + + if(source == &object) + { + return node; + } + } + + return NULL; +} + +// ---------------------------------------------------------------------- + +CityPathNode * CityPathGraph::findNearestNodeForName( Unicode::String const & nodeName, Vector const & pos ) +{ + if (m_namedNodes == NULL) + return NULL; + + std::map >::iterator found = m_namedNodes->find(nodeName); + if (found != m_namedNodes->end() && !found->second.empty()) + { + std::set & nodes = found->second; + if (nodes.size() == 1) + return *(nodes.begin()); + + CityPathNode * node = NULL; + float distance = FLT_MAX; + for (std::set::iterator i = nodes.begin(); i != nodes.end(); ++i) + { + float testDistance = pos.magnitudeBetweenSquared((*i)->getPosition_w()); + if (node == NULL || testDistance < distance) + { + distance = testDistance; + node = *i; + } + } + return node; + } + + return NULL; +} + +// ---------------------------------------------------------------------- + +CityPathNode const * CityPathGraph::findNearestNodeForName( Unicode::String const & nodeName, Vector const & pos ) const +{ + if (m_namedNodes == NULL) + return NULL; + + std::map >::const_iterator found = m_namedNodes->find(nodeName); + if (found != m_namedNodes->end() && !found->second.empty()) + { + std::set const & nodes = found->second; + if (nodes.size() == 1) + return *(nodes.begin()); + + CityPathNode const * node = NULL; + float distance = FLT_MAX; + for (std::set::const_iterator i = nodes.begin(); i != nodes.end(); ++i) + { + float testDistance = pos.magnitudeBetweenSquared((*i)->getPosition_w()); + if (node == NULL || testDistance < distance) + { + distance = testDistance; + node = *i; + } + } + return node; + } + + return NULL; +} + +// ---------------------------------------------------------------------- + +int CityPathGraph::findNearestNode ( Vector const & position ) const +{ + PathNode * temp = NULL; + + float dummy1 = REAL_MAX; + float dummy2 = REAL_MAX; + + if( m_nodeTree->findClosest(position,REAL_MAX,temp,dummy1,dummy2) ) + { + return temp->getIndex(); + } + else + { + return -1; + } +} + +//@todo - I have no idea why, but the compiler bitches if this isn't here. + +int CityPathGraph::findNearestNode ( PathNodeType type, Vector const & position_p ) const +{ + return PathGraph::findNearestNode(type,position_p); +} + +// ---------------------------------------------------------------------- + +void CityPathGraph::findNodesInRange ( Vector const & position_p, float range, PathNodeList & results ) const +{ + m_nodeTree->findInRange(position_p,range,results); +} + +// ---------------------------------------------------------------------- + +void CityPathGraph::saveGraph ( void ) +{ + int nodeCount = getNodeCount(); + + for(int i = 0; i < nodeCount; i++) + { + CityPathNode * node = _getNode(i); + + if(node) node->saveToObjvars(); + } +} + +// ---------------------------------------------------------------------- + +bool CityPathGraph::sanityCheck ( bool doWarnings ) const +{ + bool sane = true; + + int nodeCount = getNodeCount(); + + for(int i = 0; i < nodeCount; i++) + { + CityPathNode const * node = _getNode(i); + + if(node) + { + sane &= node->sanityCheck(doWarnings); + } + } + + return sane; +} + +// ---------------------------------------------------------------------- + +void CityPathGraph::reloadPathNodes ( void ) +{ + int nodeCount = getNodeCount(); + + for(int i = 0; i < nodeCount; i++) + { + CityPathNode * node = _getNode(i); + + if(node) node->reload(); + } +} + +// ---------------------------------------------------------------------- + +ServerObject const * CityPathGraph::getCreator ( void ) const +{ + return safe_cast(m_creatorId.getObject()); +} + +void CityPathGraph::setCreator ( NetworkId const & creatorId ) +{ + m_creatorId = creatorId; +} + +// ---------------------------------------------------------------------- + +void CityPathGraph::addDirtyBox ( AxialBox const & box ) +{ + if(ConfigSharedPathfinding::getEnableDirtyBoxes()) + { + m_dirtyBoxes->push_back(box); + } +} + +// ---------- + +bool CityPathGraph::isDirty ( Vector const & point_w ) const +{ + int count = m_dirtyBoxes->size(); + + for(int i = 0; i < count; i++) + { + AxialBox const & box = m_dirtyBoxes->at(i); + + if(Containment2d::TestPointABox(point_w,box)) + { + return true; + } + } + + return false; +} + +// ---------------------------------------------------------------------- + +float CityPathGraph::getLinkDistance ( void ) +{ + return g_linkDistance; +} + +void CityPathGraph::setLinkDistance ( float dist ) +{ + g_linkDistance = dist; +} + +// ---------------------------------------------------------------------- +// the neighbor code has to be order-independent, so to make the code +// we cast the addresses of all the neighbors to ints, multiply them +// by a random large prime number, then xor the bits together. + +int CityPathGraph::getNeighborCode ( int whichNode ) const +{ + CityPathNode const * node = _getNode(whichNode); + + if(node == NULL) return 0; + + int edgeCount = node->getEdgeCount(); + + int code = 0; + + for(int i = 0; i < edgeCount; i++) + { + int neighborId = node->getNeighbor(i); + + CityPathNode const * neighbor = _getNode(neighborId); + + if(neighbor == NULL) continue; + + int neighborInt = reinterpret_cast(neighbor); + + int mungedInt = neighborInt * 1295183; + + code ^= mungedInt; + } + + return code; +} + +// ---------------------------------------------------------------------- diff --git a/engine/server/library/serverPathfinding/src/shared/CityPathGraph.h b/engine/server/library/serverPathfinding/src/shared/CityPathGraph.h new file mode 100644 index 00000000..d39dae83 --- /dev/null +++ b/engine/server/library/serverPathfinding/src/shared/CityPathGraph.h @@ -0,0 +1,111 @@ +// ====================================================================== +// +// CityPathGraph.h +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_CityPathGraph_H +#define INCLUDED_CityPathGraph_H + +#include "sharedPathfinding/DynamicPathGraph.h" + +#include "sharedObject/CachedNetworkId.h" + +class CityPathNode; +class ServerObject; +class PathNodeSphereAccessor; +class AxialBox; + +template +class SphereTree; + +typedef SphereTree PathNodeTree; + +typedef stdvector::fwd BoxList; + +// ====================================================================== +// CityPathGraph is a DynamicPathGraph with some specializations that +// allow it to be constructed from objvars on server-side waypoint +// objects + +class CityPathGraph : public DynamicPathGraph +{ +public: + + CityPathGraph ( int cityToken ); + + virtual ~CityPathGraph(); + + // ---------- + + virtual int addNode ( DynamicPathNode * newNode ); + virtual void removeNode ( int nodeIndex ); + virtual void moveNode ( int nodeIndex, Vector const & newPosition ); + + virtual void relinkNode ( int nodeIndex ); + virtual void destroyNode ( int nodeIndex ); + + // ---------- + + CityPathNode * _getNode ( int whichNode ); + CityPathNode const * _getNode ( int whichNode ) const; + + // ---------- + + CityPathNode * findNodeForObject ( ServerObject const & object ); + CityPathNode const * findNodeForObject ( ServerObject const & object ) const; + CityPathNode * findNearestNodeForName ( Unicode::String const & nodeName, Vector const & pos ); + CityPathNode const * findNearestNodeForName ( Unicode::String const & nodeName, Vector const & pos ) const; + + int findNearestNode ( Vector const & position_p ) const; + int findNearestNode ( PathNodeType type, Vector const & position_p ) const; + + void findNodesInRange ( Vector const & position_p, float range, PathNodeList & results ) const; + + // ---------- + + void saveGraph ( void ); + bool sanityCheck ( bool doWarnings ) const; + + void reloadPathNodes ( void ); + + int getCityToken ( void ) const; + + // ---------- + + ServerObject const * getCreator ( void ) const; + void setCreator ( NetworkId const & creator ); + + void addDirtyBox ( AxialBox const & box ); + bool isDirty ( Vector const & point_w ) const; + + static float getLinkDistance ( void ); + static void setLinkDistance ( float dist ); + + int getNeighborCode ( int whichNode ) const; + +protected: + + PathNodeTree * m_nodeTree; + //@todo: order the CityPathNodes below in such a way as to make searching for the closest one quick + stdmap::fwd >::fwd * m_namedNodes; + int m_token; + + CachedNetworkId m_creatorId; + + BoxList * m_dirtyBoxes; +}; + +// ---------- + +inline int CityPathGraph::getCityToken ( void ) const +{ + return m_token; +} + +// ====================================================================== + +#endif + diff --git a/engine/server/library/serverPathfinding/src/shared/CityPathGraphManager.cpp b/engine/server/library/serverPathfinding/src/shared/CityPathGraphManager.cpp new file mode 100644 index 00000000..af8e7e5e --- /dev/null +++ b/engine/server/library/serverPathfinding/src/shared/CityPathGraphManager.cpp @@ -0,0 +1,1180 @@ +// ====================================================================== +// +// CityPathGraphManager.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "serverPathfinding/FirstServerPathfinding.h" +#include "serverPathfinding/CityPathGraphManager.h" + +#include "serverGame/BuildingObject.h" +#include "serverGame/PlanetObject.h" +#include "serverGame/Region.h" +#include "serverGame/RegionMaster.h" +#include "serverGame/ServerObject.h" +#include "serverGame/ServerUniverse.h" +#include "serverGame/ServerWorld.h" + +#include "serverPathfinding/CityPathGraph.h" +#include "serverPathfinding/CityPathNode.h" +#include "serverPathfinding/ServerPathfindingConstants.h" +#include "serverPathfinding/ServerPathfindingMessaging.h" +#include "serverPathfinding/ServerPathfindingNotification.h" + +#include "sharedCollision/CollisionProperty.h" +#include "sharedCollision/Floor.h" +#include "sharedCollision/FloorMesh.h" +#include "sharedCollision/Containment3d.h" + +#include "sharedDebug/PerformanceTimer.h" + +#include "sharedFoundation/Crc.h" +#include "sharedFoundation/DynamicVariable.h" +#include "sharedFoundation/DynamicVariableList.h" +#include "sharedFoundation/NetworkId.h" + +#include "sharedMath/Vector2d.h" +#include "sharedMath/Vector.h" +#include "sharedMath/MultiShape.h" +#include "sharedMath/AxialBox.h" +#include "sharedMath/Cylinder.h" +#include "sharedMath/MxCifQuadTreeBounds.h" +#include "sharedMath/ShapeUtils.h" + +#include "sharedObject/CellProperty.h" + +#include "sharedPathfinding/ConfigSharedPathfinding.h" + +#include "sharedTerrain/TerrainObject.h" + +#include "StringId.h" + +#include +#include +#include +#include + +struct RegionCacheEntry +{ + RegionCacheEntry ( void ) + : m_shape(), m_graph(NULL) + { + } + + RegionCacheEntry ( MultiShape const & shape, CityPathGraph * graph ) + : m_shape(shape), m_graph(graph) + { + } + + MultiShape m_shape; + CityPathGraph * m_graph; +}; + +typedef std::vector RegionCache; +typedef std::vector NetworkIdList; +typedef std::vector NodeList; + +namespace CityPathGraphManagerNamespace +{ + StringId g_emptyStringId; + + Unicode::String g_emptyString; + Unicode::String g_defaultString(Unicode::narrowToWide("default")); + + float g_linkDistance; + + RegionCache g_regionCache; + + int g_scrubberGraphIndex = 0; + int g_scrubberNodeIndex = 0; + int g_scrubberPassCount = 0; +}; + +using namespace CityPathGraphManagerNamespace; + +// ====================================================================== + +void CityPathGraphManager::install ( void ) +{ +} + +void CityPathGraphManager::remove ( void ) +{ + int count = g_regionCache.size(); + + for(int i = 0; i < count; i++) + { + delete g_regionCache[i].m_graph; + } + + g_regionCache.clear(); +} + +// ---------------------------------------------------------------------- + +extern float pathScrubTime; + +void CityPathGraphManager::update ( float time ) +{ + pathScrubTime = 0.0f; + + PerformanceTimer timer; + + timer.start(); + + UNREF(time); + + if(ConfigSharedPathfinding::getEnablePathScrubber()) + { + // Scrub the path graphs - check for bad nodes and fix them + + if(g_regionCache.size() == 0) return; + + int graphCount = g_regionCache.size(); + + if(g_scrubberGraphIndex >= graphCount) + { + DEBUG_REPORT_LOG(true,("CityPathGraphManager path scrubber pass %d complete\n",g_scrubberPassCount)); + + g_scrubberGraphIndex = 0; + return; + } + + CityPathGraph * graph = g_regionCache[g_scrubberGraphIndex].m_graph; + + if(graph == NULL) return; + + if(g_scrubberNodeIndex >= graph->getNodeCount()) + { + g_scrubberNodeIndex = 0; + g_scrubberGraphIndex++; + return; + } + + CityPathNode * node = graph->_getNode(g_scrubberNodeIndex); + + g_scrubberNodeIndex++; + + if(node == NULL) return; + + if(!node->sanityCheck(false)) + { + graph->relinkNode(node->getIndex()); + node->saveAllData(); + ServerPathfindingMessaging::getInstance().sendNodeInfo(node); + } + } + + timer.stop(); + + pathScrubTime = timer.getElapsedTime(); +} + +// ---------------------------------------------------------------------- + +void CityPathGraphManager::sanityCheck ( void ) +{ + int count = g_regionCache.size(); + + for(int i = 0; i < count; i++) + { + g_regionCache[i].m_graph->sanityCheck(true); + } +} + +// ---------------------------------------------------------------------- + +class RegionTest +{ +public: + + int m_type; + + RegionTest( int type ) : m_type(type) {} + + bool operator () ( Region const * r ) const + { + return r->getGeography() != m_type; + } +}; + +// ---------------------------------------------------------------------- + +bool getRegionsWithTypeAtPoint( Vector const & point, int type, std::vector & results ) +{ + RegionMaster::getRegionsAtPoint(ServerWorld::getSceneId(), point.x, point.z, results); + + if(!results.empty()) + { + results.erase(std::remove_if(results.begin(),results.end(),RegionTest(type)),results.end()); + } + + return !results.empty(); +} + +// ---------------------------------------------------------------------- + +Region const * getCityRegionFor( Vector const & position ) +{ + static std::vector results; + + getRegionsWithTypeAtPoint( position, CITY_REGION_TYPE, results ); + + if(!results.empty()) + { + return results[0]; + } + + getRegionsWithTypeAtPoint( position, PATHFINDING_REGION_TYPE, results ); + + if(!results.empty()) + { + return results[0]; + } + + return NULL; +} + +// ---------------------------------------------------------------------- + +int getCityTokenFor ( Region const * region ) +{ + if(region == NULL) return -1; + + Unicode::String const & name = region->getName(); + + if(name.empty() || (name == g_defaultString)) + { + return -1; + } + else + { + int token = static_cast(Crc::calculate(Unicode::wideToNarrow(name).c_str())); + + if(token == -1) + { + DEBUG_FATAL(true,("CityPathGraphManager::getCityTokenFor - City name hashed to -1 (shouldn't happen)\n")); + } + + return token; + } +} + +// ---------- + +int getCityTokenFor( Vector const & position ) +{ + Region const * region = getCityRegionFor(position); + + return getCityTokenFor(region); +} + +// ---------------------------------------------------------------------- + +bool checkRegionCache ( Vector const & position, CityPathGraph * & outGraph ) +{ + int count = g_regionCache.size(); + + for(int i = 0; i < count; i++) + { + RegionCacheEntry & entry = g_regionCache[i]; + + if(Containment3d::Test(position,entry.m_shape)) + { + outGraph = entry.m_graph; + return true; + } + } + + return false; +} + +// ---------- + +bool addToRegionCache ( MultiShape const & shape, CityPathGraph * graph ) +{ + if(graph == NULL) return false; + + RegionCacheEntry entry(shape,graph); + + g_regionCache.push_back(entry); + + return true; +} + +// ---------- + +bool addToRegionCache ( Cylinder const & cylinder, CityPathGraph * graph ) +{ + MultiShape multiShape(cylinder); + + return addToRegionCache(multiShape,graph); +} + +// ---------- + +bool addToRegionCache ( AxialBox const & box, CityPathGraph * graph ) +{ + MultiShape multiShape(box); + + return addToRegionCache(multiShape,graph); +} + +// ---------- + +bool addToRegionCache ( Region const * region, CityPathGraph * graph ) +{ + if(region == NULL) return false; + if(graph == NULL) return false; + + MxCifQuadTreeBounds const * bounds = ®ion->getBounds(); + + if(bounds == NULL) return false; + + MxCifQuadTreeCircleBounds const * circleBounds = dynamic_cast(bounds); + + if(circleBounds) + { + Vector base( circleBounds->getCenterX(), -2000.0f, circleBounds->getCenterY() ); + float radius = circleBounds->getRadius(); + + Cylinder cylinder(base,radius,4000.0f); + + return addToRegionCache(cylinder,graph); + } + else + { + Vector min( bounds->getMinX(), -2000.0f, bounds->getMinY() ); + Vector max( bounds->getMaxX(), 2000.0f, bounds->getMaxY() ); + + AxialBox box(min,max); + + return addToRegionCache(box,graph); + } +} + +// ---------- + +bool removeFromRegionCache ( CityPathGraph * graph ) +{ + int count = g_regionCache.size(); + + for(int i = 0; i < count; i++) + { + RegionCacheEntry & entry = g_regionCache[i]; + + if(entry.m_graph == graph) + { + entry = g_regionCache.back(); + g_regionCache.resize(count - 1); + return true; + } + } + + return false; +} + +// ---------- + +CityPathGraph * createCityGraphFor ( MultiShape const & shape ) +{ + CityPathGraph * newGraph = new CityPathGraph(-1); + + addToRegionCache(shape,newGraph); + + return newGraph; +} + +CityPathGraph * createCityGraphFor ( Region const * region ) +{ + int token = getCityTokenFor(region); + + if(token == -1) return NULL; + + CityPathGraph * graph = new CityPathGraph(token); + + addToRegionCache(region,graph); + + return graph; +} + +CityPathGraph * createCityGraphFor ( ServerObject const * creator, MultiShape const & shape ) +{ + if(creator == NULL) return NULL; + + CityPathGraph * newGraph = new CityPathGraph(-1); + + newGraph->setCreator(creator->getNetworkId()); + + addToRegionCache(shape,newGraph); + + return newGraph; +} + +// ---------------------------------------------------------------------- + +CityPathGraph * _getCityGraphFor ( Vector const & position ) +{ + CityPathGraph * graph = NULL; + + if(checkRegionCache(position,graph)) + { + return graph; + } + else + { + Region const * region = getCityRegionFor(position); + + graph = createCityGraphFor(region); + + return graph; + } +} + +// ---------- + +CityPathGraph * _getCityGraphFor ( ServerObject const * object ) +{ + if(object == NULL) + { + return NULL; + } + else + { + return _getCityGraphFor(object->getPosition_w()); + } +} + +// ---------------------------------------------------------------------- + +CityPathNode * _getCityNodeFor ( ServerObject const * object, CityPathGraph * graph ) +{ + if(object == NULL) return NULL; + if(graph == NULL) return NULL; + + return graph->findNodeForObject(*object); +} + +// ---------- + +CityPathNode * _getCityNodeFor ( ServerObject const * object ) +{ + CityPathGraph * graph = _getCityGraphFor(object); + + if(graph == NULL) return NULL; + + return _getCityNodeFor(object,graph); +} + +// ---------------------------------------------------------------------- + +PathGraph const * _getExteriorGraph ( ServerObject const * object ) +{ + if(object == NULL) return NULL; + + CollisionProperty const * collision = object->getCollisionProperty(); + + if(collision == NULL) return NULL; + + Floor const * floor = collision->getFloor(); + + if(floor == NULL) return NULL; + + FloorMesh const * floorMesh = floor->getFloorMesh(); + + if(floorMesh == NULL) return NULL; + + PathGraph const * pathGraph = safe_cast(floorMesh->getPathGraph()); + + return pathGraph; +} + +// ---------------------------------------------------------------------- + +CityPathGraph const * CityPathGraphManager::getCityGraphFor ( ServerObject const * object ) +{ + return _getCityGraphFor(object); +} + +CityPathGraph const * CityPathGraphManager::getCityGraphFor ( Vector const & position ) +{ + return _getCityGraphFor(position); +} + +// ---------------------------------------------------------------------- + +CityPathNode const * CityPathGraphManager::getNamedNodeFor( ServerObject const & object, Unicode::String const & nodeName ) +{ + CityPathGraph const * cityGraph = getCityGraphFor(&object); + if (cityGraph == NULL) + return NULL; + + return cityGraph->findNearestNodeForName(nodeName, object.getPosition_w()); +} + +// ---------------------------------------------------------------------- + +bool CityPathGraphManager::getClosestPathNodePos ( ServerObject const * object, Vector & outPos ) +{ + if(object == NULL) return false; + + if(object->getParentCell() == CellProperty::getWorldCellProperty()) + { + CityPathGraph const * graph = getCityGraphFor(object); + + if(graph) + { + int closestIndex = graph->findNearestNode(object->getPosition_p()); + + if(closestIndex != -1) + { + PathNode const * node = graph->getNode(closestIndex); + + if(node) + { + outPos = node->getPosition_p(); + + return true; + } + } + } + } + + return false; +} + +// ---------------------------------------------------------------------- + +void CityPathGraphManager::addWaypoint ( ServerObject * sourceObject ) +{ + if(sourceObject == NULL) return; + + CityPathGraph * graph = _getCityGraphFor(sourceObject); + + if(graph == NULL) + { + return; + } + + // ---------- + + DynamicVariableList const & objvars = sourceObject->getObjVars(); + + CityPathNode * newNode = NULL; + + Vector sourcePos_w = sourceObject->getPosition_w(); + + float height = 0.0f; + + if(TerrainObject::getConstInstance ()->getHeightForceChunkCreation(sourcePos_w,height)) + { + if(height > sourcePos_w.y) + { + sourcePos_w.y = height; + } + } + + NetworkId sourceId = sourceObject->getNetworkId(); + + NetworkId creatorId; + + if( objvars.getItem(OBJVAR_PATHFINDING_WAYPOINT_CREATOR,creatorId) ) + { + newNode = new CityPathNode(sourcePos_w,sourceId,creatorId); + } + else + { + newNode = new CityPathNode(sourcePos_w,sourceId); + } + + + if(objvars.hasItem(OBJVAR_PATHFINDING)) + { + // minor hack - make objects that don't have their node type set default to CityWaypoint + + int type = PNT_Invalid; + + objvars.getItem(OBJVAR_PATHFINDING_WAYPOINT_TYPE,type); + + if(type == PNT_Invalid) + { + sourceObject->setObjVarItem(OBJVAR_PATHFINDING_WAYPOINT_TYPE, static_cast(PNT_CityWaypoint) ); + } + + newNode->loadInfoFromObjvars(); + } + else + { + newNode->setType(PNT_CityWaypoint); + newNode->setKey(-1); + + newNode->saveInfoToObjvars(); + } + + // ---------- + + IGNORE_RETURN( graph->addNode(newNode) ); + + ServerPathfindingMessaging::getInstance().sendNodeInfo(newNode); + ServerPathfindingMessaging::getInstance().sendNeighborInfo(newNode); +} + +// ---------------------------------------------------------------------- + +void CityPathGraphManager::removeWaypoint ( ServerObject * sourceObject ) +{ + CityPathGraph * graph = _getCityGraphFor(sourceObject); + + if(graph == NULL) return; + + CityPathNode * unloadingNode = _getCityNodeFor(sourceObject,graph); + + if(unloadingNode == NULL) return; + + // ---------- + + // Remember who was a neighbor of the node + + ServerPathfindingMessaging::getInstance().sendEraseNode(unloadingNode); + + std::vector oldNeighbors; + + int edgeCount = unloadingNode->getEdgeCount(); + + int i; + + for(i = 0; i < edgeCount; i++) + { + oldNeighbors.push_back( unloadingNode->getNeighbor(i) ); + } + + // Erase the node + + graph->removeNode(unloadingNode->getIndex()); + + // Update the neighbors of the deleted node on the client + + for(i = 0; i < edgeCount; i++) + { + CityPathNode * oldNeighbor = graph->_getNode(oldNeighbors[i]); + + if(oldNeighbor) ServerPathfindingMessaging::getInstance().sendNodeInfo( oldNeighbor ); + } + + // If the graph no longer has any nodes in it, destroy it and remove it from the map + + if(graph->getLiveNodeCount() == 0) + { + removeFromRegionCache(graph); + + delete graph; + } +} + +// ---------------------------------------------------------------------- +//@todo - This is inefficient, but waypoints shouldn't be moving much. + +void CityPathGraphManager::moveWaypoint ( ServerObject * sourceObject, Vector const & oldPosition ) +{ + UNREF(oldPosition); + + if(sourceObject == NULL) return; + + CityPathGraph * graph = _getCityGraphFor(sourceObject); + + if(graph == NULL) return; + + CityPathNode * node = _getCityNodeFor(sourceObject,graph); + + if(node == NULL) return; + + // ---------- + + std::vector oldNeighbors; + + int edgeCount = node->getEdgeCount(); + + int i; + + for(i = 0; i < edgeCount; i++) + { + oldNeighbors.push_back( node->getNeighbor(i) ); + } + + graph->moveNode( node->getIndex(), sourceObject->getPosition_w() ); + + ServerPathfindingMessaging::getInstance().sendNodeInfo( node ); + ServerPathfindingMessaging::getInstance().sendNeighborInfo( node ); + + for(i = 0; i < edgeCount; i++) + { + CityPathNode * oldNeighbor = graph->_getNode(oldNeighbors[i]); + + if(oldNeighbor) ServerPathfindingMessaging::getInstance().sendNodeInfo( oldNeighbor ); + } +} + +// ---------------------------------------------------------------------- + +void CityPathGraphManager::addBuilding ( BuildingObject * building ) +{ + if(building == NULL) return; + + CityPathGraph * graph = _getCityGraphFor(building); + + if(graph == NULL) + { + return; + } + + // ---------- + + NetworkIdList ids; + if (!building->getObjVars().getItem(OBJVAR_PATHFINDING_BUILDING_WAYPOINTS,ids)) + { + // Building hasn't spawned its waypoints. If we're supposed to do that + // automatically, do it now. + + if(ConfigSharedPathfinding::getAutoCreateBuildingPathNodes()) + { + createPathNodes(building); + } + } + else + { + // Building has spawned its waypoints. Make sure all the waypoints + // have their link to this building as their creator + + int idCount = ids.size(); + + for(int i = 0; i < idCount; i++) + { + ServerObject * serverObject = ServerWorld::findObjectByNetworkId(ids[i]); + + if(serverObject == NULL) continue; + + CityPathNode * node = _getCityNodeFor(serverObject,graph); + + if(node == NULL) continue; + + node->setCreator(building->getNetworkId()); + } + } +} + +// ---------------------------------------------------------------------- + +void CityPathGraphManager::removeBuilding ( BuildingObject * building ) +{ + UNREF(building); +} + +// ---------------------------------------------------------------------- +// When a building is destroyed, we have to (try to) destroy all of its +// associated path nodes + +void CityPathGraphManager::destroyBuilding ( BuildingObject * building ) +{ + destroyPathNodes(building); +} + +// ---------------------------------------------------------------------- + +void CityPathGraphManager::moveBuilding ( BuildingObject * building, Vector const & oldPosition ) +{ + if(building == NULL) return; + + CityPathGraph * graph = _getCityGraphFor(building); + + if(graph == NULL) return; + + UNREF(oldPosition); + + if(building == NULL) return; + + NetworkIdList ids; + if (!building->getObjVars().getItem(OBJVAR_PATHFINDING_BUILDING_WAYPOINTS,ids)) return; + + int idCount = ids.size(); + + for(int i = 0; i < idCount; i++) + { + ServerObject * serverObject = ServerWorld::findObjectByNetworkId(ids[i]); + + if(serverObject == NULL) continue; + + CityPathNode * node = _getCityNodeFor(serverObject,graph); + + if(node == NULL) continue; + + Vector relativePos_o = node->getRelativePosition_o(); + + Vector newPos_w = building->rotateTranslate_o2w( relativePos_o ); + + serverObject->setPosition_w(newPos_w); + } +} + +// ---------------------------------------------------------------------- + +bool CityPathGraphManager::destroyPathGraph ( ServerObject const * creator ) +{ + int count = g_regionCache.size(); + + for(int i = 0; i < count; i++) + { + RegionCacheEntry & entry = g_regionCache[i]; + + CityPathGraph * graph = entry.m_graph; + + NOT_NULL(graph); + + if(graph->getCreator() == creator) + { + ServerPathfindingMessaging::getInstance().sendEraseGraph(graph); + + removeFromRegionCache(graph); + + delete graph; + + return true; + } + } + + return false; +} + +// ---------------------------------------------------------------------- +// Spawn the city path nodes for the given object, and mark the object +// as processed + +// Only works for buildings right now. + +bool CityPathGraphManager::createPathNodes ( ServerObject * building ) +{ + if(building == NULL) return false; + + // Destroy any old path nodes for the building + + destroyPathNodes(building); + + // ---------- + // Get the path graph for the exterior of the building + + PathGraph const * pathGraph = _getExteriorGraph(building); + + if(pathGraph == NULL) return false; + + // ---------- + // Go through all the nodes in the building's graph and create city + // graph nodes for them. + + int nodeCount = pathGraph->getNodeCount(); + + NetworkIdList idList; + + AxialBox bounds; + + for(int i = 0; i < nodeCount; i++) + { + PathNode const * node = pathGraph->getNode(i); + + if(node == NULL) continue; + + // ---------- + + PathNodeType baseType = node->getType(); + + PathNodeType newType = baseType; + + if(baseType == PNT_CellPortal) + { + newType = PNT_CityBuildingEntrance; + } + else + { + newType = PNT_CityWaypoint; + } + + // ---------- + + Vector position_p = node->getPosition_p(); + + Vector position_w = building->rotateTranslate_o2w(position_p); + + bounds.add(position_w); + + Transform tr; + tr.setPosition_p(position_w); + ServerObject * newWaypoint = ServerWorld::createNewObject(SERVER_PATHFINDING_WAYPOINT_TEMPLATE_AUTO_SPAWN, tr, 0, true); + + // ServerWorld should handle adding the waypoint to the world, and the notifications will take care of the rest. + + newWaypoint->setObjVarItem(OBJVAR_PATHFINDING_WAYPOINT_CREATOR,building->getNetworkId()); + newWaypoint->setObjVarItem(OBJVAR_PATHFINDING_WAYPOINT_KEY, node->getKey() ); + newWaypoint->setObjVarItem(OBJVAR_PATHFINDING_WAYPOINT_TYPE, static_cast(newType) ); + + newWaypoint->addToWorld(); + + idList.push_back(newWaypoint->getNetworkId()); + } + + // ---------- + // Add a city path node for the building itself. + + // Building nodes have links to all the building entrances, and those links + // shouldn't change. + + { + Vector position_w = building->getPosition_w(); + + bounds.add(position_w); + + Transform tr; + tr.setPosition_p(position_w); + ServerObject * newWaypoint = ServerWorld::createNewObject( SERVER_PATHFINDING_WAYPOINT_TEMPLATE_AUTO_SPAWN, tr, 0, true); + + NOT_NULL(newWaypoint); + + newWaypoint->setObjVarItem(OBJVAR_PATHFINDING_WAYPOINT_CREATOR,building->getNetworkId()); + newWaypoint->setObjVarItem(OBJVAR_PATHFINDING_WAYPOINT_KEY, static_cast(building->getNetworkId().getHashValue()) ); + newWaypoint->setObjVarItem(OBJVAR_PATHFINDING_WAYPOINT_TYPE, static_cast(PNT_CityBuilding) ); + + newWaypoint->addToWorld(); + + idList.push_back(newWaypoint->getNetworkId()); + } + + // ---------- + // Done. Mark the building as processed. + + building->setObjVarItem(OBJVAR_PATHFINDING_BUILDING_PROCESSED,1); + building->setObjVarItem(OBJVAR_PATHFINDING_BUILDING_WAYPOINTS,idList); + + + // ---------- + // And mark the chunk of the path graph the building is in as dirty + + { + CityPathGraph * cityGraph = _getCityGraphFor(building); + + if(cityGraph) + { + AxialBox dirty = ShapeUtils::inflate(bounds,getLinkDistance()); + + cityGraph->addDirtyBox(dirty); + } + } + + + return true; +} + +// ---------------------------------------------------------------------- + +void CityPathGraphManager::destroyWaypoint ( ServerObject * object ) +{ + CityPathGraph * graph = _getCityGraphFor(object); + + if(graph == NULL) return; + + CityPathNode * deadNode = _getCityNodeFor(object,graph); + + if(deadNode == NULL) return; + + // ---------- + + // Remember who was a neighbor of the node + + ServerPathfindingMessaging::getInstance().sendEraseNode(deadNode); + + std::vector oldNeighbors; + + int edgeCount = deadNode->getEdgeCount(); + + int i; + + for(i = 0; i < edgeCount; i++) + { + oldNeighbors.push_back( deadNode->getNeighbor(i) ); + } + + // Erase the node + + graph->destroyNode(deadNode->getIndex()); + + // Update the neighbors of the deleted node on the client + + for(i = 0; i < edgeCount; i++) + { + CityPathNode * oldNeighbor = graph->_getNode(oldNeighbors[i]); + + if(oldNeighbor) ServerPathfindingMessaging::getInstance().sendNodeInfo( oldNeighbor ); + } + + // If the graph no longer has any nodes in it, destroy it and remove it from the map + + if(graph->getLiveNodeCount() == 0) + { + removeFromRegionCache(graph); + + delete graph; + } +} + +// ---------------------------------------------------------------------- + +bool CityPathGraphManager::destroyPathNodes ( ServerObject * object ) +{ + if(object == NULL) return false; + + BuildingObject * building = dynamic_cast(object); + + if(building == NULL) return false; + + NetworkIdList ids; + if (!building->getObjVars().getItem(OBJVAR_PATHFINDING_BUILDING_WAYPOINTS,ids)) return false; + + int idCount = ids.size(); + + for(int i = 0; i < idCount; i++) + { + NetworkId const & id = ids[i]; + + if(!id.isValid()) continue; + + ServerObject * serverObject = ServerWorld::findObjectByNetworkId(id); + + if(serverObject == NULL) continue; + + serverObject->permanentlyDestroy(DeleteReasons::Replaced); + } + + // wipe all pathfinding-related objvars off of the building + + building->removeObjVarItem(OBJVAR_PATHFINDING); + + return true; +} + +// ---------------------------------------------------------------------- + +bool CityPathGraphManager::reloadPathNodes ( void ) +{ + int count = g_regionCache.size(); + + for(int i = 0; i < count; i++) + { + g_regionCache[i].m_graph->reloadPathNodes(); + } + + return true; +} + +// ---------------------------------------------------------------------- + +bool CityPathGraphManager::reloadPathNodes ( stdvector< ServerObject * >::fwd const & objects ) +{ + int objectCount = objects.size(); + + if(objects.size() == 0) return false; + + CityPathGraph * graph = _getCityGraphFor(objects[0]); + + if(graph == 0) return false; + + for(int i = 0; i < objectCount; i++) + { + CityPathNode * node = _getCityNodeFor(objects[i],graph); + + if(node) node->reload(); + } + + return true; +} + +// ---------------------------------------------------------------------- + +bool CityPathGraphManager::markCityEntrance ( ServerObject * object ) +{ + CityPathNode * node = _getCityNodeFor(object); + + if(node && (node->getType() == PNT_CityWaypoint)) + { + node->setType(PNT_CityEntrance); + node->saveInfoToObjvars(); + return true; + } + else + { + return false; + } +} + +// ---------------------------------------------------------------------- + +bool CityPathGraphManager::unmarkCityEntrance ( ServerObject * object ) +{ + CityPathNode * node = _getCityNodeFor(object); + + if(node && (node->getType() == PNT_CityEntrance)) + { + node->setType(PNT_CityWaypoint); + node->saveInfoToObjvars(); + return true; + } + else + { + return false; + } +} + +// ---------------------------------------------------------------------- + +int CityPathGraphManager::getGraphCount ( void ) +{ + return g_regionCache.size(); +} + +CityPathGraph * CityPathGraphManager::getGraph ( int index ) +{ + return g_regionCache[index].m_graph; +} + +// ---------------------------------------------------------------------- + +float CityPathGraphManager::getLinkDistance ( void ) +{ + return CityPathGraph::getLinkDistance(); +} + +void CityPathGraphManager::setLinkDistance ( float dist ) +{ + CityPathGraph::setLinkDistance(dist); +} + +// ---------------------------------------------------------------------- + +void CityPathGraphManager::relinkGraph ( CityPathGraph const * constGraph ) +{ + if(constGraph == NULL) return; + + CityPathGraph * graph = const_cast(constGraph); + + int nodeCount = graph->getNodeCount(); + + int i; + + for(i = 0; i < nodeCount; i++) + { + graph->relinkNode(i); + } + + for(i = 0; i < nodeCount; i++) + { + ServerPathfindingMessaging::getInstance().sendNodeInfo(graph->_getNode(i)); + } +} + +// ====================================================================== diff --git a/engine/server/library/serverPathfinding/src/shared/CityPathGraphManager.h b/engine/server/library/serverPathfinding/src/shared/CityPathGraphManager.h new file mode 100644 index 00000000..bef09c61 --- /dev/null +++ b/engine/server/library/serverPathfinding/src/shared/CityPathGraphManager.h @@ -0,0 +1,91 @@ +// ====================================================================== +// +// CityPathGraphManager.h +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_CityPathGraphManager_H +#define INCLUDED_CityPathGraphManager_H + +class ServerObject; +class PathGraph; +class Vector; +class CityPathGraph; +class CityPathNode; +class BuildingObject; + +typedef stdmap< int, CityPathGraph * >::fwd CityGraphMap; + +typedef stdvector< Vector >::fwd PositionList; + +// ====================================================================== + +class CityPathGraphManager +{ +public: + + static void install ( void ); + static void remove ( void ); + + static void update ( float time ); + + static void preloadComplete ( void ); + + static void sanityCheck ( void ); + + static void addWaypoint ( ServerObject * object ); + static void removeWaypoint ( ServerObject * object ); + static void moveWaypoint ( ServerObject * object, Vector const & oldPosition ); + static void destroyWaypoint ( ServerObject * object ); + + static void addBuilding ( BuildingObject * building ); + static void removeBuilding ( BuildingObject * building ); + static void moveBuilding ( BuildingObject * building, Vector const & oldPosition ); + static void destroyBuilding ( BuildingObject * building ); + + // ---------- + + static bool destroyPathGraph ( ServerObject const * creator ); + + // ---------- + + static bool createPathNodes ( ServerObject * building ); + static bool destroyPathNodes ( ServerObject * building ); + + static bool reloadPathNodes ( void ); + static bool reloadPathNodes ( stdvector< ServerObject * >::fwd const & objects ); + + static bool markCityEntrance ( ServerObject * object ); + static bool unmarkCityEntrance ( ServerObject * object ); + + static float getLinkDistance ( void ); + static void setLinkDistance ( float dist ); + + static void relinkGraph ( CityPathGraph const * graph ); + + // ---------- + + static int getGraphCount ( void ); + static CityPathGraph * getGraph ( int index ); + + static CityPathGraph const * getCityGraphFor ( ServerObject const * object ); + static CityPathGraph const * getCityGraphFor ( Vector const & position ); + + static CityPathNode const * getNamedNodeFor( ServerObject const & object, Unicode::String const & nodeName ); + + // ---------- + + static bool getClosestPathNodePos ( ServerObject const * object, Vector & outPos ); + +protected: + + CityPathGraphManager(); + ~CityPathGraphManager(); +}; + +// ====================================================================== + +#endif + diff --git a/engine/server/library/serverPathfinding/src/shared/CityPathNode.cpp b/engine/server/library/serverPathfinding/src/shared/CityPathNode.cpp new file mode 100644 index 00000000..8e4df130 --- /dev/null +++ b/engine/server/library/serverPathfinding/src/shared/CityPathNode.cpp @@ -0,0 +1,558 @@ +// ====================================================================== +// +// CityPathNode.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "serverPathfinding/FirstServerPathfinding.h" +#include "serverPathfinding/CityPathNode.h" + +#include "serverGame/ServerObject.h" +#include "serverGame/ServerWorld.h" + +#include "serverPathfinding/CityPathGraph.h" +#include "serverPathfinding/ServerPathfindingConstants.h" + +#include "sharedCollision/CollisionWorld.h" +#include "sharedCollision/CollisionUtils.h" + +#include "sharedFoundation/DynamicVariable.h" +#include "sharedFoundation/DynamicVariableList.h" +#include "sharedFoundation/NetworkId.h" + +#include "sharedObject/CellProperty.h" +#include "sharedObject/NetworkIdManager.h" + +#include "sharedPathfinding/PathEdge.h" + +#include "sharedTerrain/TerrainObject.h" + +#include + +typedef std::vector NetworkIdList; + +namespace CityPathNodeNamespace +{ + int gs_debugIdCounter = 0; +}; + +using namespace CityPathNodeNamespace; + +// ====================================================================== + +CityPathNode::CityPathNode ( Vector const & position_w, NetworkId const & sourceId ) +: DynamicPathNode(position_w), + m_source(sourceId), + m_creator(), + m_relativePosition_o(Vector::zero), + m_spatialHandle(NULL), + m_debugId( gs_debugIdCounter++ ) +{ + snapToTerrain(); +} + +// ---------- + +CityPathNode::CityPathNode ( Vector const & position_w, NetworkId const & sourceId, NetworkId const & creatorId ) +: DynamicPathNode(position_w), + m_source(sourceId), + m_creator(creatorId), + m_relativePosition_o(Vector::zero), + m_spatialHandle(NULL), + m_debugId( gs_debugIdCounter++ ) +{ + updateRelativePosition(); + + snapToTerrain(); +} + +// ---------- + +CityPathNode::~CityPathNode() +{ +} + +// ---------------------------------------------------------------------- + +void CityPathNode::clearEdges ( void ) +{ + ServerObject * sourceObject = getSourceObject(); + + if(sourceObject) + { + sourceObject->removeObjVarItem(OBJVAR_PATHFINDING_WAYPOINT_EDGES); + } + + DynamicPathNode::clearEdges(); +} + +// ---------------------------------------------------------------------- + +CellProperty const * CityPathNode::getCell ( void ) const +{ + ServerObject const * sourceObject = getSourceObject(); + + if(sourceObject) + { + return sourceObject->getParentCell(); + } + else + { + return CellProperty::getWorldCellProperty(); + } +} + +// ---------------------------------------------------------------------- + +Vector CityPathNode::getPosition_w ( void ) const +{ + return CollisionUtils::transformToWorld(getCell(),getPosition_p()); +} + +// ---------------------------------------------------------------------- + +void CityPathNode::setPosition_p ( Vector const & newPosition_p ) +{ + DynamicPathNode::setPosition_p(newPosition_p); + + updateRelativePosition(); + + snapToTerrain(); +} + +// ---------------------------------------------------------------------- + +void CityPathNode::setPosition_w ( Vector const & newPosition_w ) +{ + Vector newPosition_p = CollisionUtils::transformFromWorld(newPosition_w,getCell()); + + setPosition_p(newPosition_p); +} + +// ---------------------------------------------------------------------- + +void CityPathNode::updateRelativePosition ( void ) +{ + ServerObject const * sourceObject = getSourceObject(); + + ServerObject const * creatorObject = getCreatorObject(); + + if(sourceObject && creatorObject) + { + m_relativePosition_o = creatorObject->rotateTranslate_w2o(sourceObject->getPosition_w()); + } +} + +// ---------------------------------------------------------------------- + +void CityPathNode::loadFromObjvars ( void ) +{ + loadInfoFromObjvars(); + loadEdgesFromObjvars(); +} + +// ---------------------------------------------------------------------- + +void CityPathNode::loadInfoFromObjvars ( void ) +{ + ServerObject const * sourceObject = getSourceObject(); + + if(sourceObject == NULL) return; + + const DynamicVariableList & objvars = sourceObject->getObjVars(); + + // ---------- + + m_creator = NetworkId::cms_invalid; + m_key = -1; + m_name.clear(); + m_type = PNT_Invalid; + + NetworkId creatorId; + if (objvars.getItem(OBJVAR_PATHFINDING_WAYPOINT_CREATOR,creatorId)) + m_creator = creatorId; + + objvars.getItem(OBJVAR_PATHFINDING_WAYPOINT_KEY, m_key); + objvars.getItem(OBJVAR_PATHFINDING_WAYPOINT_NAME, m_name); + + int typeInt; + if(objvars.getItem(OBJVAR_PATHFINDING_WAYPOINT_TYPE, typeInt)) + m_type = static_cast(typeInt); + +} + +// ---------------------------------------------------------------------- + +void CityPathNode::loadEdgesFromObjvars ( void ) +{ + ServerObject const * sourceObject = getSourceObject(); + + if(sourceObject == NULL) return; + + DynamicVariableList const & objvars = sourceObject->getObjVars(); + + // ---------- + + NetworkIdList idList; + if(objvars.getItem(OBJVAR_PATHFINDING_WAYPOINT_EDGES,idList)) + { + int idCount = idList.size(); + + for(int i = 0; i < idCount; i++) + { + ServerObject * serverObject = ServerWorld::findObjectByNetworkId( idList[i] ); + + if(serverObject == NULL) continue; + + CityPathNode * otherNode = _getGraph()->findNodeForObject(*serverObject); + + if(otherNode == NULL) continue; + + addEdge(otherNode->getIndex()); + otherNode->addEdge(getIndex()); + } + } + else + { + DEBUG_WARNING(true,("CityPathNode::loadEdgesFromObjvars - Source object has no edge list objvar\n")); + } +} + +// ---------------------------------------------------------------------- + +void CityPathNode::saveToObjvars ( void ) +{ + saveInfoToObjvars(); + saveEdgesToObjvars(); +} + +// ---------------------------------------------------------------------- + +void CityPathNode::saveInfoToObjvars ( void ) +{ + ServerObject * sourceObject = getSourceObject(); + + if(sourceObject == NULL) return; + + // ---------- + + NetworkId const & creatorId = getCreatorId(); + + if(creatorId.isValid()) + { + sourceObject->setObjVarItem(OBJVAR_PATHFINDING_WAYPOINT_CREATOR, creatorId); + } + else + { + sourceObject->removeObjVarItem(OBJVAR_PATHFINDING_WAYPOINT_CREATOR); + } + + if(m_key != -1) + { + sourceObject->setObjVarItem(OBJVAR_PATHFINDING_WAYPOINT_KEY,static_cast(m_key)); + } + else + { + sourceObject->removeObjVarItem(OBJVAR_PATHFINDING_WAYPOINT_KEY); + } + + if(!m_name.empty()) + { + sourceObject->setObjVarItem(OBJVAR_PATHFINDING_WAYPOINT_NAME,m_name); + } + else + { + sourceObject->removeObjVarItem(OBJVAR_PATHFINDING_WAYPOINT_NAME); + } + + if(m_type != PNT_Invalid) + { + sourceObject->setObjVarItem(OBJVAR_PATHFINDING_WAYPOINT_TYPE,static_cast(m_type)); + } + else + { + sourceObject->removeObjVarItem(OBJVAR_PATHFINDING_WAYPOINT_TYPE); + } +} + +// ---------------------------------------------------------------------- + +void CityPathNode::saveEdgesToObjvars ( void ) +{ + ServerObject * sourceObject = getSourceObject(); + + // ---------- + + NetworkIdList idList; + + int edgeCount = getEdgeCount(); + + for(int i = 0; i < edgeCount; i++) + { + int neighborIndex = getNeighbor(i); + + CityPathNode * neighborNode = _getGraph()->_getNode(neighborIndex); + + if(neighborNode == NULL) continue; + + NetworkId const & neighborSourceId = neighborNode->getSourceId(); + + if(neighborSourceId.isValid()) + { + idList.push_back(neighborSourceId); + } + } + + if(!idList.empty()) + { + sourceObject->setObjVarItem(OBJVAR_PATHFINDING_WAYPOINT_EDGES,idList); + } + else + { + sourceObject->removeObjVarItem(OBJVAR_PATHFINDING_WAYPOINT_EDGES); + } +} + + +// ---------------------------------------------------------------------- + +void CityPathNode::saveNeighbors ( void ) +{ + int edgeCount = getEdgeCount(); + + for(int i = 0; i < edgeCount; i++) + { + int neighborIndex = getNeighbor(i); + + CityPathNode * neighborNode = _getGraph()->_getNode(neighborIndex); + + if(neighborNode == NULL) continue; + + neighborNode->saveToObjvars(); + } +} + +// ---------------------------------------------------------------------- + +void CityPathNode::saveAllData ( void ) +{ + saveToObjvars(); + saveNeighbors(); +} + +// ---------------------------------------------------------------------- + +ServerObject * CityPathNode::getSourceObject ( void ) +{ + return safe_cast(m_source.getObject()); +} + +ServerObject const * CityPathNode::getSourceObject ( void ) const +{ + return safe_cast(m_source.getObject()); +} + +NetworkId const & CityPathNode::getSourceId ( void ) const +{ + return m_source; +} + +// ---------- + +ServerObject * CityPathNode::getCreatorObject ( void ) +{ + return safe_cast(m_creator.getObject()); +} + +ServerObject const * CityPathNode::getCreatorObject ( void ) const +{ + return safe_cast(m_creator.getObject()); +} + +NetworkId const & CityPathNode::getCreatorId ( void ) const +{ + return m_creator; +} + +// ---------- + +void CityPathNode::setCreator ( NetworkId const & creatorId ) +{ + m_creator = creatorId; + + updateRelativePosition(); +} + +// ---------------------------------------------------------------------- + +CityPathGraph * CityPathNode::_getGraph ( void ) +{ + return safe_cast(getGraph()); +} + +CityPathGraph const * CityPathNode::_getGraph ( void ) const +{ + return safe_cast(getGraph()); +} + +// ---------------------------------------------------------------------- + +int CityPathNode::getDebugId ( void ) const +{ + return m_debugId; +} + +// ---------------------------------------------------------------------- + +bool CityPathNode::sanityCheck ( bool doWarnings ) const +{ + UNREF(doWarnings); //for release build + int insaneCount = 0; + + int edgeCount = getEdgeCount(); + + int i; + + for(i = 0; i < edgeCount; i++) + { + int neighborIndex = getNeighbor(i); + + CityPathNode const * neighborNode = _getGraph()->_getNode(neighborIndex); + + if(neighborNode == NULL) + { + DEBUG_WARNING(doWarnings,("CityPathNode::sanityCheck - Node has an edge to a non-existent node\n")); + insaneCount++; + } + + if(!neighborNode->hasEdge(getIndex())) + { + DEBUG_WARNING(doWarnings,("CityPathNode::sanityCheck - Node has a one-way edge to another node\n")); + insaneCount++; + } + } + + NetworkIdList idList; + + ServerObject const * sourceObject = getSourceObject(); + + if(sourceObject && sourceObject->getObjVars().getItem(OBJVAR_PATHFINDING_WAYPOINT_EDGES,idList)) + { + int idCount = idList.size(); + + for(int i = 0; i < idCount; i++) + { + if(!hasEdgeTo(idList[i])) + { + DEBUG_WARNING(doWarnings,("CityPathNode::sanityCheck - Node has a link in its objvar list that's not present in the edge list\n")); + insaneCount++; + } + } + } + + if(getType() != PNT_CityBuilding) + { + for(i = 0; i < edgeCount; i++) + { + CityPathNode const * nodeA = this; + CityPathNode const * nodeB = _getGraph()->_getNode(getNeighbor(i)); + + if(nodeB == NULL) continue; + + if(nodeB->getType() == PNT_CityBuilding) continue; + + Vector posA = nodeA->getPosition_p(); + Vector posB = nodeB->getPosition_p(); + + bool moveAB = (CollisionWorld::canMove( CellProperty::getWorldCellProperty(), posA, posB, 0.0f, true, true, false ) == CMR_MoveOK); + + if(!moveAB) + { + DEBUG_WARNING(doWarnings,("CityPathNode::sanityCheck - Node has a link that's not traversable\n")); + insaneCount++; + } + } + } + + int redundantCount = markRedundantEdges(); + + if(redundantCount > 0) + { + DEBUG_WARNING(doWarnings,("CityPathNode::sanityCheck - Node has %d redundant edges\n",redundantCount)); + insaneCount++; + } + + return insaneCount == 0; +} + +// ---------------------------------------------------------------------- +// Reload the parts of the node data that are set up by designers + +void CityPathNode::reload ( void ) +{ + ServerObject const * sourceObject = getSourceObject(); + + if(sourceObject == NULL) return; + + // ---------- + + DynamicVariableList const & objvars = sourceObject->getObjVars(); + + // ---------- + + objvars.getItem(OBJVAR_PATHFINDING_WAYPOINT_NAME,m_name); + int pathNodeTypeInt; + objvars.getItem(OBJVAR_PATHFINDING_WAYPOINT_TYPE,pathNodeTypeInt); + m_type = static_cast(pathNodeTypeInt); +} + +// ---------------------------------------------------------------------- + +bool CityPathNode::hasEdgeTo ( NetworkId const & neighborId ) const +{ + if(!neighborId.isValid()) return false; + + int edgeCount = getEdgeCount(); + + for(int i = 0; i < edgeCount; i++) + { + int neighborIndex = getNeighbor(i); + + CityPathNode const * neighborNode = _getGraph()->_getNode(neighborIndex); + + if(neighborNode == NULL) continue; + + if(neighborNode->getSourceId() == neighborId) return true; + } + + return false; +} + +// ---------------------------------------------------------------------- + +void CityPathNode::snapToTerrain ( void ) +{ + CellProperty const * cell = getCell(); + + if((cell == NULL) || (cell == CellProperty::getWorldCellProperty())) + { + Vector pos_w = getPosition_w(); + + float height = 0.0f; + + if(TerrainObject::getConstInstance ()->getHeightForceChunkCreation(pos_w,height)) + { + if(height > pos_w.y) + { + pos_w.y = height; + + Vector pos_p = CollisionUtils::transformFromWorld(pos_w,getCell()); + + DynamicPathNode::setPosition_p(pos_p); + } + } + } +} + +// ---------------------------------------------------------------------- diff --git a/engine/server/library/serverPathfinding/src/shared/CityPathNode.h b/engine/server/library/serverPathfinding/src/shared/CityPathNode.h new file mode 100644 index 00000000..75f9effe --- /dev/null +++ b/engine/server/library/serverPathfinding/src/shared/CityPathNode.h @@ -0,0 +1,171 @@ +// ====================================================================== +// +// CityPathNode.h +// Copyright 2002 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_CityPathNode_H +#define INCLUDED_CityPathNode_H + +#include "serverGame/ServerObject.h" +#include "sharedFoundation/Watcher.h" +#include "sharedPathfinding/DynamicPathNode.h" +#include "Unicode.h" + +class CityPathGraph; +class SpatialSubdivisionHandle; + +typedef SpatialSubdivisionHandle SpatialHandle; + +// ====================================================================== +// CityPathNodes are DynamicPathNodes that know how to use objvars to +// persist their data. + +class CityPathNode : public DynamicPathNode +{ +public: + + CityPathNode ( Vector const & position_w, NetworkId const & sourceId ); + CityPathNode ( Vector const & position_w, NetworkId const & sourceId, NetworkId const & creatorId ); + + virtual ~CityPathNode(); + + // ---------- + + virtual void clearEdges ( void ); + + virtual CellProperty const * getCell ( void ) const; + + virtual Vector getPosition_w ( void ) const; + + virtual void setPosition_p ( Vector const & newPosition_p ); + + virtual void setPosition_w ( Vector const & newPosition_w ); + + Vector const & getRelativePosition_o ( void ) const; + void setRelativePosition_o ( Vector const & position_o ); + + void updateRelativePosition ( void ); + + // ---------- + + void loadFromObjvars ( void ); + void saveToObjvars ( void ); + + void loadInfoFromObjvars ( void ); + void saveInfoToObjvars ( void ); + + void loadEdgesFromObjvars ( void ); + void saveEdgesToObjvars ( void ); + + void saveNeighbors ( void ); + void saveAllData ( void ); + + int getDebugId ( void ) const; + + bool sanityCheck ( bool doWarnings ) const; + + void reload ( void ); + + // ---------- + + ServerObject * getSourceObject ( void ); + ServerObject const * getSourceObject ( void ) const; + + NetworkId const & getSourceId ( void ) const; + + ServerObject * getCreatorObject ( void ); + ServerObject const * getCreatorObject ( void ) const; + + NetworkId const & getCreatorId ( void ) const; + + void setCreator ( NetworkId const & networkId ); + + // ---------- + + CityPathGraph * _getGraph ( void ); + CityPathGraph const * _getGraph ( void ) const; + + Unicode::String const & getName ( void ) const; + void setName ( Unicode::String const & name ); + + SpatialHandle * getSpatialHandle ( void ); + SpatialHandle const * getSpatialHandle ( void ) const; + + void setSpatialHandle ( SpatialHandle * newHandle ); + + bool hasEdgeTo ( NetworkId const & neighborId ) const; + + void snapToTerrain ( void ); + + int getNeighborCode ( void ) const; + void setNeighborCode ( int newCode ); + +protected: + + typedef Watcher ObjectWatcher; + + friend class CityPathGraph; + + CachedNetworkId m_source; + CachedNetworkId m_creator; + + Vector m_relativePosition_o; // Position relative to the creator + + Unicode::String m_name; + + SpatialHandle * m_spatialHandle; + + int m_debugId; + + int m_neighborCode; +}; + +// ---------------------------------------------------------------------- +// position relative to the creator object + +inline Vector const & CityPathNode::getRelativePosition_o ( void ) const +{ + return m_relativePosition_o; +} + +inline void CityPathNode::setRelativePosition_o ( Vector const & position_o ) +{ + m_relativePosition_o = position_o; +} + +// ---------------------------------------------------------------------- + +inline Unicode::String const & CityPathNode::getName ( void ) const +{ + return m_name; +} + +inline void CityPathNode::setName ( Unicode::String const & name ) +{ + m_name = name; +} + +// ---------------------------------------------------------------------- + +inline SpatialHandle * CityPathNode::getSpatialHandle ( void ) +{ + return m_spatialHandle; +} + +inline SpatialHandle const * CityPathNode::getSpatialHandle ( void ) const +{ + return m_spatialHandle; +} + +inline void CityPathNode::setSpatialHandle ( SpatialHandle * newHandle ) +{ + m_spatialHandle = newHandle; +} + +// ====================================================================== + +#endif + diff --git a/engine/server/library/serverPathfinding/src/shared/FirstServerPathfinding.h b/engine/server/library/serverPathfinding/src/shared/FirstServerPathfinding.h new file mode 100644 index 00000000..cc7824d8 --- /dev/null +++ b/engine/server/library/serverPathfinding/src/shared/FirstServerPathfinding.h @@ -0,0 +1,17 @@ +// ====================================================================== +// +// FirstServerPathfinding.h +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_FirstServerPathfinding_H +#define INCLUDED_FirstServerPathfinding_H + +// ====================================================================== + +#include "sharedPathfinding/FirstSharedPathfinding.h" + +// ====================================================================== + +#endif diff --git a/engine/server/library/serverPathfinding/src/shared/PathAutoGenerator.cpp b/engine/server/library/serverPathfinding/src/shared/PathAutoGenerator.cpp new file mode 100644 index 00000000..d5f6cd8e --- /dev/null +++ b/engine/server/library/serverPathfinding/src/shared/PathAutoGenerator.cpp @@ -0,0 +1,253 @@ +//====================================================================== +// +// PathAutoGenerator.cpp +// copyright (c) 2005 Sony Online Entertainment +// +//====================================================================== + +#include "serverPathfinding/FirstServerPathfinding.h" +#include "serverPathfinding/PathAutoGenerator.h" + +#include "UnicodeUtils.h" +#include "serverGame/Region.h" +#include "serverGame/RegionMaster.h" +#include "serverGame/ServerObject.h" +#include "serverGame/ServerWorld.h" +#include "sharedCollision/CollisionWorld.h" +#include "sharedMath/MxCifQuadTreeBounds.h" +#include "sharedObject/CellProperty.h" +#include "sharedTerrain/TerrainObject.h" +#include + +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- + +#define USE_OBSTACLE_TEMPLATE 0 + +//---------------------------------------------------------------------- + +namespace PathAutoGeneratorNamespace +{ + char const * const s_pathWaypointTemplate = "object/path_waypoint/path_waypoint.iff"; + char const * const s_pathObstacleTemplate = "object/resource_container/energy_solid_lg.iff"; + +} + +using namespace PathAutoGeneratorNamespace; + +//---------------------------------------------------------------------- + +Region const * PathAutoGenerator::findPathRegion(Vector const & pos_w) +{ + std::string const & planetName = ServerWorld::getSceneId(); + + RegionMaster::RegionVector rv; + RegionMaster::getRegionsAtPoint(planetName, pos_w.x, pos_w.z, rv); + + for (RegionMaster::RegionVector::const_iterator it = rv.begin(); it != rv.end(); ++it) + { + Region const * const r = *it; + if (NULL != r) + { + if (r->getGeography() == RegionNamespace::RG_pathfind) + return r; + } + } + + return NULL; +} + +//---------------------------------------------------------------------- + +void PathAutoGenerator::pathAutoGenerate(Vector const & pos_w, float nodeDistance, float obstacleDistance, Unicode::String & result) +{ + Region const * region = findPathRegion(pos_w); + if (NULL == region) + { + result += Unicode::narrowToWide("No pathfinding region at position"); + return; + } + + char buf[128]; + size_t const bufsize = sizeof(buf); + snprintf(buf, bufsize, "Auto generating path for region [%s]\n", Unicode::wideToNarrow(region->getName()).c_str()); + result += Unicode::narrowToWide(buf); + + MxCifQuadTreeBounds const & bounds = region->getBounds(); + + float const minX = bounds.getMinX(); + float const minY = bounds.getMinY(); + float const maxX = bounds.getMaxX(); + float const maxY = bounds.getMaxY(); + + TerrainObject const * const terrain = TerrainObject::getConstInstance(); + + Vector testPos_w; + + Vector const goalOffsets[] = + { + //-- north + Vector(0.0f, 0.0f, obstacleDistance), + //-- east + Vector(obstacleDistance, 0.0f, 0.0f), + //-- south + Vector(0.0f, 0.0f, -obstacleDistance), + //-- west + Vector(-obstacleDistance, 0.0f, 0.0f) + }; + + int const numGoalOffsets = sizeof(goalOffsets) / sizeof(*goalOffsets); + + { + for (testPos_w.x = minX; testPos_w.x < (maxX); testPos_w.x += nodeDistance) + { + for (testPos_w.z = minY; testPos_w.z < (maxY); testPos_w.z += nodeDistance) + { + terrain->isPassableForceChunkCreation(testPos_w); + } + } + } + + int const maxCreateCount = 500; + + int createCount = 0; + int obstacleNearbySkipped = 0; + + for (testPos_w.x = minX; testPos_w.x < maxX; testPos_w.x += nodeDistance) + { + for (testPos_w.z = minY; testPos_w.z < maxY; testPos_w.z += nodeDistance) + { + if (!bounds.isPointIn(testPos_w.x, testPos_w.z)) + continue; + + if (!terrain->isPassable(testPos_w)) + continue; + + bool skip = false; + + for (int i = 0; i < numGoalOffsets; ++i) + { + Vector const & goalPos_w = testPos_w + goalOffsets[i]; + CanMoveResult const cmr = + CollisionWorld::canMove(CellProperty::getWorldCellProperty(), testPos_w, goalPos_w, 1.0f, false, false, false); + + if (cmr != CMR_MoveOK) + { + skip = true; + break; + } + } + + if (skip) + { + ++obstacleNearbySkipped; + +#if USE_OBSTACLE_TEMPLATE + if (NULL != PathAutoGeneratorNamespace::s_pathObstacleTemplate) + { + Transform transform_w; + transform_w.setPosition_p(testPos_w); + ServerObject * newObject = ServerWorld::createNewObject(s_pathObstacleTemplate, transform_w, 0, false); + newObject->addToWorld(); + } +#endif + continue; + } + + if (createCount >= maxCreateCount) + { + ++createCount; + } + + Transform transform_w; + transform_w.setPosition_p(testPos_w); + ServerObject * newObject = ServerWorld::createNewObject(s_pathWaypointTemplate, transform_w, 0, false); + + if (NULL != newObject) + { + newObject->addToWorld(); + newObject->persist(); + ++createCount; + } + + } + } + + snprintf(buf, bufsize, "Nodes created: %d, skipped %d\n", createCount, obstacleNearbySkipped); + result += Unicode::narrowToWide(buf); + + if (createCount > maxCreateCount) + { + snprintf(buf, bufsize, " Max nodes (%d) hit, try changing your parameters\n", maxCreateCount); + result += Unicode::narrowToWide(buf); + } +} + +//---------------------------------------------------------------------- + +void PathAutoGenerator::pathAutoCleanup(Vector const & pos_w, Unicode::String & result) +{ + Region const * region = findPathRegion(pos_w); + if (NULL == region) + { + result += Unicode::narrowToWide("No pathfinding region at position"); + return; + } + + + char buf[128]; + size_t const bufsize = sizeof(buf); + snprintf(buf, bufsize, "Cleanup up pathnodes for region [%s]\n", Unicode::wideToNarrow(region->getName()).c_str()); + result += Unicode::narrowToWide(buf); + + MxCifQuadTreeBounds const & bounds = region->getBounds(); + + float const minX = bounds.getMinX(); + float const minY = bounds.getMinY(); + float const maxX = bounds.getMaxX(); + float const maxY = bounds.getMaxY(); + + float const range = std::max(maxX - minX, maxY - minY); + + Vector const center((minX + maxX) * 0.5f, 0.0f, (minY + maxY) * 0.5f); + + typedef stdvector::fwd ServerObjectVector; + + ServerObjectVector sv; + + ServerWorld::findObjectsInRange(center, range, sv); + + int destroyCount = 0; + int obstacleDestroyCount = 0; + for (ServerObjectVector::const_iterator it = sv.begin(); it != sv.end(); ++it) + { + ServerObject * const so = *it; + + Vector const & pos_w = so->getPosition_w(); + + if (bounds.isPointIn(pos_w.x, pos_w.z)) + { + if (!strcmp(so->getTemplateName(), s_pathWaypointTemplate)) + { + so->permanentlyDestroy(DeleteReasons::Script); + ++destroyCount; + continue; + } + +#if USE_OBSTACLE_TEMPLATE + if (NULL != s_pathObstacleTemplate && !strcmp(so->getTemplateName(), s_pathObstacleTemplate)) + { + so->permanentlyDestroy(DeleteReasons::Script); + ++obstacleDestroyCount; + continue; + } +#endif + } + } + + snprintf(buf, bufsize, "Nodes destroyed: %d, obstacle placeholders destroyed: %d\n", destroyCount, obstacleDestroyCount); + result += Unicode::narrowToWide(buf); +} + +//---------------------------------------------------------------------- diff --git a/engine/server/library/serverPathfinding/src/shared/PathAutoGenerator.h b/engine/server/library/serverPathfinding/src/shared/PathAutoGenerator.h new file mode 100644 index 00000000..d9ee1694 --- /dev/null +++ b/engine/server/library/serverPathfinding/src/shared/PathAutoGenerator.h @@ -0,0 +1,28 @@ +//====================================================================== +// +// PathAutoGenerator.h +// copyright (c) 2005 Sony Online Entertainment +// +//====================================================================== + +#ifndef INCLUDED_PathAutoGenerator_H +#define INCLUDED_PathAutoGenerator_H + +//====================================================================== + +class Region; +class Vector; + +//---------------------------------------------------------------------- + +class PathAutoGenerator +{ +public: + static Region const * findPathRegion(Vector const & pos_w); + static void pathAutoGenerate(Vector const & pos_w, float nodeDistance, float obstacleDistance, Unicode::String & result); + static void pathAutoCleanup(Vector const & pos_w, Unicode::String & result); +}; + +//====================================================================== + +#endif diff --git a/engine/server/library/serverPathfinding/src/shared/ServerPathBuildManager.cpp b/engine/server/library/serverPathfinding/src/shared/ServerPathBuildManager.cpp new file mode 100644 index 00000000..0b8bf2a5 --- /dev/null +++ b/engine/server/library/serverPathfinding/src/shared/ServerPathBuildManager.cpp @@ -0,0 +1,108 @@ +// ====================================================================== +// +// ServerPathBuildManager.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "serverPathfinding/FirstServerPathfinding.h" +#include "serverPathfinding/ServerPathBuildManager.h" + +#include "serverPathfinding/ServerPathBuilder.h" + +#include "sharedDebug/PerformanceTimer.h" + +#include + +typedef std::list< ServerPathBuilder * > BuildQueue; + +BuildQueue gs_lowQueue; +BuildQueue gs_highQueue; + +// ---------------------------------------------------------------------- + +void ServerPathBuildManager::install ( void ) +{ +} + +void ServerPathBuildManager::remove ( void ) +{ +} + +// ---------------------------------------------------------------------- + +void updateQueue ( BuildQueue * queue, PerformanceTimer const & timer, float timeBudget ) +{ + BuildQueue::iterator it = queue->begin(); + + while(it != queue->end()) + { + if(timer.getSplitTime() >= timeBudget) return; + + ServerPathBuilder * currentBuilder = (*it); + + currentBuilder->update(); + + BuildQueue::iterator old = it; + it++; + + if(currentBuilder->buildDone()) + { + currentBuilder->setQueued(false); + queue->erase(old); + } + } +} + +// ---------- + +void ServerPathBuildManager::update ( float timeBudget ) +{ + PerformanceTimer timer; + + timer.start(); + + updateQueue( &gs_highQueue, timer, timeBudget ); + + updateQueue( &gs_lowQueue, timer, timeBudget ); +} + +// ---------------------------------------------------------------------- + +bool ServerPathBuildManager::queue ( ServerPathBuilder * builder, bool highPriority ) +{ + if(builder->getQueued()) return false; + + if(highPriority) + { + gs_highQueue.push_back(builder); + } + else + { + gs_lowQueue.push_back(builder); + } + + builder->setQueued(true); + + return true; +} + +bool ServerPathBuildManager::unqueue ( ServerPathBuilder * builder ) +{ + if(!builder->getQueued()) return false; + + BuildQueue::iterator it; + + it = std::find(gs_highQueue.begin(),gs_highQueue.end(),builder); + + if(it != gs_highQueue.end()) gs_highQueue.erase(it); + + it = std::find(gs_lowQueue.begin(),gs_lowQueue.end(),builder); + + if(it != gs_lowQueue.end()) gs_lowQueue.erase(it); + + builder->setQueued(false); + + return true; +} + diff --git a/engine/server/library/serverPathfinding/src/shared/ServerPathBuildManager.h b/engine/server/library/serverPathfinding/src/shared/ServerPathBuildManager.h new file mode 100644 index 00000000..9eae8b82 --- /dev/null +++ b/engine/server/library/serverPathfinding/src/shared/ServerPathBuildManager.h @@ -0,0 +1,32 @@ +// ====================================================================== +// +// ServerPathBuildManager.h +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_ServerPathBuildManager_H +#define INCLUDED_ServerPathBuildManager_H + +class ServerPathBuilder; + +// ====================================================================== + +class ServerPathBuildManager +{ +public: + + static void install ( void ); + static void remove ( void ); + + static void update ( float timeBudget ); + + static bool queue ( ServerPathBuilder * builder, bool highPriority ); + static bool unqueue ( ServerPathBuilder * builder ); +}; + +// ====================================================================== + +#endif // INCLUDED_ServerPathBuildManager_H + diff --git a/engine/server/library/serverPathfinding/src/shared/ServerPathBuilder.cpp b/engine/server/library/serverPathfinding/src/shared/ServerPathBuilder.cpp new file mode 100644 index 00000000..4ffdd288 --- /dev/null +++ b/engine/server/library/serverPathfinding/src/shared/ServerPathBuilder.cpp @@ -0,0 +1,1293 @@ +// ====================================================================== +// +// ServerPathBuilder.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "serverPathfinding/FirstServerPathfinding.h" +#include "serverPathfinding/ServerPathBuilder.h" + +#include "serverGame/AiLocation.h" +#include "serverGame/BuildingObject.h" +#include "serverGame/CreatureObject.h" +#include "serverGame/ServerObject.h" + +#include "serverPathfinding/CityPathGraph.h" +#include "serverPathfinding/CityPathGraphManager.h" +#include "serverPathfinding/CityPathNode.h" +#include "serverPathfinding/ServerPathBuildManager.h" + +#include "sharedCollision/CollisionWorld.h" +#include "sharedCollision/CollisionUtils.h" + +#include "sharedObject/CellProperty.h" +#include "sharedObject/PortalProperty.h" +#include "sharedObject/PortalPropertyTemplate.h" + +#include "sharedPathfinding/PathSearch.h" +#include "sharedPathfinding/PathGraph.h" + +#ifdef _DEBUG + +#include "sharedDebug/PerformanceTimer.h" + +#endif + +const float gs_maxCanMoveDistance = 64.0f; +const float gs_maxCanMoveDistance2 = (64.0f * 64.0f); + +// ---------------------------------------------------------------------- + +int findClosestReachablePathNode_slow( CreatureObject const * creature, PathGraph const * graph ) +{ + if(graph == NULL) return -1; + + Vector creaturePos = creature->getPosition_p(); + + static std::vector results; + + results.clear(); + + graph->findNodesInRange( creaturePos, gs_maxCanMoveDistance, results); + + int resultCount = results.size(); + + PathNode const * reachableNode = NULL; + float reachableDist2 = gs_maxCanMoveDistance2; + + for(int i = 0; i < resultCount; i++) + { + PathNode const * node = results[i]; + + Vector nodePos = node->getPosition_p(); + + float dist = nodePos.magnitudeBetweenSquared(creaturePos); + + if(dist < reachableDist2) + { + //@todo - use creature radius + + if(CollisionWorld::canMove(creature,nodePos,0.0f,true,false,false) == CMR_MoveOK) + { + reachableNode = node; + reachableDist2 = dist; + } + } + } + + return reachableNode ? reachableNode->getIndex() : -1; +} + +int findClosestReachablePathNode( CreatureObject const * creature, PathGraph const * graph ) +{ + if(graph == NULL) return -1; + + Vector creaturePos = creature->getPosition_p(); + + // ---------- + // Check to see if the closest node is reachable. + // This will usually save us a lot of canMove tests. + + // If there is no closest node, or the closest node is farther away than maxCanMoveDistance, + // return -2 to indicate that the path is incomplete. + + int closestIndex = graph->findNearestNode(creaturePos); + + if(closestIndex < 0) return -2; + + PathNode const * node = graph->getNode(closestIndex); + + if(node == NULL) return -2; + + Vector nodePos = node->getPosition_p(); + float dist2 = nodePos.magnitudeBetweenSquared(creaturePos); + + if(dist2 > gs_maxCanMoveDistance2) return -2; + + // ---------- + + if(CollisionWorld::canMove(creature,nodePos,0.0f,true,false,false) == CMR_MoveOK) + { + return node->getIndex(); + } + else + { + // ---------- + // The closest node is not reachable. Search for one that is. + + return findClosestReachablePathNode_slow(creature,graph); + } +} + +// ---------------------------------------------------------------------- + +int findClosestReachablePathNode_slow ( CellProperty const * cell, Vector const & goal, float radius, PathGraph const * graph ) +{ + // ---------- + // The closest node is not reachable. Search for one that is. + + static std::vector results; + + results.clear(); + + graph->findNodesInRange( goal, gs_maxCanMoveDistance, results); + + int resultCount = results.size(); + + PathNode const * reachableNode = NULL; + float reachableDist2 = gs_maxCanMoveDistance2; + + for(int i = 0; i < resultCount; i++) + { + PathNode const * node = results[i]; + + Vector nodePos = node->getPosition_p(); + + float dist = nodePos.magnitudeBetweenSquared(goal); + + if(dist < reachableDist2) + { + //@todo - use creature radius + + if(CollisionWorld::canMove(cell,nodePos,goal,radius,true,false,false) == CMR_MoveOK) + { + reachableNode = node; + reachableDist2 = dist; + } + } + } + + return reachableNode ? reachableNode->getIndex() : -1; +} + +int findClosestReachablePathNode ( CellProperty const * cell, Vector const & goal, float radius, PathGraph const * graph ) +{ + // ---------- + // Check to see if the closest node is reachable. + // This will usually save us a lot of canMove tests. + + int closestIndex = graph->findNearestNode(goal); + + if(closestIndex < 0) return -2; + + PathNode const * node = graph->getNode(closestIndex); + + if(node == NULL) return -2; + + Vector nodePos = node->getPosition_p(); + float dist2 = nodePos.magnitudeBetweenSquared(goal); + + if(dist2 >= gs_maxCanMoveDistance2) return -2; + + // ---------- + + if(CollisionWorld::canMove(cell,nodePos,goal,radius,true,false,false) == CMR_MoveOK) + { + return node->getIndex(); + } + + // ---------- + + return findClosestReachablePathNode_slow(cell,goal,radius,graph); +} + +// ---------------------------------------------------------------------- + +PathGraph const * getGraph ( CellProperty const * cell ) +{ + if(cell) + return safe_cast(cell->getPathGraph()); + else + return NULL; +} + +PathGraph const * getGraph ( PortalProperty const * building ) +{ + if(building) + return safe_cast(building->getPortalPropertyTemplate().getBuildingPathGraph()); + else + return NULL; +} + +// ---------- + +int getKey ( CellProperty const * cell ) +{ + if(cell && (cell != CellProperty::getWorldCellProperty())) + return cell->getCellIndex(); + else + return -1; +} + +// ---------- + +int getKey ( PortalProperty const * building ) +{ + if(building) + return building->getOwner().getNetworkId().getHashValue(); + else + return -1; +} + +// ---------- + +PortalProperty const * getBuilding ( BuildingObject const * buildingObject ) +{ + if(buildingObject) + return buildingObject->getPortalProperty(); + else + return NULL; +} + +PortalProperty const * getBuilding ( CreatureObject const * creature ) +{ + if(creature == NULL) return NULL; + + CellProperty const * cell = creature->getParentCell(); + + if(cell) + return cell->getPortalProperty(); + else + return NULL; +} + +PortalProperty const * getBuilding ( AiLocation const & loc ) +{ + CellProperty const * cell = loc.getCell(); + + if(cell) + return cell->getPortalProperty(); + else + return NULL; +} + +// ---------- + +int getIndexFor ( CityPathGraph const * cityGraph, PortalProperty const * building, CreatureObject const * creature ) +{ + if(cityGraph && building) + return cityGraph->findNode(PNT_CityBuilding,getKey(building)); + else if(cityGraph) + return findClosestReachablePathNode(creature,cityGraph); + else + return -1; +} + +int getIndexFor ( CityPathGraph const * cityGraph, PortalProperty const * building, AiLocation const & loc ) +{ + if(cityGraph && building) + return cityGraph->findNode(PNT_CityBuilding,getKey(building)); + else if(cityGraph) + return findClosestReachablePathNode(CellProperty::getWorldCellProperty(),loc.getPosition_p(),loc.getRadius(),cityGraph); + else + return -1; +} + +// ---------- + +int getIndexFor ( PortalProperty const * building, PathGraph const * graph, CreatureObject const * creature ) +{ + if(building && graph) + return graph->findNode(PNT_BuildingCell,getKey(creature->getParentCell())); + else + return -1; +} + + +int getIndexFor ( PortalProperty const * building, PathGraph const * graph, AiLocation const & loc) +{ + if(building && graph) + return graph->findNode(PNT_BuildingCell,getKey(loc.getCell())); + else + return -1; +} + +// ---------- + +int getIndexFor ( PortalProperty const * building, PathGraph const * graph, CreatureObject const * creature, int partId ) +{ + int cellIndex = getIndexFor(building,graph,creature); + + if(partId < 0) return cellIndex; + + int neighborCount = graph->getEdgeCount(cellIndex); + + for(int i = 0; i < neighborCount; i++) + { + PathNode const * neighbor = graph->getNeighbor(cellIndex,i); + + NOT_NULL(neighbor); + + if(neighbor->getType() == PNT_BuildingCellPart) + { + if(neighbor->getId() == partId) + { + return neighbor->getIndex(); + } + } + } + + return -1; +} + +// ---------- + +int getIndexFor ( PortalProperty const * building, PathGraph const * graph, AiLocation const & loc, int partId ) +{ + int cellIndex = getIndexFor(building,graph,loc); + + if(partId < 0) return cellIndex; + + int neighborCount = graph->getEdgeCount(cellIndex); + + for(int i = 0; i < neighborCount; i++) + { + PathNode const * neighbor = graph->getNeighbor(cellIndex,i); + + NOT_NULL(neighbor); + + if(neighbor->getType() == PNT_BuildingCellPart) + { + if(neighbor->getId() == partId) + { + return neighbor->getIndex(); + } + } + } + + return -1; +} + +// ---------- + +int getIndexFor ( CellProperty const * cell, PathGraph const * graph, CreatureObject const * creature ) +{ + if(cell && graph) + return findClosestReachablePathNode(creature,graph); + else + return -1; +} + +int getIndexFor ( CellProperty const * cell, PathGraph const * graph, AiLocation const & loc ) +{ + if(cell && graph) + return findClosestReachablePathNode(cell,loc.getPosition_p(),loc.getRadius(),graph); + else + return -1; +} + +int getIndexFor ( CellProperty const * cell, PathGraph const * graph, AiLocation const & loc, float overrideRadius ) +{ + if(cell && graph) + return findClosestReachablePathNode(cell,loc.getPosition_p(),overrideRadius,graph); + else + return -1; +} + +// ---------------------------------------------------------------------- + +ServerPathBuilder::ServerPathBuilder() +: m_creatureCell(NULL), + m_creatureCellGraph(NULL), + m_creatureCellKey(-1), + m_creatureCellNodeIndex(-1), + m_creatureCellPart(-1), + m_creatureBuilding(NULL), + m_creatureBuildingGraph(NULL), + m_creatureBuildingKey(-1), + m_creatureBuildingNodeIndex(-1), + m_creaturePosition(), + m_goalCell(NULL), + m_goalCellGraph(NULL), + m_goalCellKey(-1), + m_goalCellNodeIndex(-1), + m_goalCellPart(-1), + m_goalBuilding(NULL), + m_goalBuildingGraph(NULL), + m_goalBuildingKey(-1), + m_goalBuildingNodeIndex(-1), + m_goalCityGraph(NULL), + m_goalCityNodeIndex(-1), + m_path(new AiPath()), + m_async(false), + m_buildDone(false), + m_buildFailed(false), + m_pathIncomplete(false), + m_enableJitter(false), + m_cellSearch( new PathSearch() ), + m_buildingSearch( new PathSearch() ), + m_citySearch( new PathSearch() ), + m_queued(false) +{ +} + +ServerPathBuilder::~ServerPathBuilder() +{ + ServerPathBuildManager::unqueue(this); + + delete m_path; + m_path = NULL; + + delete m_cellSearch; + m_cellSearch = NULL; + + delete m_buildingSearch; + m_buildingSearch = NULL; + + delete m_citySearch; + m_citySearch = NULL; +} + + +// ---------------------------------------------------------------------- +// Cell searches + +bool ServerPathBuilder::buildPathInternal( CellProperty const * cell, PathGraph const * graph, int indexA, int indexB ) +{ + if(indexA < 0) return false; + if(indexB < 0) return false; + + if(!m_cellSearch->search(graph,indexA,indexB)) return false; + + // ---------- + + IndexList const & path = m_cellSearch->getPath(); + + int pathLength = path.size(); + + for(int i = 0; i < pathLength; i++) + { + int nodeIndex = path[i]; + + PathNode const * node = graph->getNode(nodeIndex); + + if(node == NULL) return false; + + addPathNode( cell, node ); + } + + return true; +} + +// ---------------------------------------------------------------------- +// Building searches + +bool ServerPathBuilder::buildPathInternal ( PortalProperty const * building, PathGraph const * graph, int indexA, int indexB ) +{ + if(indexA < 0) return false; + if(indexB < 0) return false; + + if(!m_buildingSearch->search(graph,indexA,indexB)) return false; + + IndexList const & path = m_buildingSearch->getPath(); + + // ---------- + + PathNode const * nodeA = NULL; + PathNode const * nodeB = NULL; + PathNode const * nodeC = NULL; + + int pathLength = path.size(); + + for(int i = 0; i < pathLength + 2; i++) + { + if(i < pathLength) + { + PathNode const * nextNode = graph->getNode(path[i]); + + if(nextNode == NULL) continue; + + nodeA = nodeB; + nodeB = nodeC; + nodeC = nextNode; + } + else + { + nodeA = nodeB; + nodeB = nodeC; + nodeC = NULL; + } + + if( nodeB == NULL ) continue; + + // ---------- + + if( nodeB->hasSubgraph() ) + { + int cellIndex = nodeB->getKey(); + + CellProperty const * subobject = building->getCell(cellIndex); + + if(subobject == NULL) return false; + + PathGraph const * subgraph = getGraph(subobject); + + if(subgraph == NULL) return false; + + // ---------- + + int indexA = m_creatureCellNodeIndex; + int indexB = m_goalCellNodeIndex; + + if(nodeA) indexA = subgraph->findEntrance( nodeA->getKey() ); + if(nodeC) indexB = subgraph->findEntrance( nodeC->getKey() ); + + if(!buildPathInternal(subobject,subgraph,indexA,indexB)) return false; + } + else + { + if(nodeB->isConcrete()) + { + addPathNode( CellProperty::getWorldCellProperty(), nodeB ); + } + } + } + + return true; +} + +// ---------------------------------------------------------------------- +// City searches + +bool ServerPathBuilder::buildPathInternal ( CityPathGraph const * graph, int indexA, int indexB ) +{ + if(indexA < 0) return false; + if(indexB < 0) return false; + + if(!m_citySearch->search(graph,indexA,indexB)) return false; + + return expandPath( graph, m_citySearch->getPath() ); +} + +// ---------- + +bool ServerPathBuilder::buildPathInternal ( CityPathGraph const * graph, int indexA, IndexList const & indexBList ) +{ + if(indexA < 0) return false; + if(indexBList.empty()) return false; + + if(!m_citySearch->search(graph,indexA,indexBList)) return false; + + return expandPath( graph, m_citySearch->getPath() ); +} + +// ---------------------------------------------------------------------- + +bool ServerPathBuilder::expandPath ( CityPathGraph const * graph, IndexList const & path ) +{ + PathNode const * nodeA = NULL; + PathNode const * nodeB = NULL; + PathNode const * nodeC = NULL; + + int pathLength = path.size(); + + for(int i = 0; i < pathLength + 2; i++) + { + if(i < pathLength) + { + PathNode const * nextNode = graph->getNode(path[i]); + + if(nextNode == NULL) continue; + + nodeA = nodeB; + nodeB = nodeC; + nodeC = nextNode; + } + else + { + nodeA = nodeB; + nodeB = nodeC; + nodeC = NULL; + } + + if( nodeB == NULL ) continue; + + // ---------- + + if( nodeB->hasSubgraph() ) + { + CityPathNode const * cityNode = safe_cast(nodeB); + + if(cityNode == NULL) return false; + + BuildingObject const * buildingObject = safe_cast(cityNode->getCreatorObject()); + + if(buildingObject == NULL) return false; + + PortalProperty const * subobject = getBuilding(buildingObject); + + if(subobject == NULL) return false; + + PathGraph const * subgraph = getGraph(subobject); + + if(subgraph == NULL) return false; + + // ---------- + + int indexA = m_creatureBuildingNodeIndex; + int indexB = m_goalBuildingNodeIndex; + + if(nodeA) indexA = subgraph->findEntrance( nodeA->getKey() ); + if(nodeC) indexB = subgraph->findEntrance( nodeC->getKey() ); + + if(!buildPathInternal(subobject,subgraph,indexA,indexB)) return false; + } + else + { + if(nodeB->isConcrete()) + { + addPathNode( CellProperty::getWorldCellProperty(), nodeB ); + } + } + } + + return true; +} + + +// ---------------------------------------------------------------------- + +bool ServerPathBuilder::buildPath_World ( void ) +{ + Vector exitPoint(m_creature ? m_creature->getPosition_w() : m_creaturePosition); + + if((m_creatureCityGraph != NULL) && (m_creatureCityNodeIndex >= 0)) + { + int indexA = m_creatureCityNodeIndex; + int indexB = m_creatureCityGraph->findNearestNode(m_goal.getPosition_w()); + + if(!buildPathInternal(m_creatureCityGraph,indexA,indexB)) return false; + + if(indexB >= 0) + { + PathNode const * exitNode = m_creatureCityGraph->getNode(indexB); + + if(exitNode) + { + exitPoint = exitNode->getPosition_p(); + } + } + } + + if((m_goalCityGraph != NULL) && (m_goalCityNodeIndex >= 0)) + { + int indexA = m_goalCityGraph->findNearestNode(exitPoint); + int indexB = m_goalCityNodeIndex; + + if(!buildPathInternal(m_goalCityGraph,indexA,indexB)) return false; + } + + return true; +} + +// ---------------------------------------------------------------------- + +bool ServerPathBuilder::buildPath_ToGoal ( void ) +{ + m_path->clear(); + + m_goal.update(); + + if(!m_goal.isValid()) + { + return false; + } + + CellProperty const * worldCell = CellProperty::getWorldCellProperty(); + + // ---------- + + m_creatureCell = m_creature->getParentCell(); + m_goalCell = m_goal.getCell(); + + if(m_creatureCell == NULL) m_creatureCell = worldCell; + if(m_goalCell == NULL) m_goalCell = worldCell; + + { + Vector goalPos_p = m_goal.getPosition_p(m_creatureCell); + + Vector creaturePos_p = m_creature->getPosition_p(); + + if(goalPos_p.magnitudeBetween(creaturePos_p) < gs_maxCanMoveDistance2) + { + if(CollisionWorld::canMove(m_creature,goalPos_p,0.0f,true,false,false) == CMR_MoveOK) + { + return true; + } + } + } + + if((m_creatureCell == worldCell) && (m_goalCell == worldCell)) + { + // Both the creature and the goal are in the world cell, so + // we can skip some work with looking up their cell and building + // info. + + m_creatureCellGraph = NULL; + m_creatureCellKey = -1; + m_creatureCellNodeIndex = -1; + m_creatureCellPart = -1; + + m_goalCellGraph = NULL; + m_goalCellKey = -1; + m_goalCellNodeIndex = -1; + m_goalCellPart = -1; + + m_creatureBuilding = NULL; + m_creatureBuildingGraph = NULL; + m_creatureBuildingKey = -1; + m_creatureBuildingNodeIndex = -1; + + m_goalBuilding = NULL; + m_goalBuildingGraph = NULL; + m_goalBuildingKey = -1; + m_goalBuildingNodeIndex = -1; + } + else + { + // Look up cell info + + m_creatureCellGraph = getGraph(m_creatureCell); + m_creatureCellKey = getKey(m_creatureCell); + m_creatureCellNodeIndex = getIndexFor(m_creatureCell,m_creatureCellGraph,m_creature); + + if(m_creatureCellGraph && (m_creatureCellNodeIndex >= 0)) + { + m_creatureCellPart = m_creatureCellGraph->getNode(m_creatureCellNodeIndex)->getPartId(); + } + else + { + m_creatureCellPart = -1; + } + + m_goalCellGraph = getGraph(m_goalCell); + m_goalCellKey = getKey(m_goalCell); + m_goalCellNodeIndex = getIndexFor(m_goalCell,m_goalCellGraph,m_goal,0.0f); + + if(m_goalCellGraph && (m_goalCellNodeIndex >= 0)) + { + m_goalCellPart = m_goalCellGraph->getNode(m_goalCellNodeIndex)->getPartId(); + } + else + { + m_goalCellPart = -1; + } + + // If they're in the same cell, start the search in the cell + + if((m_creatureCell == m_goalCell) && (m_creatureCell != NULL) && (m_creatureCell != CellProperty::getWorldCellProperty()) && (m_creatureCellPart == m_goalCellPart)) + { + return buildPathInternal(m_creatureCell,m_creatureCellGraph,m_creatureCellNodeIndex,m_goalCellNodeIndex); + } + + // Look up building info + + m_creatureBuilding = m_creatureCell->getPortalProperty(); + m_creatureBuildingGraph = getGraph(m_creatureBuilding); + m_creatureBuildingKey = getKey(m_creatureBuilding); + m_creatureBuildingNodeIndex = getIndexFor(m_creatureBuilding,m_creatureBuildingGraph,m_creature,m_creatureCellPart); + + m_goalBuilding = m_goalCell->getPortalProperty(); + m_goalBuildingGraph = getGraph(m_goalBuilding); + m_goalBuildingKey = getKey(m_goalBuilding); + m_goalBuildingNodeIndex = getIndexFor(m_goalBuilding,m_goalBuildingGraph,m_goal,m_goalCellPart); + + // If they're in the same building, start the search in the building + + if((m_creatureBuilding == m_goalBuilding) && (m_creatureBuilding != NULL)) + { + return buildPathInternal(m_creatureBuilding,m_creatureBuildingGraph,m_creatureBuildingNodeIndex,m_goalBuildingNodeIndex); + } + } + + // ---------- + // If they're in the same city, start the search in the city + + m_creatureCityGraph = CityPathGraphManager::getCityGraphFor(m_creature); + m_creatureCityNodeIndex = getIndexFor(m_creatureCityGraph,m_creatureBuilding,m_creature); + + m_goalCityGraph = CityPathGraphManager::getCityGraphFor(m_goal.getPosition_w()); + m_goalCityNodeIndex = getIndexFor(m_goalCityGraph,m_goalBuilding,m_goal); + + if((m_creatureCityGraph == m_goalCityGraph) && (m_creatureCityGraph != NULL)) + { + // hack - If a creature in a city region tries to path search but it's not near a path node, + // make its path search succeed + + if(m_creatureCell == worldCell) + { + if((m_creatureCityNodeIndex == -2) && (m_goalCityNodeIndex == -2)) + { + m_pathIncomplete = true; + return true; + } + + if(m_creatureCityNodeIndex == -2) + { + m_creatureCityNodeIndex = m_creatureCityGraph->findNearestNode(m_creature->getPosition_p()); + } + + if(m_goalCityNodeIndex == -2) + { + m_goalCityNodeIndex = m_goalCityGraph->findNearestNode(m_goal.getPosition_p()); + } + } + + return buildPathInternal(m_creatureCityGraph,m_creatureCityNodeIndex,m_goalCityNodeIndex); + } + + // ---------- + // They're not in the same city, but they have to be in the same world. + + return buildPath_World(); +} + +// ---------------------------------------------------------------------- + +bool ServerPathBuilder::buildPath_Named ( void ) +{ + m_path->clear(); + + // ---------- + + m_creatureCell = m_creature->getParentCell(); + m_creatureCellGraph = getGraph(m_creatureCell); + m_creatureCellKey = getKey(m_creatureCell); + m_creatureCellNodeIndex = getIndexFor(m_creatureCell,m_creatureCellGraph,m_creature); + + if(m_creatureCellGraph && (m_creatureCellNodeIndex >= 0)) + { + m_creatureCellPart = m_creatureCellGraph->getNode(m_creatureCellNodeIndex)->getPartId(); + } + else + { + m_creatureCellPart = -1; + } + + m_creatureBuilding = m_creatureCell->getPortalProperty(); + m_creatureBuildingGraph = getGraph(m_creatureBuilding); + m_creatureBuildingKey = getKey(m_creatureBuilding); + m_creatureBuildingNodeIndex = getIndexFor(m_creatureBuilding,m_creatureBuildingGraph,m_creature); + + m_creatureCityGraph = CityPathGraphManager::getCityGraphFor(m_creature); + m_creatureCityNodeIndex = getIndexFor(m_creatureCityGraph,m_creatureBuilding,m_creature); + + // ---------- + + if(m_creatureCityGraph != NULL) + { + IndexList goalList; + + int nodeCount = m_creatureCityGraph->getNodeCount(); + + for(int i = 0; i < nodeCount; i++) + { + CityPathNode const * node = m_creatureCityGraph->_getNode(i); + + if(node == NULL) continue; + + if(node->getName() == m_goalName) + { + goalList.push_back(i); + } + } + + return buildPathInternal(m_creatureCityGraph,m_creatureCityNodeIndex,goalList); + } + else + { + return false; + } +} + +// ---------------------------------------------------------------------- +// Fine(er)-grained time management isn't in yet - this is an +// all-or-nothing update + +extern float pathSearchTime; +extern float pathBuildTime; + +void ServerPathBuilder::update ( void ) +{ + bool buildOk = false; + + pathSearchTime = 0; + +#ifdef _DEBUG + + PerformanceTimer timer; + + timer.start(); + +#endif + + if(!m_buildDone) + { + if(m_goalName.empty()) + { + buildOk = buildPath_ToGoal(); + } + else + { + buildOk = buildPath_Named(); + } + } + +#ifdef _DEBUG + + timer.stop(); + + pathBuildTime = timer.getElapsedTime(); + +#endif + + m_buildDone = true; + + if(!buildOk) + { + m_buildFailed = true; + } +} + +// ---------------------------------------------------------------------- + +bool ServerPathBuilder::setupBuildPath ( CreatureObject const * creature, AiLocation const & goal ) +{ + if(creature == NULL) return false; + if(!goal.isValid()) return false; + + m_creature = creature; + m_goal = goal; + m_goalName.clear(); + m_buildDone = false; + m_buildFailed = false; + m_pathIncomplete = false; + + return true; +} + +// ---------- + +bool ServerPathBuilder::setupBuildPath ( CreatureObject const * creature, Unicode::String const & goalName ) +{ + if(creature == NULL) return false; + if(goalName.empty()) return false; + + m_creature = creature; + m_goal = AiLocation(); + m_goalName = goalName; + m_buildDone = false; + m_buildFailed = false; + m_pathIncomplete = false; + + return true; +} + +// ---------------------------------------------------------------------- + +bool ServerPathBuilder::buildPath_Async ( CreatureObject const * creature, AiLocation const & goal ) +{ + if(!setupBuildPath(creature,goal)) return false; + + ServerPathBuildManager::queue(this,false); + + return true; +} + +// ---------- + +bool ServerPathBuilder::buildPath_Async ( CreatureObject const * creature, Unicode::String const & goalName ) +{ + if(!setupBuildPath(creature,goalName)) return false; + + ServerPathBuildManager::queue(this,false); + + return true; +} + +// ---------------------------------------------------------------------- + +bool ServerPathBuilder::buildPath ( CreatureObject const * creature, AiLocation const & goal ) +{ + if(!setupBuildPath(creature,goal)) return false; + + update(); + + return !m_buildFailed; +} + +// ---------- + +bool ServerPathBuilder::buildPath ( CreatureObject const * creature, Unicode::String const & goalName ) +{ + if(!setupBuildPath(creature,goalName)) return false; + + update(); + + return !m_buildFailed; +} + +// ---------------------------------------------------------------------- + +bool ServerPathBuilder::buildWorldPath(AiLocation const &startLocation, AiLocation const &endLocation) +{ + if (!startLocation.isValid() || !endLocation.isValid()) + return false; + + m_creature = 0; + m_goal = endLocation; + m_goalName.clear(); + m_buildDone = false; + m_buildFailed = false; + m_pathIncomplete = false; + + m_path->clear(); + + m_goal.update(); + + if (!m_goal.isValid()) + return false; + + CellProperty const * const worldCell = CellProperty::getWorldCellProperty(); + + m_creatureCell = worldCell; + m_goalCell = worldCell; + + // Both the creature and the goal are in the world cell, so + // we can skip some work with looking up their cell and building + // info. + + m_creatureCellGraph = NULL; + m_creatureCellKey = -1; + m_creatureCellNodeIndex = -1; + m_creatureCellPart = -1; + + m_goalCellGraph = NULL; + m_goalCellKey = -1; + m_goalCellNodeIndex = -1; + m_goalCellPart = -1; + + m_creatureBuilding = NULL; + m_creatureBuildingGraph = NULL; + m_creatureBuildingKey = -1; + m_creatureBuildingNodeIndex = -1; + + m_goalBuilding = NULL; + m_goalBuildingGraph = NULL; + m_goalBuildingKey = -1; + m_goalBuildingNodeIndex = -1; + + // ---------- + // If they're in the same city, start the search in the city + + m_creatureCityGraph = CityPathGraphManager::getCityGraphFor(startLocation.getPosition_p()); + m_creatureCityNodeIndex = getIndexFor(m_creatureCityGraph, m_creatureBuilding, startLocation); + + m_goalCityGraph = CityPathGraphManager::getCityGraphFor(m_goal.getPosition_p()); + m_goalCityNodeIndex = getIndexFor(m_goalCityGraph, m_goalBuilding, m_goal); + + if (m_creatureCityGraph == m_goalCityGraph && m_creatureCityGraph) + { + if (m_creatureCityNodeIndex == -2) + m_creatureCityNodeIndex = m_creatureCityGraph->findNearestNode(startLocation.getPosition_p()); + if (m_goalCityNodeIndex == -2) + m_goalCityNodeIndex = m_goalCityGraph->findNearestNode(m_goal.getPosition_p()); + + return buildPathInternal(m_creatureCityGraph, m_creatureCityNodeIndex, m_goalCityNodeIndex); + } + + // ---------- + // They're not in the same city, but they have to be in the same world. + + Vector exitPoint = startLocation.getPosition_p(); + + if (m_creatureCityGraph && m_creatureCityNodeIndex >= 0) + { + int const indexA = m_creatureCityNodeIndex; + int const indexB = m_creatureCityGraph->findNearestNode(m_goal.getPosition_p()); + + if (!buildPathInternal(m_creatureCityGraph, indexA, indexB)) + return false; + + if (indexB >= 0) + { + PathNode const * const exitNode = m_creatureCityGraph->getNode(indexB); + if (exitNode) + exitPoint = exitNode->getPosition_p(); + } + } + + if (m_goalCityGraph && m_goalCityNodeIndex >= 0) + { + int const indexA = m_goalCityGraph->findNearestNode(exitPoint); + int const indexB = m_goalCityNodeIndex; + + if (!buildPathInternal(m_goalCityGraph, indexA, indexB)) + return false; + } + + return true; +} + +// ---------------------------------------------------------------------- + +void ServerPathBuilder::addPathNode ( CellProperty const * cell, PathNode const * node ) +{ + if(node == NULL) return; + if(cell == NULL) cell = CellProperty::getWorldCellProperty(); + + AiLocation loc(cell,node->getPosition_p()); + + float dist2 = REAL_MAX; + + if(m_path && !m_path->empty()) dist2 = m_path->back().getPosition_w().magnitudeBetweenSquared(loc.getPosition_w()); + + if(dist2 > 0.01) + { + // jitter the node if it's a city waypoint + + if(m_enableJitter && (node->getType() == PNT_CityWaypoint)) + { + Vector offset = Vector::zero; + + do + { + offset = Vector( Random::randomReal(-1.0f,1.0f), 0.0f, Random::randomReal(-1.0f,1.0f) ); + } + while(offset.magnitudeSquared() > 1.0f); + + static float tweakValue = 1.0f; + + offset *= tweakValue; + + loc.setPosition_p( loc.getPosition_p() + offset ); + } + + m_path->push_back(loc); + } +} + + +// ---------------------------------------------------------------------- + +bool ServerPathBuilder::buildPathImmediate(AiLocation const & creature, AiLocation const & goal) +{ + m_creature = NULL; + m_goal = goal; + m_buildDone = false; + m_buildFailed = false; + m_pathIncomplete = false; + + m_creatureCell = creature.getCell(); + m_goalCell = m_goal.getCell(); + m_creaturePosition = creature.getPosition_w(); + + m_path->clear(); + m_goalName.clear(); + m_goal.update(); + + + // ---------- + CellProperty const * worldCell = CellProperty::getWorldCellProperty(); + if(m_creatureCell == NULL) + m_creatureCell = worldCell; + if(m_goalCell == NULL) + m_goalCell = worldCell; + + + // Look up cell info + m_creatureCellGraph = getGraph(m_creatureCell); + m_creatureCellKey = getKey(m_creatureCell); + m_creatureCellNodeIndex = getIndexFor(m_creatureCell, m_creatureCellGraph, creature); + + if(m_creatureCellGraph && (m_creatureCellNodeIndex >= 0)) + { + m_creatureCellPart = m_creatureCellGraph->getNode(m_creatureCellNodeIndex)->getPartId(); + } + else + { + m_creatureCellPart = -1; + } + + m_goalCellGraph = getGraph(m_goalCell); + m_goalCellKey = getKey(m_goalCell); + m_goalCellNodeIndex = getIndexFor(m_goalCell, m_goalCellGraph, m_goal, 0.0f); + + if(m_goalCellGraph && (m_goalCellNodeIndex >= 0)) + { + m_goalCellPart = m_goalCellGraph->getNode(m_goalCellNodeIndex)->getPartId(); + } + else + { + m_goalCellPart = -1; + } + + + // Look up building info + m_creatureBuilding = m_creatureCell->getPortalProperty(); + m_creatureBuildingGraph = getGraph(m_creatureBuilding); + m_creatureBuildingKey = getKey(m_creatureBuilding); + m_creatureBuildingNodeIndex = getIndexFor(m_creatureBuilding, m_creatureBuildingGraph, creature, m_creatureCellPart); + + m_goalBuilding = m_goalCell->getPortalProperty(); + m_goalBuildingGraph = getGraph(m_goalBuilding); + m_goalBuildingKey = getKey(m_goalBuilding); + m_goalBuildingNodeIndex = getIndexFor(m_goalBuilding, m_goalBuildingGraph, m_goal, m_goalCellPart); + + // If they're in the same building, start the search in the building + if((m_creatureBuilding == m_goalBuilding) && (m_creatureBuilding != NULL)) + { + if (buildPathInternal(m_creatureBuilding, m_creatureBuildingGraph, m_creatureBuildingNodeIndex, m_goalBuildingNodeIndex)) + return true; + } + + // If they're in the same cell, start the search in the cell + if((m_creatureCell == m_goalCell) && (m_creatureCell != NULL) && (m_creatureCell != CellProperty::getWorldCellProperty()) && (m_creatureCellPart == m_goalCellPart)) + { + if (buildPathInternal(m_creatureCell, m_creatureCellGraph, m_creatureCellNodeIndex, m_goalCellNodeIndex)) + return true; + } + + // ---------- + // If they're in the same city, start the search in the city + m_creatureCityGraph = CityPathGraphManager::getCityGraphFor(m_creaturePosition); + m_creatureCityNodeIndex = getIndexFor(m_creatureCityGraph,m_creatureBuilding, creature); + + m_goalCityGraph = CityPathGraphManager::getCityGraphFor(m_goal.getPosition_w()); + m_goalCityNodeIndex = getIndexFor(m_goalCityGraph,m_goalBuilding,m_goal); + + if((m_creatureCityGraph == m_goalCityGraph) && (m_creatureCityGraph != NULL)) + { + // hack - If a creature in a city region tries to path search but it's not near a path node, + // make its path search succeed + + if(m_creatureCell == worldCell) + { + if((m_creatureCityNodeIndex == -2) && (m_goalCityNodeIndex == -2)) + { + m_pathIncomplete = true; + return true; + } + + if(m_creatureCityNodeIndex == -2) + { + m_creatureCityNodeIndex = m_creatureCityGraph->findNearestNode(m_creaturePosition); + } + + if(m_goalCityNodeIndex == -2) + { + m_goalCityNodeIndex = m_goalCityGraph->findNearestNode(m_goal.getPosition_w()); + } + } + + if (buildPathInternal(m_creatureCityGraph,m_creatureCityNodeIndex,m_goalCityNodeIndex)) + return true; + } + + // ---------- + // They're not in the same city, but they have to be in the same world. + + return buildPath_World(); +} + diff --git a/engine/server/library/serverPathfinding/src/shared/ServerPathBuilder.h b/engine/server/library/serverPathfinding/src/shared/ServerPathBuilder.h new file mode 100644 index 00000000..ab9615f0 --- /dev/null +++ b/engine/server/library/serverPathfinding/src/shared/ServerPathBuilder.h @@ -0,0 +1,182 @@ +// ====================================================================== +// +// ServerPathBuilder.h +// Copyright 2002 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_ServerPathBuilder_H +#define INCLUDED_ServerPathBuilder_H + +#include "serverGame/AiLocation.h" +#include "Unicode.h" + +class CreatureObject; +class AiLocation; +class CellProperty; +class PortalProperty; +class CityPathGraph; +class PathGraph; +class PathSearch; +class PathNode; +class ServerObject; + +typedef stdlist::fwd AiPath; +typedef stdvector::fwd IndexList; + +// ====================================================================== + +int findClosestPathNode( CreatureObject const * creature, PathGraph const * graph ); +int findClosestReachablePathNode( CreatureObject const * creature, PathGraph const * graph ); +int findClosestReachablePathNode ( CellProperty const * cell, Vector const & start, float radius, PathGraph const * graph ); + +// ====================================================================== + +class ServerPathBuilder +{ +public: + + ServerPathBuilder(); + virtual ~ServerPathBuilder(); + + bool buildPath ( CreatureObject const * creature, AiLocation const & goal ); + bool buildPath ( CreatureObject const * creature, Unicode::String const & goalName ); + bool buildWorldPath ( AiLocation const & startLocation, AiLocation const & goal ); + bool buildPathImmediate ( AiLocation const & startLocation, AiLocation const & goalLocation ); + + bool buildPath_Async ( CreatureObject const * creature, AiLocation const & goal ); + bool buildPath_Async ( CreatureObject const * creature, Unicode::String const & goalName ); + + void update ( void ); + + bool buildDone ( void ) const; + bool buildFailed ( void ) const; + + AiPath * getPath ( void ); + bool getPathIncomplete ( void ) const; + + bool getQueued ( void ) const; + void setQueued ( bool queued ); + + void setEnableJitter ( bool enable ); + +protected: + + bool buildPath_ToGoal ( void ); + bool buildPath_Named ( void ); + + bool setupBuildPath ( CreatureObject const * creature, AiLocation const & goal ); + bool setupBuildPath ( CreatureObject const * creature, Unicode::String const & goalName ); + + bool buildPathInternal ( CellProperty const * cell, PathGraph const * graph, int indexA, int indexB ); + bool buildPathInternal ( PortalProperty const * building, PathGraph const * graph, int indexA, int indexB ); + + bool buildPathInternal ( CityPathGraph const * cityGraph, int indexA, int indexB ); + bool buildPathInternal ( CityPathGraph const * cityGraph, int indexA, IndexList const & indexBList ); + + bool expandPath ( CityPathGraph const * cityGraph, IndexList const & path ); + + bool buildPath_World ( void ); + + void addPathNode ( CellProperty const * cell, PathNode const * node ); + + // ---------- + + CreatureObject const * m_creature; + + CellProperty const * m_creatureCell; + PathGraph const * m_creatureCellGraph; + int m_creatureCellKey; + int m_creatureCellNodeIndex; + int m_creatureCellPart; + PortalProperty const * m_creatureBuilding; + PathGraph const * m_creatureBuildingGraph; + int m_creatureBuildingKey; + int m_creatureBuildingNodeIndex; + CityPathGraph const * m_creatureCityGraph; + int m_creatureCityNodeIndex; + Vector m_creaturePosition; + + // ---------- + + AiLocation m_goal; + Unicode::String m_goalName; + + CellProperty const * m_goalCell; + PathGraph const * m_goalCellGraph; + int m_goalCellKey; + int m_goalCellNodeIndex; + int m_goalCellPart; + PortalProperty const * m_goalBuilding; + PathGraph const * m_goalBuildingGraph; + int m_goalBuildingKey; + int m_goalBuildingNodeIndex; + CityPathGraph const * m_goalCityGraph; + int m_goalCityNodeIndex; + + AiPath * m_path; + + // ---------- + + bool m_async; + bool m_buildDone; + bool m_buildFailed; + bool m_pathIncomplete; + bool m_enableJitter; + + // ---------- + + PathSearch * m_cellSearch; + + PathSearch * m_buildingSearch; + + PathSearch * m_citySearch; + + // ---------- + + bool m_queued; +}; + +// ---------------------------------------------------------------------- + +inline bool ServerPathBuilder::getQueued ( void ) const +{ + return m_queued; +} + +inline void ServerPathBuilder::setQueued ( bool queued ) +{ + m_queued = queued; +} + +// ---------- + +inline void ServerPathBuilder::setEnableJitter ( bool enable ) +{ + m_enableJitter = enable; +} + +// ---------- + +inline AiPath * ServerPathBuilder::getPath ( void ) +{ + return m_path; +} + +// ---------- + +inline bool ServerPathBuilder::buildDone ( void ) const +{ + return m_buildDone; +} + +inline bool ServerPathBuilder::buildFailed ( void ) const +{ + return m_buildFailed; +} + +// ====================================================================== + +#endif + diff --git a/engine/server/library/serverPathfinding/src/shared/ServerPathfinding.cpp b/engine/server/library/serverPathfinding/src/shared/ServerPathfinding.cpp new file mode 100644 index 00000000..1649dfc0 --- /dev/null +++ b/engine/server/library/serverPathfinding/src/shared/ServerPathfinding.cpp @@ -0,0 +1,46 @@ +// ====================================================================== +// +// ServerPathfinding.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "serverPathfinding/FirstServerPathfinding.h" +#include "serverPathfinding/ServerPathfinding.h" + +#include "serverPathfinding/CityPathGraphManager.h" +#include "serverPathfinding/ServerPathBuildManager.h" + +#ifdef _DEBUG + +#include "sharedDebug/PerformanceTimer.h" + +#endif + +// ====================================================================== + +void ServerPathfinding::update ( float timeBudget ) +{ + CityPathGraphManager::update(0.0f); + +#ifdef _DEBUG + extern float pathfindingTime; + + PerformanceTimer timer; + + timer.start(); + +#endif + + ServerPathBuildManager::update(timeBudget); + +#ifdef _DEBUG + + timer.stop(); + + pathfindingTime = timer.getElapsedTime(); + +#endif +} + +// ====================================================================== diff --git a/engine/server/library/serverPathfinding/src/shared/ServerPathfinding.h b/engine/server/library/serverPathfinding/src/shared/ServerPathfinding.h new file mode 100644 index 00000000..96eff882 --- /dev/null +++ b/engine/server/library/serverPathfinding/src/shared/ServerPathfinding.h @@ -0,0 +1,24 @@ +// ====================================================================== +// +// ServerPathfinding.h +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_ServerPathfinding_H +#define INCLUDED_ServerPathfinding_H + +// ====================================================================== + +class ServerPathfinding +{ +public: + + static void update ( float timeBudget ); +}; + +// ====================================================================== + +#endif + diff --git a/engine/server/library/serverPathfinding/src/shared/ServerPathfindingConstants.cpp b/engine/server/library/serverPathfinding/src/shared/ServerPathfindingConstants.cpp new file mode 100644 index 00000000..845e2e4d --- /dev/null +++ b/engine/server/library/serverPathfinding/src/shared/ServerPathfindingConstants.cpp @@ -0,0 +1,30 @@ +// ====================================================================== +// +// ServerPathfindingConstants.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "serverPathfinding/FirstServerPathfinding.h" +#include "serverPathfinding/ServerPathfindingConstants.h" + +#include + +const int CITY_REGION_TYPE = 20; +const int PATHFINDING_REGION_TYPE = 22; + +std::string const SERVER_PATHFINDING_WAYPOINT_TEMPLATE("object/path_waypoint/path_waypoint.iff"); +std::string const SERVER_PATHFINDING_WAYPOINT_TEMPLATE_BASE("object/path_waypoint/base/path_waypoint_base.iff"); +std::string const SERVER_PATHFINDING_WAYPOINT_TEMPLATE_AUTO_SPAWN("object/path_waypoint/path_waypoint_auto_spawn.iff"); + +std::string const OBJVAR_PATHFINDING("pathfinding"); + +std::string const OBJVAR_PATHFINDING_WAYPOINT_CREATOR("pathfinding.waypoint.creator"); +std::string const OBJVAR_PATHFINDING_WAYPOINT_EDGES("pathfinding.waypoint.edges"); +std::string const OBJVAR_PATHFINDING_WAYPOINT_KEY("pathfinding.waypoint.key"); +std::string const OBJVAR_PATHFINDING_WAYPOINT_NAME("pathfinding.waypoint.name"); +std::string const OBJVAR_PATHFINDING_WAYPOINT_TYPE("pathfinding.waypoint.type"); + +std::string const OBJVAR_PATHFINDING_BUILDING_PROCESSED("pathfinding.building.processed"); +std::string const OBJVAR_PATHFINDING_BUILDING_WAYPOINTS("pathfinding.building.waypoints"); + diff --git a/engine/server/library/serverPathfinding/src/shared/ServerPathfindingConstants.h b/engine/server/library/serverPathfinding/src/shared/ServerPathfindingConstants.h new file mode 100644 index 00000000..0ed88239 --- /dev/null +++ b/engine/server/library/serverPathfinding/src/shared/ServerPathfindingConstants.h @@ -0,0 +1,36 @@ +// ====================================================================== +// +// ServerPathfindingConstants.h +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_ServerPathfindingConstants_H +#define INCLUDED_ServerPathfindingConstants_H + +// ====================================================================== + +extern int const CITY_REGION_TYPE; +extern int const PATHFINDING_REGION_TYPE; + +extern std::string const SERVER_PATHFINDING_WAYPOINT_TEMPLATE; +extern std::string const SERVER_PATHFINDING_WAYPOINT_TEMPLATE_BASE; +extern std::string const SERVER_PATHFINDING_WAYPOINT_TEMPLATE_AUTO_SPAWN; + +extern std::string const OBJVAR_PATHFINDING; + +extern std::string const OBJVAR_PATHFINDING_WAYPOINT_CREATOR; +extern std::string const OBJVAR_PATHFINDING_WAYPOINT_EDGES; +extern std::string const OBJVAR_PATHFINDING_WAYPOINT_KEY; +extern std::string const OBJVAR_PATHFINDING_WAYPOINT_NAME; +extern std::string const OBJVAR_PATHFINDING_WAYPOINT_TYPE; + +extern std::string const OBJVAR_PATHFINDING_BUILDING_PROCESSED; +extern std::string const OBJVAR_PATHFINDING_BUILDING_WAYPOINTS; + + +// ====================================================================== + +#endif + diff --git a/engine/server/library/serverPathfinding/src/shared/ServerPathfindingMessaging.cpp b/engine/server/library/serverPathfinding/src/shared/ServerPathfindingMessaging.cpp new file mode 100644 index 00000000..068f9d3a --- /dev/null +++ b/engine/server/library/serverPathfinding/src/shared/ServerPathfindingMessaging.cpp @@ -0,0 +1,549 @@ +// ====================================================================== +// +// ServerPathfindingMessaging.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "serverPathfinding/FirstServerPathfinding.h" +#include "serverPathfinding/ServerPathfindingMessaging.h" + +#include "serverGame/AiLocation.h" +#include "serverGame/CellObject.h" +#include "serverGame/Client.h" +#include "serverGame/ContainerInterface.h" +#include "serverGame/CreatureController.h" +#include "serverGame/CreatureObject.h" +#include "serverGame/GameServer.h" +#include "serverGame/PlayerCreatureController.h" +#include "serverGame/ServerObject.h" +#include "serverGame/ServerWorld.h" +#include "serverPathfinding/CityPathGraph.h" +#include "serverPathfinding/CityPathGraphManager.h" +#include "serverPathfinding/CityPathNode.h" +#include "serverScript/GameScriptObject.h" +#include "serverScript/ScriptFunctionTable.h" +#include "serverScript/ScriptParameters.h" +#include "sharedCollision/CollisionWorld.h" +#include "sharedFoundation/Crc.h" +#include "sharedGame/CommandTable.h" +#include "sharedNetworkMessages/AIDebuggingMessages.h" +#include +#include + +ServerPathfindingMessaging * g_messaging = NULL; + +// ====================================================================== + +void ServerPathfindingMessaging::install ( void ) +{ + g_messaging = new ServerPathfindingMessaging(); + + g_messaging->connectToMessage(RequestWatchObjectPath::MESSAGE_TYPE); + g_messaging->connectToMessage(RequestWatchPathMap::MESSAGE_TYPE); + g_messaging->connectToMessage(RequestUnstick::MESSAGE_TYPE); +} + +void ServerPathfindingMessaging::remove ( void ) +{ + g_messaging->disconnectFromMessage(RequestWatchObjectPath::MESSAGE_TYPE); + g_messaging->disconnectFromMessage(RequestWatchPathMap::MESSAGE_TYPE); + g_messaging->disconnectFromMessage(RequestUnstick::MESSAGE_TYPE); + + delete g_messaging; + g_messaging = NULL; +} + +ServerPathfindingMessaging & ServerPathfindingMessaging::getInstance ( void ) +{ + return *g_messaging; +} + +// ---------------------------------------------------------------------- + +ServerPathfindingMessaging::ServerPathfindingMessaging() +: m_clientList( new ClientList() ), + m_callback( new MessageDispatch::Callback ) +{ +} + +ServerPathfindingMessaging::~ServerPathfindingMessaging() +{ + for(ClientList::iterator it = m_clientList->begin(); it != m_clientList->end(); ++it) + { + ignorePathMap(*it); + } + + delete m_clientList; + m_clientList = NULL; + + delete m_callback; + m_callback = NULL; +} + +// ---------- + +void ServerPathfindingMessaging::receiveMessage(const MessageDispatch::Emitter & source, const MessageDispatch::MessageBase & message) +{ + UNREF(source); + + if(message.isType(RequestWatchObjectPath::MESSAGE_TYPE)) + { + const RequestWatchObjectPath &m = dynamic_cast(message); + CachedNetworkId cid(m.getClientId()); + ServerObject * s = static_cast(cid.getObject()); + Client * client = s->getClient(); + if (m.getEnable()) + { + watchObjectPath(client, m.getObjectId()); + } + else + { + ignoreObjectPath(client, m.getObjectId()); + } + } + else if(message.isType(RequestWatchPathMap::MESSAGE_TYPE)) + { + const RequestWatchPathMap &m = dynamic_cast(message); + CachedNetworkId cid(m.getClientId()); + ServerObject * s = static_cast(cid.getObject()); + Client * client = s->getClient(); + if (m.getEnable()) + { + watchPathMap(client); + } + else + { + ignorePathMap(client); + } + } + else if(message.isType(RequestUnstick::MESSAGE_TYPE)) + { + const RequestUnstick &m = dynamic_cast(message); + CachedNetworkId cid(m.getClientId()); + ServerObject * s = static_cast(cid.getObject()); + NOT_NULL(s); + + // Give the scripts a chance to handle the "unsticking" + GameScriptObject * const gso = s->getScriptObject(); + if (gso) + { + ScriptParams scriptParams; + if (SCRIPT_OVERRIDE == gso->trigAllScripts(Scripting::TRIG_UNSTICKING, scriptParams)) + { + //-- script has handled the unstick + return; + } + } + + // unsticking a player character in Restuss always takes the character + // to the imperial cloning center if he is imperial, rebel cloning + // center if he is rebel, or starport if he is neutral + if (ServerWorld::getSceneId() == std::string("rori")) + { + CreatureObject * co = s->asCreatureObject(); + if (co && PlayerCreatureController::getPlayerObject(co)) + { + Vector const location = s->getPosition_w(); + + // restuss_nobuild_1 region + if ((location.x >= 4518.0f) && (location.x <= 6118.0f) && (location.z >= 4880.0f) && (location.z <= 6480.0f)) + { + Vector unstickPoint; + + if (PvpData::isImperialFactionId(co->getPvpFaction())) + { + // imperial installation + unstickPoint.x = 5878.0f; + unstickPoint.y = 81.0f; + unstickPoint.z = 5581.0f; + } + else if (PvpData::isRebelFactionId(co->getPvpFaction())) + { + // rebel installation + unstickPoint.x = 4863.0f; + unstickPoint.y = 77.0f; + unstickPoint.z = 5876.0f; + } + else + { + // starport + unstickPoint.x = 5304.0f; + unstickPoint.y = 80.0f; + unstickPoint.z = 6185.0f; + } + + CreatureController * controller = co->getCreatureController(); + if (controller) + { + Transform newTransform = Transform::identity; + newTransform.setPosition_p(unstickPoint); + controller->teleport(newTransform, NULL); + } + + return; + } + } + } + + Vector unstickPoint; + CellObject * cell = ContainerInterface::getContainingCellObject(*s); + if (cell != NULL && s->asCreatureObject() != NULL) + { + // try finding a waypoint in the cell first + if (!cell->getClosestPathNodePos(*s, unstickPoint)) + { + // if there are no waypoints, use the /eject command + s->asCreatureObject()->commandQueueEnqueue(CommandTable::getCommand( + Crc::calculate("eject")), NetworkId::cms_invalid, Unicode::String()); + } + } + else + { + // teleport the object to a close-by waypoint + if (!CityPathGraphManager::getClosestPathNodePos(s,unstickPoint)) + { + // try using ServerWorld::getGoodLocation to find a spot + static const float SEARCH_SIZE = 32.0f; + const Vector center(s->getPosition_w()); + const Vector llArea(center.x - SEARCH_SIZE, center.y, center.z - SEARCH_SIZE); + const Vector urArea(center.x + SEARCH_SIZE, center.y, center.z + SEARCH_SIZE); + unstickPoint = ServerWorld::getGoodLocation(5.0f, 5.0f, llArea, urArea, false, true); + + // unstick failed - warp them to Mos Eisley starport + if(unstickPoint.x == 0 && unstickPoint.y == 0 && unstickPoint.z == 0) + { + // only warp them to mos eisley if they are on one of the 10 original planets + const std::string mySceneId = s->getSceneId(); + if(mySceneId == "corellia" + || mySceneId == "dantooine" + || mySceneId == "dathomir" + || mySceneId == "endor" + || mySceneId == "lok" + || mySceneId == "naboo" + || mySceneId == "rori" + || mySceneId == "talus" + || mySceneId == "tatooine" + || mySceneId == "yavin4" + ) + { + GameServer::getInstance().requestSceneWarp(CachedNetworkId(*s),"tatooine",Vector(3528,5,-4804),NetworkId::cms_invalid,Vector(3528,5,-4804)); + return; + } + } + } + } + if (unstickPoint.x != 0 || unstickPoint.y != 0 || unstickPoint.z != 0) + { + CreatureController * controller = dynamic_cast(s->getController()); + if (controller) + { + Transform newTransform = Transform::identity; + newTransform.setPosition_p(unstickPoint); + controller->teleport(newTransform, cell); + } + } + } +} + +// ---------------------------------------------------------------------- + +void ServerPathfindingMessaging::watchObjectPath(Client * client, const NetworkId &object) +{ + UNREF(client); + UNREF(object); +} + +// ---------- + +void ServerPathfindingMessaging::ignoreObjectPath(Client * client, const NetworkId &object) +{ + UNREF(client); + UNREF(object); +} + +// ---------------------------------------------------------------------- + +void ServerPathfindingMessaging::watchPathMap(Client * client) +{ + if(client == NULL) return; + + // Add the client to our client list + + m_clientList->insert(client); + + // and send it all the graphs we have + + int count = CityPathGraphManager::getGraphCount(); + + for(int i = 0; i < count; i++) + { + CityPathGraph const * graph = CityPathGraphManager::getGraph(i); + + sendGraphInfo(graph,client); + } + + m_callback->connect(client->getDestroyNotifier(), *this, &ServerPathfindingMessaging::onClientDestroy); +} + +// ---------- + +void ServerPathfindingMessaging::ignorePathMap(Client * client) +{ + if(client == NULL) return; + + m_clientList->erase(client); + + int count = CityPathGraphManager::getGraphCount(); + + for(int i = 0; i < count; i++) + { + CityPathGraph const * graph = CityPathGraphManager::getGraph(i); + + sendEraseGraph(graph,client); + } + + m_callback->disconnect(client->getDestroyNotifier(), *this, &ServerPathfindingMessaging::onClientDestroy); +} + +// ---------------------------------------------------------------------- + +void ServerPathfindingMessaging::onClientDestroy(ClientDestroy & d) +{ + m_clientList->erase(d.client); + + m_callback->disconnect(d.client->getDestroyNotifier(), *this, &ServerPathfindingMessaging::onClientDestroy); +} + +// ---------------------------------------------------------------------- + +void ServerPathfindingMessaging::sendGraphInfo ( CityPathGraph const * graph ) +{ + if(graph == NULL) return; + + for(ClientList::iterator it = m_clientList->begin(); it != m_clientList->end(); ++it) + { + sendGraphInfo( graph, (*it) ); + } +} + +// ---------- + +void ServerPathfindingMessaging::sendGraphInfo ( CityPathGraph const * graph, Client * client ) +{ + if(client == NULL) return; + if(graph == NULL) return; + + int nodeCount = graph->getNodeCount(); + + for(int i = 0; i < nodeCount; i++) + { + CityPathNode const * node = graph->_getNode(i); + + if(node) sendNodeInfo(node,client); + } +} + +// ---------------------------------------------------------------------- + +void ServerPathfindingMessaging::sendEraseGraph ( CityPathGraph const * graph ) +{ + if(graph == NULL) return; + + for(ClientList::iterator it = m_clientList->begin(); it != m_clientList->end(); ++it) + { + sendEraseGraph( graph, (*it) ); + } +} + +// ---------- + +void ServerPathfindingMessaging::sendEraseGraph ( CityPathGraph const * graph, Client * client ) +{ + if(client == NULL) return; + if(graph == NULL) return; + + int nodeCount = graph->getNodeCount(); + + for(int i = 0; i < nodeCount; i++) + { + CityPathNode const * node = graph->_getNode(i); + + if(node) sendEraseNode(node,client); + } +} + +// ---------------------------------------------------------------------- + +void ServerPathfindingMessaging::sendNodeInfo ( CityPathNode const * node ) +{ + if(node == NULL) return; + + for(ClientList::iterator it = m_clientList->begin(); it != m_clientList->end(); ++it) + { + sendNodeInfo( node, (*it) ); + } +} + +// ---------- + +void ServerPathfindingMessaging::sendNodeInfo ( CityPathNode const * node, Client * client ) +{ + if(node == NULL) return; + if(client == NULL) return; + + AINodeInfo m; + + m.setNodeId(node->getDebugId()); + m.setLocation(node->getPosition_p()); + m.setLevel(0); + m.setParent(0); + + std::vector children; + m.setChildren(children); + + std::vector siblings; + + int edgeCount = node->getEdgeCount(); + + for(int i = 0; i < edgeCount; i++) + { + int neighborIndex = node->getNeighbor(i); + + CityPathNode const * neighbor = node->_getGraph()->_getNode(neighborIndex); + + if(neighbor) siblings.push_back(neighbor->getDebugId()); + } + + m.setSiblings(siblings); + + m.setType(0); + + // ---------- + + client->send(m, true); +} + +// ---------------------------------------------------------------------- + +void ServerPathfindingMessaging::sendNeighborInfo ( CityPathNode const * node ) +{ + if(node == NULL) return; + + for(ClientList::iterator it = m_clientList->begin(); it != m_clientList->end(); ++it) + { + sendNeighborInfo( node, (*it) ); + } +} + +// ---------- + +void ServerPathfindingMessaging::sendNeighborInfo ( CityPathNode const * node, Client * client ) +{ + if(node == NULL) return; + if(client == NULL) return; + + int edgeCount = node->getEdgeCount(); + + for(int i = 0; i < edgeCount; i++) + { + int neighborIndex = node->getNeighbor(i); + + CityPathNode const * neighbor = node->_getGraph()->_getNode(neighborIndex); + + if(neighbor) sendNodeInfo(neighbor,client); + } +} + +// ---------------------------------------------------------------------- + +void ServerPathfindingMessaging::sendEraseNode ( CityPathNode const * node ) +{ + if(node == NULL) return; + + for(ClientList::iterator it = m_clientList->begin(); it != m_clientList->end(); ++it) + { + sendEraseNode( node, (*it) ); + } +} + +// ---------- + +void ServerPathfindingMessaging::sendEraseNode ( CityPathNode const * node, Client * client ) +{ + if(node == NULL) return; + if(client == NULL) return; + + AINodeInfo m; + + m.setNodeId(node->getDebugId()); + m.setLocation(Vector::zero); + m.setLevel(0); + m.setParent(0); + m.setType(-1); + + client->send(m, true); +} + +// ---------------------------------------------------------------------- + +void ServerPathfindingMessaging::sendWaypointInfo ( AiLocation const & loc ) +{ + for(ClientList::iterator it = m_clientList->begin(); it != m_clientList->end(); ++it) + { + sendWaypointInfo( loc, (*it) ); + } +} + +void ServerPathfindingMessaging::sendWaypointInfo ( AiLocation const & loc, Client * client ) +{ + if(client == NULL) return; + + AINodeInfo m; + + m.setNodeId(loc.getDebugId()); + m.setLocation(loc.getPosition_w()); + m.setLevel(0); + m.setParent(0); + + std::vector children; + m.setChildren(children); + + std::vector siblings; + m.setSiblings(siblings); + + m.setType(1); + + // ---------- + + client->send(m, true); +} + +// ---------------------------------------------------------------------- + +void ServerPathfindingMessaging::sendEraseWaypoint ( AiLocation const & loc ) +{ + for(ClientList::iterator it = m_clientList->begin(); it != m_clientList->end(); ++it) + { + sendEraseWaypoint( loc, (*it) ); + } +} + +void ServerPathfindingMessaging::sendEraseWaypoint ( AiLocation const & loc, Client * client ) +{ + if(client == NULL) return; + + AINodeInfo m; + + m.setNodeId(loc.getDebugId()); + m.setLocation(Vector::zero); + m.setLevel(0); + m.setParent(0); + m.setType(-1); + + client->send(m, true); +} + + +// ====================================================================== + diff --git a/engine/server/library/serverPathfinding/src/shared/ServerPathfindingMessaging.h b/engine/server/library/serverPathfinding/src/shared/ServerPathfindingMessaging.h new file mode 100644 index 00000000..1c351675 --- /dev/null +++ b/engine/server/library/serverPathfinding/src/shared/ServerPathfindingMessaging.h @@ -0,0 +1,82 @@ +// ====================================================================== +// +// ServerPathfindingMessaging.h +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_ServerPathfindingMessaging_H +#define INCLUDED_ServerPathfindingMessaging_H + +#include "sharedMessageDispatch/Receiver.h" +#include "sharedMessageDispatch/Transceiver.h" + +class CityPathGraph; +class CityPathNode; +class Client; +class NetworkId; +struct ClientDestroy; +class AiLocation; + +// ====================================================================== + +class ServerPathfindingMessaging : public MessageDispatch::Receiver +{ +public: + + static void install ( void ); + static void remove ( void ); + + static ServerPathfindingMessaging & getInstance ( void ); + + // ---------- + + ServerPathfindingMessaging(); + virtual ~ServerPathfindingMessaging(); + + // ---------- + + void sendGraphInfo ( CityPathGraph const * graph ); + void sendEraseGraph ( CityPathGraph const * graph ); + void sendNodeInfo ( CityPathNode const * node ); + void sendNeighborInfo ( CityPathNode const * node ); + void sendEraseNode ( CityPathNode const * node ); + void sendWaypointInfo ( AiLocation const & loc ); + void sendEraseWaypoint( AiLocation const & loc ); + +protected: + + void sendGraphInfo ( CityPathGraph const * graph, Client * client ); + void sendEraseGraph ( CityPathGraph const * graph, Client * client ); + void sendNodeInfo ( CityPathNode const * node, Client * client ); + void sendNeighborInfo ( CityPathNode const * node, Client * client ); + void sendEraseNode ( CityPathNode const * node, Client * client ); + void sendWaypointInfo ( AiLocation const & loc, Client * client ); + void sendEraseWaypoint( AiLocation const & loc, Client * client ); + + // ---------- + + void receiveMessage ( MessageDispatch::Emitter const & source, MessageDispatch::MessageBase const & message ); + + void watchObjectPath ( Client * client, NetworkId const & object ); + void ignoreObjectPath ( Client * client, NetworkId const & object ); + + void watchPathMap ( Client * client ); + void ignorePathMap ( Client * client ); + + void onClientDestroy ( ClientDestroy & d ); + + // ---------- + + typedef stdset::fwd ClientList; + + ClientList * m_clientList; + + MessageDispatch::Callback * m_callback; +}; + +// ====================================================================== + +#endif + diff --git a/engine/server/library/serverPathfinding/src/shared/ServerPathfindingNotification.cpp b/engine/server/library/serverPathfinding/src/shared/ServerPathfindingNotification.cpp new file mode 100644 index 00000000..d524776c --- /dev/null +++ b/engine/server/library/serverPathfinding/src/shared/ServerPathfindingNotification.cpp @@ -0,0 +1,127 @@ +// ====================================================================== +// +// ServerPathfindingNotification.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "serverPathfinding/FirstServerPathfinding.h" +#include "serverPathfinding/ServerPathfindingNotification.h" + +#include "serverGame/ServerObject.h" +#include "serverGame/BuildingObject.h" + +#include "serverPathfinding/CityPathGraphManager.h" +#include "serverPathfinding/ServerPathfindingConstants.h" + +#include "sharedObject/Object.h" + +namespace ServerPathfindingNotificationNamespace +{ + ServerPathfindingNotification g_notification; +}; + +using namespace ServerPathfindingNotificationNamespace; + +// ====================================================================== +// CityPathGraphManager notification + +ServerPathfindingNotification::ServerPathfindingNotification() +{ +} + +ServerPathfindingNotification::~ServerPathfindingNotification() +{ +} + +// ---------------------------------------------------------------------- + +void ServerPathfindingNotification::addToWorld ( Object & object ) const +{ + BuildingObject * building = dynamic_cast(&object); + + if(building) + { + CityPathGraphManager::addBuilding( building ); + } + else if(object.asServerObject() != NULL && object.asServerObject()->isWaypoint()) + { + CityPathGraphManager::addWaypoint( object.asServerObject() ); + } + else + { + } +} + +void ServerPathfindingNotification::removeFromWorld ( Object & object ) const +{ + BuildingObject * building = dynamic_cast(&object); + + if(building) + { + CityPathGraphManager::removeBuilding( building ); + } + else if(object.asServerObject() != NULL && object.asServerObject()->isWaypoint()) + { + CityPathGraphManager::removeWaypoint( object.asServerObject() ); + } + else + { + CityPathGraphManager::destroyPathGraph(object.asServerObject()); + } +} + +bool ServerPathfindingNotification::positionChanged ( Object & object, bool /*dueToParentChange*/, Vector const & oldPosition) const +{ + BuildingObject * building = dynamic_cast(&object); + + if(building) + { + CityPathGraphManager::moveBuilding( building, oldPosition ); + } + else if(object.asServerObject() != NULL && object.asServerObject()->isWaypoint()) + { + CityPathGraphManager::moveWaypoint( object.asServerObject(), oldPosition ); + } + + return true; +} + +bool ServerPathfindingNotification::positionAndRotationChanged ( Object & object, bool /*dueToParentChange*/, Vector const & oldPosition ) const +{ + BuildingObject * building = dynamic_cast(&object); + + if(building) + { + CityPathGraphManager::moveBuilding( building, oldPosition ); + } + else if(object.asServerObject() != NULL && object.asServerObject()->isWaypoint()) + { + CityPathGraphManager::moveWaypoint( object.asServerObject(), oldPosition ); + } + + return true; +} + +// ---------------------------------------------------------------------- + +void ServerPathfindingNotification::destroyBuilding ( BuildingObject * building ) +{ + CityPathGraphManager::destroyBuilding(building); +} + +// ---------------------------------------------------------------------- + +void ServerPathfindingNotification::destroyWaypoint ( ServerObject * building ) +{ + CityPathGraphManager::destroyWaypoint(building); +} + +// ---------------------------------------------------------------------- + +ServerPathfindingNotification & ServerPathfindingNotification::getInstance ( void ) +{ + return g_notification; +} + +// ====================================================================== diff --git a/engine/server/library/serverPathfinding/src/shared/ServerPathfindingNotification.h b/engine/server/library/serverPathfinding/src/shared/ServerPathfindingNotification.h new file mode 100644 index 00000000..72d58332 --- /dev/null +++ b/engine/server/library/serverPathfinding/src/shared/ServerPathfindingNotification.h @@ -0,0 +1,52 @@ +// ====================================================================== +// +// ServerPathfindingNotification.h +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_ServerPathfindingNotification_H +#define INCLUDED_ServerPathfindingNotification_H + +#include "sharedObject/ObjectNotification.h" + +class Object; +class Vector; +class BuildingObject; +class ServerObject; + +// ====================================================================== + +class ServerPathfindingNotification : public ObjectNotification +{ +public: + + ServerPathfindingNotification(); + virtual ~ServerPathfindingNotification(); + + virtual void addToWorld ( Object & object ) const; + virtual void removeFromWorld ( Object & object ) const; + + virtual bool positionChanged ( Object & object, bool dueToParentChange, Vector const & oldPosition) const; + virtual bool positionAndRotationChanged ( Object & object, bool dueToParentChange, Vector const & oldPosition ) const; + + // ---------- + + static void destroyBuilding ( BuildingObject * building ); + static void destroyWaypoint ( ServerObject * waypoint ); + + static ServerPathfindingNotification & getInstance ( void ); + +protected: + +private: + + ServerPathfindingNotification(const ServerPathfindingNotification &); + ServerPathfindingNotification &operator =(const ServerPathfindingNotification &); +}; + +// ====================================================================== + +#endif + diff --git a/engine/server/library/serverPathfinding/src/shared/SetupServerPathfinding.cpp b/engine/server/library/serverPathfinding/src/shared/SetupServerPathfinding.cpp new file mode 100644 index 00000000..1ba7a320 --- /dev/null +++ b/engine/server/library/serverPathfinding/src/shared/SetupServerPathfinding.cpp @@ -0,0 +1,37 @@ +// ====================================================================== +// +// SetupServerPathfinding.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "serverPathfinding/FirstServerPathfinding.h" +#include "serverPathfinding/SetupServerPathfinding.h" + +#include "serverPathfinding/CityPathGraphManager.h" +#include "serverPathfinding/ServerPathfindingMessaging.h" + +#include "sharedFoundation/ExitChain.h" + +#include "sharedPathfinding/SetupSharedPathfinding.h" + +void SetupServerPathfinding::install ( void ) +{ + SetupSharedPathfinding::install(); + + ServerPathfindingMessaging::install(); + + CityPathGraphManager::install(); + + ExitChain::add( SetupServerPathfinding::remove, "SetupServerPathfinding" ); +} + +void SetupServerPathfinding::remove ( void ) +{ + CityPathGraphManager::remove(); + + ServerPathfindingMessaging::remove(); + + SetupSharedPathfinding::remove(); +} + diff --git a/engine/server/library/serverPathfinding/src/shared/SetupServerPathfinding.h b/engine/server/library/serverPathfinding/src/shared/SetupServerPathfinding.h new file mode 100644 index 00000000..d9dba916 --- /dev/null +++ b/engine/server/library/serverPathfinding/src/shared/SetupServerPathfinding.h @@ -0,0 +1,25 @@ +// ====================================================================== +// +// SetupServerPathfinding.h +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_SetupServerPathfinding_H +#define INCLUDED_SetupServerPathfinding_H + +// ====================================================================== + +class SetupServerPathfinding +{ +public: + + static void install ( void ); + static void remove ( void ); +}; + +// ====================================================================== + +#endif + diff --git a/engine/server/library/serverPathfinding/src/win32/FirstServerPathfinding.cpp b/engine/server/library/serverPathfinding/src/win32/FirstServerPathfinding.cpp new file mode 100644 index 00000000..ac6ecea0 --- /dev/null +++ b/engine/server/library/serverPathfinding/src/win32/FirstServerPathfinding.cpp @@ -0,0 +1,8 @@ +// ====================================================================== +// +// FirstServerPathfinding.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "serverPathfinding/FirstServerPathfinding.h" diff --git a/engine/server/library/serverScript/src/CMakeLists.txt b/engine/server/library/serverScript/src/CMakeLists.txt index 583b92a6..510c39d6 100644 --- a/engine/server/library/serverScript/src/CMakeLists.txt +++ b/engine/server/library/serverScript/src/CMakeLists.txt @@ -126,6 +126,7 @@ include_directories( ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedUtility/include/public ${SWG_ENGINE_SOURCE_DIR}/server/library/serverGame/include/public ${SWG_ENGINE_SOURCE_DIR}/server/library/serverNetworkMessages/include/public + ${SWG_ENGINE_SOURCE_DIR}/server/library/serverPathfinding/include/public ${SWG_ENGINE_SOURCE_DIR}/server/library/serverUtility/include/public ${SWG_GAME_SOURCE_DIR}/shared/library/swgSharedUtility/include/public ${SWG_EXTERNALS_SOURCE_DIR}/ours/library/archive/include diff --git a/engine/shared/library/sharedFoundation/src/shared/StlForwardDeclaration.h b/engine/shared/library/sharedFoundation/src/shared/StlForwardDeclaration.h index 143db163..bd9cf89b 100644 --- a/engine/shared/library/sharedFoundation/src/shared/StlForwardDeclaration.h +++ b/engine/shared/library/sharedFoundation/src/shared/StlForwardDeclaration.h @@ -31,7 +31,8 @@ // ====================================================================== // grab stlport configuration -#include "stl/config/features.h" +//#include "stl/config/features.h" // uncomment for newer stlport versions +#include "stl/_config.h" namespace std {