Fix #20104: [Plugin] Some network APIs use player index and group index (#20115)

Change all APIs that took a player index or group index so that they now take unique IDs.
This commit is contained in:
Ted John 2023-05-02 15:25:05 +01:00 committed by GitHub
parent 42fa4cb6b9
commit 530dfac7c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 219 additions and 43 deletions

View File

@ -42,6 +42,7 @@
- Fix: [#20016] The group box for small scenery details in the Tile Inspector window has unused empty space. - Fix: [#20016] The group box for small scenery details in the Tile Inspector window has unused empty space.
- Fix: [#20018] Shops not calculating up-keep cost. - Fix: [#20018] Shops not calculating up-keep cost.
- Fix: [#20033] Asset packs cannot reference game data. - Fix: [#20033] Asset packs cannot reference game data.
- Fix: [#20104] [Plugin] Some network APIs use player index and group index.
0.4.4 (2023-03-28) 0.4.4 (2023-03-28)
------------------------------------------------------------------------ ------------------------------------------------------------------------

View File

@ -2886,25 +2886,100 @@ declare global {
* Use `network.mode` to determine whether the current game is a client, server or in single player mode. * Use `network.mode` to determine whether the current game is a client, server or in single player mode.
*/ */
interface Network { interface Network {
/**
* The current network mode. This can be used to determine whether the current
* session is single player, a multiplayer server, or a multiplayer client.
*/
readonly mode: NetworkMode; readonly mode: NetworkMode;
/**
* The number of multiplayer groups there are in the server.
*/
readonly numGroups: number; readonly numGroups: number;
/**
* The number of players there are in the server.
*/
readonly numPlayers: number; readonly numPlayers: number;
/**
* Gets all the multiplayer groups within the server. Groups are used to give individual
* players roles and permissions.
*/
readonly groups: PlayerGroup[]; readonly groups: PlayerGroup[];
/**
* Gets all the players that are currently in the server.
*/
readonly players: Player[]; readonly players: Player[];
/**
* The player this instance of the game is controlling.
*/
readonly currentPlayer: Player; readonly currentPlayer: Player;
/**
* Gets or sets the default group ID that new players joining the server should be assigned to.
*/
defaultGroup: number; defaultGroup: number;
/**
* Various statistics related to networking.
*/
readonly stats: NetworkStats; readonly stats: NetworkStats;
getServerInfo(): ServerInfo; /**
* Creates a new multiplayer group for managing player permissions.
*/
addGroup(): void; addGroup(): void;
getGroup(index: number): PlayerGroup;
removeGroup(index: number): void; /**
getPlayer(index: number): Player; * Gets the player group with the specified ID.
kickPlayer(index: number): void; * @param id The group ID. Prior to API version 77, this is the group index.
*/
getGroup(id: number): PlayerGroup;
/**
* Removes the player group with the specified ID.
* @param id The group ID. Prior to API version 77, this is the group index.
*/
removeGroup(id: number): void;
/*
* Gets the player with the specified ID.
* @param id The player ID. Prior to API version 77, this is the player index.
*/
getPlayer(id: number): Player;
/*
* Kicks the player with the specified ID from the server.
* @param id The player ID. Prior to API version 77, this is the player index.
*/
kickPlayer(id: number): void;
/**
* Sends a chat message to all players.
* @param message The message text.
*/
sendMessage(message: string): void; sendMessage(message: string): void;
/**
* Sends a chat message to only the specified players.
* @param message The message text.
* @param players A list of player IDs that should receive the chat message.
* Note: the message will be internally transmitted to players via
* the server, even if the server is not a recipient.
*/
sendMessage(message: string, players: number[]): void; sendMessage(message: string, players: number[]): void;
/**
* Creates a new listener that can accept TCP connections on a given port.
*/
createListener(): Listener; createListener(): Listener;
/**
* Creates a new TCP client that can connect to a server.
*/
createSocket(): Socket; createSocket(): Socket;
} }
@ -2914,34 +2989,81 @@ declare global {
* Represents a player within a network game. * Represents a player within a network game.
*/ */
interface Player { interface Player {
/**
* The unique ID for the player.
*/
readonly id: number; readonly id: number;
/**
* The name of the player.
*/
readonly name: string; readonly name: string;
/**
* The group ID the player is a member of.
*/
group: number; group: number;
/**
* The latest measured ping in milliseconds for the player.
*/
readonly ping: number; readonly ping: number;
/**
* The number of actions the player has successfully executed.
*/
readonly commandsRan: number; readonly commandsRan: number;
/**
* The total amount of cash spent from actions performed by the player.
*/
readonly moneySpent: number; readonly moneySpent: number;
/**
* The player's IP address.
*/
readonly ipAddress: string; readonly ipAddress: string;
/**
* A hash of the player's public key used to authenticate with the server.
*/
readonly publicKeyHash: string; readonly publicKeyHash: string;
} }
/**
* Represents a group in a network game for assigning roles and permissions
* to one or more players.
*/
interface PlayerGroup { interface PlayerGroup {
/**
* The unique ID for the group.
*/
readonly id: number; readonly id: number;
/**
* The name of the group.
*/
name: string; name: string;
/**
* The permissions granted to each player belonging to the group.
*/
permissions: PermissionType[]; permissions: PermissionType[];
} }
interface ServerInfo { /**
readonly name: string; * Represents various network statistics.
readonly description: string; */
readonly greeting: string;
readonly providerName: string;
readonly providerEmail: string;
readonly providerWebsite: string;
}
interface NetworkStats { interface NetworkStats {
bytesReceived: number[]; /**
bytesSent: number[]; * The number of bytes received for each category.
*/
readonly bytesReceived: number[];
/**
* The number of bytes sent for each category.
*/
readonly bytesSent: number[];
} }
type PermissionType = type PermissionType =

View File

@ -59,6 +59,7 @@ As of version 34 there are breaking Api changes.
- **Version 34:** `Entity.type` will now return `"guest"` or `"staff"` instead of `"peep"`. - **Version 34:** `Entity.type` will now return `"guest"` or `"staff"` instead of `"peep"`.
- **Version 63:** Accessing G2 sprites by id directly is now deprecated in favor of a future-proof implementation using `IconName` and/or `context.getIcon()`. - **Version 63:** Accessing G2 sprites by id directly is now deprecated in favor of a future-proof implementation using `IconName` and/or `context.getIcon()`.
- **Version 68:** Custom game actions registered through `context.registerAction()` now wrap the callback arguments in a `GameActionEventArgs`, similar to `context.subscribe()` callbacks. - **Version 68:** Custom game actions registered through `context.registerAction()` now wrap the callback arguments in a `GameActionEventArgs`, similar to `context.subscribe()` callbacks.
- **Version 77:** Network APIs that take player index and group index now take player ID and group ID instead.
## Frequently Asked Questions ## Frequently Asked Questions

View File

@ -47,12 +47,13 @@ namespace OpenRCT2
namespace OpenRCT2::Scripting namespace OpenRCT2::Scripting
{ {
static constexpr int32_t OPENRCT2_PLUGIN_API_VERSION = 76; static constexpr int32_t OPENRCT2_PLUGIN_API_VERSION = 77;
// Versions marking breaking changes. // Versions marking breaking changes.
static constexpr int32_t API_VERSION_33_PEEP_DEPRECATION = 33; static constexpr int32_t API_VERSION_33_PEEP_DEPRECATION = 33;
static constexpr int32_t API_VERSION_63_G2_REORDER = 63; static constexpr int32_t API_VERSION_63_G2_REORDER = 63;
static constexpr int32_t API_VERSION_68_CUSTOM_ACTION_ARGS = 68; static constexpr int32_t API_VERSION_68_CUSTOM_ACTION_ARGS = 68;
static constexpr int32_t API_VERSION_77_NETWORK_IDS = 77;
# ifndef DISABLE_NETWORK # ifndef DISABLE_NETWORK
class ScSocketBase; class ScSocketBase;

View File

@ -111,15 +111,28 @@ namespace OpenRCT2::Scripting
return player; return player;
} }
std::shared_ptr<ScPlayer> ScNetwork::getPlayer(int32_t index) const std::shared_ptr<ScPlayer> ScNetwork::getPlayer(int32_t id) const
{ {
# ifndef DISABLE_NETWORK # ifndef DISABLE_NETWORK
auto numPlayers = NetworkGetNumPlayers(); if (GetTargetAPIVersion() < API_VERSION_77_NETWORK_IDS)
if (index < numPlayers)
{ {
auto playerId = NetworkGetPlayerID(index); auto index = id;
return std::make_shared<ScPlayer>(playerId); auto numPlayers = NetworkGetNumPlayers();
if (index < numPlayers)
{
auto playerId = NetworkGetPlayerID(index);
return std::make_shared<ScPlayer>(playerId);
}
} }
else
{
auto index = NetworkGetPlayerIndex(id);
if (index != -1)
{
return std::make_shared<ScPlayer>(id);
}
}
# endif # endif
return nullptr; return nullptr;
} }
@ -157,14 +170,26 @@ namespace OpenRCT2::Scripting
# endif # endif
} }
std::shared_ptr<ScPlayerGroup> ScNetwork::getGroup(int32_t index) const std::shared_ptr<ScPlayerGroup> ScNetwork::getGroup(int32_t id) const
{ {
# ifndef DISABLE_NETWORK # ifndef DISABLE_NETWORK
auto numGroups = NetworkGetNumGroups(); if (GetTargetAPIVersion() < API_VERSION_77_NETWORK_IDS)
if (index < numGroups)
{ {
auto groupId = NetworkGetGroupID(index); auto index = id;
return std::make_shared<ScPlayerGroup>(groupId); auto numGroups = NetworkGetNumGroups();
if (index < numGroups)
{
auto groupId = NetworkGetGroupID(index);
return std::make_shared<ScPlayerGroup>(groupId);
}
}
else
{
auto index = NetworkGetGroupIndex(id);
if (index != -1)
{
return std::make_shared<ScPlayerGroup>(id);
}
} }
# endif # endif
return nullptr; return nullptr;
@ -178,28 +203,54 @@ namespace OpenRCT2::Scripting
# endif # endif
} }
void ScNetwork::removeGroup(int32_t index) void ScNetwork::removeGroup(int32_t id)
{ {
# ifndef DISABLE_NETWORK # ifndef DISABLE_NETWORK
auto numGroups = NetworkGetNumGroups(); if (GetTargetAPIVersion() < API_VERSION_77_NETWORK_IDS)
if (index < numGroups)
{ {
auto groupId = NetworkGetGroupID(index); auto index = id;
auto networkAction = NetworkModifyGroupAction(ModifyGroupType::RemoveGroup, groupId); auto numGroups = NetworkGetNumGroups();
GameActions::Execute(&networkAction); if (index < numGroups)
{
auto groupId = NetworkGetGroupID(index);
auto networkAction = NetworkModifyGroupAction(ModifyGroupType::RemoveGroup, groupId);
GameActions::Execute(&networkAction);
}
}
else
{
auto index = NetworkGetGroupIndex(id);
if (index != -1)
{
auto networkAction = NetworkModifyGroupAction(ModifyGroupType::RemoveGroup, id);
GameActions::Execute(&networkAction);
}
} }
# endif # endif
} }
void ScNetwork::kickPlayer(int32_t index) void ScNetwork::kickPlayer(int32_t id)
{ {
# ifndef DISABLE_NETWORK # ifndef DISABLE_NETWORK
auto numPlayers = NetworkGetNumPlayers(); if (GetTargetAPIVersion() < API_VERSION_77_NETWORK_IDS)
if (index < numPlayers)
{ {
auto playerId = NetworkGetPlayerID(index); auto index = id;
auto kickPlayerAction = PlayerKickAction(playerId); auto numPlayers = NetworkGetNumPlayers();
GameActions::Execute(&kickPlayerAction); if (index < numPlayers)
{
auto playerId = NetworkGetPlayerID(index);
auto kickPlayerAction = PlayerKickAction(playerId);
GameActions::Execute(&kickPlayerAction);
}
}
else
{
auto index = NetworkGetPlayerIndex(id);
if (index != -1)
{
auto kickPlayerAction = PlayerKickAction(id);
GameActions::Execute(&kickPlayerAction);
}
} }
# endif # endif
} }

View File

@ -43,17 +43,17 @@ namespace OpenRCT2::Scripting
std::shared_ptr<ScPlayer> currentPlayer_get() const; std::shared_ptr<ScPlayer> currentPlayer_get() const;
std::shared_ptr<ScPlayer> getPlayer(int32_t index) const; std::shared_ptr<ScPlayer> getPlayer(int32_t id) const;
DukValue stats_get() const; DukValue stats_get() const;
std::shared_ptr<ScPlayerGroup> getGroup(int32_t index) const; std::shared_ptr<ScPlayerGroup> getGroup(int32_t id) const;
void addGroup(); void addGroup();
void removeGroup(int32_t index); void removeGroup(int32_t id);
void kickPlayer(int32_t index); void kickPlayer(int32_t id);
void sendMessage(std::string message, DukValue players); void sendMessage(std::string message, DukValue players);