Just wanted to share that my first first-author paper is now online! In the journal Stem Cells and Development, here’s my paper on “Roles of Integrins in Human Induced Pluripotent Stem Cell Growth on Matrigel and Vitronectin.”
So, I’ve been having a great deal of fun playing Minecraft with my friends lately. I’m hosting a server on the Ubuntu 12.04 box in my basement that doubles as my media center, and it works pretty well supporting 6 or 7 simultaneous players.
One of my favorite things about minecraft is the high detail that the log files contain: when players join, when they leave, number and causes of player deaths. Being the data-driven type that I am, I’ve been writing some quick python scripts to combine the log files and strip out extraneous information (MC_LogParse.py), make a nice csv file of the deaths of each player (MC_DeathLog.py), and add up total time played for each player (MC_Playtime.py). I thought I’d share them below, for anyone interested– all should be compatible with stock Minecraft 1.7.4. They work on Ubuntu and OSX, at least. I also included the list of terms I strip out of log files (log_terms.txt).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | #!/usr/bin/env python # Minecraft Log File Parser # v 0.1 # Copyright 2014, Andrew J. Bonham #Imports import os import argparse import glob from subprocess import Popen, PIPE #Set up a command line parser to help use the script effectively parser = argparse.ArgumentParser(description='Process Minecraft Log Files') parser.add_argument("directory", help="select a directory of logfiles to process") parser.add_argument("logterms", help="text file with a list of terms to exclude from the logs (one term per line)") parser.add_argument("output", help="specify an output file") args = parser.parse_args() #Grab the list of log files and sort by date os.chdir(args.directory) files = glob.glob('*.log.gz') files.sort() bigLog = [] #File Processing - read each file and remove unnecessary lines ("Served Saved", etc) for each in files: bigLog.append(str(each)) process=Popen(['zcat', each],stdout=PIPE) process2=Popen(['grep','-i','-v','-f',str(args.logterms)],stdin=process.stdout,stdout=PIPE) out2,err2 = process2.communicate() bigLog.append(out2) #Write it all to a final log file logfile = open(args.output,'w') for item in bigLog: logfile.write("{}\n".format(item)) logfile.close() |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | #!/usr/bin/env python # Add up deaths in Minecraft Logs # v 0.1 # Copyright 2014, Andrew J. Bonham #Imports and constants import re import argparse import csv #Parse command line parser = argparse.ArgumentParser() parser.add_argument("logfile", help="specify a logfile to process") parser.add_argument("output", help="specify an output file") args = parser.parse_args() #Read the logfile into a list of lines theLog = [] fileObject = open(args.logfile,'r') for line in fileObject: theLog.append(line) fileObject.close() #Setup an output list outputDict = {} #Player List #TODO: Extract names with a regex \w+ search nameList = ['mrwynd','Paradoxdruid', 'duv67','BoulderMeg','chrreev','Moakalot','Siruial','tetriseyes', 'wolpoff','Davide303','Ryujinamida','SusaBee'] #Have a set of death messages to match deathMsg= ["was squashed by a falling anvil","was pricked to death", "walked into a cactus whilst trying to escape", "was shot by arrow", "drowned", "blew up", "was blown up by", "hit the ground too hard", "fell from a high place", "fell off a ladder", "fell off some vines", "fell out of the water", "fell into a patch of fire", "fell into a patch of cacti", "was doomed to fall", "was shot off some vines by", "was shot off a ladder by", "was blown from a high place by", "went up in flames", "burned to death", "was burnt to a crisp whilst fighting", "walked into a fire whilst fighting", "was slain by", "was shot by", "was fireballed by", "was killed by", "got finished off by", "was slain by", "tried to swim in lava", "died", "got finished off by", "was slain by", "was shot by", "was killed by", "was killed by magic", "starved to death", "suffocated in a wall", "was killed while trying to hurt", "fell out of the world", "fell from a high place and fell out of the world", "was knocked into the void by", "withered away"] #Add names to the Dictionary for name in nameList: outputDict[name] = [] #Process the logfile looking for death events for line in theLog: for message in deathMsg: diedOnServer = re.search(message,line) if diedOnServer: for name in nameList: playerName = re.search(name,line) if playerName: chatter = re.search(r".*\< .*",line) if chatter: #if people chatted using the keywords, exclude it pass else: cause = re.search(r"\[(.*)\] \[Server thread/INFO\]: \w+ (.*)$",line) if cause.group(2): outputDict[name].append(cause.group(2)) #Tally Dictionary tallyDict = {} for key, value in outputDict.items(): if not key in tallyDict.keys(): tallyDict[key] = {} else: pass for item in value: if not item in tallyDict[key].keys(): tallyDict[key][item] = 0 tallyDict[key][item] += 1 #Write the output to a CSV file with open(args.output,'wb') as csvfile: writer = csv.writer(csvfile) for key, value in tallyDict.items(): writer.writerow([key]) for key_, value_ in value.items(): writer.writerow([key_,value_]) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | #!/usr/bin/env python # Add up playtime in Minecraft Logs # v 0.1 # Copyright 2014, Andrew J. Bonham #Imports and constants import time import re import argparse import csv import datetime #Parse command line parser = argparse.ArgumentParser() parser.add_argument("logfile", help="specify a logfile to process") parser.add_argument("output", help="specify an output file") args = parser.parse_args() #Read the logfile into a list of lines theLog = [] fileObject = open(args.logfile,'r') for line in fileObject: theLog.append(line) fileObject.close() #Setup an output list outputDict = {} #Player list #TODO: Extract automagically nameList = ['mrwynd','Paradoxdruid', 'duv67','BoulderMeg','chrreev','Moakalot','Siruial','tetriseyes', 'wolpoff','Davide303','Ryujinamida','SusaBee'] date_pattern = '%H:%M:%S %Y-%m-%d' #Add names to the Dictionary for name in nameList: outputDict[name] = 0 #Process the logfile looking for join and leave events for line in theLog: #find each log file start logstart = re.search(r"^(201\d-\d+-\d+).*",line) if logstart: start_time = logstart.group(1) continue #Find player joined notifications joinedServer = re.search(r"\[(.*)\] \[Server thread/INFO\]: (.*) joined the game",line) if joinedServer: full_start = str(joinedServer.group(1))+" "+str(start_time) log_start_time = int(time.mktime(time.strptime(full_start,date_pattern))) outputDict[joinedServer.group(2)] -= log_start_time continue #Find player left notifications leftServer = re.search(r"\[(.*)\] \[Server thread/INFO\]: (.*) left the game",line) if leftServer: full_stop = str(leftServer.group(1))+" "+str(start_time) log_stop_time = int(time.mktime(time.strptime(full_stop,date_pattern))) outputDict[leftServer.group(2)] += log_stop_time continue #Convert seconds into human readable format for key,value in outputDict.items(): outputDict[key] = str(datetime.timedelta(seconds=value)) #Write the output to a CSV file with open(args.output,'wb') as csvfile: writer = csv.writer(csvfile) for key, value in outputDict.items(): writer.writerow([key]) writer.writerow([value]) |
1 2 3 4 5 6 7 8 9 | saved saving online given uuid connection overloaded backup game mode |
You must be logged in to post a comment.
Welcome to Paradoxdruid's Rants... a community based webblog. Feel free to snag an account and post.
Contributors Login
advice animals books computers crafts environment family food gadgets games garden honeymoon Links linux movies pedagogy personal pets philosophy photos politics rpg school science travel tv weddings whining work writing
Just wanted to share that my first first-author paper is now online! In the journal Stem Cells and Development, here’s my paper on “Roles of Integrins in Human Induced Pluripotent Stem Cell Growth on Matrigel and Vitronectin.”
Just read a fascinating (if lengthy) essay on disruptive technology and the future of scientific publishing. Well worth the read!
Just wanted to share Mint.com’s Visual Guide to Deflation, which is quite explanatory.
Hey all Paradoxdruid readers! I recently started up a blog on stem cells that I’d love you all to take a look at: http://www.allthingsstemcell.com/
I participated in another Barely literate book review podcast, this time on Nicholson Baker’s “The Fermata”. Give it a listen!
Obama has outlined a strategy for America, in great depth. Read all about Change.gov!
Okay, I’ll admit that it’s entirely possible that I am the last person to learn about this website*, but it’s really addictive.Â
(continued)
Site best viewed in Mozilla Firefox. Site CSS template by Andrea Pitschmann. Banner photo by photocase.