All pastes #1013779 Raw Edit

RandomMovementGenerator

public diff v1 · immutable
#1013779 ·published 2008-05-10 15:21 UTC
rendered paste body
Index: src/game/RandomMovementGenerator.cpp===================================================================--- src/game/RandomMovementGenerator.cpp	(revision 5789)+++ src/game/RandomMovementGenerator.cpp	(working copy)@@ -21,69 +21,220 @@ #include "Opcodes.h" #include "RandomMovementGenerator.h" #include "DestinationHolderImp.h"+#include "VMapFactory.h"+#include "Map.h" -/*-Here interpolation is disabled by default due to it causing crashing-in some compile environments.-If your server can handle the small amount of lag this may cause-and you can build without experiencing a significant increase in crashes-then you may uncomment the following line to have correct random motion.-*/-// uncomment now for wide testing purpose-#define USE_INTERPOLATION+/**+ * Those define the size of the table of the ground/object heights around the spawn point,+ * bigger they are, more time is needed to calculate.+ */+#define ANGLE_PRECISSION 8+#define RANGE_PRECISSION 8  template<> void RandomMovementGenerator<Creature>::Initialize(Creature &creature) {-    float x,y,z,z2, wander_distance;-    creature.GetRespawnCoord(x, y, z,NULL,&wander_distance);-    uint32 mapid=creature.GetMapId();+	QueryResult *result = NULL;+	bool cached = false;+	// Try cache+	result = WorldDatabase.PQuery("SELECT position_x, position_y, position_z FROM cache_random_movement_generator WHERE guid = '%u' ORDER BY point", creature.GetGUIDLow());	+	if( result ) {+		if(result->GetRowCount()==MAX_RAND_WAYPOINTS + 1)+		{+			for(unsigned int idx = 0; idx < MAX_RAND_WAYPOINTS + 1; ++idx)+			{+				Field *fields = result->Fetch();+				// Read from cache+				i_waypoints[idx][0] = fields[0].GetFloat();+				i_waypoints[idx][1] = fields[1].GetFloat();+				i_waypoints[idx][2] = fields[2].GetFloat();+				result->NextRow();+			}+			// Mark creature as loaded from cache+			cached = true;+		}+	}+	// If we couldn't load creature from cache, do all the calc+	if(!cached)+	{+		// We need vmap manager, to make creatures walk properly over the objects+		VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager();+		// To use new algorithm, vmaps are needed, if not, just fall back to the previous one+		bool vmaps_enabled = vmgr->isLineOfSightCalcEnabled() && vmgr->isHeightCalcEnabled();+		if(vmaps_enabled)+		{+			float x,y,z,wander_distance;+			float waypoints[(ANGLE_PRECISSION*RANGE_PRECISSION)+1][3];+			int waypoint_count = 1; -    Map const* map = MapManager::Instance().GetBaseMap(mapid);-    // Initialization is done in bulk. Dont use vamps for that (4. parameter = false). It is too costly when entering a new map grid-    z2 = map->GetHeight(x,y,z, false);                      // use .map base surface height-    if( fabs( z2 - z ) < 5 )-        z = z2;+			creature.GetRespawnCoord(x, y, z,NULL,&wander_distance);+			uint32 mapid=creature.GetMapId(); -    i_nextMove = 1;-    i_waypoints[0][0] = x;-    i_waypoints[0][1] = y;-    i_waypoints[0][2] = z;+			Map const* map = MapManager::Instance().GetBaseMap(mapid); -    bool is_water_ok = creature.isCanSwimOrFly();-    bool is_land_ok  = creature.isCanWalkOrFly();+			bool is_water_ok = creature.isCanSwimOrFly();+			bool is_land_ok  = creature.isCanWalkOrFly(); -    for(unsigned int idx=1; idx < MAX_RAND_WAYPOINTS+1; ++idx)-    {-        const float angle = 2*M_PI*rand_norm();-        const float range = wander_distance*rand_norm();+			float step = wander_distance/RANGE_PRECISSION; -        i_waypoints[idx][0] = x+ range * cos(angle);-        i_waypoints[idx][1] = y+ range * sin(angle);+			waypoints[0][0] = x;+			waypoints[0][1] = y;+			waypoints[0][2] = z;+			// Build the table of ground/object heights around spawn point+			for(int a = 0; a < ANGLE_PRECISSION; a++)+			{+				float angle = (2*M_PI/ANGLE_PRECISSION) * (float)a;+				// We use the previous Z value as a reference point to find out the map height+				float last_z = z;+				for(int r = 0; r < RANGE_PRECISSION; r++)+				{+					float range = step * ((float) r + 1.0);+					// Calculate the test around the spawn point+					float px = x + range * cos(angle);+					float py = y + range * sin(angle);+					MaNGOS::NormalizeMapCoord(px);+					MaNGOS::NormalizeMapCoord(py);+					float map_height = map->GetHeight(px, py , last_z, true);+					float obj_height; -        // prevent invalid coordinates generation-        MaNGOS::NormalizeMapCoord(i_waypoints[idx][0]);-        MaNGOS::NormalizeMapCoord(i_waypoints[idx][1]);+					// Calculate the object height			+					vmgr->getObjectHitPos(mapid, +						px, py, last_z + 2.0f,+						px, py, ((map_height!=VMAP_INVALID_HEIGHT_VALUE) ? (map_height) : (last_z-2.0f)),+						px, py, obj_height,+						0.0f); -        bool is_water = map->IsInWater(i_waypoints[idx][0],i_waypoints[idx][1],z);-        // if generated wrong path just ignore-        if( is_water && !is_water_ok || !is_water && !is_land_ok )-        {-            i_waypoints[idx][0] = i_waypoints[idx-1][0];-            i_waypoints[idx][1] = i_waypoints[idx-1][1];-            i_waypoints[idx][2] = i_waypoints[idx-1][2];-            continue;-        }+					float pz = VMAP_INVALID_HEIGHT_VALUE;+					if(obj_height>last_z-2.0f)+					{+						// Z value in the map will be the bigger of the two: map or object+						pz = (((map_height) > (obj_height)) ? (map_height) : (obj_height)); +					} -        // Initialization is done in bulk. Dont use vamps for that (4. parameter = false).-        // It is too costly when entering a new map grid, use .map base surface height-        z2 = map->GetHeight(i_waypoints[idx][0],i_waypoints[idx][1],z, false);-        if( fabs( z2 - z ) < 5 )-            z = z2;-        i_waypoints[idx][2] =  z;-    }-    i_nextMoveTime.Reset(urand(0, 10000-1));                // TODO: check the lower bound (it is probably too small)+					if(pz!=VMAP_INVALID_HEIGHT_VALUE)+					{+						bool is_water = map->IsInWater(px,py,pz);	+						// If it is bad place for the creature (water for non water creature, ect), just mark it as invalid.+						if(is_water && !is_water_ok || !is_water && !is_land_ok)+						{				+							pz = VMAP_INVALID_HEIGHT_VALUE;+						}++						// If point is not invalid, add to possible walk points+						if(pz!=VMAP_INVALID_HEIGHT_VALUE)+						{+							last_z = pz;+							waypoints[waypoint_count][0] = px;+							waypoints[waypoint_count][1] = py;+							waypoints[waypoint_count][2] = pz;+							waypoint_count++;+						}+					}+				}+			}	++			// Here, we calculate the walk points+			i_nextMove = 1;+			// First waypoint is always a spawn point, easy here.+			i_waypoints[0][0] = x;+			i_waypoints[0][1] = y;+			i_waypoints[0][2] = z;	    ++			for(unsigned int idx=1; idx < MAX_RAND_WAYPOINTS+1; ++idx)+			{+				bool goodPoint = false;+				int r = urand(0, waypoint_count-1);+				while(!goodPoint)+				{+					float dx = waypoints[r][0];+					float dy = waypoints[r][1];+					float dz = waypoints[r][2];+					// And check LOS+					vmgr->getObjectHitPos(mapid, +						i_waypoints[0][0], i_waypoints[0][1], i_waypoints[0][2] + creature.GetObjectSize()/2.0f,+						dx, dy, dz + creature.GetObjectSize()/2.0f,+						i_waypoints[idx][0], i_waypoints[idx][1], i_waypoints[idx][2],+						creature.GetObjectSize()*2.0);+					i_waypoints[idx][2] = i_waypoints[idx][2]- creature.GetObjectSize()/2.0f;+					float x_dx = i_waypoints[idx][0] - i_waypoints[idx-1][0];+					float x_dy = i_waypoints[idx][1] - i_waypoints[idx-1][1];+					float x_dist = sqrt((x_dx*x_dx) + (x_dy*x_dy));+					float x_dz = i_waypoints[idx][2]-i_waypoints[idx-1][2];+					// Check if creature is not attempting to do >45 deg. walk+					if(abs(x_dz)<=x_dist)+					{+						goodPoint = true;+					} else {+						// If yes, try next point+						r = r + 1;+						if(r==waypoint_count)+						{+							r = 0;+						}+					}+				}+			}+			// Perform database dump of calculated waypoints to populate cache for future use+			for(unsigned int idx=0; idx < MAX_RAND_WAYPOINTS+1; ++idx)+			{+				WorldDatabase.PExecuteLog("INSERT INTO cache_random_movement_generator (guid, point, position_x, position_y, position_z) VALUES ('%u','%u','%f','%f','%f')", +					creature.GetGUIDLow(), idx,+					i_waypoints[idx][0], i_waypoints[idx][1], i_waypoints[idx][2]);	+			}+		} else {+			// Fallback algorithm (previous one)+			float x,y,z,z2, wander_distance;+			creature.GetRespawnCoord(x, y, z,NULL,&wander_distance);+			uint32 mapid=creature.GetMapId();++			Map const* map = MapManager::Instance().GetBaseMap(mapid);+			// Initialization is done in bulk. Dont use vamps for that (4. parameter = false). It is too costly when entering a new map grid+			z2 = map->GetHeight(x,y,z, false);                      // use .map base surface height+			if( fabs( z2 - z ) < 5 )+				z = z2;++			i_nextMove = 1;+			i_waypoints[0][0] = x;+			i_waypoints[0][1] = y;+			i_waypoints[0][2] = z;++			bool is_water_ok = creature.isCanSwimOrFly();+			bool is_land_ok  = creature.isCanWalkOrFly();++			for(unsigned int idx=1; idx < MAX_RAND_WAYPOINTS+1; ++idx)+			{+				const float angle = 2*M_PI*rand_norm();+				const float range = wander_distance*rand_norm();++				i_waypoints[idx][0] = x+ range * cos(angle);+				i_waypoints[idx][1] = y+ range * sin(angle);++				// prevent invalid coordinates generation+				MaNGOS::NormalizeMapCoord(i_waypoints[idx][0]);+				MaNGOS::NormalizeMapCoord(i_waypoints[idx][1]);++				bool is_water = map->IsInWater(i_waypoints[idx][0],i_waypoints[idx][1],z);+				// if generated wrong path just ignore+				if( is_water && !is_water_ok || !is_water && !is_land_ok )+				{+					i_waypoints[idx][0] = i_waypoints[idx-1][0];+					i_waypoints[idx][1] = i_waypoints[idx-1][1];+					i_waypoints[idx][2] = i_waypoints[idx-1][2];+					continue;+				}++				// Initialization is done in bulk. Dont use vamps for that (4. parameter = false).+				// It is too costly when entering a new map grid, use .map base surface height+				z2 = map->GetHeight(i_waypoints[idx][0],i_waypoints[idx][1],z, false);+				if( fabs( z2 - z ) < 5 )+					z = z2;+				i_waypoints[idx][2] =  z;+			}+		}+	}++	i_nextMoveTime.Reset(urand(0, 10000-1));                // TODO: check the lower bound (it is probably too small)     creature.StopMoving(); } @@ -105,10 +256,8 @@     if(creature.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNDED))         return true;     i_nextMoveTime.Update(diff);-    #ifdef USE_INTERPOLATION     CreatureTraveller traveller(creature);     i_destinationHolder.UpdateTraveller(traveller, diff, false);-    #endif     if( i_nextMoveTime.Passed() )     {         if( creature.IsStopped() )@@ -120,9 +269,7 @@             creature.addUnitState(UNIT_STAT_ROAMING);             CreatureTraveller traveller(creature);             i_destinationHolder.SetDestination(traveller, x, y, z);-            #ifndef USE_INTERPOLATION             traveller.Relocation(x,y,z);-            #endif             i_nextMoveTime.Reset( i_destinationHolder.GetTotalTravelTime() );         }         else