Files
vgstation13/code/game/jobs/job_controller.dm
sieve32@gmail.com 7bf6788082 -OPTIMIZATION TIME
-Almost every instance of 'for(mob in world)' has been killed. Because GODDAMN was it being run a bunch. Instead, a series of global lists have been made, and they are all handled auto-magically through New()'s, Del()'s, Login()'s, death()'s, etc...

Lists are as follows:
-mob_list : Contains all atom/mobs by ref
-player_list : Like mob_list, but only contains mobs with clients attached
-admin_list : Like player_list, but holds all mobs with clients attached and admin status
-living_mob_list : Contains all mobs that ARE alive, regardless of client status
-dead_mob_list : Contains all mobs that are dead, which comes down to corpses and ghosts
-cable_list : A list containing every obj/structure/cable in existence
Note: There is an object (/obj/item/debuglist) that you can use to check the contents of each of the lists except for cables (Since getting a message saying "a cable," x9001 isn't very helpful)

These lists have been tested as much as I could on my own, and have been mostly implemented. There are still places where they could be used, but for now it's important that the core is working. If this all checks out I would really like to implement it into the MC as well, simply so it doesn't check call Life() on every mob by checking for all the ones in world every damn tick.

Just testing locally I was able to notice improvements with certain aspects, like admin verbs being MUCH more responsive (They checked for every mob in the world every time they were clicked), many sources of needless lag were cut out (Like Adminwho and Who checking every single mob when clicked), and due to the cable_list powernet rebuilding is MUCH more efficient, because instead of checking for every cable in the world every time a powernet was broken (read: A cable was deleted), it runs though the pre-made list, and even with a singulo tearing all the way across the station, the powernet load was VERY small compared to pretty much everything else.

If you want to know how any of this works, check global_lists.dm, there I have it rigorously commented, and it should provide an understanding of what's going on.

Mob related in worlds before this commit: 1262
After: 4
I'm helping


git-svn-id: http://tgstation13.googlecode.com/svn/trunk@4179 316c924e-a436-60f5-8080-3fe189b3f50e
2012-07-26 03:04:05 +00:00

434 lines
13 KiB
Plaintext

//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31
var/global/datum/controller/occupations/job_master
/datum/controller/occupations
//List of all jobs
var/list/occupations = list()
//Players who need jobs
var/list/unassigned = list()
//Debug info
var/list/job_debug = list()
New()
spawn(1)
SetupOccupations()
return
proc/SetupOccupations(var/faction = "Station")
occupations = list()
var/list/all_jobs = typesof(/datum/job)
if(!all_jobs.len)
world << "\red \b Error setting up jobs, no job datums found"
return 0
for(var/J in all_jobs)
var/datum/job/job = new J()
if(!job) continue
if(job.faction != faction) continue
occupations += job
return 1
proc/Debug(var/text)
if(!Debug2) return 0
job_debug.Add(text)
return 1
proc/GetJob(var/rank)
if(!rank) return null
for(var/datum/job/J in occupations)
if(!J) continue
if(J.title == rank) return J
return null
proc/AssignRole(var/mob/new_player/player, var/rank, var/latejoin = 0)
Debug("Running AR, Player: [player], Rank: [rank], LJ: [latejoin]")
if((player) && (player.mind) && (rank))
var/datum/job/job = GetJob(rank)
if(!job) return 0
if(jobban_isbanned(player, rank)) return 0
var/position_limit = job.total_positions
if(!latejoin)
position_limit = job.spawn_positions
if((job.current_positions < position_limit) || position_limit == -1)
Debug("Player: [player] is now Rank: [rank], JCP:[job.current_positions], JPL:[position_limit]")
player.mind.assigned_role = rank
unassigned -= player
job.current_positions++
return 1
Debug("AR has failed, Player: [player], Rank: [rank]")
return 0
proc/FindOccupationCandidates(datum/job/job, level, flag)
Debug("Running FOC, Job: [job], Level: [level], Flag: [flag]")
var/list/candidates = list()
for(var/mob/new_player/player in unassigned)
if(jobban_isbanned(player, job.title))
Debug("FOC isbanned failed, Player: [player]")
continue
if(flag && (!player.preferences.be_special & flag))
Debug("FOC flag failed, Player: [player], Flag: [flag], ")
continue
if(player.preferences.GetJobDepartment(job, level) & job.flag)
Debug("FOC pass, Player: [player], Level:[level]")
candidates += player
return candidates
proc/GiveRandomJob(var/mob/new_player/player)
Debug("FOC Giving random job, Player: [player]")
for(var/datum/job/job in shuffle(occupations))
if(!job)
continue
if(istype(job, GetJob("Assistant"))) // We don't want to give him assistant, that's boring!
continue
if(job in command_positions) //If you want a command position, select it!
continue
if(jobban_isbanned(player, job.title))
Debug("FOC isbanned failed, Player: [player], Job: [job.title]")
continue
if((job.current_positions < job.spawn_positions) || job.spawn_positions == -1)
Debug("FOC Random job given, Player: [player], Job: [job]")
AssignRole(player, job.title)
unassigned -= player
break
proc/ResetOccupations()
for(var/mob/new_player/player in player_list)
if((player) && (player.mind))
player.mind.assigned_role = null
player.mind.special_role = null
SetupOccupations()
unassigned = list()
return
proc/FillHeadPosition()
for(var/level = 1 to 3)
for(var/command_position in command_positions)
var/datum/job/job = GetJob(command_position)
if(!job) continue
var/list/candidates = FindOccupationCandidates(job, level)
if(!candidates.len) continue
var/mob/new_player/candidate = pick(candidates)
if(AssignRole(candidate, command_position))
return 1
return 0
proc/FillAIPosition()
var/ai_selected = 0
var/datum/job/job = GetJob("AI")
if(!job) return 0
if((job.title == "AI") && (config) && (!config.allow_ai)) return 0
for(var/i = job.total_positions, i > 0, i--)
for(var/level = 1 to 3)
var/list/candidates = list()
if(ticker.mode.name == "AI malfunction")//Make sure they want to malf if its malf
candidates = FindOccupationCandidates(job, level, BE_MALF)
else
candidates = FindOccupationCandidates(job, level)
if(candidates.len)
var/mob/new_player/candidate = pick(candidates)
if(AssignRole(candidate, "AI"))
ai_selected++
break
//Malf NEEDS an AI so force one if we didn't get a player who wanted it
if((ticker.mode.name == "AI malfunction")&&(!ai_selected))
unassigned = shuffle(unassigned)
for(var/mob/new_player/player in unassigned)
if(jobban_isbanned(player, "AI")) continue
if(AssignRole(player, "AI"))
ai_selected++
break
if(ai_selected) return 1
return 0
/** Proc DivideOccupations
* fills var "assigned_role" for all ready players.
* This proc must not have any side effect besides of modifying "assigned_role".
**/
proc/DivideOccupations()
//Setup new player list and get the jobs list
Debug("Running DO")
SetupOccupations()
//Holder for Triumvirate is stored in the ticker, this just processes it
if(ticker)
for(var/datum/job/ai/A in occupations)
if(ticker.triai)
A.spawn_positions = 3
//Get the players who are ready
for(var/mob/new_player/player in player_list)
if((player) && (player.client) && (player.ready) && (player.mind) && (!player.mind.assigned_role))
unassigned += player
Debug("DO, Len: [unassigned.len]")
if(unassigned.len == 0) return 0
//Shuffle players and jobs
unassigned = shuffle(unassigned)
HandleFeedbackGathering()
//People who wants to be assistants, sure, go on.
Debug("DO, Running Assistant Check 1")
var/datum/job/assist = new /datum/job/assistant()
var/list/assistant_candidates = FindOccupationCandidates(assist, 3)
Debug("AC1, Candidates: [assistant_candidates.len]")
for(var/mob/new_player/player in assistant_candidates)
Debug("AC1 pass, Player: [player]")
AssignRole(player, "Assistant")
assistant_candidates -= player
Debug("DO, AC1 end")
//Select one head
Debug("DO, Running Head Check")
FillHeadPosition()
Debug("DO, Head Check end")
//Check for an AI
Debug("DO, Running AI Check")
FillAIPosition()
Debug("DO, AI Check end")
//Other jobs are now checked
Debug("DO, Running Standard Check")
// New job giving system by Donkie
// This will cause lots of more loops, but since it's only done once it shouldn't really matter much at all.
// Hopefully this will add more randomness and fairness to job giving.
// Loop through all levels from high to low
var/list/shuffledoccupations = shuffle(occupations)
for(var/level = 1 to 3)
// Loop through all unassigned players
for(var/mob/new_player/player in unassigned)
// Loop through all jobs
for(var/datum/job/job in shuffledoccupations) // SHUFFLE ME BABY
if(!job)
continue
if(jobban_isbanned(player, job.title))
Debug("FOC isbanned failed, Player: [player], Job:[job.title]")
continue
// If the player wants that job on this level, then try give it to him.
if(player.preferences.GetJobDepartment(job, level) & job.flag)
// If the job isn't filled
if((job.current_positions < job.spawn_positions) || job.spawn_positions == -1)
Debug("FOC pass, Player: [player], Level:[level], Job:[job.title]")
AssignRole(player, job.title)
unassigned -= player
break
// Hand out random jobs to the people who didn't get any in the last check
// Also makes sure that they got their preference correct
for(var/mob/new_player/player in unassigned)
if(player.preferences.userandomjob)
GiveRandomJob(player)
/*
Old job system
for(var/level = 1 to 3)
for(var/datum/job/job in occupations)
Debug("Checking job: [job]")
if(!job)
continue
if(!unassigned.len)
break
if((job.current_positions >= job.spawn_positions) && job.spawn_positions != -1)
continue
var/list/candidates = FindOccupationCandidates(job, level)
while(candidates.len && ((job.current_positions < job.spawn_positions) || job.spawn_positions == -1))
var/mob/new_player/candidate = pick(candidates)
Debug("Selcted: [candidate], for: [job.title]")
AssignRole(candidate, job.title)
candidates -= candidate*/
Debug("DO, Standard Check end")
Debug("DO, Running AC2")
// For those who wanted to be assistant if their preferences were filled, here you go.
for(var/mob/new_player/player in unassigned)
Debug("AC2 Assistant located, Player: [player]")
AssignRole(player, "Assistant")
return 1
proc/EquipRank(var/mob/living/carbon/human/H, var/rank, var/joined_late = 0)
if(!H) return 0
var/datum/job/job = GetJob(rank)
if(job)
job.equip(H)
else
H << "Your job is [rank] and the game just can't handle it! Please report this bug to an administrator."
spawnId(H,rank)
H << "<B>You are the [rank].</B>"
H << "<b>As the [rank] you answer directly to [job.supervisors]. Special circumstances may change this.</b>"
H.job = rank
if(H.mind)
H.mind.assigned_role = rank
if(!joined_late)
var/obj/S = null
for(var/obj/effect/landmark/start/sloc in world)
if(sloc.name != rank) continue
if(locate(/mob/living) in sloc.loc) continue
S = sloc
break
if(!S)
S = locate("start*[rank]") // use old stype
if(istype(S, /obj/effect/landmark/start) && istype(S.loc, /turf))
H.loc = S.loc
if(H.mind && H.mind.assigned_role == "Cyborg")//This could likely be done somewhere else
H.Robotize()
return 1
H.equip_if_possible(new /obj/item/device/radio/headset(H), H.slot_ears)
if(H.mind && H.mind.assigned_role != "Cyborg" && H.mind.assigned_role != "AI" && H.mind.assigned_role != "Clown")
if(H.backbag == 1) //Clown always gets his backbuddy.
H.equip_if_possible(new /obj/item/weapon/storage/box/survival(H), H.slot_r_hand)
if(H.backbag == 2)
var/obj/item/weapon/storage/backpack/BPK = new/obj/item/weapon/storage/backpack(H)
new /obj/item/weapon/storage/box/survival(BPK)
H.equip_if_possible(BPK, H.slot_back,1)
if(H.backbag == 3)
var/obj/item/weapon/storage/backpack/BPK = new/obj/item/weapon/storage/backpack/satchel_norm(H)
new /obj/item/weapon/storage/box/survival(BPK)
H.equip_if_possible(BPK, H.slot_back,1)
H.regenerate_icons()
return 1
proc/spawnId(var/mob/living/carbon/human/H, rank)
if(!H) return 0
var/obj/item/weapon/card/id/C = null
var/datum/job/job = null
for(var/datum/job/J in occupations)
if(J.title == rank)
job = J
break
if(job)
if(job.title == "Cyborg")
return
else
C = new job.idtype(H)
else
C = new /obj/item/weapon/card/id(H)
if(C)
C.registered_name = H.real_name
C.assignment = rank
C.name = "[C.registered_name]'s ID Card ([C.assignment])"
C.access = get_access(C.assignment)
H.equip_if_possible(C, H.slot_wear_id)
if(prob(50))
H.equip_if_possible(new /obj/item/weapon/pen(H), H.slot_r_store)
else
H.equip_if_possible(new /obj/item/weapon/pen/blue(H), H.slot_r_store)
H.equip_if_possible(new /obj/item/device/pda(H), H.slot_belt)
if(locate(/obj/item/device/pda,H))//I bet this could just use locate. It can --SkyMarshal
var/obj/item/device/pda/pda = locate(/obj/item/device/pda,H)
pda.owner = H.real_name
pda.ownjob = H.wear_id.assignment
pda.name = "PDA-[H.real_name] ([pda.ownjob])"
if(rank == "Clown")
spawn(1)
clname(H)
return 1
proc/LoadJobs(jobsfile) //ran during round setup, reads info from jobs.txt -- Urist
if(!config.load_jobs_from_txt)
return 0
var/text = file2text(jobsfile)
if(!text)
world << "No jobs.txt found, using defaults."
return
var/list/jobEntries = dd_text2list(text, "\n")
for(var/job in jobEntries)
if(!job)
continue
job = trim(job)
if (!length(job))
continue
var/pos = findtext(job, "=")
var/name = null
var/value = null
if(pos)
name = copytext(job, 1, pos)
value = copytext(job, pos + 1)
else
continue
if(name && value)
var/datum/job/J = GetJob(name)
if(!J) continue
J.total_positions = text2num(value)
J.spawn_positions = text2num(value)
if(name == "AI" || name == "Cyborg")//I dont like this here but it will do for now
J.total_positions = 0
return 1
proc/HandleFeedbackGathering()
for(var/datum/job/job in occupations)
var/tmp_str = "|[job.title]|"
var/level1 = 0 //high
var/level2 = 0 //medium
var/level3 = 0 //low
var/level4 = 0 //never
var/level5 = 0 //banned
for(var/mob/new_player/player in player_list)
if(!((player) && (player.client) && (player.ready) && (player.mind) && (!player.mind.assigned_role)))
continue //This player is not ready
if(jobban_isbanned(player, job.title))
level5++
continue
if(player.preferences.GetJobDepartment(job, 1) & job.flag)
level1++
else if(player.preferences.GetJobDepartment(job, 2) & job.flag)
level2++
else if(player.preferences.GetJobDepartment(job, 3) & job.flag)
level3++
else level4++ //not selected
tmp_str += "HIGH=[level1]|MEDIUM=[level2]|LOW=[level3]|NEVER=[level4]|BANNED=[level5]|-"
feedback_add_details("job_preferences",tmp_str)