New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for custom polls via plug-ins #61
Conversation
096db40
to
a998b29
Compare
Be sure to change the comments (in the header files, at a minimum) to reflect the change in API. For example, in VotingArbiter.h you changed "std::string getPollRequestor()" to "int getPollOrganizer" but the comments still say "return a string representing the player who requested the poll". |
this is a nit, but "const int" as a function parameter is silly. There is no valid reason to declare a pass-by-value parameter "const" since it's impossible to change the underlying value. It is an artifact of a global replace of "std::string&" to "int" in the signatures. |
This is one of my pet peeves, but if you are modifying a ctor, make every effort to initialize members in the member initializer list, and not in the function body. |
bz_ePollStartEvent, | ||
bz_ePollVoteEvent, | ||
bz_ePollVetoEvent, | ||
bz_ePollEndEvent, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this change require incrementing the API version? Previously compiled plugins are likely to be incompatible.
@jwmelto I've made some commits (that I'll squash when this is ready to merge). Regarding your comment about the API version, I've bumped As for initializing members, would I do all of the members or only the members that would have default values? I've also fixed the comment in VotingArbiter and changed it to just an |
sorry for the spam comments. I finally figured out how to group them in a review... but to member initialization: default initialization may be elided, but may be explicit for pedantic and documentation purposes. |
So taking |
VotingArbiter will keep track of player IDs now and fetch the player callsigns from that ID when a poll is created
bcb07d5
to
217804b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like we should seriously consider refactoring all of the server functions into built-in plugins. This is reasonable and no glaring errors, but the maintenance would be cleaner if there were just "plugins"
bz_ApiString pollTarget; | ||
|
||
// This value will be set to the victim's IP if it's a 'kick' 'kill' or 'ban' | ||
bz_ApiString pollValue; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
overloaded values are a poor API. Wouldn't it be better to have a polymorphic "poll details" structure where each type of poll carries its own details?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pollValue
since then has been removed since it's only available on certain occasions and having overload values are a pain, as you said. Besides, the information is only an IP so that can be fetched/stored by the plug-in
struct PollOption { | ||
std::string pollParameters; | ||
bz_CustomPollOptionHandler* pollHandler; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This structure needs a ctor to initialize the pollHandler member to 0 or else the map below will have incoherent semantics.
std::string pollParameters; | ||
bz_CustomPollOptionHandler* pollHandler; | ||
}; | ||
extern std::map<std::string, PollOption> customPollOptions; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't gotten the the body yet, but I suspect that exposing the global is neither necessary or prudent. It will interfere with any future goals of writing threaded code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without making this extern, I wouldn't be able to access the map in other files as is. Do you have a better approach in mind for this?
if (vote == 0) { | ||
if ((cast = arbiter->voteNo(callsign)) == true) { | ||
/* player voted no */ | ||
if (vote == 0 || vote == 1) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor point, but this kind of value checking is a maintenance issue. The logic is that "vote" is initialized to -1, and it only gets a different value if a valid "yes" or "no" answer is provided. So this test is more completely "vote != -1" or "vote > -1".
The problem with this logic is seen on line 2668. What is really needed is a "tri-state" boolean that carries the information of whether it has been initialized, and whether it is true or false. Ideally, it would have an "operator bool()" method so it could be tested here and assigned natively on line 2668. But that's a nuance that doesn't need fixing here.
bz_AllowPollEventData_V1 allowPollData; | ||
allowPollData.playerID = t; | ||
|
||
worldEventManager.callEvents(bz_eAllowPollEvent, &allowPollData); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't the "allow" event handling include the type of poll? Might a plugin want to allow a player to do some kind of poll and not another?
|
||
/* poof */ | ||
_suffraged.clear(); | ||
|
||
return true; | ||
} | ||
|
||
bool VotingArbiter::poll(const std::string &player, const std::string &playerRequesting, std::string action, std::string playerIP) | ||
bool VotingArbiter::poll(const std::string &target, const int playerRequestingID, std::string action, std::string playerIP) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"const int" is superfluous. "int" is sufficient.
Kind of a side note, but I get the impression that you're planning on making a habit of squashing your pull requests when you merge them in. It would be one thing if all development was done in pull requests, and our main repository's history was basically a list of merges. However, since it's not, I personally think that commit history from within pull requests is just as useful as that of commits we push to the main repository, so I would encourage you to keep them intact. |
@@ -45,7 +45,7 @@ | |||
|
|||
class bz_Plugin; | |||
|
|||
#define BZ_API_VERSION 26 | |||
#define BZ_API_VERSION 27 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
after confirmation, no version bump is needed. it's only necessary when existing constructors, objects, or functions are modified
@@ -0,0 +1,80 @@ | |||
// CustomZoneSample.cpp : Defines the entry point for the DLL application. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fix the copy paste
Flush(); | ||
|
||
// Remove the poll option when this plugin is loaded or else what other plugin would handle it? | ||
bz_removeCustomMapObject("mute"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bz_removeCustomPollOption
*
|
||
// Should return false to prevent the poll from starting | ||
virtual bool PollOpen (int playerID, bz_ApiString action, bz_ApiString value) = 0; | ||
virtual void PollClose (bz_ApiString action, bz_ApiString value, bool success) = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since these values won't change/shouldn't be changed, making them const char*
would work
bz_eAllowPollEvent -> bz_AllowPollEventData_V1 Called before a poll is started to give plug-in developers access to prevent a poll from starting bz_ePollStartEvent -> bz_PollStartEventData_V1 Called whenever a new poll is started bz_ePollVoteEvent -> bz_PollVoteEventData_V1 Called whenever a vote is cast. Grants access to plug-ins to disallow votes from being cast bz_ePollVetoEvent -> bz_PollVetoEventData_V1 Called whenever an admin /veto's a poll or bz_pollVeto() is called. If bz_pollVeto() is called, the playerID will be set to BZ_SERVER bz_ePollEndEvent -> bz_PollEndEventData_V1 Called whenever a poll is closed without being vetoed
- Created a bz_CustomPollOptionHandler class with two virtual functions: PollOpen() Called before a custom poll is started and allows plug-in developers to have any necessary checks and disallow the poll, for example. PollClose() Called at the end of a custom poll that has ended without being vetoed. This is were plug-in developers can implement the logic for what the poll should do. - Add two API functions bz_registerCustomPollOption() bz_removeCustomPollOption() - Custom polls are stored in a map stored in VotingArbiter - Custom poll options are displayed when an invalid '/poll' command is used in addition to the built-in ones (e.g. kick, ban, kill)
This plug-in is designed to demonstrate how to create custom polls
This will allow plugins to decide whether they need to handle the poll or not
- Fix misc issues from feedback (BZFlag-Dev#61) - bz_PollStartEventData_V1 no longer contains the 'pollValue' variable. This information is only available on certain cases and overloaded values are poor in an API. This information contains the IP of the targeted player and there are other ways of getting that information
217804b
to
0ebffef
Compare
Made some updates with the given feedback. Still waiting on a few more opinions before this can be merged in. |
I think I'm all set. Any other feedback is welcome and would be appreciated before I merge this in the coming days. |
1cfbf61
to
54c8ee0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me, and I'm looking forward to having this new feature available.
54c8ee0
to
82c5284
Compare
Since values being passed to these functions won't need to be changed, it's better to make them 'const char*' and instead of passing the player ID as an int we'll pass through a player record
e180807
to
c15c18a
Compare
I know this is tangential to this pull request, but this program:
illustrates the type of situation where it may be reasonable to declare a function parameter as |
So are you advocating for the style? Because if a programmer doesn't know the difference between "int value" and "int& value", it's unlikely that even the compiler error is going to help them. The function signature is a contract between the caller and the writer of the method, not between the writer and himself. YMMV |
A programmer can know the difference between those two declarations and still fail to be aware of which is in effect for a specific variable. You may not need more safety in your programming style, but I appreciate it when I see code that shows an extra effort (a not-so-superfluous use of |
This pull request introduces the ability to create custom poll types to the API. A custom poll type is defined as adding your own action to
/poll <action>
. I've added a sample plug-in showing how to create a primitive/poll mute
option.New API Events + Data Objects
bz_eAllowPollEvent
->bz_AllowPollEventData_V1
bz_ePollStartEvent
->bz_PollStartEventData_V1
bz_ePollVoteEvent
->bz_PollVoteEventData_V1
bz_ePollVetoEvent
->bz_PollVetoEventData_V1
bz_ePollEndEvent
->bz_PollEndEventData_V1
New API Functions
bool bz_registerCustomPollOption (const char* option, const char* parameters, bz_CustomPollOptionHandler *handler);
bool bz_removeCustomPollOption (const char* option);
bz_CustomPollOptionHandler Usage
bool PollOpen (bz_BasePlayerRecord *player, const char* action, const char* parameters)
This function is called before every custom poll begins. When this function returns true, the server will proceed and begin the poll. If the plugin returns false, then the poll will not begin. This function is intended for allowing plug-in developers to check conditions or permissions before the poll is begun. Any messages or errors that occur should be sent to the player from this function, otherwise it will appear as if the poll failed to start.
void PollClose (const char* action, const char* parameters, bool success)
This function is called after every custom poll has ended. This is where the business logic of a successful poll should be defined.
I'd appreciate feedback and help testing too ❤️