Fixed server failing to assign jobs to all clients on some modded servers: if the max amount of players per job had been reached on all the jobs the client has in their preferences, the client would not get a job at all (causing crashes later on when trying to access the client's job). Now the server assigns a random job if none of the preferred jobs are available.

+ Fix for exceptions in Client constructor if there are less than 3 job prefabs.
This commit is contained in:
Joonas Rikkonen
2017-08-01 19:46:24 +03:00
parent 7553d63a99
commit 1e11d5ab28
2 changed files with 47 additions and 26 deletions

View File

@@ -111,7 +111,7 @@ namespace Barotrauma.Networking
votes = new object[Enum.GetNames(typeof(VoteType)).Length];
jobPreferences = new List<JobPrefab>(JobPrefab.List.GetRange(0, 3));
jobPreferences = new List<JobPrefab>(JobPrefab.List.GetRange(0, Math.Min(JobPrefab.List.Count, 3)));
entityEventLastSent = new Dictionary<UInt16, float>();
}
@@ -135,7 +135,7 @@ namespace Barotrauma.Networking
name = name.Substring(0, 20);
}
string rName = "";
for (int i=0;i<name.Length;i++)
for (int i = 0; i < name.Length; i++)
{
if (name[i] < 32)
{

View File

@@ -1921,7 +1921,11 @@ namespace Barotrauma.Networking
{
unassigned = new List<Client>(unassigned);
int[] assignedClientCount = new int[JobPrefab.List.Count];
Dictionary<JobPrefab, int> assignedClientCount = new Dictionary<JobPrefab, int>();
foreach (JobPrefab jp in JobPrefab.List)
{
assignedClientCount.Add(jp, 0);
}
int teamID = 0;
if (unassigned.Count > 0) teamID = unassigned[0].TeamID;
@@ -1930,16 +1934,16 @@ namespace Barotrauma.Networking
{
if (characterInfo != null)
{
assignedClientCount[JobPrefab.List.FindIndex(jp => jp == GameMain.NetLobbyScreen.JobPreferences[0])] = 1;
assignedClientCount[GameMain.NetLobbyScreen.JobPreferences[0]] = 1;
}
else if (myCharacter != null && !myCharacter.IsDead)
{
assignedClientCount[JobPrefab.List.IndexOf(myCharacter.Info.Job.Prefab)] = 1;
assignedClientCount[myCharacter.Info.Job.Prefab] = 1;
}
}
else if (myCharacter != null && !myCharacter.IsDead && myCharacter.TeamID == teamID)
{
assignedClientCount[JobPrefab.List.IndexOf(myCharacter.Info.Job.Prefab)]++;
assignedClientCount[myCharacter.Info.Job.Prefab]++;
}
//count the clients who already have characters with an assigned job
@@ -1948,7 +1952,7 @@ namespace Barotrauma.Networking
if (c.TeamID != teamID || unassigned.Contains(c)) continue;
if (c.Character != null && !c.Character.IsDead)
{
assignedClientCount[JobPrefab.List.IndexOf(c.Character.Info.Job.Prefab)]++;
assignedClientCount[c.Character.Info.Job.Prefab]++;
}
}
@@ -1965,39 +1969,56 @@ namespace Barotrauma.Networking
while (unassignedJobsFound && unassigned.Count > 0)
{
unassignedJobsFound = false;
for (int i = 0; i < JobPrefab.List.Count; i++)
foreach (JobPrefab jobPrefab in JobPrefab.List)
{
if (unassigned.Count == 0) break;
if (JobPrefab.List[i].MinNumber < 1 || assignedClientCount[i] >= JobPrefab.List[i].MinNumber) continue;
if (jobPrefab.MinNumber < 1 || assignedClientCount[jobPrefab] >= jobPrefab.MinNumber) continue;
//find the client that wants the job the most, or force it to random client if none of them want it
Client assignedClient = FindClientWithJobPreference(unassigned, JobPrefab.List[i], true);
Client assignedClient = FindClientWithJobPreference(unassigned, jobPrefab, true);
assignedClient.assignedJob = JobPrefab.List[i];
assignedClientCount[i]++;
assignedClient.assignedJob = jobPrefab;
assignedClientCount[jobPrefab]++;
unassigned.Remove(assignedClient);
//the job still needs more crew members, set unassignedJobsFound to true to keep the while loop running
if (assignedClientCount[i] < JobPrefab.List[i].MinNumber) unassignedJobsFound = true;
if (assignedClientCount[jobPrefab] < jobPrefab.MinNumber) unassignedJobsFound = true;
}
}
//find a suitable job for the rest of the players
for (int i = unassigned.Count - 1; i >= 0; i--)
foreach (Client c in unassigned)
{
for (int preferenceIndex = 0; preferenceIndex < 3; preferenceIndex++)
foreach (JobPrefab preferredJob in c.jobPreferences)
{
int jobIndex = JobPrefab.List.FindIndex(jp => jp == unassigned[i].jobPreferences[preferenceIndex]);
//the maximum number of players that can have this job hasn't been reached yet
// -> assign it to the client
if (assignedClientCount[preferredJob] < preferredJob.MaxNumber)
{
c.assignedJob = preferredJob;
assignedClientCount[preferredJob]++;
break;
}
//none of the jobs the client prefers are available anymore
else if (preferredJob == c.jobPreferences.Last())
{
//find all jobs that are still available
var remainingJobs = JobPrefab.List.FindAll(jp => assignedClientCount[preferredJob] < jp.MaxNumber);
//if there's enough crew members assigned to the job already, continue
if (assignedClientCount[jobIndex] >= JobPrefab.List[jobIndex].MaxNumber) continue;
unassigned[i].assignedJob = JobPrefab.List[jobIndex];
assignedClientCount[jobIndex]++;
unassigned.RemoveAt(i);
break;
//all jobs taken, give a random job
if (remainingJobs.Count == 0)
{
DebugConsole.ThrowError("Failed to assign a suitable job for \"" + c.name + "\" (all jobs already have the maximum numbers of players). Assigning a random job...");
c.assignedJob = JobPrefab.List[Rand.Range(0, JobPrefab.List.Count)];
assignedClientCount[c.assignedJob]++;
}
else //some jobs still left, choose one of them by random
{
c.assignedJob = remainingJobs[Rand.Range(0, remainingJobs.Count)];
assignedClientCount[c.assignedJob]++;
}
}
}
}
}