{"action":"created","comment":{"url":"https://api.github.com/repos/cuberite/cuberite/pulls/comments/41100188","id":41100188,"diff_hunk":"@@ -0,0 +1,226 @@\n+\n+\n+#include \"Globals.h\"\n+#include \"PathFinder.h\"\n+#include \"../Chunk.h\"\n+\n+cPathFinder::cPathFinder(double a_MobWidth, double a_MobHeight)\n+\t: m_Path(nullptr)\n+\t, m_IsFollowingPath(false)\n+\t, m_GiveUpCounter(0)\n+\t, m_TicksSinceLastPathReset(1000)\n+{\n+\tm_Width = a_MobWidth;\n+\tm_Height = a_MobHeight;\n+\n+}\n+\n+\n+\n+ePathFinderStatus cPathFinder::GetNextWayPoint(cChunk &a_Chunk, Vector3d a_Source, Vector3d a_Destination, Vector3d &a_OutputWaypoint)\n+{\n+\tm_FinalDestination = a_Destination;\n+\tm_Source = a_Source;\n+\n+\tif (m_TicksSinceLastPathReset < 1000)\n+\t{\n+\t\t// No need to count beyond 1000. 1000 is arbitary here.\n+\t\t++m_TicksSinceLastPathReset;\n+\t}\n+\n+\t/* if (ReachedFinalDestination())\n+\t{\n+\t\tStopMovingToPosition();\n+\t\treturn false;\n+\t} */\n+\n+\tif ((m_FinalDestination - m_PathFinderDestination).Length() > 0.25)  // if the distance between where we're going and where we should go is too big.\n+\t{\n+\t\t/* If we reached the last path waypoint,\n+\t\tOr if we haven't re-calculated for too long.\n+\t\tInterval is proportional to distance squared, and its minimum is 10.\n+\t\t(Recalculate lots when close, calculate rarely when far) */\n+\t\tif (\n+\t\t\t((m_Source - m_PathFinderDestination).Length() < 0.25) ||\n+\t\t\t((m_TicksSinceLastPathReset > 10) && (m_TicksSinceLastPathReset > (0.4 * (m_FinalDestination - m_Source).SqrLength())))\n+\t\t)\n+\t\t{\n+\t\t\t/* Re-calculating is expensive when there's no path to target, and it results in mobs freezing very often as a result of always recalculating.\n+\t\t\tThis is a workaround till we get better path recalculation. */\n+\t\t\tif (!m_NoPathToTarget)\n+\t\t\t{\n+\t\t\t\tResetPathFinding();\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tif (m_Path == nullptr)\n+\t{\n+\t\tif (!EnsureProperDestination(a_Chunk))\n+\t\t{\n+\t\t\treturn ePathFinderStatus::PATH_NOT_FOUND;\n+\t\t}\n+\n+\t\tm_GiveUpCounter = 40;\n+\t\tm_NoPathToTarget = false;\n+\t\tm_NoMoreWayPoints = false;\n+\t\tm_PathFinderDestination = m_FinalDestination;\n+\t\tm_Path = new cPath(a_Chunk, m_Source, m_PathFinderDestination, 20, m_Width, m_Height);\n+\t}\n+\n+\tswitch (m_Path->Step(a_Chunk))\n+\t{\n+\t\tcase ePathFinderStatus::NEARBY_FOUND:\n+\t\t{\n+\t\t\tm_NoPathToTarget = true;\n+\t\t\tm_PathFinderDestination = m_Path->AcceptNearbyPath();\n+\t\t\treturn ePathFinderStatus::PATH_FOUND;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tcase ePathFinderStatus::PATH_NOT_FOUND:\n+\t\t{\n+\t\t\treturn ePathFinderStatus::PATH_NOT_FOUND;\n+\t\t}\n+\t\tcase ePathFinderStatus::CALCULATING:\n+\t\t{\n+\t\t\tm_TicksSinceLastPathReset = 0;  // Start ticking only after a path is found.\n+\t\t\treturn ePathFinderStatus::CALCULATING;\n+\t\t}\n+\t\tcase ePathFinderStatus::PATH_FOUND:\n+\t\t{\n+\t\t\tif (m_NoMoreWayPoints || (--m_GiveUpCounter == 0))\n+\t\t\t{\n+\t\t\t\tResetPathFinding();  // Try to calculate a path again.\n+\t\t\t\treturn ePathFinderStatus::CALCULATING;\n+\t\t\t}\n+\t\t\telse if (!m_Path->IsLastPoint())  // Have we arrived at the next cell, as denoted by m_NextWayPointPosition?\n+\t\t\t{\n+\t\t\t\tif ((m_Path->IsFirstPoint() || (m_NextWayPointPosition - m_Source).SqrLength() < 0.25))\n+\t\t\t\t{\n+\t\t\t\t\tm_NextWayPointPosition = m_Path->GetNextPoint();\n+\t\t\t\t\ta_OutputWaypoint = m_NextWayPointPosition;\n+\t\t\t\t\tm_GiveUpCounter = 40;  // Give up after 40 ticks (2 seconds) if failed to reach m_NextWayPointPosition.\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\telse\n+\t\t\t{\n+\t\t\t\tm_NoMoreWayPoints = true;\n+\t\t\t}\n+\n+\t\t\tm_IsFollowingPath = true;\n+\t\t\treturn ePathFinderStatus::PATH_FOUND;\n+\t\t}\n+\n+\tdefault:  // Dummy to get rid of compiler warning.\n+\t\treturn ePathFinderStatus::PATH_FOUND;\n+\t\tbreak;\n+\t}\n+}\n+\n+","path":"src/Mobs/PathFinder.cpp","position":121,"original_position":121,"commit_id":"f88b126e04a1c61945e16e06decbc97d2fbbea68","original_commit_id":"f88b126e04a1c61945e16e06decbc97d2fbbea68","user":{"login":"SafwatHalaby","id":5030488,"avatar_url":"https://avatars.githubusercontent.com/u/5030488?v=3","gravatar_id":"","url":"https://api.github.com/users/SafwatHalaby","html_url":"https://github.com/SafwatHalaby","followers_url":"https://api.github.com/users/SafwatHalaby/followers","following_url":"https://api.github.com/users/SafwatHalaby/following{/other_user}","gists_url":"https://api.github.com/users/SafwatHalaby/gists{/gist_id}","starred_url":"https://api.github.com/users/SafwatHalaby/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/SafwatHalaby/subscriptions","organizations_url":"https://api.github.com/users/SafwatHalaby/orgs","repos_url":"https://api.github.com/users/SafwatHalaby/repos","events_url":"https://api.github.com/users/SafwatHalaby/events{/privacy}","received_events_url":"https://api.github.com/users/SafwatHalaby/received_events","type":"User","site_admin":false},"body":"5 spaces","created_at":"2015-10-04T17:47:42Z","updated_at":"2015-10-04T17:47:42Z","html_url":"https://github.com/cuberite/cuberite/pull/2523#discussion_r41100188","pull_request_url":"https://api.github.com/repos/cuberite/cuberite/pulls/2523","_links":{"self":{"href":"https://api.github.com/repos/cuberite/cuberite/pulls/comments/41100188"},"html":{"href":"https://github.com/cuberite/cuberite/pull/2523#discussion_r41100188"},"pull_request":{"href":"https://api.github.com/repos/cuberite/cuberite/pulls/2523"}}},"pull_request":{"url":"https://api.github.com/repos/cuberite/cuberite/pulls/2523","id":46729248,"html_url":"https://github.com/cuberite/cuberite/pull/2523","diff_url":"https://github.com/cuberite/cuberite/pull/2523.diff","patch_url":"https://github.com/cuberite/cuberite/pull/2523.patch","issue_url":"https://api.github.com/repos/cuberite/cuberite/issues/2523","number":2523,"state":"open","locked":false,"title":"Decoupled cMonster and path recalculation logic, created cPathFinder","user":{"login":"SafwatHalaby","id":5030488,"avatar_url":"https://avatars.githubusercontent.com/u/5030488?v=3","gravatar_id":"","url":"https://api.github.com/users/SafwatHalaby","html_url":"https://github.com/SafwatHalaby","followers_url":"https://api.github.com/users/SafwatHalaby/followers","following_url":"https://api.github.com/users/SafwatHalaby/following{/other_user}","gists_url":"https://api.github.com/users/SafwatHalaby/gists{/gist_id}","starred_url":"https://api.github.com/users/SafwatHalaby/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/SafwatHalaby/subscriptions","organizations_url":"https://api.github.com/users/SafwatHalaby/orgs","repos_url":"https://api.github.com/users/SafwatHalaby/repos","events_url":"https://api.github.com/users/SafwatHalaby/events{/privacy}","received_events_url":"https://api.github.com/users/SafwatHalaby/received_events","type":"User","site_admin":false},"body":"cMonster had too much path-finding code. I've moved the path recalculation logic into a new class called cPathFinder.\r\n\r\nAdvantages:\r\n - Cleaner cMonster, seperation of concerns.\r\n - The path recalculation algorithm can be swapped without having to edit the AI code simply by reimplementing by  `cPathFinder`.\r\n\r\n\r\n**Some background**\r\n\r\n**cPath**: A device which takes two points as an input, and returns a path.\r\n\r\nThe most accurate pathfinding would be calling cPath every single step. But that's very resource-intensive. A saner approach would be calling cPath less often, but that's a delicate task: If we call cPath too little, the mob would move along stalled paths and it ends going to where the player has been long ago. Until now,  cMonster had this path recalculation logic, but that made it too tightly coupled with pathfinding and too messy. This commit moves that recalculation logic to a new class called cPathFinder.\r\n\r\n**cPathFinder**: Wraps cPath, takes two points as an input each tick, returns the next way point the mob should move to. It internally decides whether to use an old cPath or to recalculate. That decision is based on both the time since the last recalculation and the distance to the target.\r\n\r\nIn most cases, no one should use cPath directly. The only exception I can think of is when one needs to pre-calculate static paths, but perhaps that should also be wrapped in some class like `cStaticPathFinder`.","created_at":"2015-10-04T17:44:46Z","updated_at":"2015-10-04T17:47:42Z","closed_at":null,"merged_at":null,"merge_commit_sha":"887b2d82ff491cb86d98a082a72f23b852952c3c","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/cuberite/cuberite/pulls/2523/commits","review_comments_url":"https://api.github.com/repos/cuberite/cuberite/pulls/2523/comments","review_comment_url":"https://api.github.com/repos/cuberite/cuberite/pulls/comments{/number}","comments_url":"https://api.github.com/repos/cuberite/cuberite/issues/2523/comments","statuses_url":"https://api.github.com/repos/cuberite/cuberite/statuses/f88b126e04a1c61945e16e06decbc97d2fbbea68","head":{"label":"SafwatHalaby:decoupleMonster","ref":"decoupleMonster","sha":"f88b126e04a1c61945e16e06decbc97d2fbbea68","user":{"login":"SafwatHalaby","id":5030488,"avatar_url":"https://avatars.githubusercontent.com/u/5030488?v=3","gravatar_id":"","url":"https://api.github.com/users/SafwatHalaby","html_url":"https://github.com/SafwatHalaby","followers_url":"https://api.github.com/users/SafwatHalaby/followers","following_url":"https://api.github.com/users/SafwatHalaby/following{/other_user}","gists_url":"https://api.github.com/users/SafwatHalaby/gists{/gist_id}","starred_url":"https://api.github.com/users/SafwatHalaby/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/SafwatHalaby/subscriptions","organizations_url":"https://api.github.com/users/SafwatHalaby/orgs","repos_url":"https://api.github.com/users/SafwatHalaby/repos","events_url":"https://api.github.com/users/SafwatHalaby/events{/privacy}","received_events_url":"https://api.github.com/users/SafwatHalaby/received_events","type":"User","site_admin":false},"repo":{"id":43133123,"name":"cuberite","full_name":"SafwatHalaby/cuberite","owner":{"login":"SafwatHalaby","id":5030488,"avatar_url":"https://avatars.githubusercontent.com/u/5030488?v=3","gravatar_id":"","url":"https://api.github.com/users/SafwatHalaby","html_url":"https://github.com/SafwatHalaby","followers_url":"https://api.github.com/users/SafwatHalaby/followers","following_url":"https://api.github.com/users/SafwatHalaby/following{/other_user}","gists_url":"https://api.github.com/users/SafwatHalaby/gists{/gist_id}","starred_url":"https://api.github.com/users/SafwatHalaby/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/SafwatHalaby/subscriptions","organizations_url":"https://api.github.com/users/SafwatHalaby/orgs","repos_url":"https://api.github.com/users/SafwatHalaby/repos","events_url":"https://api.github.com/users/SafwatHalaby/events{/privacy}","received_events_url":"https://api.github.com/users/SafwatHalaby/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/SafwatHalaby/cuberite","description":"A performant C++ Minecraft compatible game server","fork":true,"url":"https://api.github.com/repos/SafwatHalaby/cuberite","forks_url":"https://api.github.com/repos/SafwatHalaby/cuberite/forks","keys_url":"https://api.github.com/repos/SafwatHalaby/cuberite/keys{/key_id}","collaborators_url":"https://api.github.com/repos/SafwatHalaby/cuberite/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/SafwatHalaby/cuberite/teams","hooks_url":"https://api.github.com/repos/SafwatHalaby/cuberite/hooks","issue_events_url":"https://api.github.com/repos/SafwatHalaby/cuberite/issues/events{/number}","events_url":"https://api.github.com/repos/SafwatHalaby/cuberite/events","assignees_url":"https://api.github.com/repos/SafwatHalaby/cuberite/assignees{/user}","branches_url":"https://api.github.com/repos/SafwatHalaby/cuberite/branches{/branch}","tags_url":"https://api.github.com/repos/SafwatHalaby/cuberite/tags","blobs_url":"https://api.github.com/repos/SafwatHalaby/cuberite/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/SafwatHalaby/cuberite/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/SafwatHalaby/cuberite/git/refs{/sha}","trees_url":"https://api.github.com/repos/SafwatHalaby/cuberite/git/trees{/sha}","statuses_url":"https://api.github.com/repos/SafwatHalaby/cuberite/statuses/{sha}","languages_url":"https://api.github.com/repos/SafwatHalaby/cuberite/languages","stargazers_url":"https://api.github.com/repos/SafwatHalaby/cuberite/stargazers","contributors_url":"https://api.github.com/repos/SafwatHalaby/cuberite/contributors","subscribers_url":"https://api.github.com/repos/SafwatHalaby/cuberite/subscribers","subscription_url":"https://api.github.com/repos/SafwatHalaby/cuberite/subscription","commits_url":"https://api.github.com/repos/SafwatHalaby/cuberite/commits{/sha}","git_commits_url":"https://api.github.com/repos/SafwatHalaby/cuberite/git/commits{/sha}","comments_url":"https://api.github.com/repos/SafwatHalaby/cuberite/comments{/number}","issue_comment_url":"https://api.github.com/repos/SafwatHalaby/cuberite/issues/comments{/number}","contents_url":"https://api.github.com/repos/SafwatHalaby/cuberite/contents/{+path}","compare_url":"https://api.github.com/repos/SafwatHalaby/cuberite/compare/{base}...{head}","merges_url":"https://api.github.com/repos/SafwatHalaby/cuberite/merges","archive_url":"https://api.github.com/repos/SafwatHalaby/cuberite/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/SafwatHalaby/cuberite/downloads","issues_url":"https://api.github.com/repos/SafwatHalaby/cuberite/issues{/number}","pulls_url":"https://api.github.com/repos/SafwatHalaby/cuberite/pulls{/number}","milestones_url":"https://api.github.com/repos/SafwatHalaby/cuberite/milestones{/number}","notifications_url":"https://api.github.com/repos/SafwatHalaby/cuberite/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/SafwatHalaby/cuberite/labels{/name}","releases_url":"https://api.github.com/repos/SafwatHalaby/cuberite/releases{/id}","created_at":"2015-09-25T10:43:49Z","updated_at":"2015-09-25T10:44:01Z","pushed_at":"2015-10-04T17:24:32Z","git_url":"git://github.com/SafwatHalaby/cuberite.git","ssh_url":"git@github.com:SafwatHalaby/cuberite.git","clone_url":"https://github.com/SafwatHalaby/cuberite.git","svn_url":"https://github.com/SafwatHalaby/cuberite","homepage":"http://cuberite.org","size":76291,"stargazers_count":0,"watchers_count":0,"language":"C","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"cuberite:master","ref":"master","sha":"0786fda18b08ee26a9bdcda7b17ef9979be4585a","user":{"login":"cuberite","id":8973961,"avatar_url":"https://avatars.githubusercontent.com/u/8973961?v=3","gravatar_id":"","url":"https://api.github.com/users/cuberite","html_url":"https://github.com/cuberite","followers_url":"https://api.github.com/users/cuberite/followers","following_url":"https://api.github.com/users/cuberite/following{/other_user}","gists_url":"https://api.github.com/users/cuberite/gists{/gist_id}","starred_url":"https://api.github.com/users/cuberite/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cuberite/subscriptions","organizations_url":"https://api.github.com/users/cuberite/orgs","repos_url":"https://api.github.com/users/cuberite/repos","events_url":"https://api.github.com/users/cuberite/events{/privacy}","received_events_url":"https://api.github.com/users/cuberite/received_events","type":"Organization","site_admin":false},"repo":{"id":11693709,"name":"cuberite","full_name":"cuberite/cuberite","owner":{"login":"cuberite","id":8973961,"avatar_url":"https://avatars.githubusercontent.com/u/8973961?v=3","gravatar_id":"","url":"https://api.github.com/users/cuberite","html_url":"https://github.com/cuberite","followers_url":"https://api.github.com/users/cuberite/followers","following_url":"https://api.github.com/users/cuberite/following{/other_user}","gists_url":"https://api.github.com/users/cuberite/gists{/gist_id}","starred_url":"https://api.github.com/users/cuberite/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cuberite/subscriptions","organizations_url":"https://api.github.com/users/cuberite/orgs","repos_url":"https://api.github.com/users/cuberite/repos","events_url":"https://api.github.com/users/cuberite/events{/privacy}","received_events_url":"https://api.github.com/users/cuberite/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/cuberite/cuberite","description":"A performant C++ Minecraft compatible game server","fork":false,"url":"https://api.github.com/repos/cuberite/cuberite","forks_url":"https://api.github.com/repos/cuberite/cuberite/forks","keys_url":"https://api.github.com/repos/cuberite/cuberite/keys{/key_id}","collaborators_url":"https://api.github.com/repos/cuberite/cuberite/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/cuberite/cuberite/teams","hooks_url":"https://api.github.com/repos/cuberite/cuberite/hooks","issue_events_url":"https://api.github.com/repos/cuberite/cuberite/issues/events{/number}","events_url":"https://api.github.com/repos/cuberite/cuberite/events","assignees_url":"https://api.github.com/repos/cuberite/cuberite/assignees{/user}","branches_url":"https://api.github.com/repos/cuberite/cuberite/branches{/branch}","tags_url":"https://api.github.com/repos/cuberite/cuberite/tags","blobs_url":"https://api.github.com/repos/cuberite/cuberite/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/cuberite/cuberite/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/cuberite/cuberite/git/refs{/sha}","trees_url":"https://api.github.com/repos/cuberite/cuberite/git/trees{/sha}","statuses_url":"https://api.github.com/repos/cuberite/cuberite/statuses/{sha}","languages_url":"https://api.github.com/repos/cuberite/cuberite/languages","stargazers_url":"https://api.github.com/repos/cuberite/cuberite/stargazers","contributors_url":"https://api.github.com/repos/cuberite/cuberite/contributors","subscribers_url":"https://api.github.com/repos/cuberite/cuberite/subscribers","subscription_url":"https://api.github.com/repos/cuberite/cuberite/subscription","commits_url":"https://api.github.com/repos/cuberite/cuberite/commits{/sha}","git_commits_url":"https://api.github.com/repos/cuberite/cuberite/git/commits{/sha}","comments_url":"https://api.github.com/repos/cuberite/cuberite/comments{/number}","issue_comment_url":"https://api.github.com/repos/cuberite/cuberite/issues/comments{/number}","contents_url":"https://api.github.com/repos/cuberite/cuberite/contents/{+path}","compare_url":"https://api.github.com/repos/cuberite/cuberite/compare/{base}...{head}","merges_url":"https://api.github.com/repos/cuberite/cuberite/merges","archive_url":"https://api.github.com/repos/cuberite/cuberite/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/cuberite/cuberite/downloads","issues_url":"https://api.github.com/repos/cuberite/cuberite/issues{/number}","pulls_url":"https://api.github.com/repos/cuberite/cuberite/pulls{/number}","milestones_url":"https://api.github.com/repos/cuberite/cuberite/milestones{/number}","notifications_url":"https://api.github.com/repos/cuberite/cuberite/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/cuberite/cuberite/labels{/name}","releases_url":"https://api.github.com/repos/cuberite/cuberite/releases{/id}","created_at":"2013-07-26T19:56:59Z","updated_at":"2015-09-28T02:17:01Z","pushed_at":"2015-10-04T17:44:46Z","git_url":"git://github.com/cuberite/cuberite.git","ssh_url":"git@github.com:cuberite/cuberite.git","clone_url":"https://github.com/cuberite/cuberite.git","svn_url":"https://github.com/cuberite/cuberite","homepage":"http://cuberite.org","size":169664,"stargazers_count":734,"watchers_count":734,"language":"C","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":236,"mirror_url":null,"open_issues_count":396,"forks":236,"open_issues":396,"watchers":734,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/cuberite/cuberite/pulls/2523"},"html":{"href":"https://github.com/cuberite/cuberite/pull/2523"},"issue":{"href":"https://api.github.com/repos/cuberite/cuberite/issues/2523"},"comments":{"href":"https://api.github.com/repos/cuberite/cuberite/issues/2523/comments"},"review_comments":{"href":"https://api.github.com/repos/cuberite/cuberite/pulls/2523/comments"},"review_comment":{"href":"https://api.github.com/repos/cuberite/cuberite/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/cuberite/cuberite/pulls/2523/commits"},"statuses":{"href":"https://api.github.com/repos/cuberite/cuberite/statuses/f88b126e04a1c61945e16e06decbc97d2fbbea68"}}}}