Load internal text files?

Hi all

I would like to ask how could i make a script load external texts (not-scripts).

My game actually uses text files to extend information for the game. But i want to avoid it to be in an separate folder.

It has been always this:


beatmaps="beatmaps/"

with open(bge.logic.expandPath("//"+beatmaps+vm['beatfile']), 'r') as f:
        for lines in f:
            line=lines.strip()

Is it possible to replace expandPath by something else, so that these lines with open the text internally from the game?

The only way (besides creating the text block as a module, and creating a string variable within) is to assign the text block to a Python Script Controller, and read the controller source.

If it’s not a big file I sometimes do what Agoose said, put it in a string or dictionary format in a script, then import it as a module. If you check out my BGMC16 entry you can see that the level data is saved as a dictionary and then imported.

The good thing about this is you can preserve python structures such as dictionaries more easily than you would loading a text file.

Thank you for sharing

agoose77, said to read the script attribute from the controller. He did not mention to surround the text by python code. This is a different method.

One question: Why would you place a configuration file inside the blend?
This contradicts the idea of separating configuration from code. You force the user to open and edit the blend file to adjust the configuration.

If the user has to do that anyway you can choose other methods of configuration which is a bit more handy e.g. setting up properties, editing python modules with configuration code.

Sometimes I want to pack all external files in the blend for sharing.

Technically, I said both :wink: I prefer loading it as a text file, externally, but otherwise I would likely (and have done) use the script controller.

In that case you do not need a configuration file as there is none available to the user.

I suggest to implement a way to read an external configuration file with handling default values internally. This way any missing parameter will be set to a valid default value. This includes the situation when there is no configuration file.

This should satisfy both, the wish of you to deliver a single file and the wish of the user to adjust the game to the environment (without the need to edit it with Blender).

Thanks all for your methodes. Actually i dont really know how to apply these all to my game… Please tell me more about that.

Monster, as you know i am making a music game. All the timing configurations are saved in the file like this. Its formated as txt… and so if player just opens the file and reedit everything. The gameplay will be changed too. Currently all the timing files are placed in one separate folder.


songname=Kickdown (EN)
artist=JAJO & GITH
level=S
duration=1:34
bpm=143.02
delay=107
dancer=35
speed=2.38


###DANCE###
157-0
1494-1 #animation example ('-' is separator for dancer animation)
2170-2 # dance 2
2506-3 #dance3
2842-6 #dance 6
3177-1 #dance 1
3849-2  #dance 2
4184-3 #dance3 
4520-6 #dance 6
5023-4 #dance4
5694-7 #dance7
6030-5 #dance5
6366-4 #dance4
7037-7 #dance7
7373-5 #dance5
###Camera###
157>cam 9 #2
828>cam 3
1494>cam 8
2170>cam 7
2506>cam 1
3177>cam 4
###Arrows####
1494,u
1541,o
1583,j
1625,l
1667,u
1709,o
1751,j
1793,k
....

So if I understand correctly. You deliver the game as single file.

When running the game creates a configuration file.
The user can manipulate the configuration file.
The game reads the updated configuration.

The game updates the configuration when running?

If that is the case it sounds you need one of the libraries that can read/write configuration data (e.g. .ini files, .property files)

Ah, there’s some confusion.
Configuration file would be a small text file that holds some variables that you can change, either manually editing or using a GUI…
Usually it would set how the game plays, like screen resolution, debugging, Anti-aliasing etc… right?

But sometimes there’s a need to include some non-blender data in a game, like map data, or song titles or enemy stats or whatever.
This data is sometimes pretty big, hundreds of lines. It could be stored as a text file and opened, or you could paste it in to blender’s internal text editor and import it as a module (something I sometimes like to do with casual games, because as I said, it keeps everything in a single file). The downside of this is IDK if it can be written to, or if it would even be wise to try, but anyway, this data is usually read only data anyway.

Kind of like getter.blend (428 KB).

@ Monster

The file actually gets loaded everytime i change the song number. It will load every lines into the memory. When the game runs, it just actually compares the timer with those loaded values. So the text files outside are just static and used once. It will not be updated during the game play. I figured that it could be something like encrypting for that? Or just give all the text files into the game…

@ Smoking Mirror

thanks for the provided file. I took a look into it. But somehow i dont understand really clearly. The whole system of loading text files was done by Pohjan from our forum. And its kinda working with expandPath like this. It gonna be difficult for me to change all of that.
Is there another way to imitate the function of expandPath but just internally in the game?


beatmaps="beatmaps/"

with open(bge.logic.expandPath("//"+beatmaps+vm['beatfile']), 'r') as f:
        for lines in f:
            line=lines.strip()

So it is supposed to be a save state? With that I even see less problems.

Btw. You can place your data in globalDict and save it with the SaveActuator. This way it is not human readable and you do not need to fiddle with file i/o by yourself.

Self manipulating applications are a no-go (as you would need when you want to write to a blender file). Very suspicious to any malware detection system.

Hm i dont know how to figure all that out. So its about saving all those into another files?

maybe you just need some help with the file string?

right now you’ve got expandPath going to a folder called beatmaps to pick up a file called ??? (specified by vm[‘beatfile’])

So maybe you just need:



path  = bge.logic.expandPath("//")

with open(path + vm['beatfile'], 'r') as f:
        for lines in f:
            line=lines.strip()

If you want to put your text file in the same folder as your blend.

You can take a look around the net for some help with filepaths.

so it cannot be inside the game :confused: i just want to avoide players to change the information in vm[‘beatfile’] ( song.txt )

As I said, you can put it in a text file in game (the text window), name it with .py and import it.
It takes more work to change your code though.
You have to make it a string, and import the string.


song_data = """songname=Kickdown (EN)
artist=JAJO & GITH
level=S
...

###DANCE###
157-0
1494-1 #animation example ('-' is separator for dancer animation)
2170-2 # dance 2
2506-3 #dance3

...."""

Use three quotes at the start and end to preserve the lines.
Then import it (as I did in the demo above) and use string.splitlines() to get your lines.

i just then use this?

with open(path + vm[‘beatfile’], ‘r’) as f:
for lines in f:
line=lines.strip()

Here’s an example of what I proposed
untitled.blend (463 KB)

Here’s an example of SmokingMirror’s proposal
untitled1.blend (463 KB)

thank you alot for the examples. I see they load all the text information

In agoose’s example. the lines are loaded but not separated. The one of Smoking mirrors shows exactly how the text is structured. I see it in the console.

Because all these information will be translated into different timing values for the game. So it should be loaded into the script like this way
path = bge.logic.expandPath("//beatmaps/")

with open(path + vm[‘beatfile’], ‘r’) as f:
for lines in f:
line=lines.strip()

how can we change that path line so that it will load the text?
the arrows under here are just supposed to point the converted information and the script. The error below is caused by libload. but its harmless