region_map_v1.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867
  1. #include "region_map_v1.h"
  2. #include "../../common/Log.h"
  3. #include "../client.h"
  4. #include "../Spawn.h"
  5. #include "../LuaInterface.h"
  6. #include "../World.h"
  7. #undef snprintf
  8. #include <boost/filesystem.hpp>
  9. extern LuaInterface* lua_interface;
  10. extern World world;
  11. RegionMapV1::RegionMapV1() {
  12. mVersion = 1;
  13. }
  14. RegionMapV1::~RegionMapV1() {
  15. std::unique_lock lock(MRegions);
  16. map<Region_Node*, ZBSP_Node*>::const_iterator itr;
  17. int region_num = 0;
  18. for (itr = Regions.begin(); itr != Regions.end();)
  19. {
  20. Region_Node* node = itr->first;
  21. ZBSP_Node* bsp_node = itr->second;
  22. map<Region_Node*, ZBSP_Node*>::const_iterator deleteItr = itr;
  23. itr++;
  24. Regions.erase(deleteItr);
  25. safe_delete(node);
  26. safe_delete_array(bsp_node);
  27. }
  28. Regions.clear();
  29. }
  30. WaterRegionType RegionMapV1::ReturnRegionType(const glm::vec3& location, int32 gridid) const {
  31. return BSPReturnRegionType(1, glm::vec3(location.x, location.y, location.z), gridid);
  32. }
  33. bool RegionMapV1::InWater(const glm::vec3& location, int32 gridid) const {
  34. return ReturnRegionType(location, gridid) == RegionTypeWater;
  35. }
  36. bool RegionMapV1::InLava(const glm::vec3& location, int32 gridid) const {
  37. return ReturnRegionType(location, gridid) == RegionTypeLava;
  38. }
  39. bool RegionMapV1::InLiquid(const glm::vec3& location) const {
  40. return InWater(location) || InLava(location);
  41. }
  42. bool RegionMapV1::InPvP(const glm::vec3& location) const {
  43. return ReturnRegionType(location) == RegionTypePVP;
  44. }
  45. bool RegionMapV1::InZoneLine(const glm::vec3& location) const {
  46. return ReturnRegionType(location) == RegionTypeZoneLine;
  47. }
  48. std::string RegionMapV1::TestFile(std::string testFile)
  49. {
  50. std::string tmpStr(testFile);
  51. std::size_t pos = tmpStr.find(".");
  52. if ( pos != testFile.npos )
  53. tmpStr = testFile.substr (0, pos);
  54. string tmpScript("RegionScripts/");
  55. tmpScript.append(mZoneNameLower);
  56. tmpScript.append("/" + tmpStr + ".lua");
  57. std::ifstream f(tmpScript.c_str());
  58. return f.good() ? tmpScript : string("");
  59. }
  60. bool RegionMapV1::Load(FILE* fp, std::string inZoneNameLwr, int32 version) {
  61. mZoneNameLower = string(inZoneNameLwr.c_str());
  62. uint32 region_size;
  63. if (fread(&region_size, sizeof(uint32), 1, fp) != 1) {
  64. return false;
  65. }
  66. LogWrite(REGION__DEBUG, 0, "RegionMap", "region count = %u", region_size);
  67. for (int i = 0; i < region_size; i++)
  68. {
  69. uint32 region_num;
  70. if (fread(&region_num, sizeof(uint32), 1, fp) != 1) {
  71. return false;
  72. }
  73. uint32 region_type;
  74. if (fread(&region_type, sizeof(uint32), 1, fp) != 1) {
  75. return false;
  76. }
  77. float x, y, z, dist;
  78. if (fread(&x, sizeof(float), 1, fp) != 1) {
  79. return false;
  80. }
  81. if (fread(&y, sizeof(float), 1, fp) != 1) {
  82. return false;
  83. }
  84. if (fread(&z, sizeof(float), 1, fp) != 1) {
  85. return false;
  86. }
  87. if (fread(&dist, sizeof(float), 1, fp) != 1) {
  88. return false;
  89. }
  90. int8 strSize;
  91. char envName[256] = {""};
  92. char regionName[256] = {""};
  93. uint32 grid_id = 0;
  94. if ( version > 1 )
  95. {
  96. fread(&strSize, sizeof(int8), 1, fp);
  97. LogWrite(REGION__DEBUG, 7, "Region", "Region environment strSize = %u", strSize);
  98. if(strSize)
  99. {
  100. size_t len = fread(&envName, sizeof(char), strSize, fp);
  101. envName[len] = '\0';
  102. }
  103. LogWrite(REGION__DEBUG, 7, "Region", "Region environment file name = %s", envName);
  104. fread(&strSize, sizeof(int8), 1, fp);
  105. LogWrite(REGION__DEBUG, 7, "Region", "Region name strSize = %u", strSize);
  106. if(strSize)
  107. {
  108. size_t len = fread(&regionName, sizeof(char), strSize, fp);
  109. regionName[len] = '\0';
  110. }
  111. LogWrite(REGION__DEBUG, 7, "Region", "Region name file name = %s", regionName);
  112. if (fread(&grid_id, sizeof(uint32), 1, fp) != 1) {
  113. return false;
  114. }
  115. }
  116. int32 bsp_tree_size;
  117. if (fread(&bsp_tree_size, sizeof(int32), 1, fp) != 1) {
  118. return false;
  119. }
  120. LogWrite(REGION__DEBUG, 7, "Region", "region x,y,z,dist = %f, %f, %f, %f, region bsp tree size: %i\n", x, y, z, dist, bsp_tree_size);
  121. ZBSP_Node* BSP_Root = new ZBSP_Node[bsp_tree_size];
  122. if (fread(BSP_Root, sizeof(ZBSP_Node), bsp_tree_size, fp) != bsp_tree_size) {
  123. LogWrite(REGION__ERROR, 0, "RegionMap", "Failed to load region.");
  124. return false;
  125. }
  126. Region_Node* tmpNode = new Region_Node;
  127. tmpNode->x = x;
  128. tmpNode->y = y;
  129. tmpNode->z = z;
  130. tmpNode->dist = dist;
  131. tmpNode->region_type = region_type;
  132. tmpNode->regionName = string(regionName);
  133. tmpNode->regionEnvFileName = string(envName);
  134. tmpNode->grid_id = grid_id;
  135. tmpNode->regionScriptName = string("");
  136. tmpNode->regionScriptName = TestFile(regionName);
  137. if ( tmpNode->regionScriptName.size() < 1 )
  138. {
  139. tmpNode->regionScriptName = TestFile(envName);
  140. }
  141. if ( tmpNode->regionScriptName.size() < 1 )
  142. {
  143. tmpNode->regionScriptName = TestFile("default");
  144. }
  145. tmpNode->vert_count = bsp_tree_size;
  146. MRegions.lock();
  147. Regions.insert(make_pair(tmpNode, BSP_Root));
  148. MRegions.unlock();
  149. }
  150. fclose(fp);
  151. LogWrite(REGION__DEBUG, 0, "RegionMap", "completed load!");
  152. return true;
  153. }
  154. void RegionMapV1::IdentifyRegionsInGrid(Client *client, const glm::vec3 &location) const
  155. {
  156. std::shared_lock lock(MRegions);
  157. map<Region_Node*, ZBSP_Node*>::const_iterator itr;
  158. int region_num = 0;
  159. int32 grid = 0;
  160. int32 widget_id = 0;
  161. float x =0.0f,y = 0.0f,z = 0.0f;
  162. if (client->GetPlayer()->GetMap() != nullptr && client->GetPlayer()->GetMap()->IsMapLoaded())
  163. {
  164. auto loc = glm::vec3(location.x, location.z, location.y);
  165. float new_z = client->GetPlayer()->GetMap()->FindBestZ(loc, nullptr, &grid, &widget_id);
  166. std::map<int32, glm::vec3>::iterator itr = client->GetPlayer()->GetMap()->widget_map.find(widget_id);
  167. if(itr != client->GetPlayer()->GetMap()->widget_map.end()) {
  168. x = itr->second.x;
  169. y = itr->second.y;
  170. z = itr->second.z;
  171. }
  172. }
  173. else
  174. client->SimpleMessage(CHANNEL_COLOR_RED, "No map to establish grid id, using grid id 0 (attempt match all).");
  175. client->Message(2, "Region check against location %f / %f / %f. Grid to try: %u, player grid is %u, widget id is %u. Widget location is %f %f %f.", location.x, location.y, location.z, grid, client->GetPlayer()->appearance.pos.grid_id, widget_id, x, y, z);
  176. for (itr = Regions.begin(); itr != Regions.end(); itr++)
  177. {
  178. Region_Node *node = itr->first;
  179. ZBSP_Node *BSP_Root = itr->second;
  180. if (grid == 0 || node->grid_id == grid)
  181. {
  182. float x1 = node->x - location.x;
  183. float y1 = node->y - location.y;
  184. float z1 = node->z - location.z;
  185. float dist = sqrt(x1 *x1 + y1 *y1 + z1 *z1);
  186. glm::vec3 testLoc(location.x, location.y, location.z);
  187. if(!BSP_Root) {
  188. if(client)
  189. client->Message(CHANNEL_COLOR_YELLOW, "[%s] Region %i, GridID: %u, RegionName: %s, RegionEnvFileName: %s, Script: %s. X: %f, Y: %f, Z: %f, Distance: %f, Widget ID Marker: %u", (widget_id == node->trigger_widget_id) ? "IN REGION" : "WIDGET MARKER", region_num,
  190. node->grid_id, node->regionName.c_str(), node->regionEnvFileName.c_str(), node->regionScriptName.c_str(), node->x, node->y, node->z, node->dist, node->trigger_widget_id);
  191. }
  192. else if (dist <= node->dist)
  193. {
  194. WaterRegionType regionType = RegionTypeUntagged;
  195. if (node->region_type == ClassWaterRegion)
  196. regionType = BSPReturnRegionWaterRegion(node, BSP_Root, 1, testLoc, dist);
  197. else
  198. regionType = BSPReturnRegionTypeNode(node, BSP_Root, 1, testLoc, dist);
  199. if (regionType != RegionTypeNormal)
  200. {
  201. client->Message(CHANNEL_COLOR_YELLOW, "[DETECTED IN REGION %i] Region %i, GridID: %u, RegionName: %s, RegionEnvFileName: %s, distance: %f, X/Y/Z: %f / %f / %f. Script: %s", regionType, region_num, node->grid_id, node->regionName.c_str(), node->regionEnvFileName.c_str(),
  202. node->dist, node->x, node->y, node->z, node->regionScriptName.c_str());
  203. }
  204. else
  205. {
  206. client->Message(CHANNEL_COLOR_RED, "[IN DIST RANGE] Region %i, GridID: %u, RegionName: %s, RegionEnvFileName: %s, distance: %f, X/Y/Z: %f / %f / %f. Script: %s", region_num, node->grid_id, node->regionName.c_str(), node->regionEnvFileName.c_str(),
  207. node->dist, node->x, node->y, node->z, node->regionScriptName.c_str());
  208. }
  209. }
  210. else
  211. client->Message(CHANNEL_COLOR_RED, "[OUT OF RANGE] Region %i, GridID: %u, RegionName: %s, RegionEnvFileName: %s, distance: %f, X/Y/Z: %f / %f / %f. Script: %s", region_num, node->grid_id, node->regionName.c_str(), node->regionEnvFileName.c_str(),
  212. node->dist, node->x, node->y, node->z, node->regionScriptName.c_str());
  213. }
  214. else
  215. client->Message(CHANNEL_COLOR_RED, "[OUT OF GRID] Region %i, GridID: %u, RegionName: %s, RegionEnvFileName: %s, distance: %f, X/Y/Z: %f / %f / %f. Script: %s", region_num, node->grid_id, node->regionName.c_str(), node->regionEnvFileName.c_str(),
  216. node->dist, node->x, node->y, node->z, node->regionScriptName.c_str());
  217. region_num++;
  218. }
  219. }
  220. void RegionMapV1::MapRegionsNearSpawn(Spawn *spawn, Client *client) const
  221. {
  222. std::shared_lock lock(MRegions);
  223. map<Region_Node*, ZBSP_Node*>::const_iterator itr;
  224. int region_num = 0;
  225. spawn->RegionMutex.writelock();
  226. glm::vec3 testLoc(spawn->GetX(), spawn->GetY(), spawn->GetZ());
  227. for (itr = Regions.begin(); itr != Regions.end(); itr++)
  228. {
  229. Region_Node *node = itr->first;
  230. ZBSP_Node *BSP_Root = itr->second;
  231. if (node->regionScriptName.size() < 1) // only track ones that are used with LUA scripting
  232. continue;
  233. if(!BSP_Root) {
  234. int32 currentGridID = spawn->appearance.pos.grid_id;
  235. bool inRegion = false;
  236. if(!(inRegion = spawn->InRegion(node, nullptr)) && currentGridID == node->grid_id &&
  237. ( node->trigger_widget_id == spawn->trigger_widget_id || (node->dist > 0.0f && spawn->GetDistance(node->x, node->y, node->z) < node->dist)) ) {
  238. int32 returnValue = spawn->InsertRegionToSpawn(node, nullptr, RegionTypeUntagged);
  239. if (client)
  240. client->Message(CHANNEL_COLOR_YELLOW, "[ENTER REGION %i %u] Region %i, GridID: %u, RegionName: %s, RegionEnvFileName: %s, distance: %f, X/Y/Z: %f / %f / %f. Script: %s", RegionTypeUntagged, returnValue, region_num, node->grid_id, node->regionName.c_str(), node->regionEnvFileName.c_str(),
  241. node->dist, node->x, node->y, node->z, node->regionScriptName.c_str());
  242. }
  243. continue;
  244. }
  245. float x1 = node->x - testLoc.x;
  246. float y1 = node->y - testLoc.y;
  247. float z1 = node->z - testLoc.z;
  248. float dist = sqrt(x1 *x1 + y1 *y1 + z1 *z1);
  249. if (dist <= node->dist)
  250. {
  251. WaterRegionType regionType = RegionTypeUntagged;
  252. if (node->region_type == ClassWaterRegion)
  253. regionType = BSPReturnRegionWaterRegion(node, BSP_Root, 1, testLoc, dist);
  254. else
  255. regionType = BSPReturnRegionTypeNode(node, BSP_Root, 1, testLoc, dist);
  256. if (regionType != RegionTypeNormal)
  257. {
  258. if (!spawn->InRegion(node, BSP_Root))
  259. {
  260. spawn->DeleteRegion(node, BSP_Root);
  261. int32 returnValue = spawn->InsertRegionToSpawn(node, BSP_Root, regionType);
  262. if (client)
  263. client->Message(CHANNEL_COLOR_YELLOW, "[ENTER REGION %i %u] Region %i, GridID: %u, RegionName: %s, RegionEnvFileName: %s, distance: %f, X/Y/Z: %f / %f / %f. Script: %s", regionType, returnValue, region_num, node->grid_id, node->regionName.c_str(), node->regionEnvFileName.c_str(),
  264. node->dist, node->x, node->y, node->z, node->regionScriptName.c_str());
  265. }
  266. }
  267. else
  268. {
  269. if(spawn->HasRegionTracked(node, BSP_Root, false)) {
  270. continue;
  271. } // UpdateRegionsNearSpawn will capture it for nodes that have BSP_Root's
  272. if (spawn->InRegion(node, BSP_Root))
  273. {
  274. if (client)
  275. client->Message(CHANNEL_COLOR_RED, "[LEAVE REGION] Region %i, GridID: %u, RegionName: %s, RegionEnvFileName: %s, distance: %f, X/Y/Z: %f / %f / %f. Script: %s", region_num, node->grid_id, node->regionName.c_str(), node->regionEnvFileName.c_str(),
  276. node->dist, node->x, node->y, node->z, node->regionScriptName.c_str());
  277. WaterRegionType whatWasRegionType = (WaterRegionType) spawn->GetRegionType(node, BSP_Root);
  278. lua_interface->RunRegionScript(node->regionScriptName, "LeaveRegion", spawn->GetZone(), spawn, whatWasRegionType);
  279. }
  280. spawn->DeleteRegion(node, BSP_Root);
  281. spawn->InsertRegionToSpawn(node, BSP_Root, RegionTypeNormal, false);
  282. if (client)
  283. client->Message(CHANNEL_COLOR_RED, "[NEAR REGION] Region %i, GridID: %u, RegionName: %s, RegionEnvFileName: %s, distance: %f, X/Y/Z: %f / %f / %f. Script: %s", region_num, node->grid_id, node->regionName.c_str(), node->regionEnvFileName.c_str(),
  284. node->dist, node->x, node->y, node->z, node->regionScriptName.c_str());
  285. }
  286. }
  287. region_num++;
  288. }
  289. spawn->RegionMutex.releasewritelock();
  290. }
  291. void RegionMapV1::UpdateRegionsNearSpawn(Spawn *spawn, Client *client) const
  292. {
  293. std::shared_lock lock(MRegions);
  294. map<map<Region_Node*, ZBSP_Node*>, Region_Status>::iterator testitr;
  295. int region_num = 0;
  296. spawn->RegionMutex.writelock();
  297. glm::vec3 testLoc(spawn->GetX(), spawn->GetY(), spawn->GetZ());
  298. map<Region_Node*, ZBSP_Node*> deleteNodes;
  299. for (testitr = spawn->Regions.begin(); testitr != spawn->Regions.end(); testitr++)
  300. {
  301. map<Region_Node*, ZBSP_Node*>::const_iterator actualItr = testitr->first.begin();
  302. Region_Node *node = actualItr->first;
  303. ZBSP_Node *BSP_Root = actualItr->second;
  304. std::map<Region_Node*, bool>::const_iterator dead_itr = dead_nodes.find(node);
  305. if(dead_itr != dead_nodes.end()) {
  306. deleteNodes.insert(make_pair(node, BSP_Root));
  307. continue;
  308. }
  309. if(!BSP_Root) {
  310. continue;
  311. }
  312. float x1 = node->x - testLoc.x;
  313. float y1 = node->y - testLoc.y;
  314. float z1 = node->z - testLoc.z;
  315. float dist = sqrt(x1 *x1 + y1 *y1 + z1 *z1);
  316. if (dist <= node->dist)
  317. {
  318. WaterRegionType regionType = RegionTypeUntagged;
  319. if (node->region_type == ClassWaterRegion)
  320. regionType = BSPReturnRegionWaterRegion(node, BSP_Root, 1, testLoc, dist);
  321. else
  322. regionType = BSPReturnRegionTypeNode(node, BSP_Root, 1, testLoc, dist);
  323. if (regionType != RegionTypeNormal)
  324. {
  325. if (!testitr->second.inRegion)
  326. {
  327. testitr->second.inRegion = true;
  328. int32 returnValue = 0;
  329. lua_interface->RunRegionScript(node->regionScriptName, "EnterRegion", spawn->GetZone(), spawn, regionType, &returnValue);
  330. if (client)
  331. client->Message(CHANNEL_COLOR_YELLOW, "[ENTER RANGE %i %u] Region %i, GridID: %u, RegionName: %s, RegionEnvFileName: %s, distance: %f, X/Y/Z: %f / %f / %f. Script: %s", regionType, returnValue, region_num, node->grid_id, node->regionName.c_str(), node->regionEnvFileName.c_str(),
  332. node->dist, node->x, node->y, node->z, node->regionScriptName.c_str());
  333. testitr->second.timerTic = returnValue;
  334. testitr->second.lastTimerTic = returnValue ? Timer::GetCurrentTime2() : 0;
  335. }
  336. }
  337. else
  338. {
  339. if (testitr->second.inRegion)
  340. {
  341. testitr->second.inRegion = false;
  342. testitr->second.timerTic = 0;
  343. testitr->second.lastTimerTic = 0;
  344. if (client)
  345. client->Message(CHANNEL_COLOR_RED, "[LEAVE RANGE] Region %i, GridID: %u, RegionName: %s, RegionEnvFileName: %s, distance: %f, X/Y/Z: %f / %f / %f. Script: %s", region_num, node->grid_id, node->regionName.c_str(), node->regionEnvFileName.c_str(),
  346. node->dist, node->x, node->y, node->z, node->regionScriptName.c_str());
  347. WaterRegionType whatWasRegionType = (WaterRegionType) spawn->GetRegionType(node, BSP_Root);
  348. lua_interface->RunRegionScript(node->regionScriptName, "LeaveRegion", spawn->GetZone(), spawn, whatWasRegionType);
  349. }
  350. }
  351. }
  352. else
  353. {
  354. if (client)
  355. client->Message(CHANNEL_COLOR_RED, "[LEAVE RANGE - OOR] Region %i, GridID: %u, RegionName: %s, RegionEnvFileName: %s, distance: %f, X/Y/Z: %f / %f / %f. Script: %s", region_num, node->grid_id, node->regionName.c_str(), node->regionEnvFileName.c_str(),
  356. node->dist, node->x, node->y, node->z, node->regionScriptName.c_str());
  357. deleteNodes.insert(make_pair(node, BSP_Root));
  358. }
  359. region_num++;
  360. }
  361. map<Region_Node*, ZBSP_Node*>::const_iterator deleteItr;
  362. for (deleteItr = deleteNodes.begin(); deleteItr != deleteNodes.end(); deleteItr++)
  363. {
  364. Region_Node *tmpNode = deleteItr->first;
  365. ZBSP_Node *bspNode = deleteItr->second;
  366. spawn->DeleteRegion(tmpNode, bspNode);
  367. }
  368. spawn->RegionMutex.releasewritelock();
  369. }
  370. void RegionMapV1::TicRegionsNearSpawn(Spawn *spawn, Client *client) const
  371. {
  372. std::shared_lock lock(MRegions);
  373. map<map<Region_Node*, ZBSP_Node*>, Region_Status>::iterator testitr;
  374. int region_num = 0;
  375. spawn->RegionMutex.writelock();
  376. for (testitr = spawn->Regions.begin(); testitr != spawn->Regions.end();)
  377. {
  378. map<Region_Node*, ZBSP_Node*>::const_iterator actualItr = testitr->first.begin();
  379. if(actualItr == testitr->first.end()) {
  380. testitr++;
  381. continue;
  382. }
  383. Region_Node *node = actualItr->first;
  384. ZBSP_Node *BSP_Root = actualItr->second;
  385. std::map<Region_Node*, bool>::const_iterator dead_itr = dead_nodes.find(node);
  386. if(dead_itr != dead_nodes.end()) {
  387. testitr++;
  388. continue;
  389. }
  390. if(!BSP_Root) {
  391. bool passDistCheck = false;
  392. int32 currentGridID = spawn->appearance.pos.grid_id;
  393. if(testitr->second.timerTic && currentGridID == node->grid_id && (node->trigger_widget_id == spawn->trigger_widget_id || (node->dist > 0.0f && spawn->GetDistance(node->x, node->y, node->z) <= node->dist && (passDistCheck = true)))
  394. && Timer::GetCurrentTime2() >= (testitr->second.lastTimerTic + testitr->second.timerTic)) {
  395. testitr->second.lastTimerTic = Timer::GetCurrentTime2();
  396. if (client)
  397. client->Message(CHANNEL_COLOR_RED, "[TICK] Region %i, GridID: %u, RegionName: %s, RegionEnvFileName: %s, distance: %f, X/Y/Z: %f / %f / %f. Script: %s", region_num, node->grid_id, node->regionName.c_str(), node->regionEnvFileName.c_str(),
  398. node->dist, node->x, node->y, node->z, node->regionScriptName.c_str());
  399. int32 returnValue = 0;
  400. lua_interface->RunRegionScript(node->regionScriptName, "Tick", spawn->GetZone(), spawn, RegionTypeUntagged, &returnValue);
  401. if (returnValue == 1)
  402. {
  403. testitr->second.lastTimerTic = 0;
  404. testitr->second.timerTic = 0;
  405. }
  406. }
  407. else if(currentGridID != node->grid_id || (node->trigger_widget_id != spawn->trigger_widget_id && !passDistCheck)) {
  408. if (client)
  409. client->Message(CHANNEL_COLOR_RED, "[LEAVE REGION] Region %i, GridID: %u, RegionName: %s, RegionEnvFileName: %s, distance: %f, X/Y/Z: %f / %f / %f. Script: %s", region_num, node->grid_id, node->regionName.c_str(), node->regionEnvFileName.c_str(),
  410. node->dist, node->x, node->y, node->z, node->regionScriptName.c_str());
  411. lua_interface->RunRegionScript(node->regionScriptName, "LeaveRegion", spawn->GetZone(), spawn, RegionTypeUntagged);
  412. map<map<Region_Node*, ZBSP_Node*>, Region_Status>::iterator endItr = testitr;
  413. endItr++;
  414. spawn->DeleteRegion(node, nullptr);
  415. if(endItr == spawn->Regions.end()) {
  416. break;
  417. }
  418. else {
  419. testitr++;
  420. continue;
  421. }
  422. }
  423. }
  424. else if (testitr->second.timerTic && testitr->second.inRegion && Timer::GetCurrentTime2() >= (testitr->second.lastTimerTic + testitr->second.timerTic))
  425. {
  426. testitr->second.lastTimerTic = Timer::GetCurrentTime2();
  427. if (client)
  428. client->Message(CHANNEL_COLOR_RED, "[TICK] Region %i, GridID: %u, RegionName: %s, RegionEnvFileName: %s, distance: %f, X/Y/Z: %f / %f / %f. Script: %s", region_num, node->grid_id, node->regionName.c_str(), node->regionEnvFileName.c_str(),
  429. node->dist, node->x, node->y, node->z, node->regionScriptName.c_str());
  430. WaterRegionType whatWasRegionType = RegionTypeNormal; // default will be 0
  431. if (BSP_Root->special == SPECIAL_REGION_LAVA_OR_DEATH)
  432. whatWasRegionType = RegionTypeLava; // 2
  433. else if (BSP_Root->special == SPECIAL_REGION_WATER)
  434. whatWasRegionType = RegionTypeWater; // 1
  435. int32 returnValue = 0;
  436. lua_interface->RunRegionScript(node->regionScriptName, "Tick", spawn->GetZone(), spawn, whatWasRegionType, &returnValue);
  437. if (returnValue == 1)
  438. {
  439. testitr->second.lastTimerTic = 0;
  440. testitr->second.timerTic = 0;
  441. }
  442. }
  443. region_num++;
  444. testitr++;
  445. }
  446. spawn->RegionMutex.releasewritelock();
  447. }
  448. WaterRegionType RegionMapV1::BSPReturnRegionType(int32 node_number, const glm::vec3& location, int32 gridid) const {
  449. std::shared_lock lock(MRegions);
  450. map<Region_Node*, ZBSP_Node*>::const_iterator itr;
  451. int region_num = 0;
  452. for (itr = Regions.begin(); itr != Regions.end(); itr++)
  453. {
  454. Region_Node* node = itr->first;
  455. // did not match grid id of current region, skip
  456. //if ( gridid > 0 && gridid != node->grid_id)
  457. // continue;
  458. ZBSP_Node* BSP_Root = itr->second;
  459. float x1 = node->x - location.x;
  460. float y1 = node->y - location.y;
  461. float z1 = node->z - location.z;
  462. float dist = sqrt(x1 * x1 + y1 * y1 + z1 * z1);
  463. #ifdef REGIONDEBUG
  464. printf("Region %i (%i) dist %f / node dist %f. NodeXYZ: %f %f %f, XYZ: %f %f %f.\n", region_num, node->region_type, dist, node->dist, node->x, node->y, node->z, location.x, location.y, location.z);
  465. #endif
  466. if (dist <= node->dist)
  467. {
  468. ZBSP_Node* BSP_Root = itr->second;
  469. WaterRegionType regionType = RegionTypeUntagged;
  470. if (node->region_type == ClassWaterRegion)
  471. regionType = BSPReturnRegionWaterRegion(node, BSP_Root, node_number, location, dist);
  472. else
  473. regionType = BSPReturnRegionTypeNode(node, BSP_Root, node_number, location, dist);
  474. if (regionType != RegionTypeNormal)
  475. return regionType;
  476. }
  477. region_num++;
  478. }
  479. return(RegionTypeNormal);
  480. }
  481. WaterRegionType RegionMapV1::BSPReturnRegionTypeNode(const Region_Node* region_node, const ZBSP_Node* BSP_Root, int32 node_number, const glm::vec3& location, float distToNode) const {
  482. if(node_number > region_node->vert_count)
  483. {
  484. LogWrite(REGION__DEBUG, 0, "Region", "Region %s grid %u (%s) - Node %u is out of range for region max vert count of %i. Hit at location %f %f %f.",
  485. region_node->regionName.c_str(), region_node->grid_id, region_node->regionScriptName.c_str(), node_number, region_node->vert_count,
  486. location.x, location.y, location.z);
  487. return (RegionTypeWater);
  488. }
  489. const ZBSP_Node* current_node = &BSP_Root[node_number - 1];
  490. float distance;
  491. #ifdef REGIONDEBUG
  492. printf("left = %u, right %u (Size: %i)\n", current_node->left, current_node->right, region_node->vert_count);
  493. #endif
  494. if (region_node->region_type == ClassWaterRegion2)
  495. {
  496. distance = (location.x * current_node->normal[0]) +
  497. (location.y * current_node->normal[1]) +
  498. (location.z * current_node->normal[2]) +
  499. current_node->splitdistance;
  500. }
  501. else {
  502. distance = (location.x * current_node->normal[0]) +
  503. (location.y * current_node->normal[1]) +
  504. (location.z * current_node->normal[2]) -
  505. current_node->splitdistance;
  506. }
  507. float absDistance = distance;
  508. if (absDistance < 0.0f)
  509. absDistance *= -1.0f;
  510. float absSplitDist = current_node->splitdistance;
  511. if (absSplitDist < 0.0f)
  512. absSplitDist *= -1.0f;
  513. #ifdef REGIONDEBUG
  514. printf("distance = %f, normals: %f %f %f, location: %f %f %f, split distance: %f\n", distance, current_node->left, current_node->right, current_node->normal[0], current_node->normal[1], current_node->normal[2],
  515. location.x, location.y, location.z, current_node->splitdistance);
  516. #endif
  517. if ((current_node->left == -2) &&
  518. (current_node->right == -1 || current_node->right == -2)) {
  519. if (region_node->region_type == ClassWaterOcean || region_node->region_type == ClassWaterOcean2)
  520. {
  521. if ( region_node->region_type == ClassWaterOcean && current_node->right == -1 &&
  522. current_node->normal[1] >= 0.9f && distance > 0 )
  523. return RegionTypeWater;
  524. else
  525. return EstablishDistanceAtAngle(region_node, current_node, distance, absDistance, absSplitDist, true);
  526. }
  527. else
  528. {
  529. if (distance > 0)
  530. return(RegionTypeWater);
  531. else
  532. return RegionTypeNormal;
  533. }
  534. }
  535. else if ((region_node->region_type == ClassWaterOcean || region_node->region_type == ClassWaterOcean2) && current_node->normal[1] != 1.0f && current_node->normal[1] != -1.0f)
  536. {
  537. float fraction = abs(current_node->normal[0] * current_node->normal[2]);
  538. float diff = distToNode / region_node->dist;
  539. if (distance > 0)
  540. diff = distance * diff;
  541. #ifdef REGIONDEBUG
  542. printf("Diff: %f (%f + %f), fraction %f\n", diff, distToNode, distance, fraction);
  543. #endif
  544. if ((abs(diff) / 2.0f) > (absSplitDist * (1.0f / fraction)) * 2.0f)
  545. return RegionTypeNormal;
  546. }
  547. if (distance == 0.0f) {
  548. return(RegionTypeNormal);
  549. }
  550. if (distance > 0.0f) {
  551. #ifdef REGIONDEBUG
  552. printf("to left node %i\n", current_node->left);
  553. #endif
  554. if (current_node->left == -2)
  555. {
  556. switch(region_node->region_type)
  557. {
  558. case ClassWaterVolume:
  559. case ClassWaterOcean:
  560. return RegionTypeWater;
  561. break;
  562. case ClassWaterOcean2:
  563. return EstablishDistanceAtAngle(region_node, current_node, distance, absDistance, absSplitDist, false);
  564. break;
  565. case ClassWaterCavern:
  566. return EstablishDistanceAtAngle(region_node, current_node, distance, absDistance, absSplitDist, true);
  567. break;
  568. default:
  569. return RegionTypeNormal;
  570. break;
  571. }
  572. }
  573. else if (current_node->left == -1) {
  574. return(RegionTypeNormal);
  575. }
  576. return BSPReturnRegionTypeNode(region_node, BSP_Root, current_node->left + 1, location, distToNode);
  577. }
  578. #ifdef REGIONDEBUG
  579. printf("to right node %i, sign bit %i\n", current_node->right, signbit(current_node->normal[1]));
  580. #endif
  581. if (current_node->right == -1) {
  582. if (region_node->region_type == ClassWaterOcean2 && signbit(current_node->normal[1]) == 0 && absDistance < absSplitDist)
  583. return RegionTypeWater;
  584. else if ((region_node->region_type == ClassWaterOcean || region_node->region_type == ClassWaterOcean2) &&
  585. (current_node->normal[1] > 0.0f && distance < 0.0f && absDistance < absSplitDist))
  586. {
  587. return(RegionTypeWater);
  588. }
  589. return(RegionTypeNormal);
  590. }
  591. return BSPReturnRegionTypeNode(region_node, BSP_Root, current_node->right + 1, location, distToNode);
  592. }
  593. WaterRegionType RegionMapV1::BSPReturnRegionWaterRegion(const Region_Node* region_node, const ZBSP_Node* BSP_Root, int32 node_number, const glm::vec3& location, float distToNode) const {
  594. if(node_number > region_node->vert_count)
  595. {
  596. LogWrite(REGION__DEBUG, 0, "Region", "Region %s grid %u (%s) - Node %u is out of range for region max vert count of %i. Hit at location %f %f %f.",
  597. region_node->regionName.c_str(), region_node->grid_id, region_node->regionScriptName.c_str(), node_number, region_node->vert_count,
  598. location.x, location.y, location.z);
  599. return (RegionTypeNormal);
  600. }
  601. const ZBSP_Node* current_node = &BSP_Root[node_number - 1];
  602. float distance;
  603. #ifdef REGIONDEBUG
  604. printf("left = %u, right %u\n", current_node->left, current_node->right);
  605. #endif
  606. distance = (location.x * current_node->normal[0]) +
  607. (location.y * current_node->normal[1]) +
  608. (location.z * current_node->normal[2]) -
  609. current_node->splitdistance;
  610. #ifdef REGIONDEBUG
  611. printf("distance = %f, normals: %f %f %f, location: %f %f %f, split distance: %f\n", distance, current_node->left, current_node->right, current_node->normal[0], current_node->normal[1], current_node->normal[2],
  612. location.x, location.y, location.z, current_node->splitdistance);
  613. #endif
  614. if (distance > 0.0f) {
  615. #ifdef REGIONDEBUG
  616. printf("to left node %i\n", current_node->left);
  617. #endif
  618. if (current_node->left == -1) {
  619. return(RegionTypeNormal);
  620. }
  621. else if (current_node->left == -2) {
  622. switch(current_node->special)
  623. {
  624. case SPECIAL_REGION_LAVA_OR_DEATH:
  625. return(RegionTypeLava);
  626. break;
  627. case SPECIAL_REGION_WATER:
  628. return(RegionTypeWater);
  629. break;
  630. default:
  631. return(RegionTypeUntagged);
  632. break;
  633. }
  634. }
  635. return BSPReturnRegionWaterRegion(region_node, BSP_Root, current_node->left + 1, location, distToNode);
  636. }
  637. #ifdef REGIONDEBUG
  638. printf("to right node %i, sign bit %i\n", current_node->right, signbit(current_node->normal[1]));
  639. #endif
  640. if (current_node->right == -1) {
  641. return(RegionTypeNormal);
  642. }
  643. return BSPReturnRegionWaterRegion(region_node, BSP_Root, current_node->right + 1, location, distToNode);
  644. }
  645. WaterRegionType RegionMapV1::EstablishDistanceAtAngle(const Region_Node* region_node, const ZBSP_Node* current_node, float distance, float absDistance, float absSplitDist, bool checkEdgedAngle) const {
  646. float fraction = abs(current_node->normal[0] * current_node->normal[2]);
  647. #ifdef REGIONDEBUG
  648. printf("Distcheck: %f < %f\n", absDistance, absSplitDist);
  649. #endif
  650. if (absDistance < absSplitDist &&
  651. (current_node->normal[0] >= 1.0f || current_node->normal[0] <= -1.0f ||
  652. (current_node->normal[1] >= .9f && distance < 0.0f) ||
  653. (current_node->normal[1] <= -.9f && distance > 0.0f)))
  654. {
  655. return RegionTypeWater;
  656. }
  657. else if (fraction > 0.0f && (region_node->region_type == ClassWaterOcean2 || checkEdgedAngle))
  658. {
  659. if (current_node->normal[2] >= 1.0f || current_node->normal[2] <= -1.0f)
  660. return RegionTypeNormal;
  661. else if (current_node->normal[1] == 0.0f && (current_node->normal[0] < -0.5f || current_node->normal[0] > 0.5f) &&
  662. ((abs(absDistance * current_node->normal[0]) / 2.0f) < ((abs(absSplitDist * (1.0f / fraction))))))
  663. {
  664. return RegionTypeWater;
  665. }
  666. else if (current_node->normal[1] == 0.0f && (current_node->normal[2] < -0.5f || current_node->normal[2] > 0.5f) &&
  667. ((abs(absDistance * current_node->normal[2]) / 2.0f) < ((abs(absSplitDist * (1.0f / fraction))))))
  668. {
  669. return RegionTypeWater;
  670. }
  671. }
  672. return RegionTypeNormal;
  673. }
  674. void RegionMapV1::InsertRegionNode(ZoneServer* zone, int32 version, std::string regionName, std::string envName, uint32 gridID, uint32 triggerWidgetID, float dist)
  675. {
  676. Region_Node* tmpNode = new Region_Node;
  677. tmpNode->x = 0.0f;
  678. tmpNode->y = 0.0f;
  679. tmpNode->z = 0.0f;
  680. if(!zone)
  681. return;
  682. Map* current_map = world.GetMap(std::string(zone->GetZoneFile()), version);
  683. if(current_map) {
  684. std::map<int32, glm::vec3>::iterator itr = current_map->widget_map.find(triggerWidgetID);
  685. if(itr != current_map->widget_map.end()) {
  686. tmpNode->x = itr->second.x;
  687. tmpNode->y = itr->second.y;
  688. tmpNode->z = itr->second.z;
  689. }
  690. }
  691. tmpNode->dist = dist;
  692. tmpNode->region_type = RegionTypeUntagged;
  693. tmpNode->regionName = string(regionName);
  694. tmpNode->regionEnvFileName = string(envName);
  695. tmpNode->grid_id = gridID;
  696. tmpNode->regionScriptName = string("");
  697. tmpNode->trigger_widget_id = triggerWidgetID;
  698. tmpNode->regionScriptName = TestFile(regionName);
  699. if ( tmpNode->regionScriptName.size() < 1 )
  700. {
  701. tmpNode->regionScriptName = TestFile(envName);
  702. }
  703. if ( tmpNode->regionScriptName.size() < 1 )
  704. {
  705. tmpNode->regionScriptName = TestFile("default");
  706. }
  707. tmpNode->vert_count = 0;
  708. ZBSP_Node* BSP_Root = nullptr;
  709. MRegions.lock();
  710. Regions.insert(make_pair(tmpNode, BSP_Root));
  711. MRegions.unlock();
  712. }
  713. void RegionMapV1::RemoveRegionNode(std::string name) {
  714. std::unique_lock lock(MRegions);
  715. map<Region_Node*, ZBSP_Node*>::const_iterator itr;
  716. for (itr = Regions.begin(); itr != Regions.end();)
  717. {
  718. Region_Node *node = itr->first;
  719. ZBSP_Node *BSP_Root = itr->second;
  720. if(node->regionName.find(name) != node->regionName.npos) {
  721. itr = Regions.erase(itr);
  722. dead_nodes.insert(make_pair(node, true));
  723. safe_delete(node);
  724. safe_delete_array(BSP_Root);
  725. }
  726. else {
  727. itr++;
  728. }
  729. }
  730. }