Hi, can you add the following methods to the plugin API?
bool HasHeli(BasePlayer)
DespawnHeli(BasePlayer)
SpawnHeli(BasePlayer)
Plugin API
I am open to this suggestion but I would like to discuss it further since it's not obvious how these APIs should behave.
First, before getting into the more complex details, I want to suggest that we combine the first two proposed APIs into one, basically GetHeli.
- When you want to know whether the player has a heli, simply get the heli and check if it's not already killed/destroyed
- When you wan to despawn the heli, simply get the heli and kill it if it's not already killed/destroyed
Second, I just want to note that each API probably needs to be multiplied by three since the plugin supports three types of helicopters.
Given this information (and some personal conventions which I have applied), here's a 2nd draft for the APIs.PlayerHelicopter API_GetMinicopter(BasePlayer player);
PlayerHelicopter API_GetScrapTransportHelicopter(BasePlayer player);
PlayerHelicopter API_GetAttackHelicopter(BasePlayer player);
// Similar to the commands:
// - spawnheli.minicopter.give <player>
// - spawnheli.scraptransport.give <player>
// - spawnheli.attackhelicopter.give <player>
PlayerHelicopter API_GiveMinicopter(BasePlayer player);
PlayerHelicopter API_GiveScrapTransportHelicopter(BasePlayer player);
PlayerHelicopter API_GiveAttackHelicopter(BasePlayer player);
// Similar to the commands:
// - spawnheli.minicopter.give <player> <x> <y> <z>
// - spawnheli.scraptransport.give <player> <x> <y> <z>
// - spawnheli.attackhelicopter.give <player> <x> <y> <z>
PlayerHelicopter API_GiveMinicopterAtPosition(BasePlayer player, Vector3 position);
PlayerHelicopter API_GiveScrapTransportHelicopterAtPosition(BasePlayer player, Vector3 position);
PlayerHelicopter API_GiveAttackHelicopterAtPosition(BasePlayer player, Vector3 position);Now, let's get into the major question/complexity: To what extent should the APIs behave the same as though a player ran the corresponding command? This is a really important question as there are multiple different users of any given plugin, described as follows.
- The players, who interact with the plugin by running commands like
spawnmini - The server owner, who interacts with the plugin by running commands like
spawnheli.minicopter.give - Other plugins, which interact with the plugin by calling commands like
spawnheli.minicopter.giveand API methods likeAPI_GiveMinicopter
Server owners also dictate what happens when a player tries to spawn a heli, such as whether the command is allowed in a building blocked zone, whether attempting to spawn automatically fetches the existing heli, whether fetching the heli automatically repairs it, how much fuel it spawns with, and more. It's not obvious whether a plugin calling the API should be subject to the same constraints and behaviors. If a plugin is subject to them, that means there will be cases where the action cannot be allowed, a good example being when the player is building blocked.
When it's unclear how other plugins might want to interact, there are a few different approaches we can take.
- A) Apply all constraints -- Nearly all configuration options and permissions will be consulted to determine whether to spawn the heli and how/where to spawn it. If the action should be not allowed, feedback needs to be provided (to the player or to the plugin). Providing feedback to the player is straight-forward as the plugin already does it, but feedback to a plugin needs to be designed carefully so that the plugin can actually understand what went wrong and act accordingly. Since a plugin is performing an action on behalf of a player, it's not obvious whether feedback should be given directly to the player as the player did not necessarily attempt any action.
- B) Apply no constraints -- Just spawn the heli, ignoring most or all of the configuration and permissions. This is not ideal since it effectively disables many features of the plugin.
- C) Make a judgment (as the developer of Spawn Heli) about what is the right set of behaviors/constraints. For example, check permission to determine the starting fuel amount, but don't check whether the player has a location restriction. This is tricky because how can the API developer be right about how all other plugins want to use it, especially given that the feature set of the plugin is not static?
- D) Allow other plugins to specify the behaviors/constraints via API parameters
Even if the answer seemed to obviously be D (allow other plugins to specify), it can be confusing to a server owner when another plugin is effectively overriding the configuration (e.g,. helis are spawning in building blocked zones when that was disallowed in the configuration). When API methods are allowed to override the configuration, I need to provide clear guidance to plugin developers that they should exercise caution and provide similar configuration options in their plugin that allow the server owner to dictate the behavior. However, even when other plugins follow that guidance, server owners face the confusing problem of having two sources of truth for configuring how the plugin will work under varying circumstances.
I realize I've explained many problems here. My intent is not to block or delay your suggestion, but rather to make sure it's implemented correctly and in a way that it doesn't need to be reversed later. Ideally the design pattern we select here should be something I can apply to other plugins I maintain, contribute to, and/or consult on, to make things more consistent for the plugin community in the long term. To help me move forward, please think through this carefully and let me know specifically how you would like the APIs to behave with respect to the configuration/permissions. Maybe your answer will be straight forward and will allow me to implement changes immediately. // vName = VehicleInfo.VehicleName
private PlayerHelicopter API_GetHeli(BasePlayer player) // if one
private PlayerHelicopter[] API_GetAllHeli(BasePlayer player) // if <one
private PlayerHelicopter API_GetHeli(BasePlayer player, string vName) // target
private object SpawnHeli(BasePlayer player, string vName, Vector3 pos, Quaternion rot)
private object SpawnHeli(BasePlayer player, string vName)
private object FetchHeli(BasePlayer player, string vName)
private bool DespawnHeli(BasePlayer player, string vName)
// bypass/override
private object SpawnHeli(BasePlayer player, string vName, string[] parametrs)
// or
private object SpawnHeli(BasePlayer player, string vName, bool bypassBuildBlock, etc...)
// etc...
// Example without bypass
private object SpawnHeli(BasePlayer player, string vName)
=> SpawnCommandInternal(GetVehicleByName(vName), player.IPlayer, "", new string[0] );I think this is a simple, scalable option
Merged post
PlayerHelicopter API_GiveMinicopter(BasePlayer player);
PlayerHelicopter API_GiveScrapTransportHelicopter(BasePlayer player);
PlayerHelicopter API_GiveAttackHelicopter(BasePlayer player);
=>
private object SpawnHeli(BasePlayer player, string vName)