{"action":"created","issue":{"url":"https://api.github.com/repos/TeamPorcupine/ProjectPorcupine/issues/75","repository_url":"https://api.github.com/repos/TeamPorcupine/ProjectPorcupine","labels_url":"https://api.github.com/repos/TeamPorcupine/ProjectPorcupine/issues/75/labels{/name}","comments_url":"https://api.github.com/repos/TeamPorcupine/ProjectPorcupine/issues/75/comments","events_url":"https://api.github.com/repos/TeamPorcupine/ProjectPorcupine/issues/75/events","html_url":"https://github.com/TeamPorcupine/ProjectPorcupine/issues/75","id":171697414,"number":75,"title":"Proposal for a new Job API","user":{"login":"lameox","id":13168856,"avatar_url":"https://avatars.githubusercontent.com/u/13168856?v=3","gravatar_id":"","url":"https://api.github.com/users/lameox","html_url":"https://github.com/lameox","followers_url":"https://api.github.com/users/lameox/followers","following_url":"https://api.github.com/users/lameox/following{/other_user}","gists_url":"https://api.github.com/users/lameox/gists{/gist_id}","starred_url":"https://api.github.com/users/lameox/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lameox/subscriptions","organizations_url":"https://api.github.com/users/lameox/orgs","repos_url":"https://api.github.com/users/lameox/repos","events_url":"https://api.github.com/users/lameox/events{/privacy}","received_events_url":"https://api.github.com/users/lameox/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":4,"created_at":"2016-08-17T16:07:45Z","updated_at":"2016-08-17T16:22:26Z","closed_at":null,"body":"# Proposal to rewrite parts of the Job API\r\n## Motivation\r\nWhile discussing the current codebase with other members of the community today we stumbled upon the current jobsystem many a time as a System that needed tweaking. Throughout the day we were discussing ways to improve on the current system, and it became increasingly clear, that the current system would need some work. We Proposed a partial rewrite in #63. This proposal is an attempt to write a more formal outline of what we think must be done, what should optionally be done and the reasons for doing so. It also describes a proposed Solution we should then talk about.\r\n\r\n## The Problems\r\n1. Only one global job queue. This leads to dirty hacks like local jobs for a character (fetching of materials) that never even hit the global queue and are difficult for a newcomer to understand.\r\n2. No division of jobs. a worker could have his friend move the materials in place and then just has to come up and build them, rather than doing the whole job himself\r\n3. No good way of doing priorities on a per-character level. This would allow for professions for characters, as well as designated workers.\r\n4. No easy way to compose new Jobs. Currently it is a whole mess of callbacks, subjobs, nested ifs and more.\r\n5. The scope/meaning of a job is too macroscopic. A simple \"Build\" job might entail several moves, pickups, works and more. This makes it difficult to reason about and debug.\r\n6. Jobs don't expose any real metadata, neither for UI nor programming purposes.\r\n7. No way to react to events. New jobs are only ever taken from the queue when an old one finishes.\r\n8. No way to reserve resources for a job, which might lead to resource contention.\r\n9. No good way to queue jobs from Lua and thus mods.\r\n\r\n## What must be done\r\n- [ ] Characters have their own job queue. When deciding on a job they look at the best candidate from their local and the global queue and decide on one\r\n- [ ] Jobs need to be divided into many smaller jobs. At the least the following should be separate Jobs:\r\n  - Moving\r\n  - Waiting\r\n  - Picking/Placing items\r\n  - Interacting with appropriate Objects (We suggest a new IInteractable interface)\r\n  - Deciding on a Followup Job\r\n\r\n This should make composing complex jobs easier.\r\n- [ ] Jobs need to be interruptible at any point. They should then be added back to the respecitve queue\r\n- [ ] Jobs need to  be taggable with metadata. We suggest an IMetadata Interface. This interface should also specify if the job can be executed out of order, concurrently and/or by a different character.\r\n- [ ] A extensible priority system needs to be in place. We suggest a global table of weighting functions a job can call against, based on a number of tags the job might posess in its metadata.\r\n\r\n## What should be done\r\nWe suggest a Linq - Like API based on the changes above, that makes composing jobs easy. This API should partly be exposed to Lua as well.\r\n\r\n### Needed Functions\r\nAll the below functions are just an initial proposal i came up with. I might not have thought about every use case we might want to cover so feel free to append to it.\r\n\r\n**Selectors**\r\nCallable On: Initial Method\r\nReturned Interface: IActorCollection \r\nThose select one or more characters that will be appropriate for the job. Selection should expose the following Selections:\r\n - GetNearestCharacter(Tile t) => selects the nearest character\r\n - GetNearestCharacters(Tile t, int count) => selects the \\<count\\> nearest characters\r\n - GetNearestCharacters(Tile t, float distance) => selects the nearest characters withind \\<distance\\>\r\n - GetAll(Profession p) => Selects all characters of profession p\r\n - GetAll(Predicate<IMetadata> selector) => Selects all characters where the passed predicate returns true.\r\n\r\n**Functions**\r\nCallable On: IActorCollection, IJobFunction\r\nReturned Interface: IJobFunction\r\nFunctions should be the main method of composing jobs. They are chainable and should allow for easy Syntax. The following are the proposed initial Functions:\r\n - MoveTo(Tile t) => The selected actor(s) move to this tile\r\n - MoveRelative(int deltaX, deltaY) => The selected actor(s) move relative to their current tile\r\n - PickUp (Item desiredItem, int desiredAmount) => The selected actor(s) try to pick up the provided item at their current location\r\n - PlaceDown(int desiredAmount) => The selected actor(s) place the desired amount of their currently held items on the floor at their current position\r\n - Interact() => The selected actor(s) call the IInteractable.Interact() method on the Tile in front of them, if possible\r\n - Build (Template t) => The selected actor(s) try to build the template at their current position. The required materials must be in place.\r\n - Repeat(int amount) => The selected actor(s) repeat all commands chained before this one \\<amount\\> times\r\n- RepeatUntil(Predicate<IMetadata> prdicate) => The selected actor(s) repeat all commands chained until \\<prdicate\\> returns true\r\n - Trigger (IEvent event) => The selected actor(s) trigger the provided event when they reach this function.\r\n\r\n**Triggers**\r\nCallable On: IJobFunction\r\nReturned Interface: ITriggeredAction => can be used to revoke an active.\r\nThey might react to events or just server as a final call to a composition. \r\n - OnEvent (IEvent event) => Triggers when the event occurs\r\n - OnTimer (int milliseconds) => Triggers cyclically after the amount of \\<milliseconds\\>\r\n - Queue () => Triggers instantly thus queueing the job\r\n\r\n**Modifiers**\r\nCallable On: ITriggeredAction\r\nReturned Interface: IJobDefinition\r\nThis allows us to tag a job with metadata. This is the function that will cause the actual queueing of the job. \r\n - WithMetadata(IMetadata meta) => Decorates the job with the appropriate metadata\r\n\r\n# Sample\r\nA sample snippet for the Proposed API would be\r\n```\r\nCharacter.NearestCharacter(trashcan).MoveTo(trashcan).PickUp(\"Trash\", -1).MoveTo(\"AirLock\").Drop(\"Trash\", -1).Interact().RepeatUntil(m => trashcan.IsEmpty).Queue().WithMetadata(meta)\r\n``` \r\nwhich would queue a job on the nearest character to jettison the trash from the trashcan.\r\n\r\n# Final Thoughts\r\nI think the proposed API would server really well for composing jobs on the Fly and especially from Lua code. It should also be intuitive for anyone that worked with Linq before and will also be really extensible.\r\nHowever this is a version 0.1 of the proposal that i just quickly typed down. Any feedback and criticism would be apprciated.\r\n\r\nRegards,\r\nJan"},"comment":{"url":"https://api.github.com/repos/TeamPorcupine/ProjectPorcupine/issues/comments/240466076","html_url":"https://github.com/TeamPorcupine/ProjectPorcupine/issues/75#issuecomment-240466076","issue_url":"https://api.github.com/repos/TeamPorcupine/ProjectPorcupine/issues/75","id":240466076,"user":{"login":"vogonistic","id":159568,"avatar_url":"https://avatars.githubusercontent.com/u/159568?v=3","gravatar_id":"","url":"https://api.github.com/users/vogonistic","html_url":"https://github.com/vogonistic","followers_url":"https://api.github.com/users/vogonistic/followers","following_url":"https://api.github.com/users/vogonistic/following{/other_user}","gists_url":"https://api.github.com/users/vogonistic/gists{/gist_id}","starred_url":"https://api.github.com/users/vogonistic/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vogonistic/subscriptions","organizations_url":"https://api.github.com/users/vogonistic/orgs","repos_url":"https://api.github.com/users/vogonistic/repos","events_url":"https://api.github.com/users/vogonistic/events{/privacy}","received_events_url":"https://api.github.com/users/vogonistic/received_events","type":"User","site_admin":false},"created_at":"2016-08-17T16:22:26Z","updated_at":"2016-08-17T16:22:26Z","body":"Ah. I didn't pay attention to the fact that the proposed solution was based entirely on interfaces."}}
{"actor":{"display_login":"vogonistic"}}