|
chamenas Wizard
Joined: 26 Mar 2008 Posts: 1547
|
Posted: Tue Aug 31, 2010 5:26 pm
3.24 Unidentified Bug |
I'm looking for some help in ways that I might narrow down and identify a fairly egregious bug that has suddenly appeared in the latest versions of CMUD. My Clan Highlighter script uses an alias called "Updater" which runs through the who list and gathers pertinent information for its purposes. For all previous versions, this has worked just fine.
However, starting in 3.23 and definitely in 3.24, when I type "Updater" and let it run, CMUD crashes. It freezes up, and has only once given me an error, which was some sort of memory access error.
I don't even know where to begin looking in the Updater alias in order to isolate this issue since the entire program crashes whenever I try to run it. It usually gets through a few names first and then crashes completely.
I'll post the script at the end, and the game is Dark and Shattered Lands (dsl-mud.org), but I don't really expect anyone to honestly go through looking for what might be causing the problem. However, any help identifying that this isn't just happening to me, and possibly helping me to use my own skills to isolate this bug would be extraordinarily useful.
(script is too big to copy and paste here, apparently)
Clan Highlighter
Clan Highlighter Settings
As a side note, the problem is likely happening in the Gatherer trigger as opposed to the updater alias. But, as mentioned, I'm more than happy to find the problem with myself, tips on how I might isolate it would be more than helpful. The script is only posted up to see if others can replicate this odd behavior. |
|
|
|
oldguy2 Wizard
Joined: 17 Jun 2006 Posts: 1201
|
Posted: Tue Aug 31, 2010 10:44 pm |
Did you try running the Compatibility Report?
Code: |
Alias updater
Does not compile : illegal token: (%begins( "loner", %1)) { at row 299 col 14
Alias highlight
Does not compile : illegal token: (%begins( "rank", %1)) {#IF (@_highlight.rank) { at row 368 col 10
Trigger Highlight-t
Does not compile : illegal token: (%ismember( $_clan, _highlight.no)) {} at row 60 col 2
Alias edit
Does not compile : illegal token: (%ismember( %i, _list.class)) {$_type="class"} at row 211 col 23
String list should be enclosed in {} instead of "" : ="add|delete|restore|save"
Trigger Gatherer
Does not compile : illegal token: (%match( %trigger, "%/^\[\s?(\d+) ([\w\?]{3})\] (?:\(\w+\))?\(([\w ]+)\)(?:\s[\w '-]+)?\s+([\w'-]+)(?:\s+)?(?:\(Leader\))?(?: \(Recruiter\))?/%", $_lvl, $_class, $_clan, $_name)) { at row 124 col 2
Alias find
Does not compile : unmatched braces at row 120 col 0 |
I'd try to help you more but I have to say, and I don't want to sound rude, I can't even begin to understand what you are trying to do. Why do you have multiple stringlists of like 2000 items nested in a database variable and most of the stringlist is the same word just repeated hundreds of times? |
|
|
|
oldguy2 Wizard
Joined: 17 Jun 2006 Posts: 1201
|
Posted: Tue Aug 31, 2010 10:52 pm |
In fact the stringlist is so large it broke my post trying to post what it has. _char_rec.war has "...|war|peace|war|peace|war|war|peace|peace|peace|peace..." basically repeated like 5000 times.
|
|
|
|
chamenas Wizard
Joined: 26 Mar 2008 Posts: 1547
|
Posted: Tue Aug 31, 2010 11:11 pm |
How do I run a compatibility report? I'll keep it in mind for the future. Also, I'm not sure how any of those errors would exist in the new version but not have been problems before, it doesn't appear like any of the changes would have suddenly broken them. Nevertheless, I will fix it.
Anyways, the reason I have all of those database records with stringlists is because the script stores information on characters in the game, which it then uses to properly highlight and give information on them in the right moment. A lot of values repeat and seem unnecessary, but it's because the information is still specific to each character, and thus it is actually quite necessary.
_char_rec.name provides the unique, key identifiers for all of the entries. With each corresponding value (by number) in each other list being a paired link to that name.
Thus %item(%db(@_char_rec, name), 1) contains the name Dorigar
The information linked to Dorigar is that his clan (@_char_rec.clan) is Wargar, his level is 51, his class is Crusader, his Rank is Clansmen, and he is at War with my character.
That information is different from other characters, even if some values may be the same.
Yes, I could probably make a record variable with the keys being the names of the characters, and then have a stringlist of ordered values for their other info. It's just one way to attempt the solution. The way I came up with was made because it was the best I could come up with with the skills I had in scripting at the time.
Previously they were all separate stringlists, so I had a ton of stringlists with linked values. This way condenses them to one variable. |
|
|
|
chamenas Wizard
Joined: 26 Mar 2008 Posts: 1547
|
Posted: Tue Aug 31, 2010 11:13 pm |
Hmm, #BREAK is no longer supported? What am I supposed to use in place of it?
Edit:
Also, oddly enough, my Compatibility report didn't show any of those errors. It showed other ones, which I fixed. Also, going to the individual aliases and triggers and hitting "ctrl+k" gives me "No Errors" so I can't isolate those errors to fix them. Most of those appear to be formatting errors, which could have been something which screwed up when I pasted the XML into notepad. The XML was too large for me to paste into Crimson Editor (it crashed).
Still, I suspect it's the gatherer trigger, so I will look there as I attempt to solve this problem.
Edit2:
After a bit of testing, I believe the problem may lie in the size of the lists. I'm passing the variables by-reference, however, when I type updater, there is a pronounced lag of up to 5 seconds before the who list shows up. The who list then, sometimes, lags as it displays members. And then, eventually, as it gets down the list, CMUD freezes up and crashes. There doesn't seem to be any specific event in the list which is causing this, and the fact that the one time there was an error referenced memory, leads me to believe that it's literally just running into a problem trying to update lists that literally have over 2k members. Remember that it's going through a record variable with 6 keys, each containing stringlist values with 2342 members each. Perhaps that's simply too large for CMUD? Of course, it worked before, so it would have to somehow be related to the changes that have been made.
I know that the way stringlists were enclosed has been changed, but none of those errors should exist in the script anymore, so I'm wondering what else might be the cause... |
|
|
|
oldguy2 Wizard
Joined: 17 Jun 2006 Posts: 1201
|
Posted: Tue Aug 31, 2010 11:40 pm |
Okay I found an alias you have to show list size. This is what it printed:
Code: |
@_char_rec.name: 2342
@_char_rec.clan: 2342
@_char_rec.class: 2342
@_char_rec.lvl: 2342
@_char_rec.rank: 2342
@_char_rec.war: 2342 |
The string lists of 2300+ items are just repeating values over and over and over.
I think I kind of understand what you are doing here except I still don't understand the way you are doing it. You've got two database variables holding the same thing it looks like. Also I am looking at your code and I am going to assume you are storing and retrieving data based on item number so one record is like the following:
Code: |
%item(_char_rec.name,1) and %item(_char_rec.war,1) and so on? |
So the guy in item 1 corresponds to all the other string lists item 1.
Wouldn't a much better way be to use the person's name as the key and then for the value use a nested db like the following?
Code: |
testDb.Dorigar = {war=0|lvl=51|rank=Clansmen|clan=Wargar|class=Crusader} |
For the war, this is basically true of false right? Why use war = war or peace. Obviously if "!@testDb.Dorigar.war" then it's peace!
Then to retrieve data you can simply just do:
Code: |
#print @testDb.Dorigar.rank |
This outputs "Clansmen".
To update is just as easy:
Code: |
testDb.Dorigar.rank = "Swashbuckler" |
In fact by looking at your code, from what I can even understand, you are looping through _char_rec.name until you find the name then having to lookup the other values based on the same item number. This seems like it would be so entirely slow when you could be directly accessing the values and not looping through 2000+ lists multiple times. Instead of 50 lines of code to make a simple update to a record it would take 4-5.
Additionally it is extremely hard to read your code with the thousands of underscores everyplace. Why do _char_rec when charRec or characterRecord is much more readable. You have underscores on every single variable even local ones for no reason like $_iter. |
|
|
|
oldguy2 Wizard
Joined: 17 Jun 2006 Posts: 1201
|
Posted: Tue Aug 31, 2010 11:44 pm |
chamenas wrote: |
How do I run a compatibility report? I'll keep it in mind for the future. Also, I'm not sure how any of those errors would exist in the new version but not have been problems before, it doesn't appear like any of the changes would have suddenly broken them. Nevertheless, I will fix it.
Anyways, the reason I have all of those database records with stringlists is because the script stores information on characters in the game, which it then uses to properly highlight and give information on them in the right moment. A lot of values repeat and seem unnecessary, but it's because the information is still specific to each character, and thus it is actually quite necessary.
_char_rec.name provides the unique, key identifiers for all of the entries. With each corresponding value (by number) in each other list being a paired link to that name.
Thus %item(%db(@_char_rec, name), 1) contains the name Dorigar
The information linked to Dorigar is that his clan (@_char_rec.clan) is Wargar, his level is 51, his class is Crusader, his Rank is Clansmen, and he is at War with my character.
That information is different from other characters, even if some values may be the same.
Yes, I could probably make a record variable with the keys being the names of the characters, and then have a stringlist of ordered values for their other info. It's just one way to attempt the solution. The way I came up with was made because it was the best I could come up with with the skills I had in scripting at the time.
Previously they were all separate stringlists, so I had a ton of stringlists with linked values. This way condenses them to one variable. |
Right. See my above post. |
|
|
|
oldguy2 Wizard
Joined: 17 Jun 2006 Posts: 1201
|
Posted: Tue Aug 31, 2010 11:49 pm |
Quote: |
How do I run a compatibility report? |
It's under the File menu. |
|
|
|
chamenas Wizard
Joined: 26 Mar 2008 Posts: 1547
|
Posted: Tue Aug 31, 2010 11:52 pm |
Yeah, your above post came after mine
But you do bring up an interesting point in that I'm having to loop through a massive list just to get the numbers needed to begin updating things. Which makes a fairly convincing argument for overhauling how my script works yet again (yay) since I've learned a lot more since the last time I updated it.
However, what is odd to me is that this script works just fine, with no noticeable speed issues in 3.22 and earlier. What's different about 3.23 and 3.24 that suddenly speed has become an issue. |
|
|
|
oldguy2 Wizard
Joined: 17 Jun 2006 Posts: 1201
|
Posted: Tue Aug 31, 2010 11:57 pm |
Also you should really use #PRINT instead of #SHOW to display messages. You have tons of lines of #SHOW to display simple messages. #PRINT bypasses triggers and will be much faster. That's what it is for.
|
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Wed Sep 01, 2010 4:36 pm |
#BREAK is still supported. It gets flagged in the Compatibility report because the #break command in zMUD was completely different.
|
|
|
|
chamenas Wizard
Joined: 26 Mar 2008 Posts: 1547
|
Posted: Wed Sep 01, 2010 5:47 pm |
My plan right now is to change how the script works with the variables (moving it to one variable with the key value and then the values containing a record of all the values pertinent to them. After that conversion has worked out I will test it, and see if it still crashes.
Thanks Zugg, I was worried there. I'll put it back in! :P |
|
|
|
Derar Novice
Joined: 09 Sep 2006 Posts: 44
|
Posted: Wed Sep 01, 2010 8:17 pm |
If you're getting into doing a complete rehash, might I suggest looking at a separate SQLite database to store all your data?
An SQL database is perfect for the kind of volume of data you're dealing with here, and will probably result in overall performance boost for most of your tasks, not to mention an increased flexibility in what you do with the data for the future.
Just as an example of what I mean, in your present configuration, or even in a rehash where each record is tied to a Character Name key, suppose you wanted to output all the names of players in Wargar.
Either method as mentioned so far would require you to loop through all the records and test each to see if Clan is Wargar or not:
Currently:
Code: |
#LOOP 1,%numitems(@_char_rec.clan) {
#IF (%item(@_char_rec.clan, %i) = "Wargar") {
#PRINT %item(@_char_rec.name, %i)
}
}
|
Redone with Character Name keys:
Code: |
#LOOPDB @_char_rec {
#IF (%val.Clan = "Wargar") {
#PRINT %key
}
}
|
With SQL, it would be something like this:
Code: |
#SQLDB charDB
$sql = "SELECT Name FROM _char_rec WHERE Clan = 'Wargar'"
$db = %sql(charDB, $sql)
#WHILE !$db.Eof() {
#PRINT $db.Item("Name")
#CALL $db.Next
}
|
So, you wind up with a couple of extra lines of code, but a serious performance improvement. The first two will each loop 2342 times. The SQL version loops 146 times. Hell, to find out that you have 146 Wargar members you would need to loop 2342 times - with SQL you wouldn't need to loop even once:
Code: |
#SQLDB charDB
$sql = "SELECT Count(*) AS Counter FROM _char_rec WHERE Clan = 'Wargar'"
$db = %sql(charDB, $sql)
#PRINT $db.Item("Counter")
|
Just some food for thought. :) I converted my level history storage script to use an SQLite database file with it, and it's probably the best move I ever made with it - the speed that stuff pulls up and displays for me now floored me the first few times I saw it, compared to what I had before. |
|
|
|
chamenas Wizard
Joined: 26 Mar 2008 Posts: 1547
|
Posted: Thu Sep 02, 2010 12:22 am |
It's a thought. I had wanted to use a database from the get-go. The problem is that databases remain beyond my knowledge, and I would be edging into a pond of something I've never encountered before. I'm afraid of getting in too deep and screwing everything up.
There's also the question of how it transports to other CMUDs? I make this script to be user friendly because I share it with other Mudders who are not as script savvy as I. One of the reasons I have two classes for this script is so that they can update the script without changing their settings. How would that work if I used a database, and would they have to do any sort of setting it up aside from installing the script? That's all they have to do now and I'm loathe to expect them to do much more than import an XML file. |
|
|
|
chamenas Wizard
Joined: 26 Mar 2008 Posts: 1547
|
Posted: Thu Sep 02, 2010 1:04 am |
These lines alone caused it to crash:
Code: |
#LOOP %numitems( @_char_rec.name) {
$name=%item( @_char_rec.name, %i)
$val=%concat( "{lvl=", %item( @_char_rec.lvl, %i), "|")
$val=%concat( $val, "rank=", %item( @_char_rec.rank, %i), "|")
$val=%concat( $val, "clan=", %item( @_char_rec.clan, %i), "|")
$val=%concat( $val, "class=", %item( @_char_rec.class, %i), "|")
$val=%concat( $val, "war=", %if( %item( @_char_rec.war, %i)="war", 1, 0), "}")
#ADDKEY char_rec $name $val
}
|
Those lines are meant for me to transfer all of my old data to the new variable. As doing it by hand would take waaaaaaaay too long. This really makes me suspect that CMUD is simply having a problem with the size of the lists.
Edit:
Just some confirmation:
Code: |
#LOCAL $Cname
$Cname=%item( @_char_rec.name, 1)
$val=%concat( "{lvl=", %item( @_char_rec.lvl, 1), "|")
$val=%concat( $val, "rank=", %item( @_char_rec.rank, 1), "|")
$val=%concat( $val, "clan=", %item( @_char_rec.clan, 1), "|")
$val=%concat( $val, "class=", %item( @_char_rec.class, 1), "|")
$val=%concat( $val, "war=", %if( %item( @_char_rec.war, 1)="war", 1, 0), "}")
#ADDKEY char_rec $Cname $val
|
Worked just fine. |
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Thu Sep 02, 2010 2:32 am |
if your @_char_rec.name variable is large, then you need to get rid of the @ and start using the newer "by reference". Every time you use the @ sign CMUD is making a *copy* of your entire string list. And it's doing this each time through the list. Also, each reference to $val in your %concat is also making a copy of the list.
Next, you are using the old method of creating a string list from a string value with | characters. That is horribly inefficient. Here is what you *should* be doing now:
Code: |
#LOOP %numitems( _char_rec.name) {
$name=%item( _char_rec.name, %i)
$val = ""
#ADDKEY $val lvl %item( _char_rec.lvl, %i)
#ADDKEY $val rank %item( _char_rec.rank, %i)
#ADDKEY $val clan %item( _char_rec.clan, %i)
#ADDKEY $val class %item( _char_rec.class, %i)
#ADDKEY $val war %if( %item( _char_rec.war, %i)="war", 1, 0)
#ADDKEY char_rec $name $val
} |
Note that all of the %item calls use the name of the variable (_char_rec) *without* the @ sign. That prevents a copy from being made. Then, it uses the #ADDKEY properly to create a nested database variable within $val instead of using %concat. This should be a *lot* faster and use a lot less memory.
If CMUD has trouble with using the by-reference of _char_rec.lvl directly, then you can try replacing it with %db( _char_rec, lvl). Also, hopefully CMUD doesn't have any trouble with the variable starting with the _ character. Haven't tested that in the "by reference" code.
But this is a good example for *everybody* out there...stop building string lists and database variables as strings. Use #ADDKEY, %addkey, #ADDITEM, %additem, etc. Use the commands/functions for what they were made for. |
|
|
|
chamenas Wizard
Joined: 26 Mar 2008 Posts: 1547
|
Posted: Thu Sep 02, 2010 2:50 am |
Hmm, the things you mention are definitely specific to the code I posted and I apologize for the sloppiness there. I posted it because I believed that the large size of my multiple, paired stringlists, was causing CMUD to freeze up. The code posted seemed to confirm that it might indeed be a size issue, though the fact that I didn't use the "by reference" meant it made a copy which would make it unnecessarily bigger.
However, I came to post because I just converted everything to the new method. AKA, instead of using one database variable with each key representing a stringlist of some 2300+ items (with 6 keys), I converted it to one database variable with 2300+ keys, with each key containing a value which was a mini-record variable containing data important to the character (which is the key).
This new setup doesn't crash in CMUD 2.25 like the other setup. Which makes me strongly suspect that the original bug has something to do with my script exceeding some sort of memory threshold in CMUD.
In any case, your post is still quite informative for my new setup, Zugg, and I'll put it to use. Thanks.
Now I have to get to converting the rest of the script to work off of my variable changes though. |
|
|
|
Derar Novice
Joined: 09 Sep 2006 Posts: 44
|
Posted: Thu Sep 02, 2010 4:23 am |
chamenas wrote: |
It's a thought. I had wanted to use a database from the get-go. The problem is that databases remain beyond my knowledge, and I would be edging into a pond of something I've never encountered before. I'm afraid of getting in too deep and screwing everything up. |
There's a definite learning curve to SQL if you've never dealt with it before, but in general, it's actually a pretty simple language. There are a lot of in-depth elements to it that, for the most part, you don't really need to worry about. The SQLite website has a pretty solid set of pages for SQL syntax. A lot of it is trial and error, as with any "programming" language. You can also use an application to work with the DB file(s) outside of CMud, such as SQL Expert. This is a great way to just experiment and see what you can do.
Involving the SQL in CMud is disgustingly easy. '#SQLDB <dbname>' to either create a new file or open an existing db file, and '%sql(<dbname>, <query>)' to work with it using '#CALL' or '$var ='. This post covers the CMud side of things.
Quote: |
There's also the question of how it transports to other CMUDs? I make this script to be user friendly because I share it with other Mudders who are not as script savvy as I. One of the reasons I have two classes for this script is so that they can update the script without changing their settings. How would that work if I used a database, and would they have to do any sort of setting it up aside from installing the script? That's all they have to do now and I'm loathe to expect them to do much more than import an XML file. |
My assumption here is that when you are sending out the script, you are *not* sending the existing _char_rec settings with it. I assume this since peoples' war/peace status at the least will vary. It's fairly simple to craft the script so that it will create an SQLite Database file and create the required tables if such does not already exist, and from there the script can populate the data at will. From an end-user standpoint, nothing would/should change. Effectively, the database would ideally replace the "Settings" package, and any 'Control' settings would be included with the main package. You would ship one file instead of two. |
|
|
|
chamenas Wizard
Joined: 26 Mar 2008 Posts: 1547
|
Posted: Thu Sep 02, 2010 4:51 am |
Well, control settings remain in the separate class, since there's a lot of settings in there which are still set by the user that I wouldn't want to reset on them either. I'd still ship "two" packages, it's just that this additional file will be created if it's not there, or will be updated if it is. Which, by your description, is how it works. That's fine, and will still make it easy to transport the script.
Right now I'm going to push forward with my current overhaul, as described earlier, simply because I want to get it working asap. Once I finish with the current overhaul, I can begin looking at the SQL side of things and then possibly doing another overhaul to update the script for SQL. It's a lot more work for me, but at least I'll have a functioning script while I work on learning the SQL stuff. |
|
|
|
|
|
|
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
|
|