This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
koslas's profile picture

fs.open throwing an error

Started by koslas, 04 October 2015 - 10:54 PM
koslas #1
Posted 05 October 2015 - 12:54 AM
I'm working on a game, which all information is stored onto a server (So multiple computers can be used to played on) and the way I am storing the information is getting a message on rednet from the client, and then the server does what it has to, or asks the client for more information. However I have been using this for everything else, but it doesn't seem to work right now

Server:

if msg == "updateMoney" then
	  rednet.send(id, "user?")
	  id, user, dis = rednet.receive(1)
	  rednet.send(id, "amount?")
	  id, amount, dis = rednet.receive(1)
	  coinsWrite = fs.open("/.info/"..user.."/coins", "w") -- This is line 312
	  coinsWrite.write(amount)
	  coinsWrite.close()
	  if user ~= nil and amount ~= nil then
	    print(user.." now has "..amount.." coins")
	  end
    end

Client:

function saveMoney()
  rednet.send(serverId, "updateMoney")
  id, msg, dis = rednet.receive(1)
  checkifServer()
  if msg == "user?" then
    rednet.send(serverId, username)
    id, msg, dis = rednet.receive(1)
    checkifServer()
    if msg == "amount?" then
	  rednet.send(serverId, coins)
    end
  end
end

The clients doesn't stop, however the server errors out at 312: attempt to concatenate nil and string, I don't understand what's stopped working. I thought I would only post the relevant code, but if you need more, then I will send more
TYKUHN2 #2
Posted 05 October 2015 - 12:59 AM
variable user is nil
That is all I can tell from your code.
Probably rednet.recieve is timing out. Else user would be a number (I think)
koslas #3
Posted 05 October 2015 - 01:09 AM
User is supposed to be a string, and why would it end up being nil, when the client sends it? The code like this is similar (Just different files etc.) and I've never had a problem with it
TYKUHN2 #4
Posted 05 October 2015 - 01:18 AM
rednet.receive(1) times out after 1 second and returns nil. If the message is not sent within 1 second User is nil
koslas #5
Posted 05 October 2015 - 01:50 AM
But it shouldn't be nil, due to the fact that the client sends the information
TYKUHN2 #6
Posted 05 October 2015 - 01:52 AM
Your using the rednet API so ensure the serverID is correct. Double check by replacing send with broadcast.
valithor #7
Posted 05 October 2015 - 02:13 AM
There really is no reason for the request to be separated into 3 messages, all that separating them will accomplish is more bugs and confusion down the road. I personally would send a table that contains the action the server should take "updateMoney", the username, and the amount. If you send all three at once, then there is no chance of not receiving one of the values, and it won't break if two clients are requesting something at the same time.

Sent from my phone.

Your code redone using tables:

server

if msg["action"] == "updateMoney" then
  if msg["user"] ~= nil and msg["amount"] ~= nil then
    print(msg["user"].." now has "..msg["amount"].." coins")
    coinsWrite = fs.open("/.info/"..msg["user"].."/coins", "w") -- This is line 312
    coinsWrite.write(msg["amount"])
    coinsWrite.close()
  end
end

client

function saveMoney()
  rednet.send(serverId, {["action"] = "updateMoney", ["user"] = username, ["amount"] = coins})
end

Granted you would need to change all of your requests to use tables for this to work.
Edited on 05 October 2015 - 12:27 AM
koslas #8
Posted 05 October 2015 - 03:47 AM
The first time I've used tables is in this game for another thing, which I actually need quite a bit of help with, but I guess tables work better for most things, so I may try using tables for this too, as it'll give me more experience with tables, and make the game more reliable. Would you be-able to provide a more detailed explanation on how that would work, like I understand I change ["action"] to what thing I want (Such as login/register and also other things), but would just changing that part of the code most likely work, or would I need to edit the majority of it first? Thanks for this, as it looks like it's 3 different messages in that 1 message, as I always done it the way in the OP as I thought that was the only way possible
valithor #9
Posted 05 October 2015 - 03:56 AM
The first time I've used tables is in this game for another thing, which I actually need quite a bit of help with, but I guess tables work better for most things, so I may try using tables for this too, as it'll give me more experience with tables, and make the game more reliable. Would you be-able to provide a more detailed explanation on how that would work, like I understand I change ["action"] to what thing I want (Such as login/register and also other things), but would just changing that part of the code most likely work, or would I need to edit the majority of it first? Thanks for this, as it looks like it's 3 different messages in that 1 message, as I always done it the way in the OP as I thought that was the only way possible

So tables are essentially a variable with a lot of variables inside of it. These variables are assigned "keys", which you can use to find them in the table. So "action" in the example is the key, and you will want to leave that name key name alone, so it will be easy to check in all of your if statements. The two other things I added in the table were specific to that action, so they can be changed depending on what action you want the server to perform.

Example: Keep in mind this is more psudeo code instead of actual code, the only thing that will be real in any of it will be the tables.

client code

--# if you wanted to login
rednet.send(serverId, {["action"] = "login", ["username"] = username, ["password"] = password})

--# if you wanted to register
rednet.send(serverId, {["action"] = "register", ["username"] = username, ["password"] = password})

--# updating balance
rednet.send(serverId, {["action"] = "updateMoney", ["user"] = username, ["amount"] = coins})

As you can see the only thing that has to stay the same is the "action" key. I will show why it is important to leave that key name alone below:
server side

if msg["action"] == "updateMoney" then
  if msg["user"] ~= nil and msg["amount"] ~= nil then
	print(msg["user"].." now has "..msg["amount"].." coins")
	coinsWrite = fs.open("/.info/"..msg["user"].."/coins", "w") -- This is line 312
	coinsWrite.write(msg["amount"])
	coinsWrite.close()
  end
elseif msg["action"] == "login" then
  --# handle login
  --# the username is in the table as msg["username"]
  --# password is msg["password"]
  --# these keys were made when we made the table in the client
elseif msg["action"] == "register" then
  --# handle register
  --# basically same thing as login above
end

Tables are one of LUA's most powerful features. Once you learn them they will be incredibly useful.

edit:

Looking over this might help with learning basic table usage: http://www.lua.org/pil/2.5.html

edit2:

Another thing to keep in mind is that rednet is incredibly insecure. Because of this sending the password over rednet at all would result in anyone being able to find anyones password and username, with very minimum effort.
Edited on 05 October 2015 - 02:03 AM
koslas #10
Posted 05 October 2015 - 04:21 AM
So in the example msg is the table name, action is a key, and updateMoney is the value of the key? I have looked online for help with tables, but the best way I seem to learn is by seeing something in a practical use, then usually copying that, then changing it to how I was to, so I will mess around with the code. I know rednet can be insecure, which is why I made it look for the server at the start of the program and identify it as serverId, that way it is a bit harder to find it out, and the server that I play on (Which I intend to use this on) is friendly, and there are a few people who know Lua, who helped me with my first table :P/> but they wouldn't want to mess it up. But thanks for your help :)/> I'm getting rather tired, so I will probably mess around with the code tomorrow, and see what I can manage to do with it
TYKUHN2 #11
Posted 05 October 2015 - 04:44 AM
Redbet IDs ar Modem channels. Rednet is just a formatter for modem API.

Most servers tend to be friendly, just don't tell me the server information. :D/>

EDIT: I had a squint and I saw a few typos. I cannot be bother to fix them right now. Dirty glasses irritate me so I took them off. So my typing is a lot worse (even though I can still see the keyboard, mostly)
Edited on 05 October 2015 - 02:45 AM
koslas #12
Posted 05 October 2015 - 04:47 AM
I wasn't going to mention anything about how to join the server, just letting yous know that even though messages could be found out through rednet, that the server is nice enough to not do that, and if they did what use would that be to them? Logging into a computercraft game using someone else's account? :P/> Anyway I think it's time for me to get to sleep, so night everyone, and thanks for any help you've given me :)/>
koslas #13
Posted 08 October 2015 - 04:50 AM
Never mind, was just a typo with me not reading properly doing () instead of {}
Edited on 08 October 2015 - 02:53 AM