I have tried making a Garry's Mod lua file to look for messages containing "/discord" at the beginning of them and save that message as a text file in the same directory, I'm not familliar to lua files so I am unsure of syntax but when I look at console, nothing happens, when I look at the server command line, nothing happens and no new file is created, I even serached my entire PC.
I used the following page on the Garry's mod wiki: https://wiki.garrysmod.com/page/GM/PlayerSay and the code given there works but as soon as I added anything, it stopped working completely. Here is my code:
hook.Add( "PlayerSay", "GmodToDiscord", function( player, text, team )
if ( string.sub( string.lower( text ), 0, 7 ) == "/discord" ) then -- Makes message lowercase to be read by the program.
local file = io.open("message.txt", "w") -- Opens a text file in write mode.
file:write(message) -- Pastes in the message.
file:close() -- Closes the text file.
end
end)
Any help would be greatly appreciated.
You cannot use Lua's io library within Gary's mod. Use the Gary's Mod's file module instead.
https://wiki.garrysmod.com/page/file/Open
Example:
local f = file.Open( "cfg/mapcycle.txt", "r", "MOD" )
print( f:ReadLine() )
print( f:ReadLine() )
print( f:Tell() )
f:Close()
A thing to note about Lua, and what makes it a rather whacky language, is that it's arrays begin at index 1. You will need to check between 1 and 8 to get your tags; that should help you get started on #Piglet's implementation of the file IO.
Good luck, and happy modding!
Related
I'm using Lua in Scite on Windows, but hopefully this is a general Lua question.
Let's say I want to write a temporary string content to a temporary file in Lua - which I want to be eventually read by another program, - and I tried using io.tmpfile():
mytmpfile = assert( io.tmpfile() )
mytmpfile:write( MYTMPTEXT )
mytmpfile:seek("set", 0) -- back to start
print("mytmpfile" .. mytmpfile .. "<<<")
mytmpfile:close()
I like io.tmpfile() because it is noted in https://www.lua.org/pil/21.3.html :
The tmpfile function returns a handle for a temporary file, open in read/write mode. That file is automatically removed (deleted) when your program ends.
However, when I try to print mytmpfile, I get:
C:\Users\ME/sciteLuaFunctions.lua:956: attempt to concatenate a FILE* value (global 'mytmpfile')
>Lua: error occurred while processing command
I got the explanation for that here Re: path for io.tmpfile() ?:
how do I get the path used to generate the temp file created by io.tmpfile()
You can't. The whole point of tmpfile is to give you a file handle without
giving you the file name to avoid race conditions.
And indeed, on some OSes, the file has no name.
So, it will not be possible for me to use the filename of the tmpfile in a command line that should be ran by the OS, as in:
f = io.popen("python myprog.py " .. mytmpfile)
So my questions are:
Would it be somehow possible to specify this tmpfile file handle as the input argument for the externally ran program/script, say in io.popen - instead of using the (non-existing) tmpfile filename?
If above is not possible, what is the next best option (in terms of not having to maintain it, i.e. not having to remember to delete the file) for opening a temporary file in Lua?
You can get a temp filename with os.tmpname.
local n = os.tmpname()
local f = io.open(n, 'w+b')
f:write(....)
f:close()
os.remove(n)
If your purpose is sending some data to a python script, you can also use 'w' mode in popen.
--lua
local f = io.popen(prog, 'w')
f:write(....)
#python
import sys
data = sys.stdin.readline()
I am learning the Lua IO library. I'm having trouble with io.write(). In Programming Design in Lua, there is a piece of code that iterates through the file line by line and precedes each line with a serial number.
This is the file I`m working on:
test file: "iotest.txt"
This is my code
io.input("iotest.txt")
-- io.output("iotest.txt")
local count = 0
for line in io.lines() do
count=count+1
io.write(string.format("%6d ",count), line, "\n")
end
This is the result of the terminal display, but this result cannot be written to the file, whether I add IO. Output (" iotest.txt ") or not.
the results in terminal
This is the result of file, we can see there is no change
The result after code running
Just add io.flush() after your write operations to save the data to the file.
io.input("iotest.txt")
io.output("iotestout.txt")
local count = 0
for line in io.lines() do
count=count+1
io.write(string.format("%6d ",count), line, "\n")
end
io.flush()
io.close()
Refer to Lua 5.4 Reference Manual : 6.8 - Input and Output Facilities
io.flush() will save any written data to the output file which you set with io.output
See koyaanisqatsi's answer for the optional use of file handles. This becomes especially useful if you're working on multiple files at a time and gives you more control on how to interact with the file.
That said you should also have different files for input and output. You'll agree that it doesn't make sense to read and write from and to the same file alternatingly.
For writing to a file you need a file handle.
This handle comes from: io.open()
See: https://www.lua.org/manual/5.4/manual.html#6.8
A file handle has methods that acts on self.
Thats the function after the : at file handle.
So io.write() puts out on stdout and file:write() in a file.
Example function that can dump a defined function to a file...
fdump=function(func,path)
assert(type(func)=="function")
assert(type(path)=="string")
-- Get the file handle (file)
local file,err = io.open(path, "wb")
assert(file, err)
local chunk = string.dump(func,true)
file:write(chunk)
file:flush()
file:close()
return 'DONE'
end
Here are the methods, taken from io.stdin
close = function: 0x566032b0
seek = function: 0x566045f0
flush = function: 0x56603d10
setvbuf = function: 0x56604240
write = function: 0x56603e70
lines = function: 0x566040c0
read = function: 0x56603c90
This makes it able to use it directly like...
( Lua console: lua -i )
> do io.stdout:write('Input: ') local result=io.stdin:read() return result end
Input: d
d
You are trying to open the same file for reading and writing at the same time. You cannot do that.
There are two possible solutions:
Read from file X, iterate through it and write the result to another file Y.
Read the complete file X into memory, close file X, then delete file X, open the same filename for writing and write to it while iterating through the original file (in memory).
Otherwise, your approach is correct although file operations in Lua are more often done using io.open() and file handles instead of io.write() and io.read().
I need to load configuration variables from .conf file in lua script, and use those variables to connect to a database. I have tried using:
require "host.conf"
loadfile("host.conf") - error with unexpected token '#'
os.execute("pathToConfFile/host.lua") - and I have created a lua host file with variables in bash shell
io.popen("host.conf") etc..
None of these solutions are valid.
Is there a way to use the existing host.conf file in lua, and avoid the unexpected token error?
Thank you for your suggestions.
local original = io .open('host.conf')
local hostconf = {} -- copy contents into Lua table
for line in original :lines() do
table .insert( hostconf, line )
end ; io .close( original )
print( hostconf[1] ) -- prints line 1
You haven't specified what format your host.conf comes in, but you'll likely want to parse it better than just throwing contents in a list. Perhaps splitting each line into head / tail, based upon a delimiter ( comma, space, whatever you have between variable & value )
Thank you to everyone who helped out. My question wasn't precise and I had more to learn before I have asked and sorry about that. This is what I used to solve the problem.
local open = io.open
local function read_file(path)
local file = open(path, "r")
if not file then return nil end
local content = file:read "*a" -- *a or *all reads the whole file
local lines = {}
for line in io.lines(path) do
--print(line);
if(line:find(var)~=nil)then
local varStart=string.len(var)+2
local varEnd=string.len(line)
var=string.sub(line,varStart,varEnd)
print(var);
end
--repeat for every line
end
file:close()
return lines;
end
local fileContent = read_file("path");
I think the tile explains it self how do I access these files and read and write them?
this is what my code looks like
local openFile = assert(io.open(wasd_ ,"r")) -- wasd_ is the .txt file I want to open
local t = openFile:read("r") -- read the file
I'm not sure if in the 1st line of code if I shut replace "wasd_" with "wasd_.txt" or the file path (i.e replace wasd_ with something like this --> C:/users/stuff/blah/thing/wasd_)
ant help is greatly appreciated
According to the documentation:
local Filename = "wasd_.txt"
local File = io.open(Filename, "r")
local FileContent = File:read("*all")
File:close()
The file will be open according to the current directory %CD%. If your current directory is C:\test\, then the open file will be C:\test\wasd_.txt. If you want to find another file, you could specify the full path C:\users\stuff\blah\thing\wasd_.txt
you can do it all-at-once if you want; Lua allows that, but you have more control over editing when you do it line-at-a-time; in case you need to use certain edits on certain lines. It's also much safer to write to a new file, so you still have your original, to compare and try again, if need be.
line by line, keeping original, writing to new text
local path = 'C:/users/stuff/blah/thing/wasd_.txt' -- wasd_ is the .txt file I want to open
local newpath = path :sub( 1, -5 ) ..'new.txt' -- C:/users/stuff/blah/thing/wasd_new.txt
local iput = assert( io.input( path ) )
local oput = assert( io.output( newpath ) )
local linenum = 0 -- used as a counter
while true do
linenum = linenum +1
local line = iput :read()
if line == nil then break end -- break out of loop if there's nothing else to read
local newline, _ = line :gsub( 'this', 'that' ) -- do your changes here
if linenum == 1 then newline = 'HEADER: ' ..newline end -- example of specific line edit
oput :write( linenum ..' ' ..newline ..'\n' ) -- read() line strips newline char, so add it back
end
iput :close()
oput :close()
You can take out all instances of linenum if it's not needed, but I would strongly recommend that you use two separate read & write files, at least until you're comfortable it's doing exactly what you want, and has no errors.
My script uses lfs to read files in a directory.
It then stores the value in a variable called file.
The problem is the value is actually a list.
Here is a sample value.
.
..
a.txt
b.txt
c.txt
d.txt
I can print this variable as is, but I need to integrate this variable inside a dialog box.
When I integrate this variable inside a dialog box, it prints each line in a new dialog.
Here is my code:
require 'lfs'
function main()
for file in lfs.dir[[C:\Users\QXJtaW5pdXM\Desktop\Test\test_3.4.5.6]] do
print(file)
--This works perfectly fine.
Dialog("Title", "Files:\n" .. file)
--This prints each line in a new dialog box.
end
end
return main
I need to print all the files in one dialog box.
If at all possible, I'd love to avoid printing . & ..
As a picture reference, here is what I get:
https://imgur.com/tmfQlan
Here is what I need:
https://imgur.com/mxYBO9t
Could someone please point me in the right direction?
Thank you very very very much!
Your loop's body is executed once for every file so what do you expect if you create a dialog inside the loop? Create it outside after you've created a list of files.
require 'lfs'
function main()
local files = ""
for file in lfs.dir[[C:\Users\QXJtaW5pdXM\Desktop\Test\test_3.4.5.6]] do
files = files .. file .. "\n"
end
Dialog("Title", "Files:\n" .. files)
end
Maybe there is also another function that gives you a list of file names right away.
I had to use table.insert in a for loop to add values inside a table file_list.
Then use table.remove to remove the first two inputs . & ..
In the end, the code would look something like this:
require 'lfs'
file_list = {}
function main()
for grab_files in lfs.dir[[C:\Users\QXJtaW5pdXM\Desktop\Test\test_3.4.5.6]] do
table.insert(file_list, grab_files)
-- table.insert will assign each input of grab_files into each reference of file_list table
end
table.remove(file_list,1)
-- This removes the '.'
table.remove(file_list,1)
-- This removes the '..'
file_names = table.concat(file_list, "\n")
Dialog("Title", "Files:\n" .. file_names)
end
return main