Game Development Community

Strings longer than 255 characters?

by Stony Brook University (#0001) · in Torque Game Engine · 07/18/2007 (7:27 pm) · 9 replies

I'm sorry if this has been posted before, but I've been scouring the forums and resources for anything relating to this for the past couple of hours, and I haven't found much. I'm reading a string from a file, which is supposed to be dialogue text that will go into a GUI control. That's all working fine, except that the string doesn't hold more than 255 characters.

Is there any way to store a long string, or does torquescript only allow that length? How about a character array? I can't find much information on either, so that's why I'm resorting to the forums.

I know there is an engine method to read a long string from a stream (www.garagegames.com/docs/tge/engine/classStream.php#a11), but I'm not sure how to use that to help me. I'd like to expose that to the console, and then read a long string from a file, but I don't even know if I could then store it in a string.

If anyone could point me in the right direction here, I'd really appreciate it.

Here is some example code, but its a fairly generic problem so I don't know if it will help:

%file = new FileObject();
if(%file.openForRead(%filename)) {
    while(!%file.isEOF()) {
        %input = %input @ %file.readLine();
        // This works fine, but if the line is longer than 255 characters,
        // the extra data is lost
        echo(%input);
    }
    // etc -- do whatever with the string
}

I thought about using multiple strings every 255 characters, and this would work, but since I'm trying to put this text in the GUI (Specifically, a GuiMLTextCtrl), it also won't hold more than 255 characters, right?

By the way, the file reading code I obtained from a great forum thread, www.garagegames.com/mg/forums/result.thread.php?qt=7575.

Thanks to all of you, in advance,
Dan
Student at Stony Brook University

#1
07/19/2007 (5:43 am)
Here's what I'm using. I'm not having that string problem - seems to work fine for long files. I've brought in thousands of characters this way.

Could it be that your echo is just only showing 255 characters?

%fileNameLesson = findFirstFile("starter.fps/data/lessons/lesson" @ %lessonToTry @ ".txt");

	%fileLesson = new FileObject();
	%fileOpenedLesson = %fileLesson.openForRead(%fileNameLesson);

	if (%fileOpenedLesson ) {
		//Files were found, initialize variables
		$academy_current_lesson = "";

		//Read the Lesson
		while ( !%fileLesson.isEOF() ) {
			$academy_current_lesson = $academy_current_lesson @ %fileLesson.readLine() @ "";
		}
		%fileLesson.close();
		%fileLesson.delete();
        }
#2
08/13/2007 (5:52 pm)
Hey Jay!

It's been a while since I posted my question, but I just wanted to include an update in case anyone else has a similar problem in the future.

Your code sample gave me an idea that it might have something to do with local strings (%) versus global strings ($). However, it treated the strings the same way.

Then, I realized that local or global had nothing to do with it. It seemed to work fine, until I passed it as a parameter from server to client. For some reason, the string got cut off at 255 characters only once I passed it.

Has anyone else noticed this? Anyway, I avoided it by just tacking the string to an object, and calling it from that object from the client side.

i.e. echo(StringHolderDude.string);

Hope this helps someone!
#3
08/13/2007 (6:00 pm)
Quote:
It seemed to work fine, until I passed it as a parameter from server to client. For some reason, the string got cut off at 255 characters only once I passed it.

that's it in a nutshell.

in general you don't want to be sending long strings from server to client (or client to server) anyway,
so if you find yourself doing that you might want to take a step back and think about the design.
#4
08/13/2007 (6:00 pm)
But if you really, really want to do it,
you can use multiple commandToClients() to send the string.
also the 255-char limit is a limit per argument,
and i think you can have at least 6 args.
but really it's best to avoid altogether.
#5
08/13/2007 (6:13 pm)
That's a really good point, and I don't know why I didn't think about it sooner, Orion.

Here's a question, then. If I created a ScriptObject on the server, for example:

...in startGame() from game.cs
// Start the Quest Handler
new ScriptObject(QuestHandler) {};
MissionCleanup.add(QuestHandler);
QuestHandler.initialize();

Where is that object stored? Is it duplicated constantly to all clients, or what? I guess I'm just a little confused how data is sent back and forth. As far as I can tell, that object is available to client scripts AND server scripts. I know that MissionCleanup is a simgroup, so its part of the mission, which is...client side...but then that means that every client has a different MissionCleanup, and thus a different QuestHandler?

So if thats true, then if I say in the server, QuestHandler.string = %input;, how many copies of this string am I creating?
#6
08/13/2007 (6:28 pm)
Heya -

yeah, it definitely takes a while to get used to the networking.

the short answer is: it's complicated.

part of the confusion comes in because when you're running "standalone" (aka single-player),
the one executable is actually acting as both a full server and a client,
however the server and the client are sharing the same namespace.

so if you make a global variable such as $foo or a named simObject such as new SimObject("bar"),
both client and server will have access to it.

but then when you move to a seperated client & server (ie multiplayer) then you're in a bad way.

so supposing you do have a seperate client & server,
the answer is that much less is automatically distributed to all the clients than you might initially expect.

specifically, ScriptObjects will Not be networked down to the clients.

the mission is actually better thought of as being server-side.
there's only one MissionCleanup group, and it's only on the server.
ditto all triggers and spawnspheres, for instance. - the clients never know about those at all except by the effects they end up having on the player.

actual objects in the mission such as players, items, etc, *are* automatically networked to all the clients,
and in that case the client-side copies are referred to as Ghosts.

but wait, there's more !

even if an object such as a player is automatically "ghosted" to the clients,
only specific, hand-coded fields in the object are sent down.
so if you add a new field to the player via script,
for example something like %serverSidePlayerObj.myCoolField = "yep";,
that field won't automatically exist client-side.
in order to achieve that, you need to add the field into the object's packUpdate() / unpackUpdate() method.

a final note here is that ghosting is one-way; client-side ghosts are copies of the server instances, and modifying a ghost does not update the server-side object.

.. it's a lot of details and some unexpected stuff, but once you get over the learning curve it's pretty cool.
#7
08/13/2007 (6:58 pm)
Just to echo what Orion said: Torque networking is complicated, however once you wrap your head around it, it will quickly become second nature. The relationship between data blocks, server objects, and client objects is a critical one. Once it "clicks", though, you will find a new appreciation for Torque. This is one of the features of Torque which nobody blows trumpets about, but it is easily in my top 5 favorite things.
#8
08/14/2007 (11:46 pm)
Okay, so my team and I have been rethinking our design a little bit (granted, this is less "rethinking our design" and more "trying to figure out how it all works" since we're so new to Torque), but we decided on using tagged strings as a means of storing constant string data between server and client.

After a little figuring out, the clients are receiving the tagged strings just fine. However, the same problem that was happening before is still happening -- when the client receives the string, there is a 255 character limit.

I know that I "shouldn't be sending long strings" to my client, but I figured that it would be allowed if it was just a tagged string, since it is only going to be sent once. Am I doing something wrong, or am I going to have to take a different approach?

If sending the long strings to clients is a bad approach, should I just have the clients load all of these strings from their own local files?

Sorry for all the questions at once. If you only feel like answering one, just help me figure out this 255 character deal =D

Code sample:

// Show the client the quest dialogue for this particular step

// Get the tag for the name of the quest
%questName = %this.questArray[%quest, "questname"];
// Get the tag for the quest dialogue for this particular step
%questDialogue = %this.questArray[%quest, %player.questArray[%quest], "questdialogue"];
// Send the tagged strings off to the client for gui display
commandToClient(%player.client, 'DisplayQuestDialogue', %questName, %questDialogue);

// Display quest dialogue
function clientCmdDisplayQuestDialogue(%questName, %questDialogue) {
     // Show the quest dialogue window
     toggleDialogBox(1);
     // Set the window title to the name of the quest
     GeneralDialogWindowGui.setText(detag(%questName));
     // Set the body of the dialog to the quest dialogue
     GeneralDialogTextGui.setText(detag(%questDialogue));
}

The text cuts off at exactly 255 characters. So, should I look at this from a completely different approach? Should my clients already have this data, and they just load it whenever they need it? What if I want to stick this data on a DB -- I don't want them to have to access the DB...

Anyway, I appreciate all of your help so far. Looking forward to your replies!
#9
08/15/2007 (4:15 am)
CommandToClient () packs its strings using writeString () for each argument, which only supports 255 characters, probably due to the Huffman compression it employs.

You could either write a new commandToClient () call which takes the input and seperates it into 255 buffers, or you can do this in script before you send it away. I wouldn't send so much dialog anyway. Look into SQLLite or some local database flatfile for your data.

You said you don't want them to be able to access the DB. They can access your data even if you send it across the network, and this is infact simpler than getting into a homemade DB.

Just my two cents.