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: [#20018] Shops not calculating up-keep cost.
- 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)
------------------------------------------------------------------------

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.
*/
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;
/**
* The number of multiplayer groups there are in the server.
*/
readonly numGroups: number;
/**
* The number of players there are in the server.
*/
readonly numPlayers: number;
/**
* Gets all the multiplayer groups within the server. Groups are used to give individual
* players roles and permissions.
*/
readonly groups: PlayerGroup[];
/**
* Gets all the players that are currently in the server.
*/
readonly players: Player[];
/**
* The player this instance of the game is controlling.
*/
readonly currentPlayer: Player;
/**
* Gets or sets the default group ID that new players joining the server should be assigned to.
*/
defaultGroup: number;
/**
* Various statistics related to networking.
*/
readonly stats: NetworkStats;
getServerInfo(): ServerInfo;
/**
* Creates a new multiplayer group for managing player permissions.
*/
addGroup(): void;
getGroup(index: number): PlayerGroup;
removeGroup(index: number): void;
getPlayer(index: number): Player;
kickPlayer(index: number): void;
/**
* Gets the player group with the specified ID.
* @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;
/**
* 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;
/**
* Creates a new listener that can accept TCP connections on a given port.
*/
createListener(): Listener;
/**
* Creates a new TCP client that can connect to a server.
*/
createSocket(): Socket;
}
@ -2914,34 +2989,81 @@ declare global {
* Represents a player within a network game.
*/
interface Player {
/**
* The unique ID for the player.
*/
readonly id: number;
/**
* The name of the player.
*/
readonly name: string;
/**
* The group ID the player is a member of.
*/
group: number;
/**
* The latest measured ping in milliseconds for the player.
*/
readonly ping: number;
/**
* The number of actions the player has successfully executed.
*/
readonly commandsRan: number;
/**
* The total amount of cash spent from actions performed by the player.
*/
readonly moneySpent: number;
/**
* The player's IP address.
*/
readonly ipAddress: string;
/**
* A hash of the player's public key used to authenticate with the server.
*/
readonly publicKeyHash: string;
}
/**
* Represents a group in a network game for assigning roles and permissions
* to one or more players.
*/
interface PlayerGroup {
/**
* The unique ID for the group.
*/
readonly id: number;
/**
* The name of the group.
*/
name: string;
/**
* The permissions granted to each player belonging to the group.
*/
permissions: PermissionType[];
}
interface ServerInfo {
readonly name: string;
readonly description: string;
readonly greeting: string;
readonly providerName: string;
readonly providerEmail: string;
readonly providerWebsite: string;
}
/**
* Represents various network statistics.
*/
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 =

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 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 77:** Network APIs that take player index and group index now take player ID and group ID instead.
## Frequently Asked Questions

View File

@ -47,12 +47,13 @@ namespace OpenRCT2
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.
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_68_CUSTOM_ACTION_ARGS = 68;
static constexpr int32_t API_VERSION_77_NETWORK_IDS = 77;
# ifndef DISABLE_NETWORK
class ScSocketBase;

View File

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

View File

@ -43,17 +43,17 @@ namespace OpenRCT2::Scripting
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;
std::shared_ptr<ScPlayerGroup> getGroup(int32_t index) const;
std::shared_ptr<ScPlayerGroup> getGroup(int32_t id) const;
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);