You can create and write a file using Unreal

Discussions about Coding and Scripting
User avatar
PrinceOfFunky
Godlike
Posts: 1204
Joined: Mon Aug 31, 2015 10:31 pm

You can create and write a file using Unreal

Post by PrinceOfFunky »

"You cannot write on files using Unreal" - they said.
"You can only write on INI files and read from INI and INT files using Unreal" - they said.

Fake! Like in any other programming language you can write on file and perform all the needed operations on it, like creating the file itself, opening, flushing and closing it.
This works like a charm:

Code: Select all

local StatLogFile file;
	
	file = Spawn(class'StatLogFile');
	//tmp file name.
	file.StatLogFile = "test.tmp";
	//final file name.
	file.StatLogFinal = "test.log";
	file.OpenLog();
	file.FileLog("HERE GOES WHAT YOU WANT TO WRITE ON THE FILE");
	file.FileFlush();
	file.CloseLog();
Video proof:
BhBSJanAYVM

BeginPlay set the timer to 30 and the Timer logs players info, so if you don't want your file to include the players info every 30 seconds, you should disable Timer() or overwrite BeginPlay().

StatLogFile variable can be whatever directory, the parent class of StatLogFile contains some useful functions I didn't read, so basing on what I wrote here, you could create a script file from scratch and then execute it using Unreal for the whole process.

I'm not sure if you want to see the mutator I showed in the vid, if you need it just tell me and I'll post it on here.
I think if people will start using new directories, we should make a standard before we get a lot of folders spread around.

(And I was even making Unreal communicating through TCP just to write few info using Java -__-")
Last edited by PrinceOfFunky on Mon Jan 08, 2018 7:19 am, edited 2 times in total.
nogardilaref
Masterful
Posts: 577
Joined: Tue Jun 20, 2017 1:00 pm
Personal rank: βš‹βšŠβšŒβ˜°βšžβŒ–βšŸβ˜°βšŒβšŠβš‹

Re: You can create and write a file using Unreal

Post by nogardilaref »

I truly wonder how I have missed this actor myself for all these years... very interesting indeed, this will certainly allow the sort of thing I aim to do in the future a lot more easily.
Although this is as powerful as it is dangerous, for obvious reasons.

As for appending, perhaps if you do not call "file.CloseLog();" and keep global reference in your class rather than a local one, it might keep appending stuff to it instead, until the actual actor itself is destroyed on map change or on exit.
User avatar
sektor2111
Godlike
Posts: 6433
Joined: Sun May 09, 2010 6:15 pm
Location: On the roof.

Re: You can create and write a file using Unreal

Post by sektor2111 »

nogardilaref wrote:As for appending, perhaps if you do not call "file.CloseLog();" and keep global reference in your class rather than a local one, it might keep appending stuff to it instead, until the actual actor itself is destroyed on map change or on exit.
I did not recall any chatlog file removed from my system all this time - IT USES THE same way for writing files outta sandbox. Yeah, Funky, it's done already...
User avatar
PrinceOfFunky
Godlike
Posts: 1204
Joined: Mon Aug 31, 2015 10:31 pm

Re: You can create and write a file using Unreal

Post by PrinceOfFunky »

sektor2111 wrote:
nogardilaref wrote:As for appending, perhaps if you do not call "file.CloseLog();" and keep global reference in your class rather than a local one, it might keep appending stuff to it instead, until the actual actor itself is destroyed on map change or on exit.
I did not recall any chatlog file removed from my system all this time - IT USES THE same way for writing files outta sandbox. Yeah, Funky, it's done already...
Yeah IkIk that the appending works, but I meant appending after closing/reopening the file.
I think the best thing would be to read files other than writing them, I mean we can read from INI and INTs but they must be in a standard format, reading from whatever structure would be a lot better.

EDIT: Also:
nogardilaref wrote:I truly wonder how I have missed this actor myself for all these years...
Maybe cause the name of the class/file is StatLogFile and not something like FileWriter and basing on what we are used to read in unrealscript classes, like that when you read things that are not usually from the unrealscript world we tend to think that those things must be hardcoded natively.
nogardilaref
Masterful
Posts: 577
Joined: Tue Jun 20, 2017 1:00 pm
Personal rank: βš‹βšŠβšŒβ˜°βšžβŒ–βšŸβ˜°βšŒβšŠβš‹

Re: You can create and write a file using Unreal

Post by nogardilaref »

PrinceOfFunky wrote:
nogardilaref wrote:I truly wonder how I have missed this actor myself for all these years...
Maybe cause the name of the class/file is StatLogFile and not something like FileWriter and basing on what we are used to read in unrealscript classes, like that when you read things that are not usually from the unrealscript world we tend to think that those things must be hardcoded natively.
Nah, I am used to weird names and all, and in this case is called "StatLogFile" which is actually pretty obvious, so I think it was mostly over the fact that I barely look into Info classes and I didn't expect something like this to be under "Info" at all, and be an actual actor to top it off (I assumed it would be an non-actor, so there's where I looked in the past).

Which means I will probably have to recheck every class again one of these days, once I pick stuff like this again. :mrgreen:
Higor
Godlike
Posts: 1866
Joined: Sun Mar 04, 2012 6:47 pm

Re: You can create and write a file using Unreal

Post by Higor »

You can only write 16 bit characters using statlog.
And in a certain UT build you cannot even generate characters outside of the 8 bit range.

Worthless.
nogardilaref
Masterful
Posts: 577
Joined: Tue Jun 20, 2017 1:00 pm
Personal rank: βš‹βšŠβšŒβ˜°βšžβŒ–βšŸβ˜°βšŒβšŠβš‹

Re: You can create and write a file using Unreal

Post by nogardilaref »

Well... that would at least make it a lot less dangerous, but .int files are localization files, which UT should be able to load from 16-bit characters as well, right?

Given that we can use this class to perhaps create .int files themselves, and Localize to read them, if both work well enough (with the special case of Localize remaining cached in the engine itself), there is still some very useful stuff which can be done, and which fits exactly what I need in my particular case for what I intend to do in the future.


@PrinceOfFunky: did you test to write a "new" .int file with the proper format using this, and then read it with Localize to check if it works at all?
Higor
Godlike
Posts: 1866
Joined: Sun Mar 04, 2012 6:47 pm

Re: You can create and write a file using Unreal

Post by Higor »

Self-localizing in UT has platform-specific code that requires different UnrealScript code for both windows and linux.
Also, UTF localization files require an additional character at the beginning of the text file to indicate UT should read it as UTF.
nogardilaref
Masterful
Posts: 577
Joined: Tue Jun 20, 2017 1:00 pm
Personal rank: βš‹βšŠβšŒβ˜°βšžβŒ–βšŸβ˜°βšŒβšŠβš‹

Re: You can create and write a file using Unreal

Post by nogardilaref »

Yeah, I just went ahead and tested it myself... bummer.
Well, at least with this you're not bound to a single log file, and this can still be used for plenty of stuff other than logging, although to read back it's indeed quite pointless the way things are saved.
Higor
Godlike
Posts: 1866
Joined: Sun Mar 04, 2012 6:47 pm

Re: You can create and write a file using Unreal

Post by Higor »

Forget about windows and linux, let's talk about ANSI or UNICODE

Essentially:
- ANSI: log as usual.
- UNICODE: add the special character start of file, then log as usual.

Try the following

Code: Select all

function StartHeader( string FirstLine)
{
	if ( asc(chr(1000)) == 1000 ) //ANSI UT will fail this check
		AddString( chr(65279)$ FirstLine);
	else
		AddString( FirstLine);
}
EDIT: That will only work on INT files btw.
INI will fail.
nogardilaref
Masterful
Posts: 577
Joined: Tue Jun 20, 2017 1:00 pm
Personal rank: βš‹βšŠβšŒβ˜°βšžβŒ–βšŸβ˜°βšŒβšŠβš‹

Re: You can create and write a file using Unreal

Post by nogardilaref »

Image

Worked like a charm :rock: , here's the code:

Code: Select all

function PostBeginPlay()
{
local StatLogFile file;

	//open
	file = Spawn(class'StatLogFile');
	file.StatLogFile = "TEST.tmp";
	file.StatLogFinal = "TEST.int";
	file.OpenLog();

	//header
	if (Asc(Chr(1000)) == 1000) { //ANSI UT will fail this check
		file.FileLog(Chr(65279));
	}

	//data
	file.FileLog("[MySection]");
	file.FileLog("a={\"key\":\"value\"}");
	file.FileLog("b=This proves Higor is THE MAN!");

	//finish
	file.FileFlush();
	file.CloseLog();

	//load
	Log("TEST.MySection.a = " $ Localize("MySection", "a", "TEST"), 'YOLO_TEST');
	Log("TEST.MySection.b = " $ Localize("MySection", "b", "TEST"), 'YOLO_TEST');
}
and here's the log:

Code: Select all

YOLO_TEST: TEST.MySection.a = {"key":"value"}
YOLO_TEST: TEST.MySection.b = This proves Higor is THE MAN!
Higor
Godlike
Posts: 1866
Joined: Sun Mar 04, 2012 6:47 pm

Re: You can create and write a file using Unreal

Post by Higor »

You can also create entire ANSI files using windows statlog, at least to be able to write binary files (pair amount of bytes only).
But you'll need to do a lot of buffering and character conversion, without proper unrealscript optimization the UNICODE build of the statlog may be extremely slow.
User avatar
PrinceOfFunky
Godlike
Posts: 1204
Joined: Mon Aug 31, 2015 10:31 pm

Re: You can create and write a file using Unreal

Post by PrinceOfFunky »

nogardilaref wrote:

Code: Select all

//header
Is it cause of the missing header that this localization doesn't work?:

Code: Select all

local StatLogFile file;
	
	file = Spawn(class'StatLogFile');
	
	//tmp file name.
	file.StatLogFile = "test_2.tmp";
	//final file name.
	file.StatLogFinal = "test_2.int";
	file.OpenLog();
	file.FileLog("[tests]");
	file.FileFlush();
	file.FileLog("test1=hello");
	file.FileFlush();
	file.CloseLog();
	
	Level.Game.BroadcastMessage(Localize("tests", "test1", "test_2"));
EDIT:
Higor wrote:You can also create entire ANSI files using windows statlog, at least to be able to write binary files (pair amount of bytes only).
But you'll need to do a lot of buffering and character conversion, without proper unrealscript optimization the UNICODE build of the statlog may be extremely slow.
Or you run an external script which converts the file from ANSI to UNICODE.
Higor
Godlike
Posts: 1866
Joined: Sun Mar 04, 2012 6:47 pm

Re: You can create and write a file using Unreal

Post by Higor »

Quick Goolag search results in this: http://www.fileformat.info/info/unicode ... /index.htm
nogardilaref
Masterful
Posts: 577
Joined: Tue Jun 20, 2017 1:00 pm
Personal rank: βš‹βšŠβšŒβ˜°βšžβŒ–βšŸβ˜°βšŒβšŠβš‹

Re: You can create and write a file using Unreal

Post by nogardilaref »

@PrinceOfFunky: Yeah, what I commented as header is essentially what Higor posted right before and is simply the UTF-16 BOM (Byte Order Mark), which hints a text reader in which encoding the file is, be it ANSI, UTF-8, UTF-16 or something else, as well as endianess.
In the case of UTF-16, is what Higor just posted, hence that "magic" number at the start, so when the engine loads the .int file, it gets correctly interpreted as UTF-16 rather than ANSI.

As for the first check with Chr(1000), 1000 is just a random UTF-16 character just to check if UT is able to recognize UTF-16 or not.
To be honest, until Higor posted it, I thought that Chr was limited to 255 (ANSI) for some reason, perhaps because there's a difference depending on the version from what he said which I was completely unaware about. I'm glad he sorted it out. :mrgreen:
Higor wrote:You can also create entire ANSI files using windows statlog, at least to be able to write binary files (pair amount of bytes only).
But you'll need to do a lot of buffering and character conversion, without proper unrealscript optimization the UNICODE build of the statlog may be extremely slow.
I guess it would be something like this then? (untested code)

Code: Select all

function string convert(string data)
{
local string final_data;
local int data_len, i;

	//convert
	data_len = len(data);
	for (i = 1; i < data_len; i += 2) {
		final_data = final_data $ chr((asc(data[i - 1]) << 8) | asc(data[i]));
	}
	
	//convert remaining byte
	if (data_len % 2 === 1) {
		final_data = final_data $ chr(asc(data[data_len - 1]) << 8);
	}
	
	//return
	return final_data;
}
But then, I am worried about the NULL bytes, because they break strings in this engine, given that strings are NULL terminated after all.
Hence when I created hashing functions for instance (namely MD5 and SHA family), I had to specifically create byte arrays so I could handle the NULL bytes, unless I am missing something here...