MineCraft config editor part 2


Voice Over     And now for the very first time on the silver screen comes the film from two books which once shocked a generation. From Emily Brontë’s ‘Wuthering Heights’ and from the ‘International Guide to Semaphore Code’. Twentieth Century Vole presents ‘The Semaphore Version of Wuthering Heights’.
CAPTION: ‘THE SEMAPHORE VERSION OF WUTHERING HEIGHTS’

In our last tutorial I left you with some homework to produce a docsting describing the steps we need to do in order to get our MineCraft config editor up and running.

This is what I came up with:

'''Minecraft config editor:
This is an editor for the Minecraft server.properties file.  It:
* opens the file server.properties
* reads, then closes the file
* parses each line by
-- stripping leading and trailing whitespace
-- if the line starts with "#", marks it as a comment
-- splits the line into a key, value pair, with the pair separated by a "=" sign
-- if the value of the pair is either "true" or "false", the entry is marked as a boolean (ie its only values are either true or false)
* displays each key, value entry on the screen allowing you to edit it
* renames the server.properties file to server.properties.bup (overwriting any existing file of that name from earlier edits)
* opens a new file called server.properties
* writes each of the entries to that new file
* closes the server.properties file.
'''

Did you get something like that?  This is our script for writing the program. Most of it we can already do.  In fact, the only thing we can’t do at the moment is ” displays each key, value entry on the screen allowing you to edit it”.  Hey, notice anything different about that listing?  I’ve found WordPress’s special tags for source code.  If you run your mouse over it, some widgets will pop up so you can copy and paste the code.

The other part of your homework was to save the contents of the listing in the previous tute to  a file called “server.properties”.  You need to do that in order to run this tute. Post a comment if you have problems.

Before we dive into reading data from the file we need to think about how we will store the data that we read.  From our docstring we can tell that we might need to store a property key, a property value, a comment and whether or not it’s a property which is only true or false.  We could use a dictionary to store these but, since we’ve just found out about classes, we’re going to use a class instead.  Each instance of the class will hold one line from the configuration file.   We can use the From these we can make a class which describes the properties:

class configItem(object):  # name of the class, it is based on an object called 'object'
  def __init__(self, line):# this is called each time an instance of the class is created
    line = line.strip()  # this removes any white space at the start or end of the line
    # if it starts with a # it's a comment so check for it
    if line[:1] == "#":
       self.configKey = "#"
       self.configVal = line[1:]
    else:  # otherwise assume it's of the form x = y
       spam = line.split("=")
       self.configKey = spam[0]
       self.configVal = spam[1]
    # now check to see whether the config item takes only the values "true" and "false"
    if self.configVal.lower() in ["true","false"]:
       self.isTrueFalse = True
    else:
       self.isTrueFalse = False

So, we have our class. What we need to do is read the data from the file (this, of course, won’t work if you haven’t already saved the file).  See this tute for reading data from files.

# get data from the file

fileName = "server.properties"
fileObject = open(fileName,'rb')
fileData = fileObject.read()
fileObject.close()

Now we will create a configItem instance for each line.  However, we’ll need to keep them in something, so we make an array to do that first.

configLines = []
for line in fileData.split('\n'):  # this splits it into individual lines
    configLines.append(configItem(line))

So, our code at the moment looks like this:

class configItem(object):  # name of the class, it is based on an object called 'object'
  def __init__(self, line):# this is called each time an instance of the class is created
    line = line.strip()  # this removes any white space at the start or end of the line
    # if it starts with a # it's a comment so check for it
    if line[:1] == "#":
       self.configKey = "#"
       self.configVal = line[1:]
    else:  # otherwise assume it's of the form x = y
       spam = line.split("=")
       self.configKey = spam[0]
       self.configVal = spam[1]
    # now check to see whether the config item takes only the values "true" and "false"
    if self.configVal.lower() in ["true","false"]:
       self.isTrueFalse = True
    else:
       self.isTrueFalse = False

# get data from the file

fileName = "server.properties"
fileObject = open(fileName,'rb')
fileData = fileObject.read()
fileObject.close()

configLines = []
for line in fileData.split('\n'):  # this splits it into individual lines
    configLines.append(configItem(line))

for c in configLines:
    print "%s: %s, isTruefalse= %s"%(c.configKey, c.configVal, c.isTrueFalse)

Note: see this tute for  what the %s means.

Debugging

When I run this code on my own copy of the server.properties file I get an error:

Traceback (most recent call last):
File "serverEditor.py", line 33, in <module>
configLines.append(configItem(line))
File "serverEditor.py", line 15, in __init__
self.configVal = spam[1]
IndexError: list index out of range

I added a print statement in the class to print the line it received. It turned out that it had trouble because my file had some extra, blank lines at the end of it.  So I have added some code to skip the line if it is empty:

for line in fileData.split('\n'):  # this splits it into individual lines
    if line.strip()=='':
      continue
    configLines.append(configItem(line))

So now I get this output:

>python serverEditor.py
#: Minecraft server properties, isTruefalse= False
#: Date and time of creation of file, isTruefalse= False
allow-nether: true, isTruefalse= True
level-name: world, isTruefalse= False
enable-query: false, isTruefalse= True
allow-flight: false, isTruefalse= True
server-port: 25565, isTruefalse= False
level-type: DEFAULT, isTruefalse= False
enable-rcon: false, isTruefalse= True
level-seed: , isTruefalse= False
server-ip: , isTruefalse= False
spawn-npcs: true, isTruefalse= True
white-list: false, isTruefalse= True
spawn-animals: true, isTruefalse= True
online-mode: true, isTruefalse= True
pvp: true, isTruefalse= True
difficulty: 1, isTruefalse= False
gamemode: 0, isTruefalse= False
max-players: 20, isTruefalse= False
spawn-monsters: true, isTruefalse= True
generate-structures: true, isTruefalse= True
view-distance: 10, isTruefalse= False
motd: A Minecraft Server, isTruefalse= False

You should check that the data is all correct.  Note that if a line has a value of “true” or “false”, the corresponding item has an attribute called isTrueFalse, which is set to True. So far we have:

* created a class called configItem to describe each line in the file

* opened the file, read each line, and created an instance of the class for each line.

* when a configItem is instantiated, it parses the data which it is initialised with.

Next we will have to work out how to edit them.

Homework: think about what might go wrong with this code.

Here’s the complete code again:

'''Minecraft config editor:
This is an editor for the Minecraft server.properties file.  It:
* opens the file server.properties
* reads, then closes the file
* parses each line by
-- stripping leading and trailing whitespace
-- if the line starts with "#", marks it as a comment
-- splits the line into a key, value pair, with the pair separated by a "=" sign
-- if the value of the pair is either "true" or "false", the entry is marked as a boolean (ie its only values are either true or false)
* displays each key, value entry on the screen allowing you to edit it
* renames the server.properties file to server.properties.bup (overwriting any existing file of that name from earlier edits)
* opens a new file called server.properties
* writes each of the entries to that new file
* closes the server.properties file.
'''

class configItem(object):  # name of the class, it is based on an object called 'object'
  def __init__(self, line):# this is called each time an instance of the class is created
    line = line.strip()  # this removes any white space at the start or end of the line
    # if it starts with a # it's a comment so check for it
    if line[:1] == "#":
       self.configKey = "#"
       self.configVal = line[1:]
    else:  # otherwise assume it's of the form x = y
       spam = line.split("=")
       self.configKey = spam[0]
       self.configVal = spam[1]
    # now check to see whether the config item takes only the values "true" and "false"
    if self.configVal.lower() in ["true","false"]:
       self.isTrueFalse = True
    else:
       self.isTrueFalse = False

# get data from the file

fileName = "server.properties"
fileObject = open(fileName,'rb')
fileData = fileObject.read()
fileObject.close()

configLines = []

for line in fileData.split('\n'):  # this splits it into individual lines
    if line.strip()=='':
      continue
    configLines.append(configItem(line))

for c in configLines:
  print "%s: %s, isTruefalse= %s"%(c.configKey, c.configVal, c.isTrueFalse)

2 Responses to MineCraft config editor part 2

  1. Pingback: Linux News » Python4Kids New Tutorial: MineCraft config editor part 2

  2. Pingback: Links 29/2/2012: Fedora 17 Alpha, MINIX 3.2.0 | Techrights

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.