{"action":"created","issue":{"url":"https://api.github.com/repos/OrderOfThePorcupine/ProjectPorcupine/issues/29","repository_url":"https://api.github.com/repos/OrderOfThePorcupine/ProjectPorcupine","labels_url":"https://api.github.com/repos/OrderOfThePorcupine/ProjectPorcupine/issues/29/labels{/name}","comments_url":"https://api.github.com/repos/OrderOfThePorcupine/ProjectPorcupine/issues/29/comments","events_url":"https://api.github.com/repos/OrderOfThePorcupine/ProjectPorcupine/issues/29/events","html_url":"https://github.com/OrderOfThePorcupine/ProjectPorcupine/issues/29","id":220941364,"number":29,"title":"New Job System","user":{"login":"BraedonWooding","id":22880786,"avatar_url":"https://avatars2.githubusercontent.com/u/22880786?v=3","gravatar_id":"","url":"https://api.github.com/users/BraedonWooding","html_url":"https://github.com/BraedonWooding","followers_url":"https://api.github.com/users/BraedonWooding/followers","following_url":"https://api.github.com/users/BraedonWooding/following{/other_user}","gists_url":"https://api.github.com/users/BraedonWooding/gists{/gist_id}","starred_url":"https://api.github.com/users/BraedonWooding/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/BraedonWooding/subscriptions","organizations_url":"https://api.github.com/users/BraedonWooding/orgs","repos_url":"https://api.github.com/users/BraedonWooding/repos","events_url":"https://api.github.com/users/BraedonWooding/events{/privacy}","received_events_url":"https://api.github.com/users/BraedonWooding/received_events","type":"User","site_admin":false},"labels":[{"id":581450269,"url":"https://api.github.com/repos/OrderOfThePorcupine/ProjectPorcupine/labels/discussion","name":"discussion","color":"e99695","default":false},{"id":581075342,"url":"https://api.github.com/repos/OrderOfThePorcupine/ProjectPorcupine/labels/enhancement","name":"enhancement","color":"84b6eb","default":true},{"id":581492639,"url":"https://api.github.com/repos/OrderOfThePorcupine/ProjectPorcupine/labels/imported","name":"imported","color":"ededed","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":{"url":"https://api.github.com/repos/OrderOfThePorcupine/ProjectPorcupine/milestones/1","html_url":"https://github.com/OrderOfThePorcupine/ProjectPorcupine/milestone/1","labels_url":"https://api.github.com/repos/OrderOfThePorcupine/ProjectPorcupine/milestones/1/labels","id":2449771,"number":1,"title":"Version 0.3","description":"See #1746","creator":{"login":"BraedonWooding","id":22880786,"avatar_url":"https://avatars2.githubusercontent.com/u/22880786?v=3","gravatar_id":"","url":"https://api.github.com/users/BraedonWooding","html_url":"https://github.com/BraedonWooding","followers_url":"https://api.github.com/users/BraedonWooding/followers","following_url":"https://api.github.com/users/BraedonWooding/following{/other_user}","gists_url":"https://api.github.com/users/BraedonWooding/gists{/gist_id}","starred_url":"https://api.github.com/users/BraedonWooding/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/BraedonWooding/subscriptions","organizations_url":"https://api.github.com/users/BraedonWooding/orgs","repos_url":"https://api.github.com/users/BraedonWooding/repos","events_url":"https://api.github.com/users/BraedonWooding/events{/privacy}","received_events_url":"https://api.github.com/users/BraedonWooding/received_events","type":"User","site_admin":false},"open_issues":7,"closed_issues":2,"state":"open","created_at":"2017-04-11T11:31:05Z","updated_at":"2017-04-11T12:52:26Z","due_on":null,"closed_at":null},"comments":0,"created_at":"2017-04-11T12:52:26Z","updated_at":"2017-04-11T12:52:32Z","closed_at":null,"body":"<a href=\"https://github.com/BraedonWooding\"><img src=\"https://avatars2.githubusercontent.com/u/22880786?v=3\" align=\"left\" width=\"96\" height=\"96\" hspace=\"10\"></img></a> **Issue by [BraedonWooding](https://github.com/BraedonWooding)**\n_Sunday Oct 30, 2016 at 08:16 GMT # Sample: Friday Sep 13, 2013 at 22:58 GMT_\n_Originally opened as https://github.com/TeamPorcupine/ProjectPorcupine/issues/1590_\n\n----\n\n# Outline\n- Why \n  - Job system is broken\n  - Better sooner than later\n- Initial Progress\n  - Data structures\n- The core implementation\n  - Heavily interfaced for modability/modularity\n  - Manager that designates tasks\n  - Characters get lists of tasks to get done (based upon a simple time algorithm)\n    - After x time (or when character's finish their tasks) they get new lists\n  - Manager is heavily threaded and completely modulated\n    - Private singleton with static add (like my Dev Console implementation)\n- Feedback\n  - (Table) Question | Current answer to question | Community accepted answer\n- Progress \n  - Checklist before I create a testable PR\n## Why?\n\nOkay so essentially the Job System is broken, it really needs a full re-write; and well I'm trying to do it so it'll be so perfect it'll never need another re-write/cleanup (aim for the moon so you land among the stars).  \n\nI know this is going to be a pain for other PRs, but the longer we wait on this the worse it'll get, so I'm pulling the band-aid off (so to speak).\n\nAlso I'm not going to create a PR till its testable (there will be a checklist at the end to indicate progress before PR).  Also this issue took like 2 solid hours to build so be kind if like typos or doesn't fit format or whatever 😩.\n## Initial Progress\n\nSo I'm already working on the system (super early work just getting class structures in place) and I'm building this issue so we can decide on direction and little things as well as big things.\n\nAlso I'm suffixing most classes with \"**\" just so I don't have weird conflicts (like two Job classes) and I can slowly move parts across, then i'll do a find and replace (like replace \"Job**\" with \"Job\") the double underscore makes sure that it isn't including xml or json or any text / property (which can use sometimes a single underscore).\n## The core implementation\n### Why Interfaces and Abstract classes?\n\nI'm addicted to interfaces and abstract classes (a little too much perhaps), but I think it fits this situation perfectly; below I'll place a few pictures of my proposed interface hierarchy for the Job System.  \n\n**NOTE: The layers represent inheritance (the program broke and I couldn't draw the lines), all jobs inherit from the interface above them AND BaseJob**\n![untitled](https://cloud.githubusercontent.com/assets/22880786/19840220/763f3070-9f45-11e6-9842-11d196ecc86c.png)\n\nNow as you can see it's quite extensive and VERY powerful (you could move the current state system (or other systems) to using these exact interfaces if you wanted to), so this opens up the modability a ton!  So basically interfaces and abstract classes require good structure (so no re-write in future) and open doors fully to modability and nice polymorphism (casting down/up from x to y).\n### JobManager\n\nEssentially what we are doing is building a manager that manages (lol) the current jobs by assigning specific task lists to characters based upon proximity (a radius from a tile based upon that character's current list of jobs), and preference.  \n#### Now why is this important?\n\nSpeed is the main reason, we can thread these processes and essentially do some early pathfinding to speed up the actual pathfinding (like using @koosemose current room pathfinding where it locates room -> room), then when the character gets the task it already knows what rooms it needs to pass and then can just do a finer optimised path (doesn't even need to find the most optimal just within 95% of the optimal path - one square slower for every 20).\n### Priorities\n\nThe priority system is number based, but to also have critical priorities and based off how normally managers work I have decided to implement it so the only value that matters is the absolute value of the number (its distance from zero), with a negative number indicating that the job list should be rebuilt for the character that should get that negative number.  Now this is so that 1/-1 is the highest priority, 2 being the second highest, 3 being the third highest (and 0 being just add it to the end or where-ever), if you add a job of priority 2 for example, the next time the job manager is giving a list of jobs to the character it will put the job second (well like not 'second' cause there may be multiple priority one jobs but essentially after all the priority one jobs, also if there are multiple second priority jobs then which one goes where is entirely dependent on the list creation and there is **no** way to say 1.5 or 1.9 for example.  However if you put -2 then after it calculates the most optimal character to do that job (or if you specify a character) it will grab that character and say refresh your list, the character will be given a new list of jobs with -2 being placed second in that list (with the same rules as if it was just normal 2, except it will be placed before all other second priority jobs).\n\nIf you have any questions about this (or anything at all) just pop it below, if there is still conjuncture (no definite answer) then it'll be put in the question table :D.\n### Modding\n\nNow we have some standard job 'types' (classes) that will be used mainly (stuff like haul, build object, build furniture, operate, produce object, perform on furniture/tile) but these can be subclasses for functionality, as well as whole new types can be built (stuff like a hunt job could be super easy to implement) this means that later on someone could build whole new jobs (as long as they use the interfaces provided with the game).\n## Feedback/Questions\n\n_I'll populate this as questions pop up but I've got a few to start with_\n\n| Question | Current answer to question | Community Accepted Answer |\n| --- | --- | --- |\n| How could/would 'needs' be implemented with said system? | You should never use jobs to figure out what to do, a job is saying go do this.  So with needs what you could do is let's say you have a sleep need, so the sleep need is at 20 for Bob (with 0 being that you need sleep or dead) so you could say hey JobManager add a job (sleepyJob) with priority 2, with a preference of 0 to Bob (0 meaning that only Bob can have that job); this means that the next time JobManager delegates jobs out to people make this the second highest priority job for Bob!  But now the sleep need is at 10 (due to Bob having priority 1 jobs), so you could say okay JobManager change job of type (sleepyJob) for Bob to being priority 1 (you can either pass a reference to that job or you can specify a character, or say change every job that matches this type), now this doesn't refresh Bob's list (because it's still a positive number), so Bob still doesn't get any sleep.  Now his need is at 0 so he needs sleep right now, so you set sleepyJob to -1, which means interrupt Bob's current list and pass him a new list with sleepyJob being priority 1 (the highest priority, and since you are passing an interrupting priority - negative - then it will also make sure sleepyJob is the first 1 priority). | No accepted answer yet. |\n| Batch Jobs as a flag or a job class | Now as the manager plans out jobs it could either detect one of two ways (both valid), first is that it detects a job as being a batch job (a flag that all jobs have) and then it searches for nearby jobs, so any object that COULD be batch has this flag turned on, it just does a quick proximity search (maybe max of 5/7 squares 2 dimensionally) then if similar jobs exist (same type of job or same job or whatever) it then will bunch them together in a new job type that is evaluated as a single job that is passed to a character without refreshing (unless an interruption occurs).  The other way is that the build manager in this case would pass this new job type?  Well you could do it both ways??? | No accepted answer yet. |\n| How jobs are handled/updated | The old job system implementation has functions (for LUA and C#) that it calls on start/update/pause... My suggestion is having handlers that get given a IJob (base interface) with a work modifier and handle the updating, now if you wanted an UI updater than you would create an handler and then subscribe to the job's UI Update handler (every half second??).  This way you would have generic handlers for Jobs and if you wanted to override it you will have to subclass that Job class but in most cases you won't need to override it at all?  Or we could use the old job system implementation | No accepted answer yet. |\n| How should the preference system be implemented | A weighting system of sorts (a 10 in construction may be lower than being right next to it with all the materials). | No accepted answer yet. |\n| (@Geoffrotism) Don't all jobs require a tile?  Shouldn't IJobTile be part of IJob | The current system is that a Job may 'regard a tile' or may 'regard a furniture' and so on, but the idea of having all jobs 'regard a tile' and some also 'regard a furniture' is also a possibility | No accepted answer yet. |\n| (@NogginBops @dusho) How should inheritance work?  Two ways either a interface based approach, or a generalised approach | Generalised imo (and using the previous job system as an example) in most situations is bad, you're making presumptions on how things will work in the future and what features will be added (which even if you know 100% what's going to happen can be bad for modding), which means in an open source project we need to make sure that our code lasts a long time before it needs to be re-written to allow for more functionality (otherwise every year it's just rewriting the same old stuff to allow for new stuff and you get completely unreadable hunks of mess classes like the current Job class - took me a solid hour or two just to read the 100s of functions), so it's clear we need some kind of inheritance based approach, I personally like interfaces but that's mainly because I'm using them a lot in my work, and other places so I'm a little biased. |  |\n## Progress before PR can be made/tested\n- [ ] Decide on names and hierarchy\n- [ ] Create constructors and implement How Jobs are handled/updated\n- [ ] Create base and generic job classes\n- [ ] Stylecop ( doing stylecop three times so we don't end up with like 5000 violations ).\n- [ ] Implement a core Job Manager that just can create jobs\n- [ ] Implement a core Job Manager that can delegate tasks (print result and speed but doesn't assign)\n- [ ] If speed (of above) is acceptable then make the Job Manager give tasks to 'units' or whoever.\n- [ ] Units preferences based upon proximity \n- [ ] Implement units to cancel jobs (and ask for new ones) and timer to auto cancel jobs\n- [ ] Stylecop ( doing stylecop three times so we don't end up with like 5000 violations ).\n\n--- This is far enough for testing to happen (PR request made).\n## Progress till finished\n- [ ] Implement XML/JSON for jobs\n- [ ] Implement saving\n- [ ] Implement some stronger modding (allow LUA/C# to create job types)\n- [ ] Cleanup, stylecop ( doing stylecop three times so we don't end up with like 5000 violations ).\n## Inheritance!!!\n\nOkay so I thought I really need to add a quick section here talking about the inheritance of the job system.\n\nOkay so i've tiered it, \n1) tier one is what we call the baseJob it doesn't inherit from anything and essentially acts as the old IJob & IJobPriority rolled into one small class.  \n2) Then we have our generic classes which will then have specialised classes as the third tier.  This way you may have multiple produceJobs that have different logic (maybe one takes in multiple inputs for multiple outputs and so on).\n\n"},"comment":{"url":"https://api.github.com/repos/OrderOfThePorcupine/ProjectPorcupine/issues/comments/293250364","html_url":"https://github.com/OrderOfThePorcupine/ProjectPorcupine/issues/29#issuecomment-293250364","issue_url":"https://api.github.com/repos/OrderOfThePorcupine/ProjectPorcupine/issues/29","id":293250364,"user":{"login":"BraedonWooding","id":22880786,"avatar_url":"https://avatars2.githubusercontent.com/u/22880786?v=3","gravatar_id":"","url":"https://api.github.com/users/BraedonWooding","html_url":"https://github.com/BraedonWooding","followers_url":"https://api.github.com/users/BraedonWooding/followers","following_url":"https://api.github.com/users/BraedonWooding/following{/other_user}","gists_url":"https://api.github.com/users/BraedonWooding/gists{/gist_id}","starred_url":"https://api.github.com/users/BraedonWooding/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/BraedonWooding/subscriptions","organizations_url":"https://api.github.com/users/BraedonWooding/orgs","repos_url":"https://api.github.com/users/BraedonWooding/repos","events_url":"https://api.github.com/users/BraedonWooding/events{/privacy}","received_events_url":"https://api.github.com/users/BraedonWooding/received_events","type":"User","site_admin":false},"created_at":"2017-04-11T12:52:32Z","updated_at":"2017-04-11T12:52:32Z","body":"<a href=\"https://github.com/Geoffrotism\"><img src=\"https://avatars3.githubusercontent.com/u/5430964?v=3\" align=\"left\" width=\"48\" height=\"48\" hspace=\"10\"></img></a> **Comment by [Geoffrotism](https://github.com/Geoffrotism)**\n_Sunday Oct 30, 2016 at 08:47 GMT # Sample: Friday Sep 13, 2013 at 22:58 GMT_\n\n----\n\nthe only thing i can think of immediately is the priorities. and this starts getting out there, but how do we want to do them. I know the numbers on priorities could be changed easily, but just in general. How much micromanaging do we want our user to be allowed to have? I think the system from Rimworld is perfect for us but would require just bit more sorting on job assigning.  This would mean just a bit more sorting when the job list is created but would add more micro for the user if they so wish. Need to make the default intuitive so that users not wanting to micro that much wont get ruined.\n\n"}}
{"actor":{"display_login":"BraedonWooding"}}