View previous topic :: View next topic |
Author |
Message |
Fireboar
Joined: 17 Feb 2008 Posts: 323
|
Posted: Sat Feb 07, 2009 14:45 Post subject: |
|
|
Hey, that's a great idea.
Just some clarification: is Ruby a viable replacement for NWScript, if you use it to call custom methods (such as onmodheartbeat) from preloaded scripts? Or is it better used only for more complex methods and objects? I'm thinking also in terms of reducing the overall module size and the number of scripts that have to be loaded in the toolset. |
|
Back to top |
|
|
JeffSheets
Joined: 04 Feb 2009 Posts: 18
|
Posted: Sat Feb 07, 2009 19:08 Post subject: |
|
|
Fireboar wrote: | Just some clarification: is Ruby a viable replacement for NWScript, if you use it to call custom methods (such as onmodheartbeat) from preloaded scripts? Or is it better used only for more complex methods and objects? I'm thinking also in terms of reducing the overall module size and the number of scripts that have to be loaded in the toolset. |
As far as speed is concerned, I'm not sure... but the way I'm using ruby, I'm sure I'll find out if I ever get my PW to a presentable state.
If you make extensive use of tag based item scripting you'll gain some module space there, just from not having all of those tag scripts in the module. One major headache for tag items is that the spell cast at event isn't routed through a single spot, so you have to modify every spell that makes use of it, and the include file that the tag script calling function for that event hides in. If you spread the tag based concept to other systems you can do even more pruning of NWScripts. Script memory footprint can benefit from using ruby too, since ruby keeps only one copy of a ruby module or class function around (unless you do some special stuff to them), whereas NWScript includes get mixed in over and over in scripts. I.e. using NWScript only, there would be an excessive number of SetPersistentString definitions in just about anyone's code, while with ruby, there's only one definition. It's also possible that the NWN script cache may be able to relax a bit, especially the more you use ruby tag systems. That last bit is really just a guess, though, and ruby's execution speed may negate that benefit, or even turn it into a negative.
I'm also using it for my (currently very bare bones) chat command scripts. This is a really nice part because separating out command parameters is as simple as using .split(" ") on the string. In fact ALL of the text processing power of Ruby is available.
Other nwnx systems are just as available... just use the same Set/GetLocalString/Object calls that are used in NWScript. I've converted over what I need from the fb_inc_database script and make use of the nwnx_reset command directly, other systems would be just as easy to convert, and you can put them in modules to keep things neat and tidy.
I think it's worth it to convert a great majority of the system over to ruby. You can make use of classes, modules, singletons (that, say, always act on OBJECT_SELF). You can put Ruby scripts in local strings on your objects and evaluate them there. You can even generate code on the fly and eval it as needed.
Another MAJOR benefit of ruby is the sweetest of all... its ability to reload definitions. With a little bit of work, I've created a preload system that allows me to reload all ruby scripts... after, of course, checking out the latest version of my module and ruby scripts from my Subversion repository. If a revision only makes changes to Ruby, this means I don't have to reset the server to gain the benefits... The change occurs immediately. Of course, if I need to do a reset, I can, and my watchdog script automatically checks out the latest revision and rebuilds my module using erf.linux.
I plan to create a DM ticket system that can track and maintain DM requests and user reports. I'll be doing pretty much that entire system in ruby.
I also plan to use ruby for a magic item system that will combine socketed items, items that improve based on class and/or character level, and item set bonuses. I'm working on that right now, going through and creating a ruby class that can be used to both specify and apply item properties, accumulating each ip along the way and staying within the limits when applied.
There are, however, some limitations.
DelayCommand doesn't work, so anything you put a delay on will need to be in NWScript. Of course... you can just put a delay on a RubyEval call.
AssignCommand doesn't work, though, depending on what you're doing, that can be worked around using an argument on your methods; OBJECT_SELF with a default of $OBJECT_SELF (the global accessor for OBJECT_SELF). If you then want that ruby method to be run on something other than OBJECT_SELF, you actually provide the argument. This technique, however, cannot be used to actually change the OBJECT_SELF value... for that you will need to call back into NWScript.
ExecuteScript seems... buggy to me. At least it crashed my server when I tried it the first time, but that could be any number of other things I've done. Of course, you could set a local string on the object you want to call the script on and check for that after your RubyEval returns.
There may be other limitations... I've only been working with Ruby for under a week now. (Ruby entirely... this is the first time I have touched ruby... I would've LOVED nwnx_lua. ) |
|
Back to top |
|
|
Fireboar
Joined: 17 Feb 2008 Posts: 323
|
Posted: Sun Feb 08, 2009 14:34 Post subject: |
|
|
Same with me - this is my first dabble in Ruby, and I'm hoping to build my PW around it. I guess the things that don't work just mean one has to find a different way of doing things.
You say AssignCommand doesn't work. What about the Action... methods? Do they work? Also, how does changing the self variable work? Is it as simple as this?
Code: | SpeakString("Hi", TALKVOLUME_TALK, oObject) |
|
|
Back to top |
|
|
JeffSheets
Joined: 04 Feb 2009 Posts: 18
|
Posted: Sun Feb 08, 2009 18:02 Post subject: |
|
|
Fireboar wrote: | Same with me - this is my first dabble in Ruby, and I'm hoping to build my PW around it. I guess the things that don't work just mean one has to find a different way of doing things.
You say AssignCommand doesn't work. What about the Action... methods? Do they work? Also, how does changing the self variable work? Is it as simple as this?
Code: | SpeakString("Hi", TALKVOLUME_TALK, oObject) |
|
Most of the Action... commands work, but there is no way to change what object they run on, because the "action" psuedo type of NWScript is either not currently implemented in ruby, or isn't capable of being implemented. Here's the interesting thing... at the moment, if you did use that SpeakString code above, it would completely ignore the third argument, and would run on whatever $OBJECT_SELF resolves to in ruby. The VALUE self in the functions in ruby_int.c is a different concept than OBJECT_SELF of NWScript.
After looking around, Here are the function definitions in ruby_int.c that specify that they have errors:
AssignCommand
DelayCommand
ActionDoCommand
SignalEvent
EventUserDefined
EventSpellCastAt
EventConversation
EventActivateItem
TalentSpell
TalentFeat
TalentSkill
GetCreatureHasTalent
GetCreatureTalentRandom
GetCreatureTalentBest
ActionUseTalentOnObject
ActionUseTalentOnLocation
GetIsTalentValid
GetIdFromTalent
GetTypeFromTalent
What this means is that the action, talent, and event data types from NWScript have not yet been converted to ruby. You'd have to ask Virusman if they can be converted and if they will. But what this really means is four major things:
No ability to change OBJECT_SELF, since AssignCommand doesn't work.
No Delayed Commands in ruby.
No Cutscenes in ruby.
No Artificial Intelligence scripts in ruby.
You could work around the delayed commands if you don't need perfect timing, just set up a system to run a priority queue of ruby methods on heartbeat. It'll check once every 6 seconds and would probably be good enough for everything but cutscenes. |
|
Back to top |
|
|
virusman
Joined: 30 Jan 2005 Posts: 1020 Location: Russia
|
Posted: Sun Feb 08, 2009 19:29 Post subject: |
|
|
Functions with "action" parameters (DoCommand, AssignCommand, DelayCommand) can't be exposed to NWNX Ruby because the "action" parameter is actually a pointer to NWScript bytecode.
And thanks for the list of broken functions - I'll check them when I have time. |
|
Back to top |
|
|
JeffSheets
Joined: 04 Feb 2009 Posts: 18
|
Posted: Sun Feb 08, 2009 20:14 Post subject: |
|
|
virusman wrote: | Functions with "action" parameters (DoCommand, AssignCommand, DelayCommand) can't be exposed to NWNX Ruby because the "action" parameter is actually a pointer to NWScript bytecode.
And thanks for the list of broken functions - I'll check them when I have time. |
Would it be possible to build custom NWScript bytecode that does an immediate call back into nwnx_ruby?
I'm not familiar with the C API of ruby, but maybe you could store a method and self to execute in some structure, then construct some bytecode to SetLocalInt on the module at say, NWNX!RUBY!CALLBACK, passing the id of the method/self pair, then have the ruby code look it up and execute it, removing the method/self pair from the structure when done. |
|
Back to top |
|
|
virusman
Joined: 30 Jan 2005 Posts: 1020 Location: Russia
|
Posted: Sun Feb 08, 2009 20:47 Post subject: |
|
|
JeffSheets wrote: | Would it be possible to build custom NWScript bytecode that does an immediate call back into nwnx_ruby?
I'm not familiar with the C API of ruby, but maybe you could store a method and self to execute in some structure, then construct some bytecode to SetLocalInt on the module at say, NWNX!RUBY!CALLBACK, passing the id of the method/self pair, then have the ruby code look it up and execute it, removing the method/self pair from the structure when done. | Yes, that's what I thought too, but this workaround is too complex. |
|
Back to top |
|
|
JeffSheets
Joined: 04 Feb 2009 Posts: 18
|
Posted: Sun Feb 08, 2009 20:51 Post subject: |
|
|
virusman wrote: | JeffSheets wrote: | Would it be possible to build custom NWScript bytecode that does an immediate call back into nwnx_ruby?
I'm not familiar with the C API of ruby, but maybe you could store a method and self to execute in some structure, then construct some bytecode to SetLocalInt on the module at say, NWNX!RUBY!CALLBACK, passing the id of the method/self pair, then have the ruby code look it up and execute it, removing the method/self pair from the structure when done. | Yes, that's what I thought too, but this workaround is too complex. |
If it's complexity on the ruby side, I'd be happy to take a stab at it... if it's complexity on the NWN side... well, then that sucks. :/ |
|
Back to top |
|
|
Fireboar
Joined: 17 Feb 2008 Posts: 323
|
Posted: Sun Feb 08, 2009 21:37 Post subject: |
|
|
I guess that's inevitable, since Ruby is interpreted and not compiled. That's a real drawback though... I guess a mix of NWScript and Ruby is the way to go. |
|
Back to top |
|
|
JeffSheets
Joined: 04 Feb 2009 Posts: 18
|
Posted: Sun Feb 08, 2009 23:37 Post subject: |
|
|
virusman wrote: | JeffSheets wrote: | Would it be possible to build custom NWScript bytecode that does an immediate call back into nwnx_ruby?
I'm not familiar with the C API of ruby, but maybe you could store a method and self to execute in some structure, then construct some bytecode to SetLocalInt on the module at say, NWNX!RUBY!CALLBACK, passing the id of the method/self pair, then have the ruby code look it up and execute it, removing the method/self pair from the structure when done. | Yes, that's what I thought too, but this workaround is too complex. |
Also, it seems that the Item Property Code is incorrect... I am getting a Stack underflow on calling GetFirstItemProperty. A look at the code in ruby_int.c shows that the function is using the Effect structure, which might be what is causing the problem if Item Props use a different structure. I might do a little research of my own...
Virusman, can you recommend any tools for looking at the linux server's internals? |
|
Back to top |
|
|
virusman
Joined: 30 Jan 2005 Posts: 1020 Location: Russia
|
Posted: Sun Feb 08, 2009 23:55 Post subject: |
|
|
JeffSheets wrote: | Virusman, can you recommend any tools for looking at the linux server's internals? | IDA.
JeffSheets wrote: | If it's complexity on the ruby side, I'd be happy to take a stab at it... if it's complexity on the NWN side... well, then that sucks. :/ | Complexity = a considerable amount of time is needed to make this work.
Last edited by virusman on Sun Feb 08, 2009 23:59; edited 1 time in total |
|
Back to top |
|
|
virusman
Joined: 30 Jan 2005 Posts: 1020 Location: Russia
|
Posted: Mon Feb 09, 2009 0:39 Post subject: |
|
|
A ticket has been created:
http://nwn.virusman.ru/trac/nwnx2-linux/ticket/5
You can register on Trac, add your email address to your profile and subscribe to updates by adding your username to the "Cc:" field. |
|
Back to top |
|
|
JeffSheets
Joined: 04 Feb 2009 Posts: 18
|
Posted: Mon Feb 09, 2009 4:01 Post subject: |
|
|
Cool. I've done so. I'm also going through and seeing if I can't fix the Item Property related functions myself. From what I can see in the nwserver disassembly, it seems it should be using ENGINE_STRUCTURE_ITEMPROPERTY instead of *EFFECT. Thus, I'm switching everything over to void pointers and the different constant for the Pop and Push engine structure calls. If it works I'll post a patch. |
|
Back to top |
|
|
JeffSheets
Joined: 04 Feb 2009 Posts: 18
|
Posted: Mon Feb 09, 2009 4:23 Post subject: |
|
|
JeffSheets wrote: | If it works I'll post a patch. |
It worked perfectly. Virusman... if you give me write access to the svn repo, I'll simply commit a fix, otherwise I'll post a diff or patch here tomorrow. Still want to test the hell out of this... |
|
Back to top |
|
|
JeffSheets
Joined: 04 Feb 2009 Posts: 18
|
Posted: Mon Feb 09, 2009 10:54 Post subject: |
|
|
JeffSheets wrote: | JeffSheets wrote: | If it works I'll post a patch. |
It worked perfectly. Virusman... if you give me write access to the svn repo, I'll simply commit a fix, otherwise I'll post a diff or patch here tomorrow. Still want to test the hell out of this... |
I'm convinced that my changes are bug-free. If anyone wants a copy of my changes (as a gzipped output of svn diff ruby_int.c), send me a PM.
My changes include my change to GetLocalString to prevent a crash when the local string is undefined, as well as the changes needed to make ItemProperty functions work. |
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|