Add: Company allow-list can be set to allow anyone.

This commit is contained in:
Peter Nelson
2026-02-16 14:01:05 +00:00
committed by Peter Nelson
parent a6803199d5
commit da4dd91887
8 changed files with 67 additions and 20 deletions
+1
View File
@@ -81,6 +81,7 @@ struct CompanyProperties {
std::string president_name{}; ///< Name of the president if the user changed it.
NetworkAuthorizedKeys allow_list{}; ///< Public keys of clients that are allowed to join this company.
bool allow_any = false; ///< Set if anyone is allowed to join this company.
CompanyManagerFace face{}; ///< Face description of the president.
+17 -3
View File
@@ -1014,6 +1014,16 @@ static bool ExecuteAllowListCtrlAction(CompanyAllowListCtrlAction action, Compan
case CALCA_REMOVE:
return c->allow_list.Remove(public_key);
case CALCA_ALLOW_ANY:
if (c->allow_any) return false;
c->allow_any = true;
return true;
case CALCA_ALLOW_LISTED:
if (!c->allow_any) return false;
c->allow_any = false;
return true;
default:
NOT_REACHED();
}
@@ -1031,12 +1041,16 @@ CommandCost CmdCompanyAllowListCtrl(DoCommandFlags flags, CompanyAllowListCtrlAc
Company *c = Company::GetIfValid(_current_company);
if (c == nullptr) return CMD_ERROR;
/* The public key length includes the '\0'. */
if (public_key.size() != NETWORK_PUBLIC_KEY_LENGTH - 1) return CMD_ERROR;
switch (action) {
case CALCA_ADD:
case CALCA_REMOVE:
/* The public key length includes the '\0'. */
if (public_key.size() != NETWORK_PUBLIC_KEY_LENGTH - 1) return CMD_ERROR;
break;
case CALCA_ALLOW_ANY:
case CALCA_ALLOW_LISTED:
if (public_key.size() != 0) return CMD_ERROR;
break;
default:
+2
View File
@@ -80,6 +80,8 @@ enum CompanyCtrlAction : uint8_t {
enum CompanyAllowListCtrlAction : uint8_t {
CALCA_ADD, ///< Create a public key.
CALCA_REMOVE, ///< Remove a public key.
CALCA_ALLOW_ANY, ///< Allow joining the company without a key.
CALCA_ALLOW_LISTED, ///< Allow only listed keys to join the company.
CALCA_END, ///< Sentinel for end.
};
+2
View File
@@ -2547,6 +2547,8 @@ STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE_TURN :{BLACK}Via rela
STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK :Kick
STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :Ban
STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET :Delete
STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_ALLOW_ANY :Allow any client
STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_ALLOW_LISTED :Allow only listed clients
STR_NETWORK_CLIENT_LIST_ASK_CAPTION :{WHITE}Admin action
STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}Are you sure you want to kick player '{RAW_STRING}'?
+1 -1
View File
@@ -131,7 +131,7 @@ NetworkClientInfo::~NetworkClientInfo()
bool NetworkClientInfo::CanJoinCompany(CompanyID company_id) const
{
Company *c = Company::GetIfValid(company_id);
return c != nullptr && c->allow_list.Contains(this->public_key);
return c != nullptr && (c->allow_any || c->allow_list.Contains(this->public_key));
}
/**
+24 -3
View File
@@ -1539,6 +1539,8 @@ private:
AdminKickClient, ///< Admin kick client.
AdminBanClient, ///< Admin ban client.
AdminResetCompany, ///< Admin reset company.
CompanyAllowAny, ///< Allow any client.
CompanyAllowListed, ///< Allow only listed clients.
};
ClientListWidgets query_widget{}; ///< During a query this tracks what widget caused the query.
@@ -1620,7 +1622,11 @@ private:
static void OnClickCompanyAdmin([[maybe_unused]] NetworkClientListWindow *w, [[maybe_unused]] Point pt, CompanyID company_id)
{
DropDownList list;
list.push_back(MakeDropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET, to_underlying(DropDownAction::AdminResetCompany), NetworkCompanyHasClients(company_id)));
if (_network_server) list.push_back(MakeDropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET, to_underlying(DropDownAction::AdminResetCompany), NetworkCompanyHasClients(company_id)));
if (const Company *c = Company::GetIfValid(company_id); c != nullptr) {
list.push_back(MakeDropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_ALLOW_ANY, to_underlying(DropDownAction::CompanyAllowAny), c->allow_any));
list.push_back(MakeDropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_ALLOW_LISTED, to_underlying(DropDownAction::CompanyAllowListed), !c->allow_any));
}
Rect wi_rect;
wi_rect.left = pt.x;
@@ -1631,6 +1637,7 @@ private:
w->dd_company_id = company_id;
ShowDropDownListAt(w, std::move(list), -1, WID_CL_MATRIX, wi_rect, COLOUR_GREY, DropDownOption::InstantClose);
}
/**
* Chat button on a Client is clicked.
* @param w The instance of this window.
@@ -1657,7 +1664,9 @@ private:
void RebuildListCompany(CompanyID company_id, CompanyID client_playas, bool can_join_company)
{
ButtonLine &company_line = *this->buttons.emplace_back(std::make_unique<CompanyButtonLine>(company_id));
if (_network_server) company_line.AddButton<CompanyButton>(SPR_ADMIN, STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP, COLOUR_RED, company_id, &NetworkClientListWindow::OnClickCompanyAdmin, company_id == COMPANY_SPECTATOR);
if (_network_server || company_id == _local_company) {
company_line.AddButton<CompanyButton>(SPR_ADMIN, STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP, COLOUR_RED, company_id, &NetworkClientListWindow::OnClickCompanyAdmin, company_id == COMPANY_SPECTATOR);
}
ButtonCommon &chat_button = company_line.AddButton<CompanyButton>(SPR_CHAT, company_id == COMPANY_SPECTATOR ? STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP : STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP, COLOUR_ORANGE, company_id, &NetworkClientListWindow::OnClickCompanyChat);
if (can_join_company) company_line.AddButton<CompanyButton>(SPR_JOIN, STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP, COLOUR_ORANGE, company_id, &NetworkClientListWindow::OnClickCompanyJoin, company_id != COMPANY_SPECTATOR && Company::Get(company_id)->is_ai);
@@ -1700,7 +1709,7 @@ private:
for (const Company *c : Company::Iterate()) {
if (c->index == client_playas) continue;
this->RebuildListCompany(c->index, client_playas, (own_ci != nullptr && c->allow_list.Contains(own_ci->public_key)) || _network_server);
this->RebuildListCompany(c->index, client_playas, _network_server || c->allow_any || (own_ci != nullptr && c->allow_list.Contains(own_ci->public_key)));
}
/* Spectators */
@@ -1897,6 +1906,18 @@ public:
text = GetEncodedString(STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET, _admin_company_id);
break;
case DropDownAction::CompanyAllowAny: {
AutoRestoreBackup cur_company(_current_company, this->dd_company_id);
Command<Commands::CompanyAllowListControl>::Post(CALCA_ALLOW_ANY, {});
return;
}
case DropDownAction::CompanyAllowListed: {
AutoRestoreBackup cur_company(_current_company, this->dd_company_id);
Command<Commands::CompanyAllowListControl>::Post(CALCA_ALLOW_LISTED, {});
return;
}
default:
NOT_REACHED();
}
+19 -13
View File
@@ -942,7 +942,8 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_IDENTIFY(Packet
return this->SendError(NETWORK_ERROR_COMPANY_MISMATCH);
}
if (!Company::Get(playas)->allow_list.Contains(this->peer_public_key)) {
const Company *c = Company::Get(playas);
if (!c->allow_any && !c->allow_list.Contains(this->peer_public_key)) {
/* When we're not authorized, just bump us to a spectator. */
playas = COMPANY_SPECTATOR;
}
@@ -1161,16 +1162,18 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMMAND(Packet
/* Only allow clients to add/remove currently joined clients. The server owner does not go via this method, so is allowed to do more. */
std::string public_key = std::get<1>(EndianBufferReader::ToValue<CommandTraits<Commands::CompanyAllowListControl>::Args>(cp.data));
bool found = false;
for (const NetworkClientInfo *info : NetworkClientInfo::Iterate()) {
if (info->public_key == public_key) {
found = true;
break;
if (!public_key.empty()) {
bool found = false;
for (const NetworkClientInfo *info : NetworkClientInfo::Iterate()) {
if (info->public_key == public_key) {
found = true;
break;
}
}
}
/* Maybe the client just left? */
if (!found) return NETWORK_RECV_STATUS_OKAY;
/* Maybe the client just left? */
if (!found) return NETWORK_RECV_STATUS_OKAY;
}
}
if (GetCommandFlags(cp.cmd).Test(CommandFlag::ClientID)) NetworkReplaceCommandClientId(cp, this->client_id);
@@ -1517,11 +1520,14 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_MOVE(Packet &p)
Debug(net, 9, "client[{}] Receive_CLIENT_MOVE(): company_id={}", this->client_id, company_id);
/* Check if the company is valid, we don't allow moving to AI companies */
if (company_id != COMPANY_SPECTATOR && !Company::IsValidHumanID(company_id)) return NETWORK_RECV_STATUS_OKAY;
if (company_id != COMPANY_SPECTATOR) {
if (!Company::IsValidHumanID(company_id)) return NETWORK_RECV_STATUS_OKAY;
if (company_id != COMPANY_SPECTATOR && !Company::Get(company_id)->allow_list.Contains(this->peer_public_key)) {
Debug(net, 2, "Wrong public key from client-id #{} for company #{}", this->client_id, company_id + 1);
return NETWORK_RECV_STATUS_OKAY;
const Company *c = Company::Get(company_id);
if (!c->allow_any && !c->allow_list.Contains(this->peer_public_key)) {
Debug(net, 2, "Wrong public key from client-id #{} for company #{}", this->client_id, company_id + 1);
return NETWORK_RECV_STATUS_OKAY;
}
}
/* if we get here we can move the client */
+1
View File
@@ -499,6 +499,7 @@ static const SaveLoad _company_desc[] = {
SLE_CONDVECTOR(CompanyProperties, allow_list, SLE_STR, SLV_COMPANY_ALLOW_LIST, SLV_COMPANY_ALLOW_LIST_V2),
SLEG_CONDSTRUCTLIST("allow_list", SlAllowListData, SLV_COMPANY_ALLOW_LIST_V2, SL_MAX_VERSION),
SLE_VAR(CompanyProperties, allow_any, SLE_BOOL),
SLE_VARNAME(CompanyProperties, face.bits, "face", SLE_UINT32),
SLE_CONDSSTRNAME(CompanyProperties, face.style_label, "face_style", SLE_STR, SLV_FACE_STYLES, SL_MAX_VERSION),