[crossfire] requestable spell lists.
Mark Wedel
mwedel at sonic.net
Fri Dec 16 19:25:32 CST 2005
Brendan Lally wrote:
>> I just don't really see what we get by having to do it via a purely request
>> basis. I can't really see the client not sending a request when things change.
>
> I can, that's why I started off with the status values. If a client
> only shows spell names, or only names and denied status, they would
> only request a new copy of the list on status 4 or 4 & 2 respectively.
>
>> If there is the potential of client only sending requestinfo based on what
>> changed, that could also be done with a push approach (setup spellmon val, and
>> based on val determines what events we send spell updates.
>
> This could work, but requires a new command in the protocol.
I don't know why it would require a new command. the setup command is not
true/false values, it is setting some variable to whatever value.
So a 'setup spellmon 6' is perfectly valid.
And to push the data, the same command could be used - it'd just need to be
clarified that spellist would represent updates to existing data. Or the
spellist command could send optional params to denote what it is updating.
>
>> the other advantage of push is we can be more bandwidth efficient. If a
>> player learns a new spell, only need to send that spell down the line, and not
>> all the spells if done on a pull approach.
>
> I thought about that, but I can't see how it can be done without the
> server storing the spell list for each player, which is a fairly ugly
> way to implement things. (the only other thing I could think of is to
> abuse the spell objects, and set an update value for each one (added,
> removed, changed costs, changed damage, etc)
Same way it is done for most objects - you send it at the time of the event.
So in server/apply.c, in learn_spell, you'd make a call to send_spellist()
when the player learns a spell.
This is how most all of the object updates for player inventory are currently
done - the update is sent in the code that makes the change - we don't hold the
results and send them later.
>
>> 2) I wonder if more spell info should be sent. For example, base damage values,
>> lore information, etc. If we only send spells on push, bandwidth shouldn't be
>> that costly, and it then gives the player more info to choose spells (fireball,
>> 24 dam, ...).
>
> Lore and damage seem reasonable, although then the question is, should
> that be base damage or effective damage? Both of these values have
> issues, effective damage may not do as much damage as stated (even
> before resistance) owing to quirks in how each spell propagates, if
> base damage is sent, then you need to send a lot more data and
> hardcode the calculation. (more on that below)
For damage, we obviously can't take into account resistances of creatures. So
it'd be basic damage - if the spell does more, like cones, because of multiple
effects on top of each other, we don't factor that, as you can't really know for
sure how that will work out (likewise for fireballs - damage would vary greatly
based on where the creature is in the effect). The lore info could note those
increased effects.
>
>> Related, I think it'd be easier all around to send the spell path
>> information as a bitmask - saves some bandwidth, and the bitmasks values should
>> be pretty stable (can't remember last time a new spell path was added, and even
>> then, the client could just display something like 'unknown' or whatever)
>
> This could work, although currently the clients have no information
> about spellpaths.
> This could be added, although maybe then a request_info spellpaths
> would be better to initialise it? (this way clients couldn't fall out
> of sync, and there is no restriction on adding new paths).
Perhaps, adding requesting adds complication, but not that much. At the same
time, there is a lot of communication that is defined stable. IF someone were
to add another stat for example, that would require some significant changes -
the client isn't designed for dynamic stat information.
At some level, it could be nice for the server to somehow note what current
client version is and tell the player if their client is out of date. So if the
client is out of date, they'd know to go update it - that'd be good for reasons
beyond just spellpaths.
But hardcoding them or doing via requestinfo both work. Note of course the
spell path info in this case is really the bitmask to name mapping. For all
spell calculations itself, the client wouldn't really care (player bitmask is
attuned 4, denied 24, repelled 1. This spells path is 16, so it is denied to
the player, etc). It doesn't need to know what spell path 16 is to make those
calculations.
But that is one reason why I say giving the client hte numbers is easier - it
makes handling easier. Otherwise, what I'm sure will happen is at some point
someone will come up with code in the client that takes the spellpaths and
converts them into bitmasks, etc.
If I've learned one thing through lots of client/server programming, almost
always best to send the raw data and let the client figure out what it means vs
having the server try to figure out what it thinks the data should look like and
send that processed data to the client.
>
>> 3) Related to point #2, I wonder if it would be 'easier' to just send the base
>> values for costs that the server users to calculate real cost.
>
> more consistant in terms of data sent in a single iteration. but
> SP_level_spellpoint_cost - the function that does this server side,
> calls on about half a dozen other values, all of which the client
> would need to know, and some of which
> (settings.spellpoint_level_depend for example) are quite obscure. If
> ever the method used to calculate cost changed, then this would fail
> hopelessly. I don't think a commitment to keep the same spell costing
> rate can be made, therefore hardcoding it into clients is a bad idea.
well, settings.spellpoint_level_depend determines if spellpoint costs differ -
it is either an on/off value.
Looking at other values:
Since the spell is linked to a skill, the client does know the skill level.
The client also will know the spell level (one of the most importent bits of
the spell).
As per notes above, it would also know the spell paths.
To figure out actual sp costs, it would need the sp/maxsp and grace/maxgrace
values.
the PATH_SP_MULT macro is perhaps the most variable. However, since that
macro has values hard coded in (not pulling it from settings or anyplace else),
probably relatively hard coded.
All that said, one could see something like a C->S: requestinfo spell_conf,
in which the server responds with those values. But that does make things more
complicated. But I don't think those values have changed in 5+ years, so I'd
call them relatively stable also.
>
>> Otherwise, whenever the player equips an item that changes their spellpaths,
>> you get the case of potentially all the spells changing in value. Level changes
>> can also effect costs, and that is likely to happen when you really don't want
>> more data sent down, eg, in combat.
>
> This would be where the logic behind letting the client decide when to
> request the information comes into play.
But I don't really see how the client can make any real intelligent decision
on that. It would basically seem to me that the client will request a spell
dump if the spells have changed and it matches why it wants updates.
I can't see the client really being able to know that the player is in combat
and thus now is a bad time to request all that data.
I'd think at best the client could perhaps decide 'at most, I'll request spell
info every 10 seconds' or something. But then you'll get the case where a
player equips something that makes them attuned, goes to cast the spell, and is
confused because the client is still showing old data in terms of spell cost and
damage.
This may seem trivial, but when it happens, I'm sure bugs will be filed and
people complain.
>
>> The only change needed for that to really
>> work would be to send down the players current spellpaths in the stats command.
>
> This seems like quite a good idea, it is simpler and yet more powerful
> than the status I have been using.
>
>> Thus, the only time in this case you really need to send spell information is
>> when the player learns a new spell. That said, it does complicate the client a bit.
>
> I'm more concerned with how it complicates the server, it will mean
> that each spell will need to track its status independently.
See note above. You'd just inject the appropriate send spell data command
wherever the player can learn a spell. And in fact, the number of places a
player can learn a spell is limited- in fact, I think it all leads back to
do_learn_spell(), and all the data that is needed to send the data to the client
is there (player object, spell object, etc).
>
> It might be possible to pick an unused value in the spell objects, and
> use this to hold states, and then iterate over them with a diff like
> syntax.
>
> so we might have
>
> spellupdate
> !spark shower:1:176:Electricity:0:5:0:Sparkshower is a cone of
> electrical energy.
> Creatures caught within the cone take magical and electrical damage.
> +holy word:1:170:Turning:0:0:4::
> -burning hands:1:174:Fire:1:4:0::
> (icidentally, these last two do not have msg's)
>
> In this case then, every line altering a spell would start with + - or
> ! to add, remove or modify a spell respectively, any line not starting
> with one of these characters, would be the next line of the msg
> associated with the previous spell.
>
> This could still lead to a lot of traffic at login, although maybe
> that is preferable than a lot of traffic during combat.
Right now, I believe it is basically a requirement that spell names be unique.
This, it can be assumed (within the protocol) that if a spellupdate contains a
spell name that the client already knows about, it is just and update for that
spell. If it contains info it doesn't know about, it is a new spell.
Right now, other than DM action, there is no way to lose a spell. But for
that, might just be easiest to do something like 'spellremove ....', and just
like do_learn_spell() being the only place to add a spell, the only place to
remove a spell is probably just a few places so wouldn't be hard to do.
In terms of bandwidth, I wonder if it is reasonable to do some form of caching
of the message info, eg, the client have a spell file that contains the info it
got. Instead of the server sending the message text each time, it sends a
checksum of the message data. The client could load the spell up from its
history file and see if the checksum match - if so, use the one in the history
file, if not, request info from server.
More information about the crossfire
mailing list