Register forum user name Search FAQ

Gammon Forum

Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to verify your details, confirm your email, resolve issues, making threats, or asking for money, are spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the password reset link.
 Entire forum ➜ MUSHclient ➜ Lua ➜ External Variables?

External Variables?

It is now over 60 days since the last post. This thread is closed.     Refresh page


Posted by Tiopon   USA  (71 posts)  Bio
Date Thu 26 Feb 2009 02:54 AM (UTC)
Message
Anyone know an easy way to have the variables save to an external file? I'm using a bit of lua scripting to save/load variables, but would prefer them to be saved outside of the world, given the choice, so that if my laptop loses power or some such chaos happens, I don't lose my most updated version of my variables... Thanks.
Top

Posted by Nick Gammon   Australia  (23,102 posts)  Bio   Forum Administrator
Date Reply #1 on Thu 26 Feb 2009 04:19 AM (UTC)
Message
See: http://www.gammon.com.au/forum/?id=4960

Particularly the examples near the bottom. They are for plugin state files, but with minor change you could write to any disk file using a Lua file open / serialize / write / close .

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Tiopon   USA  (71 posts)  Bio
Date Reply #2 on Thu 05 Mar 2009 05:07 AM (UTC)
Message
Thanks for the quick reply. For some reason, didn't get the message saying that it had been responded to. Not sure if subscriptions aren't quite cooperative? Anyways, I was looking at the serialize information and... well, I'm really confused. :( If I understand correctly, what I'm basically doing is using serialize to turn the variables into strings (they are already, but strings in a different, more easily exported/imported format) and then they get saved into a... not sure, something, that saves between sessions... Another single variable? Into the plugin itself?

Sorry to be so confused... I haven't done a ton of scripting in the past few years, and so I'm just staring at it and feeling rather lost as to what sorts of tweaks to try to do to turn my collection of scattered, not-nested or otherwise tabled variables into an external file.
Top

Posted by Nick Gammon   Australia  (23,102 posts)  Bio   Forum Administrator
Date Reply #3 on Thu 05 Mar 2009 05:37 AM (UTC)
Message
Well, as with a lot of these things, there are many ways of doing it. The best way can depend on the complexity of what you are trying to achieve.

For a few simple variables, simply setting a variable in the plugin will guarantee it is saved at the end of one session, and restored at the start of another, eg.


SetVariable ("mobs_killed", 22)


This happens if you ticked the "save state" box when making the plugin, which should result in something like this at the start of your plugin file:


<muclient>
<plugin
  name="Count_Mobs_Killed"
  author="Nick Gammon"
  id="f11e3bb0e48d526152798439"
  language="Lua"
  purpose="Counts how many mobs I have killed"
  save_state="y"
  date_written="2008-01-08 15:17:18"
  requires="4.00"
  version="1.0"
>


However this gets a bit tedious if you have lots of things to save, like a table of mobs and how many of them you killed. Now you have to record the mob name, when it died (maybe), and how many you killed. You soon start using up lots of individual variables that way. This is where serialization helps, as it turns a whole table into a single string.

Now (as described near the bottom of the first page of http://www.gammon.com.au/forum/?id=6030) you can simply turn the whole table into a single string.

For example, the killed mobs might look like this:


killed_mobs = {
  Tiopon = {
    count = 3,
    last_time = 1236234406,
    },
  naga = {
    count = 3,
    last_time = 1236234406,
    },
  kobold = {
    count = 3,
    last_time = 1236234406,
    },
  someone = {
    count = 25,
    last_time = 1235851630,
    },
  }


Now by assigning that string to a MUSHclient variable, the entire table gets saved. You could do that in a plugin like this:


require "var"
require "serialize"

function OnPluginSaveState ()
  var.killed_mobs = "killed_mobs = " .. serialize.save_simple (killed_mobs)
end --- function OnPluginSaveState


So, whenever the plugin saves its state, your entire table is saved.

We need another function to make sure the table is restored next time the plugin loads:


-- load data from variable in state file into a Lua table

function OnPluginInstall ()
  assert (loadstring (GetVariable ("killed_mobs") or "")) ()
  killed_mobs = killed_mobs or {}  -- ensure table exists
end -- function OnPluginInstall


Quote:

... they get saved into a... not sure, something, that saves between sessions... Another single variable? Into the plugin itself?


The plugin itself is treated as read-only. This is because plugins might be shared between multiple worlds. However if you have "save_state" checked, then each plugin automatically writes a "state" file when it saves or closes. Effectively, this saves any plugin variables to a disk file that is identified by concatenating the plugin ID with the world ID, giving a unique filename for each world, for each plugin.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nick Gammon   Australia  (23,102 posts)  Bio   Forum Administrator
Date Reply #4 on Thu 05 Mar 2009 05:39 AM (UTC)
Message
You can RH-click the plugin name in the plugin list to see its state file (if any). For example, in the example above, it looks like this:


<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>
<!-- Saved on Thursday, March 05, 2009, 5:26 PM -->
<!-- MuClient version 4.40 -->
<!-- Written by Nick Gammon -->
<!-- Home Page: http://www.mushclient.com/ -->

<!-- Plugin state saved. Plugin: "Count_Mobs_Killed". World: "smaug 2". -->

<muclient>

<!-- variables -->

<variables
   muclient_version="4.40"
   world_file_version="15"
   date_saved="2009-03-05 17:26:48"
  >
  <variable name="killed_mobs">killed_mobs = {
  Tiopon = {
    count = 3,
    last_time = 1236234406,
    },
  naga = {
    count = 3,
    last_time = 1236234406,
    },
  kobold = {
    count = 3,
    last_time = 1236234406,
    },
  someone = {
    count = 25,
    last_time = 1235851630,
    },
  }</variable>
</variables>
</muclient>


- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Tiopon   USA  (71 posts)  Bio
Date Reply #5 on Thu 05 Mar 2009 07:28 AM (UTC)
Message
What I'm really trying to do is, if possible, make it so that if for some reason my computer locks up, the variables have still been saved. From the sound of it, even if I'm using plugins and serializing it, I'll have no better luck for if my computer overheats or the like over just adding in saving the world file to the trigger that modifies the variables, correct?

And yes, there are relatively a lot of variables set, 63 so far with a single value to each, none of them related to any of the others, and that count will only go up... but they're all set through the same trigger, that automatically updates the correct variable and then tells me what the current count is.

I know my goals are slightly odd compared to most who are using moderate numbers of variables, but I was curious as to whether my goal was actually one to pursue or to merely accept as it stands. The main oddity is where, on quitting, it always says that the variables have changed and asks me if I want to save, thereby terrifying me of the possibility of losing all of my updates if I don't click yes, despite the fact that I've been hitting Ctrl-S every 1-5 minutes for the past 6-12 hours, with the numbers varying depending on specific actions being undertaken.

Suppose that the best way to do it is just to make sure that the Save("") function is included in the trigger that sets variables, as that should make them be saved to the disk immediately? As it doesn't sound especially easy to have it dynamically updating a file with the variables as soon as they are updated... I could do the serialize/savestate immediately, but there'd be no benefits over just using the natural variables and the save function, or am I misunderstanding?
Top

Posted by Worstje   Netherlands  (899 posts)  Bio
Date Reply #6 on Thu 05 Mar 2009 01:59 PM (UTC)
Message
If you are using a plugin, you can use world.SaveState() to save the variables at any time. If you feel it is essential the saved version remains in sync with the changes you make in your trigger, you can call SaveState() as often as possible - although that might cause some slowdowns depending on how often you are going to save stuff.
Top

Posted by Nick Gammon   Australia  (23,102 posts)  Bio   Forum Administrator
Date Reply #7 on Thu 05 Mar 2009 06:56 PM (UTC)

Amended on Thu 05 Mar 2009 06:57 PM (UTC) by Nick Gammon

Message
Quote:

What I'm really trying to do is, if possible, make it so that if for some reason my computer locks up, the variables have still been saved. From the sound of it, even if I'm using plugins and serializing it, I'll have no better luck for if my computer overheats or the like over just adding in saving the world file to the trigger that modifies the variables, correct?


I suppose that if the computer crashes, either method would have similar results, providing you save frequently. One approach is to use a plugin that saves the world file frequently. I described such a plugin in this thread:

http://www.gammon.com.au/forum/?id=9273&page=1

It is worth noting that saving the world file has a side-effect of also saving all plugin state files.

Another thing you might consider is using a SQLite database. These threads discuss it:

http://www.gammon.com.au/forum/?id=9262
http://www.gammon.com.au/forum/?id=9241

Now you would need to learn a bit of SQL to make use of that, but the advantage of a database is that you can save individual variables. Also SQLite claims that in the event of a power failure, the most recent transaction is either completely saved, or not at all. Using SQL you can do things like adding 1 to a count, without necessarily having to find out what the current value is, like this:


UPDATE mobs SET killed_count = killed_count + 1 WHERE name = "kobold";



I should point out that when MUSHclient saves a state file, or the world file, it simply overwrites the previous one. In the event that the computer crashes exactly halfway through a save, then you may lose the entire file (the old one is gone, and the new one is not completely written).

Under Lua you can do a "save as" to save the world file under a different name. Thus you could change names every 5 minutes, based on the time, for example:

http://www.gammon.com.au/scripts/doc.php?function=Save

Or, instead of serializing to a state file in a plugin, you could use io.open (in Lua) to simply write your own text file, and write the serialized variable(s) to that. That file could change names frequently.

However none of that really solves the problem of your PC crashing, and never being able to be recovered. In that case, frequent saves to somewhere else would be helpful. One possibility would be to insert a USB memory stick, and save to that every 30 minutes (eg. using the "save as" feature).

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Tiopon   USA  (71 posts)  Bio
Date Reply #8 on Sun 08 Mar 2009 06:17 AM (UTC)

Amended on Sun 08 Mar 2009 06:18 AM (UTC) by Tiopon

Message
Tends to usually crash when I'm going from having it up in a remote desktop window and using it remotely, to actually logging into the computer... the percentage varies, but between 5-20% of the time the screen will just stay black, and the only way out of it is to shut down the computer. What worries me is that, even when saved, the world file says:

World internal variables (only) have changed.

Save changes to <world file>?

With Yes, No, or Cancel as my options... this despite the fact that I've been saving the world file repeatedly. This is the part that makes me nervous. Can't find any reference to this and whether or not it actually can cause me to lose my variables if I say no...

I did actually register MUSHclient before it became freeware, and still prefer to use the 3.85 version as the 4.00+ versions do (did?) have a message on every world connect saying that they are freeware, etc, and I didn't want that to end up in my logs, plus it was distracting me and making me think that broken muds had actually connected when it started to come up... I'd do a quick world check, there'd be text, and I'd move on to the next, watching the activity bar to see when to check on that one... shockingly, it would never come up. Heh.

Anyways, if this (misleading?) message is gone in newer versions, great. If I can get around this by marking the "SetChanged (true)" setting or whichever it was before the "Save("")" in the trigger that updates all the variables, that works fine as well. Just want to make sure that the variables are saving, when the message on quit seems to be saying that they haven't. -_-
Top

Posted by WillFa   USA  (525 posts)  Bio
Date Reply #9 on Sun 08 Mar 2009 08:06 AM (UTC)

Amended on Sun 08 Mar 2009 08:07 AM (UTC) by WillFa

Message
If you press CTRL+ALT+G to bring up global preferences, go to the "Closing" tab, and uncheck "Offer to save world if only Variables have changed", the prompt goes away.

I think it's a bug, that if checked it uses the value of the checkbox for some If Dirty... logic, but Nick can verify that better than I...

Top

Posted by Tiopon   USA  (71 posts)  Bio
Date Reply #10 on Sun 08 Mar 2009 02:48 PM (UTC)

Amended on Mon 09 Mar 2009 07:15 AM (UTC) by Tiopon

Message
The problem is, from the sounds of things in the Serializing table data post, if just variables have changed, it sounds like it won't save without that...

Quote:
However another problem arises. If you haven't changed anything else in the world, MUSHclient will not offer to save it, and thus the serializing will not be done. Thus, you need to tell it when you have changed a variable that needs to be saved. You can now do this:


SetChanged (true) -- world has changed



You might do that in a trigger that updates internal variables. This will not cause the world to be saved, it will simply set a flag that causes it to be saved at world close time (assuming you go ahead and save it).


I tested and saving the world with that does remove the 'variables' prompt. So my current trigger that updates the variables does its little variable update, does a SetChanged (true), and then a Save ("") to send it all away. Hopefully that should work...

For the record, this is the part that causes the whole problem... the fact that if only the variables change, 'saving' the world doesn't actually DO a save, because it doesn't realize that the world has had things change. It can be forced by either having an alias that marks the world as changed, or by inserting the changed flag before a save, in whatever triggers or aliases are changing your world. Which reminds me, I need to fix the 'var' alias to also mark that and save.
Top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


33,840 views.

It is now over 60 days since the last post. This thread is closed.     Refresh page

Go to topic:           Search the forum


[Go to top] top

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.