{"action":"created","comment":{"url":"https://api.github.com/repos/OpenRA/OpenRA/pulls/comments/135397689","pull_request_review_id":58809111,"id":135397689,"diff_hunk":"@@ -58,65 +76,80 @@ public bool CanGrantCondition(Actor self, object source)\n \n \t\t\t// Timed tokens do not count towards the source cap: the condition with the shortest\n \t\t\t// remaining duration can always be revoked to make room.\n-\t\t\tif (Info.SourceCap > 0 && permanentTokens.GetOrAdd(source).Count >= Info.SourceCap)\n-\t\t\t\treturn false;\n+\t\t\tif (Info.SourceCap > 0)\n+\t\t\t{\n+\t\t\t\tHashSet<int> permanentTokensForSource;\n+\t\t\t\tif (permanentTokens.TryGetValue(source, out permanentTokensForSource) && permanentTokensForSource.Count >= Info.SourceCap)\n+\t\t\t\t\treturn false;\n+\t\t\t}\n \n-\t\t\tif (Info.TotalCap > 0 && permanentTokens.Values.SelectMany(t => t).Count() >= Info.TotalCap)\n+\t\t\tif (Info.TotalCap > 0 && permanentTokens.Values.Sum(t => t.Count) >= Info.TotalCap)\n \t\t\t\treturn false;\n \n \t\t\treturn true;\n \t\t}\n \n \t\tpublic int GrantCondition(Actor self, object source, int duration = 0)\n \t\t{\n-\t\t\tif (conditionManager == null || source == null || !CanGrantCondition(self, source))\n+\t\t\tif (!CanGrantCondition(self, source))\n \t\t\t\treturn ConditionManager.InvalidConditionToken;\n \n-\t\t\tvar token = conditionManager.GrantCondition(self, Info.Condition, duration);\n-\t\t\tvar permanent = permanentTokens.GetOrAdd(source);\n+\t\t\tvar token = conditionManager.GrantCondition(self, Info.Condition);\n+\t\t\tHashSet<int> permanent;\n+\t\t\tpermanentTokens.TryGetValue(source, out permanent);\n \n \t\t\tif (duration > 0)\n \t\t\t{\n-\t\t\t\tvar timed = timedTokens.GetOrAdd(source);\n-\n-\t\t\t\t// Remove expired tokens\n-\t\t\t\ttimed.RemoveWhere(t => t.Expires < self.World.WorldTick);\n-\n \t\t\t\t// Check level caps\n \t\t\t\tif (Info.SourceCap > 0)\n \t\t\t\t{\n-\t\t\t\t\tif (permanent.Count + timed.Count >= Info.SourceCap)\n+\t\t\t\t\tvar timedCount = timedTokens.Count(t => t.Source == source);\n+\t\t\t\t\tif ((permanent != null ? permanent.Count + timedCount : timedCount) >= Info.SourceCap)\n \t\t\t\t\t{\n-\t\t\t\t\t\tvar expire = timed.MinByOrDefault(t => t.Expires);\n-\t\t\t\t\t\tif (expire != null)\n+\t\t\t\t\t\t// Get timed token from the same source with closest expiration.\n+\t\t\t\t\t\tvar expireIndex = timedTokens.FindIndex(t => t.Source == source);\n+\t\t\t\t\t\tif (expireIndex >= 0)\n \t\t\t\t\t\t{\n-\t\t\t\t\t\t\ttimed.Remove(expire);\n-\t\t\t\t\t\t\tif (conditionManager.TokenValid(self, expire.Token))\n-\t\t\t\t\t\t\t\tconditionManager.RevokeCondition(self, expire.Token);\n+\t\t\t\t\t\t\tvar expireToken = timedTokens[expireIndex].Token;\n+\t\t\t\t\t\t\ttimedTokens.RemoveAt(expireIndex);\n+\t\t\t\t\t\t\tif (conditionManager.TokenValid(self, expireToken))\n+\t\t\t\t\t\t\t\tconditionManager.RevokeCondition(self, expireToken);\n \t\t\t\t\t\t}\n \t\t\t\t\t}\n \t\t\t\t}\n \n \t\t\t\tif (Info.TotalCap > 0)\n \t\t\t\t{\n-\t\t\t\t\tvar totalCount = permanentTokens.Values.SelectMany(t => t).Count() + timedTokens.Values.SelectMany(t => t).Count();\n+\t\t\t\t\tvar totalCount = permanentTokens.Values.Sum(t => t.Count) + timedTokens.Count;\n \t\t\t\t\tif (totalCount >= Info.TotalCap)\n \t\t\t\t\t{\n \t\t\t\t\t\t// Prefer tokens from the same source\n-\t\t\t\t\t\tvar expire = timedTokens.SelectMany(t => t.Value.Select(tt => new Tuple<object, TimedToken>(t.Key, tt)))\n-\t\t\t\t\t\t\t.MinByOrDefault(t => t.Item2.Expires);\n-\t\t\t\t\t\tif (expire != null)\n+\t\t\t\t\t\tif (timedTokens.Count > 0)\n \t\t\t\t\t\t{\n-\t\t\t\t\t\t\tif (conditionManager.TokenValid(self, expire.Item2.Token))\n-\t\t\t\t\t\t\t\tconditionManager.RevokeCondition(self, expire.Item2.Token);\n+\t\t\t\t\t\t\tvar expire = timedTokens[0].Token;","path":"OpenRA.Mods.Common/Traits/Conditions/ExternalCondition.cs","position":126,"original_position":126,"commit_id":"788ab092916605e85b2b8c99a00352358965d581","original_commit_id":"788ab092916605e85b2b8c99a00352358965d581","user":{"login":"pchote","id":167819,"avatar_url":"https://avatars1.githubusercontent.com/u/167819?v=4","gravatar_id":"","url":"https://api.github.com/users/pchote","html_url":"https://github.com/pchote","followers_url":"https://api.github.com/users/pchote/followers","following_url":"https://api.github.com/users/pchote/following{/other_user}","gists_url":"https://api.github.com/users/pchote/gists{/gist_id}","starred_url":"https://api.github.com/users/pchote/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pchote/subscriptions","organizations_url":"https://api.github.com/users/pchote/orgs","repos_url":"https://api.github.com/users/pchote/repos","events_url":"https://api.github.com/users/pchote/events{/privacy}","received_events_url":"https://api.github.com/users/pchote/received_events","type":"User","site_admin":false},"body":"This doesn't `// Prefer tokens from the same source`, but the original code didn't seem to either.  It would be good if we could fix that here.","created_at":"2017-08-26T21:05:05Z","updated_at":"2017-08-26T21:33:04Z","html_url":"https://github.com/OpenRA/OpenRA/pull/13719#discussion_r135397689","pull_request_url":"https://api.github.com/repos/OpenRA/OpenRA/pulls/13719","_links":{"self":{"href":"https://api.github.com/repos/OpenRA/OpenRA/pulls/comments/135397689"},"html":{"href":"https://github.com/OpenRA/OpenRA/pull/13719#discussion_r135397689"},"pull_request":{"href":"https://api.github.com/repos/OpenRA/OpenRA/pulls/13719"}}},"pull_request":{"url":"https://api.github.com/repos/OpenRA/OpenRA/pulls/13719","id":132104873,"html_url":"https://github.com/OpenRA/OpenRA/pull/13719","diff_url":"https://github.com/OpenRA/OpenRA/pull/13719.diff","patch_url":"https://github.com/OpenRA/OpenRA/pull/13719.patch","issue_url":"https://api.github.com/repos/OpenRA/OpenRA/issues/13719","number":13719,"state":"open","locked":false,"title":"Move condition timer logic (& some ExternalCondition refactoring)","user":{"login":"atlimit8","id":4957137,"avatar_url":"https://avatars3.githubusercontent.com/u/4957137?v=4","gravatar_id":"","url":"https://api.github.com/users/atlimit8","html_url":"https://github.com/atlimit8","followers_url":"https://api.github.com/users/atlimit8/followers","following_url":"https://api.github.com/users/atlimit8/following{/other_user}","gists_url":"https://api.github.com/users/atlimit8/gists{/gist_id}","starred_url":"https://api.github.com/users/atlimit8/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/atlimit8/subscriptions","organizations_url":"https://api.github.com/users/atlimit8/orgs","repos_url":"https://api.github.com/users/atlimit8/repos","events_url":"https://api.github.com/users/atlimit8/events{/privacy}","received_events_url":"https://api.github.com/users/atlimit8/received_events","type":"User","site_admin":false},"body":"This will make expanding trait variables easier as well.","created_at":"2017-07-24T17:37:48Z","updated_at":"2017-08-26T21:33:04Z","closed_at":null,"merged_at":null,"merge_commit_sha":"3aca728dd6f80a3f7b4cb49d3ae71288a474dbc1","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":{"url":"https://api.github.com/repos/OpenRA/OpenRA/milestones/20","html_url":"https://github.com/OpenRA/OpenRA/milestone/20","labels_url":"https://api.github.com/repos/OpenRA/OpenRA/milestones/20/labels","id":2202516,"number":20,"title":"Next + 1","description":"","creator":{"login":"pchote","id":167819,"avatar_url":"https://avatars1.githubusercontent.com/u/167819?v=4","gravatar_id":"","url":"https://api.github.com/users/pchote","html_url":"https://github.com/pchote","followers_url":"https://api.github.com/users/pchote/followers","following_url":"https://api.github.com/users/pchote/following{/other_user}","gists_url":"https://api.github.com/users/pchote/gists{/gist_id}","starred_url":"https://api.github.com/users/pchote/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pchote/subscriptions","organizations_url":"https://api.github.com/users/pchote/orgs","repos_url":"https://api.github.com/users/pchote/repos","events_url":"https://api.github.com/users/pchote/events{/privacy}","received_events_url":"https://api.github.com/users/pchote/received_events","type":"User","site_admin":false},"open_issues":27,"closed_issues":35,"state":"open","created_at":"2016-12-17T20:43:34Z","updated_at":"2017-08-26T13:32:28Z","due_on":null,"closed_at":null},"commits_url":"https://api.github.com/repos/OpenRA/OpenRA/pulls/13719/commits","review_comments_url":"https://api.github.com/repos/OpenRA/OpenRA/pulls/13719/comments","review_comment_url":"https://api.github.com/repos/OpenRA/OpenRA/pulls/comments{/number}","comments_url":"https://api.github.com/repos/OpenRA/OpenRA/issues/13719/comments","statuses_url":"https://api.github.com/repos/OpenRA/OpenRA/statuses/788ab092916605e85b2b8c99a00352358965d581","head":{"label":"atlimit8:move-condition-timer-logic","ref":"move-condition-timer-logic","sha":"788ab092916605e85b2b8c99a00352358965d581","user":{"login":"atlimit8","id":4957137,"avatar_url":"https://avatars3.githubusercontent.com/u/4957137?v=4","gravatar_id":"","url":"https://api.github.com/users/atlimit8","html_url":"https://github.com/atlimit8","followers_url":"https://api.github.com/users/atlimit8/followers","following_url":"https://api.github.com/users/atlimit8/following{/other_user}","gists_url":"https://api.github.com/users/atlimit8/gists{/gist_id}","starred_url":"https://api.github.com/users/atlimit8/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/atlimit8/subscriptions","organizations_url":"https://api.github.com/users/atlimit8/orgs","repos_url":"https://api.github.com/users/atlimit8/repos","events_url":"https://api.github.com/users/atlimit8/events{/privacy}","received_events_url":"https://api.github.com/users/atlimit8/received_events","type":"User","site_admin":false},"repo":{"id":20511242,"name":"OpenRA","full_name":"atlimit8/OpenRA","owner":{"login":"atlimit8","id":4957137,"avatar_url":"https://avatars3.githubusercontent.com/u/4957137?v=4","gravatar_id":"","url":"https://api.github.com/users/atlimit8","html_url":"https://github.com/atlimit8","followers_url":"https://api.github.com/users/atlimit8/followers","following_url":"https://api.github.com/users/atlimit8/following{/other_user}","gists_url":"https://api.github.com/users/atlimit8/gists{/gist_id}","starred_url":"https://api.github.com/users/atlimit8/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/atlimit8/subscriptions","organizations_url":"https://api.github.com/users/atlimit8/orgs","repos_url":"https://api.github.com/users/atlimit8/repos","events_url":"https://api.github.com/users/atlimit8/events{/privacy}","received_events_url":"https://api.github.com/users/atlimit8/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/atlimit8/OpenRA","description":"An open-source implementation of the Command & Conquer: Red Alert engine using .NET/Mono and OpenGL. Runs on Windows, Linux and Mac OS X.","fork":true,"url":"https://api.github.com/repos/atlimit8/OpenRA","forks_url":"https://api.github.com/repos/atlimit8/OpenRA/forks","keys_url":"https://api.github.com/repos/atlimit8/OpenRA/keys{/key_id}","collaborators_url":"https://api.github.com/repos/atlimit8/OpenRA/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/atlimit8/OpenRA/teams","hooks_url":"https://api.github.com/repos/atlimit8/OpenRA/hooks","issue_events_url":"https://api.github.com/repos/atlimit8/OpenRA/issues/events{/number}","events_url":"https://api.github.com/repos/atlimit8/OpenRA/events","assignees_url":"https://api.github.com/repos/atlimit8/OpenRA/assignees{/user}","branches_url":"https://api.github.com/repos/atlimit8/OpenRA/branches{/branch}","tags_url":"https://api.github.com/repos/atlimit8/OpenRA/tags","blobs_url":"https://api.github.com/repos/atlimit8/OpenRA/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/atlimit8/OpenRA/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/atlimit8/OpenRA/git/refs{/sha}","trees_url":"https://api.github.com/repos/atlimit8/OpenRA/git/trees{/sha}","statuses_url":"https://api.github.com/repos/atlimit8/OpenRA/statuses/{sha}","languages_url":"https://api.github.com/repos/atlimit8/OpenRA/languages","stargazers_url":"https://api.github.com/repos/atlimit8/OpenRA/stargazers","contributors_url":"https://api.github.com/repos/atlimit8/OpenRA/contributors","subscribers_url":"https://api.github.com/repos/atlimit8/OpenRA/subscribers","subscription_url":"https://api.github.com/repos/atlimit8/OpenRA/subscription","commits_url":"https://api.github.com/repos/atlimit8/OpenRA/commits{/sha}","git_commits_url":"https://api.github.com/repos/atlimit8/OpenRA/git/commits{/sha}","comments_url":"https://api.github.com/repos/atlimit8/OpenRA/comments{/number}","issue_comment_url":"https://api.github.com/repos/atlimit8/OpenRA/issues/comments{/number}","contents_url":"https://api.github.com/repos/atlimit8/OpenRA/contents/{+path}","compare_url":"https://api.github.com/repos/atlimit8/OpenRA/compare/{base}...{head}","merges_url":"https://api.github.com/repos/atlimit8/OpenRA/merges","archive_url":"https://api.github.com/repos/atlimit8/OpenRA/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/atlimit8/OpenRA/downloads","issues_url":"https://api.github.com/repos/atlimit8/OpenRA/issues{/number}","pulls_url":"https://api.github.com/repos/atlimit8/OpenRA/pulls{/number}","milestones_url":"https://api.github.com/repos/atlimit8/OpenRA/milestones{/number}","notifications_url":"https://api.github.com/repos/atlimit8/OpenRA/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/atlimit8/OpenRA/labels{/name}","releases_url":"https://api.github.com/repos/atlimit8/OpenRA/releases{/id}","deployments_url":"https://api.github.com/repos/atlimit8/OpenRA/deployments","created_at":"2014-06-05T04:01:26Z","updated_at":"2017-02-14T23:52:55Z","pushed_at":"2017-08-25T12:50:34Z","git_url":"git://github.com/atlimit8/OpenRA.git","ssh_url":"git@github.com:atlimit8/OpenRA.git","clone_url":"https://github.com/atlimit8/OpenRA.git","svn_url":"https://github.com/atlimit8/OpenRA","homepage":"http://www.openra.net","size":124721,"stargazers_count":0,"watchers_count":0,"language":"C#","has_issues":false,"has_projects":true,"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":"bleed"}},"base":{"label":"OpenRA:bleed","ref":"bleed","sha":"4c222e5f2be2faaac0b74c2793269bd267a8286a","user":{"login":"OpenRA","id":409046,"avatar_url":"https://avatars0.githubusercontent.com/u/409046?v=4","gravatar_id":"","url":"https://api.github.com/users/OpenRA","html_url":"https://github.com/OpenRA","followers_url":"https://api.github.com/users/OpenRA/followers","following_url":"https://api.github.com/users/OpenRA/following{/other_user}","gists_url":"https://api.github.com/users/OpenRA/gists{/gist_id}","starred_url":"https://api.github.com/users/OpenRA/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/OpenRA/subscriptions","organizations_url":"https://api.github.com/users/OpenRA/orgs","repos_url":"https://api.github.com/users/OpenRA/repos","events_url":"https://api.github.com/users/OpenRA/events{/privacy}","received_events_url":"https://api.github.com/users/OpenRA/received_events","type":"Organization","site_admin":false},"repo":{"id":959908,"name":"OpenRA","full_name":"OpenRA/OpenRA","owner":{"login":"OpenRA","id":409046,"avatar_url":"https://avatars0.githubusercontent.com/u/409046?v=4","gravatar_id":"","url":"https://api.github.com/users/OpenRA","html_url":"https://github.com/OpenRA","followers_url":"https://api.github.com/users/OpenRA/followers","following_url":"https://api.github.com/users/OpenRA/following{/other_user}","gists_url":"https://api.github.com/users/OpenRA/gists{/gist_id}","starred_url":"https://api.github.com/users/OpenRA/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/OpenRA/subscriptions","organizations_url":"https://api.github.com/users/OpenRA/orgs","repos_url":"https://api.github.com/users/OpenRA/repos","events_url":"https://api.github.com/users/OpenRA/events{/privacy}","received_events_url":"https://api.github.com/users/OpenRA/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/OpenRA/OpenRA","description":"Open Source real-time strategy game engine for early Westwood games such as Command & Conquer: Red Alert written in C# using SDL and OpenGL. Runs on Windows, Linux, *BSD and Mac OS X.","fork":false,"url":"https://api.github.com/repos/OpenRA/OpenRA","forks_url":"https://api.github.com/repos/OpenRA/OpenRA/forks","keys_url":"https://api.github.com/repos/OpenRA/OpenRA/keys{/key_id}","collaborators_url":"https://api.github.com/repos/OpenRA/OpenRA/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/OpenRA/OpenRA/teams","hooks_url":"https://api.github.com/repos/OpenRA/OpenRA/hooks","issue_events_url":"https://api.github.com/repos/OpenRA/OpenRA/issues/events{/number}","events_url":"https://api.github.com/repos/OpenRA/OpenRA/events","assignees_url":"https://api.github.com/repos/OpenRA/OpenRA/assignees{/user}","branches_url":"https://api.github.com/repos/OpenRA/OpenRA/branches{/branch}","tags_url":"https://api.github.com/repos/OpenRA/OpenRA/tags","blobs_url":"https://api.github.com/repos/OpenRA/OpenRA/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/OpenRA/OpenRA/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/OpenRA/OpenRA/git/refs{/sha}","trees_url":"https://api.github.com/repos/OpenRA/OpenRA/git/trees{/sha}","statuses_url":"https://api.github.com/repos/OpenRA/OpenRA/statuses/{sha}","languages_url":"https://api.github.com/repos/OpenRA/OpenRA/languages","stargazers_url":"https://api.github.com/repos/OpenRA/OpenRA/stargazers","contributors_url":"https://api.github.com/repos/OpenRA/OpenRA/contributors","subscribers_url":"https://api.github.com/repos/OpenRA/OpenRA/subscribers","subscription_url":"https://api.github.com/repos/OpenRA/OpenRA/subscription","commits_url":"https://api.github.com/repos/OpenRA/OpenRA/commits{/sha}","git_commits_url":"https://api.github.com/repos/OpenRA/OpenRA/git/commits{/sha}","comments_url":"https://api.github.com/repos/OpenRA/OpenRA/comments{/number}","issue_comment_url":"https://api.github.com/repos/OpenRA/OpenRA/issues/comments{/number}","contents_url":"https://api.github.com/repos/OpenRA/OpenRA/contents/{+path}","compare_url":"https://api.github.com/repos/OpenRA/OpenRA/compare/{base}...{head}","merges_url":"https://api.github.com/repos/OpenRA/OpenRA/merges","archive_url":"https://api.github.com/repos/OpenRA/OpenRA/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/OpenRA/OpenRA/downloads","issues_url":"https://api.github.com/repos/OpenRA/OpenRA/issues{/number}","pulls_url":"https://api.github.com/repos/OpenRA/OpenRA/pulls{/number}","milestones_url":"https://api.github.com/repos/OpenRA/OpenRA/milestones{/number}","notifications_url":"https://api.github.com/repos/OpenRA/OpenRA/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/OpenRA/OpenRA/labels{/name}","releases_url":"https://api.github.com/repos/OpenRA/OpenRA/releases{/id}","deployments_url":"https://api.github.com/repos/OpenRA/OpenRA/deployments","created_at":"2010-10-04T07:38:05Z","updated_at":"2017-08-26T16:59:48Z","pushed_at":"2017-08-26T20:32:23Z","git_url":"git://github.com/OpenRA/OpenRA.git","ssh_url":"git@github.com:OpenRA/OpenRA.git","clone_url":"https://github.com/OpenRA/OpenRA.git","svn_url":"https://github.com/OpenRA/OpenRA","homepage":"http://www.openra.net","size":125084,"stargazers_count":4419,"watchers_count":4419,"language":"C#","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1382,"mirror_url":null,"open_issues_count":1296,"forks":1382,"open_issues":1296,"watchers":4419,"default_branch":"bleed"}},"_links":{"self":{"href":"https://api.github.com/repos/OpenRA/OpenRA/pulls/13719"},"html":{"href":"https://github.com/OpenRA/OpenRA/pull/13719"},"issue":{"href":"https://api.github.com/repos/OpenRA/OpenRA/issues/13719"},"comments":{"href":"https://api.github.com/repos/OpenRA/OpenRA/issues/13719/comments"},"review_comments":{"href":"https://api.github.com/repos/OpenRA/OpenRA/pulls/13719/comments"},"review_comment":{"href":"https://api.github.com/repos/OpenRA/OpenRA/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/OpenRA/OpenRA/pulls/13719/commits"},"statuses":{"href":"https://api.github.com/repos/OpenRA/OpenRA/statuses/788ab092916605e85b2b8c99a00352358965d581"}}}}
{"actor":{"display_login":"pchote"}}