new idea for player order pref

This commit is contained in:
Tim Felgentreff 2022-03-07 22:45:36 +01:00
parent e265b6cdda
commit a00db769c6
4 changed files with 102 additions and 39 deletions

View file

@ -65,6 +65,7 @@ public:
uint32_t Host; /// Host address
uint16_t Port; /// Port on host
uint16_t PlyNr; /// Player number
int16_t PlayerIndex; /// Desired player index in game, or -1 for default
char PlyName[NetPlayerNameSize]; /// Name of player
};

View file

@ -224,6 +224,7 @@ void CNetworkHost::Clear()
this->Host = 0;
this->Port = 0;
this->PlyNr = 0;
this->PlayerIndex = -1;
memset(this->PlyName, 0, sizeof(this->PlyName));
}

View file

@ -37,6 +37,10 @@
#include <fstream>
#include <set>
#include <vector>
#include <functional>
#include <algorithm>
#include <array>
#include <utility>
#if __has_include(<filesystem>)
#include <filesystem>
namespace fs = std::filesystem;
@ -1720,29 +1724,29 @@ void NetworkServerStartGame()
LocalSetupState = ServerSetupState;
// Make a list of the available player slots.
int num[PlayerMax];
int rev[PlayerMax];
int h = 0;
int humanPlayerIndexToMapPlayerIndex[PlayerMax];
int mapPlayerIndexToHumanPlayerIndexAndBeyond[PlayerMax];
int humanPlayerCount = 0;
for (int i = 0; i < PlayerMax; ++i) {
if (Map.Info.PlayerType[i] == PlayerTypes::PlayerPerson) {
rev[i] = h;
num[h++] = i;
DebugPrint("Slot %d is available for an interactive player (%d)\n" _C_ i _C_ rev[i]);
mapPlayerIndexToHumanPlayerIndexAndBeyond[i] = humanPlayerCount;
humanPlayerIndexToMapPlayerIndex[humanPlayerCount++] = i;
DebugPrint("Slot %d is available for an interactive player (%d)\n" _C_ i _C_ mapPlayerIndexToHumanPlayerIndexAndBeyond[i]);
}
}
// Make a list of the available computer slots.
int n = h;
int n = humanPlayerCount;
for (int i = 0; i < PlayerMax; ++i) {
if (Map.Info.PlayerType[i] == PlayerTypes::PlayerComputer) {
rev[i] = n++;
DebugPrint("Slot %d is available for an ai computer player (%d)\n" _C_ i _C_ rev[i]);
mapPlayerIndexToHumanPlayerIndexAndBeyond[i] = n++;
DebugPrint("Slot %d is available for an ai computer player (%d)\n" _C_ i _C_ mapPlayerIndexToHumanPlayerIndexAndBeyond[i]);
}
}
// Make a list of the remaining slots.
for (int i = 0; i < PlayerMax; ++i) {
if (Map.Info.PlayerType[i] != PlayerTypes::PlayerPerson
&& Map.Info.PlayerType[i] != PlayerTypes::PlayerComputer) {
rev[i] = n++;
mapPlayerIndexToHumanPlayerIndexAndBeyond[i] = n++;
// PlayerTypes::PlayerNobody - not available to anything..
}
}
@ -1757,25 +1761,27 @@ void NetworkServerStartGame()
printf("\n");
}
int org[PlayerMax];
int slotIndexToMapPlayerIndex[PlayerMax];
// Reverse to assign slots to menu setup state positions.
for (int i = 0; i < PlayerMax; ++i) {
org[i] = -1;
slotIndexToMapPlayerIndex[i] = -1;
for (int j = 0; j < PlayerMax; ++j) {
if (rev[j] == i) {
org[i] = j;
if (mapPlayerIndexToHumanPlayerIndexAndBeyond[j] == i) {
slotIndexToMapPlayerIndex[i] = j;
break;
}
}
}
// Calculate NetPlayers
NetPlayers = h;
NetPlayers = humanPlayerCount;
int compPlayers = ServerSetupState.ServerGameSettings.Opponents;
for (int i = 1; i < h; ++i) {
for (int i = 1; i < humanPlayerCount; ++i) {
if (Hosts[i].PlyNr == 0 && ServerSetupState.CompOpt[i] != SlotOption::Available) {
// no host connectd and the slot is not available, not a net player
NetPlayers--;
} else if (Hosts[i].PlyName[0] == 0) {
// the slot is available, but no host connected to it
NetPlayers--;
if (--compPlayers >= 0) {
// Unused slot gets a computer player
@ -1789,8 +1795,9 @@ void NetworkServerStartGame()
}
// Compact host list.. (account for computer/closed slots in the middle..)
for (int i = 1; i < h; ++i) {
for (int i = 1; i < humanPlayerCount; ++i) {
if (Hosts[i].PlyNr == 0) {
// this host is not connected, so we can move some later host down
int j;
for (j = i + 1; j < PlayerMax - 1; ++j) {
if (Hosts[j].PlyNr) {
@ -1802,6 +1809,7 @@ void NetworkServerStartGame()
break;
}
}
// early return, in case there are no more hosts later
if (j == PlayerMax - 1) {
break;
}
@ -1810,42 +1818,95 @@ void NetworkServerStartGame()
// Randomize the position.
// It can be disabled by writing NoRandomPlacementMultiplayer() in lua files.
// Players slots are then mapped to players numbers(and colors).
// Players slots are then mapped to players numbers(and colors) or by PlayerIndex preference
// (set in lua via Hosts[i].PlyNr, which is not really changing it, just "requesting" the change).
if (NoRandomPlacementMultiplayer) {
std::array<std::pair<int, CNetworkHost>, PlayerMax> s;
for (int i = 0; i < PlayerMax; ++i) {
if (Map.Info.PlayerType[i] != PlayerTypes::PlayerComputer) {
org[i] = Hosts[i].PlyNr;
s[i] = std::make_pair(i, Hosts[i]);
}
std::sort(s.begin(), s.end(), [](std::pair<int, CNetworkHost> &a, std::pair<int, CNetworkHost> &b) {
if (std::get<1>(a).PlayerIndex < 0 && std::get<1>(b).PlayerIndex < 0) {
// no preferences here, first slot first
return std::get<0>(a) < std::get<0>(b);
} else {
if (std::get<1>(b).PlayerIndex < 0) {
return true; // a has preference, b not, a first
} else if (std::get<1>(a).PlayerIndex < 0) {
return false; // b has preference, a not, b first
} else {
return std::get<1>(a).PlayerIndex < std::get<1>(b).PlayerIndex;
}
}
});
int j = 0;
for (int i = 0; i < PlayerMax; ++i) {
if (Map.Info.PlayerType[i] == PlayerTypes::PlayerPerson) {
std::get<1>(s[j]).PlyNr = i;
int netPlayer = std::get<0>(s[j]);
int k = slotIndexToMapPlayerIndex[netPlayer];
// k is the in-game PlayerIndex for the slot i.
// we need to swap it with the in-game PlayerIndex
// that we just assigned
if (k != i) {
for (int o = 0; o < PlayerMax; ++o) {
if (slotIndexToMapPlayerIndex[o] == i) {
slotIndexToMapPlayerIndex[o] = k;
break;
}
}
slotIndexToMapPlayerIndex[i] = i;
}
DebugPrint("Assigning player %d to slot %d (%d)\n" _C_ netPlayer _C_ i _C_ slotIndexToMapPlayerIndex[netPlayer]);
j++;
}
}
} else {
int j = h;
// j is the number of human player slots the map info provides
int j = humanPlayerCount;
for (int i = 0; i < NetPlayers; ++i) {
Assert(j > 0);
int chosen = MyRand() % j;
n = num[chosen];
int chosenHumanPlayerNumber = MyRand() % j;
// we've chosen a slot on the map to assign
n = humanPlayerIndexToMapPlayerIndex[chosenHumanPlayerNumber];
// n is now the in-game PlayerIndex for this slot
Hosts[i].PlyNr = n;
int k = org[i];
int k = slotIndexToMapPlayerIndex[i];
// k is the in-game PlayerIndex for the slot i.
// we need to swap it with the in-game PlayerIndex
// that we just assigned
if (k != n) {
for (int o = 0; o < PlayerMax; ++o) {
if (org[o] == n) {
org[o] = k;
if (slotIndexToMapPlayerIndex[o] == n) {
slotIndexToMapPlayerIndex[o] = k;
break;
}
}
org[i] = n;
slotIndexToMapPlayerIndex[i] = n;
}
DebugPrint("Assigning player %d to slot %d (%d)\n" _C_ i _C_ n _C_ org[i]);
DebugPrint("Assigning player %d to slot %d (%d)\n" _C_ i _C_ n _C_ slotIndexToMapPlayerIndex[i]);
num[chosen] = num[--j];
// we replace the in-game PlayerIndex we have just assigned
// with the last one available to human players in our map
// for the next MyRand() % j call. We won't be needing this
// mapping to be correct anymore afterwards
humanPlayerIndexToMapPlayerIndex[chosenHumanPlayerNumber] = humanPlayerIndexToMapPlayerIndex[--j];
}
}
int mapPlayerIndexToAckStatus[PlayerMax];
// Complete all setup states for the assigned slots.
// At this point, LocalSetupState has all the info
// assigned in-order, that is, LocalSetupState first has
// the settings for the human players, then computers, then
// nothing. We now go through the players and set it up through
// the mapping that the server assigns each slot index to the
// correct map player index
for (int i = 0; i < PlayerMax; ++i) {
num[i] = 1;
n = org[i];
mapPlayerIndexToAckStatus[i] = 1;
n = slotIndexToMapPlayerIndex[i];
ServerSetupState.CompOpt[n] = LocalSetupState.CompOpt[i];
ServerSetupState.ServerGameSettings.Presets[n].Race = LocalSetupState.ServerGameSettings.Presets[i].Race;
}
@ -1892,10 +1953,10 @@ breakout:
for (int i = 0; i < HostsCount; ++i) {
const CHost host(message.hosts[i].Host, message.hosts[i].Port);
if (num[Hosts[i].PlyNr] == 1) { // not acknowledged yet
if (mapPlayerIndexToAckStatus[Hosts[i].PlyNr] == 1) { // not acknowledged yet
message.clientIndex = i;
NetworkSendICMessage_Log(NetworkFildes, host, message);
} else if (num[Hosts[i].PlyNr] == 2) {
} else if (mapPlayerIndexToAckStatus[Hosts[i].PlyNr] == 2) {
NetworkSendICMessage_Log(NetworkFildes, host, statemsg);
}
}
@ -1922,8 +1983,8 @@ breakout:
DebugPrint("Got ack for InitConfig from %s\n" _C_ hostStr.c_str());
const int index = FindHostIndexBy(host);
if (index != -1) {
if (num[Hosts[index].PlyNr] == 1) {
num[Hosts[index].PlyNr]++;
if (mapPlayerIndexToAckStatus[Hosts[index].PlyNr] == 1) {
mapPlayerIndexToAckStatus[Hosts[index].PlyNr]++;
}
goto breakout;
}
@ -1934,8 +1995,8 @@ breakout:
DebugPrint("Got ack for InitState from %s\n" _C_ hostStr.c_str());
const int index = FindHostIndexBy(host);
if (index != -1) {
if (num[Hosts[index].PlyNr] == 2) {
num[Hosts[index].PlyNr] = 0;
if (mapPlayerIndexToAckStatus[Hosts[index].PlyNr] == 2) {
mapPlayerIndexToAckStatus[Hosts[index].PlyNr] = 0;
--j;
DebugPrint("Removing host %d from waiting list\n" _C_ j);
}

View file

@ -45,7 +45,7 @@ tolua_readonly int NetPlayerNameSize;
struct CNetworkHost {
unsigned long Host; /// Host address
unsigned short Port; /// Port on host
unsigned short PlyNr; /// Player nummer
short PlayerIndex @ PlyNr; /// Desired player number when in game
char PlyName[NetPlayerNameSize]; /// Name of player
};
extern CNetworkHost Hosts[PlayerMax];