Quote:
Originally Posted by Harakiri23
also a selection of binding wrappers
|
This thread has kind of died down and maybe there wasn't that much interest in the first place, but: I just re-read this and want to take a moment to make a case against using any auto-generated bindings/wrappers if a Lua quest scripting system does become a thing.
I realize that manually writing functions to expose C++ will take a lot of time and that in the process some bugs will inevitably creep in, requiring even more time to notice and fix them. But I want to argue that going that route will ultimately leave you with a more sensible, user-friendly system oriented towards its actual purpose -- i.e., writing quest and combat scripts for mobs -- rather than the as-close-to-the-C++-as-possible result a wrapper will likely give you (as far as I know, anyway). Main points:
Simplification
There are some things the script writer should just never have to worry about. CastToNPC/Client is probably the most obvious example. Handing a script function a Mob reference should always be enough -- any needed checks for NPC or Client should happen on the C++ side and split the function's behavior as necessary. (Maybe the Perl system has already eliminated the need for these, but I see them used in a few old scripts up on svn so I dunno.)
For another example, consider Mob::CastSpell(). Specifically, the fact that it takes an entity id for the target rather than a Mob reference. We know that it always expects an entity id. But we also know that, in our script system, whenever we want to cast a spell on something we will always have a Mob reference to the target before we have the target's entity id. Therefore, any function exposing CastSpell() to our script system should get the entity id implicitly. There's no reason every script-writer should need to write this
Code:
self:castspell(437,target:GetID())
every time when they could just write this
Code:
self:castspell(437,target)
instead.
Furthermore, CastSpell() does not have any default targetting. It seems reasonable to expect that if a script-writer writes this
Code:
self:castspell(437)
they should expect that the spell will self-target the given caster (or even better, target the caster's target if they have one and the spell is detrimental, and target the caster otherwise). We're given a fair amount of leeway to write pseudo-overloaded functions like this, so it seem sensible to use this to provide defaults that the C++ function in question does not.
Limiting Redundancy
Going back to automating NPC/Client casts and checks, consider the case of instantaneous intra-zone movement. When we want to teleport an NPC, we use GMMove(). When we want to teleport a client, we generally use MovePC while specifying the zone they're already in, since the movement is cleaner (unless we want to put them in mid-air, anyway).
But again, the script-writer should not need to know about this distinction. From the point of view of the user, all we care about is that the function instantly moves the given Mob. As such the script system should provide a single function that does this for both NPCs and Clients, with the GMMove/MovePC distinction being handled automatically on the C++ side. For Clients, clean movement is the most sensible default, but we can easily provide the mid-air variant with a single extra boolean parameter, like so:
Code:
target:move(x,y,z,heading) --clean
target:move(x,y,z,heading,true) --mid-air
As a simpler example, consider these two Client functions: IsInAGuild() and IsInGuild(id). It's a little thing, but we can save a function here too. If we see a call like this
Code:
if client:InGuild() then
...
with no argument, it's reasonable to assume that we're checking if the client is in any guild at all. On the other hand, if we see something like this
Code:
local guild_id = other:GetGuildID()
if client:InGuild(guild_id) then
...
it's reasonable to assume that we're checking if the client is in the guild of the given id. The less the user has to remember little distinctions between functions, and the less functions there are in total, the less they're going to be tripped up. There are lots of little examples like that -- anywhere the script system can combine similar functions without making things more obscure, it should.
Opportunistic Improvements
The other two are kind of about this as well: when you take the time to look at functions one by one and think about
how they're going to be used, it gives you a good chance to customize how the function is handled, to make it more sensible without sacrificing any functionality. At the same time, it also gives the chance for you to say "you know, this function should really do x, in case anyone ever wants to do y."
As an example, on my server I made the Damage functions ultimately return the final damage value caused to the target, so that this value could be returned to Lua when used in scripts. This allows for easy scripted lifetaps at any percentage of the dealt damage, or simple tracking of dealt damage for other purposes. Or, if you feel like disabling the standard AI melee and making an NPC's melee damage cycle purely script-based, you can detect when the NPC's attacks are dodged, parried, riposted, etc. Just a general functionality that should really be available to anyone who writes custom raid-level encounters.
Maybe we could go back and do most these things after auto-generating functions with a wrapper, but I think much of the impetus would be lost if the functions are already there and, in the worst case, by the time someone gets to working on it they'll run into that dreaded situation where they have to choose between making an improvement or maintaining compatibility with the scripts that have already been made. Maybe that could be avoided by just using modules to provide simplified function calls on the Lua side of things, but modules would be optional and, in the end, we'd still have a needlessly bloated, needlessly unfriendly base system. No good!
Maybe this is all dumb and I just don't know enough about how wrappers work. In any case I think it's probably clear that opening up content development is kind of my main area of interest ;p