Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python
- #-------------------------------------------------------------------------------
- # Copyright (c) 2013 Gael Honorez.
- # All rights reserved. This program and the accompanying materials
- # are made available under the terms of the GNU Public License v3.0
- # which accompanies this distribution, and is available at
- # http://www.gnu.org/licenses/gpl.html
- #
- # This program is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #-------------------------------------------------------------------------------
- from PySide import QtCore, QtNetwork
- import _winreg
- import struct
- import os
- import miniserverlogger
- import shutil
- import re
- import subprocess
- import random
- loggerInstance = miniserverlogger.instance
- import logging
- UNIT16 = 8
- class Packet():
- def __init__(self, header=None , data=None, *values, **kwvalues):
- self._data = data
- self._values = kwvalues
- self._header = header
- def Pack(self):
- data = ""
- headerSize = len(str(self._header))
- headerField = str(self._header).replace("\t","/t").replace("\n","/n")
- chunkSize = len(self._data)
- headerPackStr = "<i" + str(headerSize) + "si"
- data += struct.pack(headerPackStr, headerSize, headerField, chunkSize)
- for field in self._data :
- fieldType = 0 if type(field) is int else 1
- chunkPackStr = ""
- fields = []
- if fieldType is 1:
- fieldSize = len(field)
- chunkPackStr += "<bi" + str(fieldSize) + "s"
- fieldStr = str(field).replace("\t","/t").replace("\n","/n")
- fields.extend([fieldType, fieldSize, fieldStr])
- elif fieldType is 0:
- chunkPackStr += "<bi"
- fields.extend([fieldType, field])
- data += struct.pack(chunkPackStr, *fields)
- return data
- class Connection(QtCore.QObject):
- def __init__(self, socket, parent=None):
- super(Connection, self).__init__(parent)
- self.parent = parent
- self.log = logging.getLogger('miniserver')
- self.log.setLevel( logging.DEBUG )
- self.log.addHandler(loggerInstance.getHandler())
- self.log.debug("Incoming FA socket")
- self.socket = QtNetwork.QTcpSocket(self)
- if self.socket.setSocketDescriptor(socket) == False :
- self.log.debug("awful error : Socket descriptor not set")
- self.socket.abort()
- return
- self.props = {}
- self.socket.readyRead.connect(self.readData)
- self.socket.disconnected.connect(self.disconnection)
- self.socket.error.connect(self.displayError)
- self.socket.stateChanged.connect(self.stateChange)
- #self.initSupcom()
- self.action = None
- self.chunks = []
- self.headerSizeRead = False
- self.headerRead = False
- self.chunkSizeRead = False
- self.fieldTypeRead = False
- self.fieldSizeRead = False
- def process(self, action, chunks):
- self.log.info(action + " : " + str(chunks))
- if action == 'GameState':
- if chunks[0] == 'Idle':
- self.initSupcom()
- elif chunks[0] == 'Lobby':
- self.hostGame()
- self.SendFaPath()
- elif action == "addProp":
- self.addProp()
- elif action.lower() == "savetofile":
- self.saveToFile(chunks[0], chunks[1])
- elif action.lower() == "appendtofile":
- self.saveToFile(chunks[0], chunks[1], chunks[2])
- elif action.lower() == "preparetemplatefiles":
- self.prepareTemplateFiles(chunks[0], chunks[1], chunks[2], chunks[3], builder=True, pattern ="'builder'")
- elif action.lower() == "savetemplatefiles":
- self.saveTemplateFiles(chunks[0], chunks[1], chunks[2], builder=True, pattern ="'builder'")
- elif action.lower() == "removetemplatefiles":
- self.removeTemplateFiles(chunks[0])
- elif action.lower() == "backuptemplatefiles":
- self.backupTemplateFiles(chunks[0])
- elif action.lower() == "savemapfiles":
- self.saveMapFiles(chunks[0], chunks[1], chunks[2], builder=True, pattern="'episodeofwar'")
- elif action.lower() == "removemapfiles":
- self.removeMapFiles(chunks[0])
- elif action.lower() == "writescenariodata":
- self.writeScenarioData(chunks[0], chunks[1])
- elif action.lower() == "backupscenariodata":
- self.backupScenarioData(chunks[0])
- elif action.lower() == "commitscenariodata":
- self.commitScenarioData(chunks[0], chunks[1])
- elif action.lower() == "writesavedata":
- self.writeSaveData(chunks[0], chunks[1])
- elif action.lower() == "backupsavedata":
- self.backupSaveData(chunks[0])
- elif action.lower() == "commitsavedata":
- self.commitSaveData(chunks[0], chunks[1])
- def SendFaPath(self):
- reply = Packet("JoinGame", [self.GetFaPath(), "FaEditor", int(100000)])
- self.send(reply)
- def prepareTemplateFiles(self, templateId, mapName, save, scenario, builder = False, pattern = None):
- faPath = self.GetFaPath()
- templatePath = os.path.join(faPath, "_templates", templateId )
- if not os.path.exists(templatePath):
- os.makedirs(templatePath)
- scenarioFile = os.path.join(templatePath, templateId + "_template_scenario.lua")
- saveFile = os.path.join(templatePath, templateId + "_template_save.lua")
- scriptFile = os.path.join(templatePath, templateId + "_template_script.lua")
- origMapFile = os.path.join(faPath, "maps", mapName, mapName + ".scmap")
- newMapFile = os.path.join(templatePath, templateId + ".scmap")
- file = QtCore.QFile(scenarioFile)
- file.open(QtCore.QIODevice.WriteOnly)
- file.write("version = 3")
- file.write("\n")
- if builder and pattern != None:
- rep = re.compile("type.*=.*('.+')")
- match = re.search(rep, scenario)
- if match:
- scenario.replace(match.group(1), pattern)
- file.write("ScenarioInfo" + " = " + scenario)
- file.close()
- file = QtCore.QFile(saveFile)
- file.open(QtCore.QIODevice.WriteOnly)
- file.write("Scenario" + " =" + save)
- file.close()
- if not os.path.exists(scriptFile):
- shutil.copy2('script.lua', scriptFile)
- if not os.path.exists(newMapFile):
- shutil.copy2(origMapFile, newMapFile)
- def saveTemplateFiles(self, scenarioid, save, scenario, builder = False, pattern = None):
- faPath = self.GetFaPath()
- templatePath = os.path.join(faPath, "_templates", scenarioid )
- self.backupTemplateFiles(scenarioid)
- if not os.path.exists(templatePath):
- os.makedirs(templatePath)
- scenarioFile = os.path.join(templatePath, scenarioid + "_template_scenario.lua")
- saveFile = os.path.join(templatePath, scenarioid + "_template_save.lua")
- scriptFile = os.path.join(templatePath, scenarioid + "_template_script.lua")
- file = QtCore.QFile(scenarioFile)
- file.open(QtCore.QIODevice.WriteOnly)
- file.write("version = 3")
- file.write("\n")
- if builder and pattern != None:
- rep = re.compile("type.*=.*('.+')")
- match = re.search(rep, scenario)
- if match:
- scenario.replace(match.group(1), pattern)
- file.write("ScenarioInfo" + " = " + scenario)
- file.close()
- file = QtCore.QFile(saveFile)
- file.open(QtCore.QIODevice.WriteOnly)
- file.write("Scenario" + " =" + save)
- file.close()
- if not os.path.exists(scriptFile):
- shutil.copy2('script.lua', scriptFile)
- def backupTemplateFiles(self, scenarioid):
- faPath = self.GetFaPath()
- templatePath = os.path.join(faPath, "_templates", scenarioid )
- backupPath = os.path.join(faPath, "_templates", scenarioid, "backup" )
- if os.path.exists(templatePath):
- if not os.path.exists(backupPath):
- os.makedirs(backupPath)
- scenarioFile = os.path.join(templatePath, scenarioid + "_template_scenario.lua")
- saveFile = os.path.join(templatePath, scenarioid + "_template_save.lua")
- scriptFile = os.path.join(templatePath, scenarioid + "_template_script.lua")
- backupScenarioFile = os.path.join(backupPath, scenarioid + "_backup_scenario.lua")
- backupSaveFile = os.path.join(backupPath, scenarioid + "_backup_save.lua")
- backupScriptFile = os.path.join(backupPath, scenarioid + "_backup_script.lua")
- shutil.copy2(scenarioFile, backupScenarioFile)
- shutil.copy2(saveFile, backupSaveFile)
- shutil.copy2(scriptFile, backupScriptFile)
- def removeTemplateFiles(self, scenarioid):
- faPath = self.GetFaPath()
- templatePath = os.path.join(faPath, "_templates", scenarioid )
- if os.path.exists(templatePath):
- shutil.rmtree(templatePath)
- def saveMapFiles(self, scenarioid, save, scenario, builder = False, pattern = None):
- faPath = self.GetFaPath()
- templatePath = os.path.join(faPath, "_templates", scenarioid )
- mapPath = os.path.join(faPath, "maps", scenarioid )
- if not os.path.exists(mapPath):
- os.makedirs(mapPath)
- scenarioFile = os.path.join(mapPath, scenarioid + "_scenario.lua")
- saveFile = os.path.join(mapPath, scenarioid + "_save.lua")
- scriptFile = os.path.join(templatePath, scenarioid + "_template_script.lua")
- newscriptFile = os.path.join(mapPath, scenarioid + "_script.lua")
- origMapFile = os.path.join(templatePath, scenarioid + ".scmap")
- newMapFile = os.path.join(mapPath, scenarioid + ".scmap")
- file = QtCore.QFile(scenarioFile)
- file.open(QtCore.QIODevice.WriteOnly)
- file.write("version = 3")
- file.write("\n")
- if builder and pattern != None:
- rep = re.compile("type.*=.*('.+')")
- match = re.search(rep, scenario)
- if match:
- scenario.replace(match.group(1), pattern)
- file.write("ScenarioInfo" + " = " + scenario)
- file.close()
- file = QtCore.QFile(saveFile)
- file.open(QtCore.QIODevice.WriteOnly)
- file.write("Scenario" + " = " + save)
- file.close()
- shutil.copy2(scriptFile, newscriptFile)
- if not os.path.exists(newMapFile):
- shutil.copy2(origMapFile, newMapFile)
- def removeMapFiles(self, scenarioid):
- faPath = self.GetFaPath()
- mapPath = os.path.join(faPath, "maps", scenarioid )
- if os.path.exists(mapPath):
- shutil.rmtree(mapPath)
- def writeScenarioData(self, scenarioid, text):
- faPath = self.GetFaPath()
- templatePath = os.path.join(faPath, "_templates", scenarioid )
- scenarioFile = os.path.join(templatePath, scenarioid + "_template_scenario.lua")
- self.backupScenarioData(scenarioid)
- if not os.path.exists(templatePath):
- os.makedirs(templatePath)
- file = QtCore.QFile(scenarioFile)
- file.open(QtCore.QIODevice.WriteOnly)
- file.write("ScenarioInfo" + " = " + text)
- file.write("\n")
- file.write("version = 3")
- file.close()
- def backupScenarioData(self, scenarioid):
- faPath = self.GetFaPath()
- templatePath = os.path.join(faPath, "_templates", scenarioid )
- backupPath = os.path.join(faPath, "_templates", scenarioid, "backup" )
- if os.path.exists(templatePath):
- if not os.path.exists(backupPath):
- os.makedirs(backupPath)
- scenarioFile = os.path.join(templatePath, scenarioid + "_template_scenario.lua")
- backupScenarioFile = os.path.join(backupPath, scenarioid + "_backup_scenario.lua")
- shutil.copy2(scenarioFile, backupScenarioFile)
- def commitScenarioData(self, scenarioid, text):
- faPath = self.GetFaPath()
- mapPath = os.path.join(faPath, "maps", scenarioid )
- scenarioFile = os.path.join(mapPath, scenarioid + "_scenario.lua")
- if os.path.exists(mapPath):
- file = QtCore.QFile(scenarioFile)
- file.open(QtCore.QIODevice.WriteOnly)
- file.write("ScenarioInfo" + " = " + text)
- file.write("\n")
- file.write("version = 3")
- file.close()
- def writeSaveData(self, scenarioid, text):
- faPath = self.GetFaPath()
- templatePath = os.path.join(faPath, "_templates", scenarioid )
- saveFile = os.path.join(templatePath, scenarioid + "_template_save.lua")
- self.backupSaveData(scenarioid)
- if not os.path.exists(templatePath):
- os.makedirs(templatePath)
- file = QtCore.QFile(saveFile)
- file.open(QtCore.QIODevice.WriteOnly)
- file.write("Scenario" + " = " + text)
- file.close()
- def backupSaveData(self, scenarioid):
- faPath = self.GetFaPath()
- templatePath = os.path.join(faPath, "_templates", scenarioid )
- backupPath = os.path.join(faPath, "_templates", scenarioid, "backup" )
- if os.path.exists(templatePath):
- if not os.path.exists(backupPath):
- os.makedirs(backupPath)
- saveFile = os.path.join(templatePath, scenarioid + "_template_save.lua")
- backupSaveFile = os.path.join(backupPath, scenarioid + "_backup_save.lua")
- shutil.copy2(saveFile, backupSaveFile)
- def commitSaveData(self, scenarioid, text):
- faPath = self.GetFaPath()
- mapPath = os.path.join(faPath, "maps", scenarioid )
- saveFile = os.path.join(mapPath, scenarioid + "_save.lua")
- if os.path.exists(mapPath):
- file = QtCore.QFile(saveFile)
- file.open(QtCore.QIODevice.WriteOnly)
- file.write("Scenario" + " = " + text)
- file.close()
- def saveToFile(self, f, text):
- if not os.path.exists(os.path.dirname(f)):
- os.makedirs(os.path.dirname(f))
- file = QtCore.QFile(f)
- file.open(QtCore.QIODevice.WriteOnly)
- file.write(text)
- file.close()
- def appendToFile(self, f, tableName, text):
- if not os.path.exists(os.path.dirname(f)):
- os.makedirs(os.path.dirname(f))
- file = QtCore.QFile(f)
- file.open(QtCore.QIODevice.Append)
- file.write(tableName + " =" + text)
- file.close()
- def addProp(self, chuncks):
- what = chuncks[0]
- x = int(chuncks[1])
- y = int(chuncks[2])
- self.props[what] = [x,y]
- def initSupcom(self):
- reply = Packet("CreateLobby", [0, 0, "Campaign Editor", 0, 1])
- self.send(reply)
- def hostGame(self):
- reply = Packet("HostGame", ["SCMP_007"])
- self.send(reply)
- def stateChange(self, socketState):
- if socketState != QtNetwork.QAbstractSocket.ClosingState :
- self.log.debug("socket about to close")
- elif socketState != QtNetwork.QAbstractSocket.UnconnectedState :
- self.log.debug("socket not connected")
- if socketState != QtNetwork.QAbstractSocket.ConnectedState :
- self.log.debug("not connected")
- self.socket.abort()
- def displayError(self, socketError):
- if socketError == QtNetwork.QAbstractSocket.RemoteHostClosedError:
- self.log.warning("RemoteHostClosedError")
- elif socketError == QtNetwork.QAbstractSocket.HostNotFoundError:
- self.log.warning("HostNotFoundError")
- elif socketError == QtNetwork.QAbstractSocket.ConnectionRefusedError:
- self.log.warning("ConnectionRefusedError")
- else:
- self.log.warning("The following Error occurred: %s." % self.socket.errorString())
- def readData(self):
- self.log.info("reading socket from FA")
- if self.socket.bytesAvailable() == 0 :
- self.log.info("data reception read done - too or not enough data")
- return
- ins = QtCore.QDataStream(self.socket)
- ins.setByteOrder(QtCore.QDataStream.LittleEndian)
- while ins.atEnd() == False :
- if self.socket.isValid() :
- if self.headerSizeRead == False :
- if self.socket.bytesAvailable() < 4:
- return
- self.blockSize = ins.readUInt32()
- self.headerSizeRead = True
- if self.headerRead == False :
- if self.socket.bytesAvailable() < self.blockSize :
- return
- self.action = ins.readRawData(self.blockSize)
- self.headerRead = True
- if self.chunkSizeRead == False :
- if self.socket.bytesAvailable() < 4:
- return
- self.chunkSize = ins.readInt32()
- self.chunks = []
- self.chunkSizeRead = True
- if self.chunkSize > 100 :
- self.__logger.info("Big error reading FA datas !")
- self.socket.readAll()
- self.fieldSize = 0
- self.blockSize = 0
- self.chunkSize = 0
- self.noSocket = True
- return
- for _ in range(len(self.chunks), self.chunkSize):
- if self.fieldTypeRead == False :
- if self.socket.bytesAvailable() < 1 :
- return
- self.fieldType = ins.readBool()
- self.fieldTypeRead = True
- if not self.fieldType :
- if self.socket.bytesAvailable() < 4 :
- return
- number = ins.readInt32()
- self.chunks.append(number)
- self.fieldTypeRead = False
- else :
- if self.fieldSizeRead == False :
- if self.socket.bytesAvailable() < 4 :
- return
- self.fieldSize = ins.readInt32()
- self.fieldSizeRead = True
- if self.socket.bytesAvailable() < self.fieldSize :
- return
- datastring = ins.readRawData(self.fieldSize)
- fixedStr = datastring.replace("/t","\t").replace("/n","\n")
- self.chunks.append(fixedStr)
- self.fieldTypeRead = False
- self.fieldSizeRead = False
- self.process(self.action, self.chunks)
- self.action = None
- self.chunks = []
- self.headerSizeRead = False
- self.headerRead = False
- self.chunkSizeRead = False
- self.fieldTypeRead = False
- self.fieldSizeRead = False
- def send(self, reply):
- self.socket.write(reply.Pack())
- def disconnection(self):
- self.parent.removeConnection(self)
- def GetFaPath(self):
- '''
- Retrieves the Path as configured in the settings
- '''
- settings = QtCore.QSettings("ForgedAllianceForever", "FA Lobby")
- settings.beginGroup("ForgedAlliance")
- path = unicode(settings.value("app/path"))
- settings.endGroup()
- return path
- class start(QtNetwork.QTcpServer):
- def __init__(self, parent=None):
- super(start, self).__init__(parent)
- self.log = logging.getLogger('miniserver.main')
- self.log.setLevel( logging.DEBUG )
- self.log.addHandler(loggerInstance.getHandler())
- self.connections = []
- FaPath = self.SetFaPath()
- if not FaPath:
- self.log.info("Forged Alliance path could not be found")
- raise Exception("Forged Alliance path could not be found")
- self.log.info("Forged Alliance Path Found.")
- print "Forged Alliance Path Found."
- if not self.listen(QtNetwork.QHostAddress.LocalHost, 1234):
- self.log.error ("Unable to start the server on port 1234")
- raise Exception("Unable to start the mini server on port 1234")
- print "Server started on port " + str(self.serverPort())
- self.log.info("starting the server on port " + str(self.serverPort()))
- FaExePath = os.path.join(FaPath, "bin" , "forgedalliance.exe")
- # if os.path.isfile(FaExePath):
- # subprocess.call([FaExePath, " -debug /enablediskwatch /purgecache /window 1024 768 /campaignbuilder /showlog /gpgnet 127.0.0.1:1234"])
- def incomingConnection(self, socketId):
- print "Forged Allaince Connection Established"
- self.log.debug("Forged Allaince Connection Established")
- self.connections.append(Connection(socketId, self))
- def removeConnection(self, connection):
- if connection in self.connections:
- self.connections.remove(connection)
- connection.deleteLater()
- def SetFaPath(self):
- for path in self.mostProbablePaths():
- if self.validatePath(path):
- self.setPathInSettings(path)
- return path
- return None
- def mostProbablePaths(self):
- '''
- Returns a list of the most probable paths where Supreme Commander: Forged Alliance might be installed
- '''
- pathlist = []
- #Retail path
- pathlist.append(os.path.expandvars("%ProgramFiles%\\THQ\\Gas Powered Games\\Supreme Commander - Forged Alliance"))
- #Direct2Drive Paths
- #... allegedly identical to impulse paths - need to confirm this
- #Impulse/GameStop Paths - might need confirmation yet
- pathlist.append(os.path.expandvars("%ProgramFiles%\\Supreme Commander - Forged Alliance"))
- #Steam path
- pathlist.append(os.path.expandvars("%ProgramFiles%\\Steam\\steamapps\\common\\supreme commander forged alliance"))
- #Construe path from registry traces - this is not a very safe method, but it seems to work for plain installs
- try :
- regkey = "SOFTWARE\\Classes\\SCFAReplayType\\Shell\\Open\\Command"
- key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, regkey)
- path = _winreg.QueryValue(key, "")
- if "ForgedAlliance.exe" in path:
- path = path[:path.rfind("bin")]
- path = path.rstrip('"/\\')
- pathlist.append(os.path.expandvars(path))
- except :
- pass
- return pathlist
- def validatePath(self, path):
- try:
- # Supcom only supports Ascii Paths
- if not path.decode("ascii"): return False
- #We check whether the base path and a gamedata/lua.scd file exists. This is a mildly naive check, but should suffice
- if not os.path.isdir(path): return False
- if not os.path.isfile(os.path.join(path, r'gamedata', r'lua.scd')): return False
- #Reject or fix paths that end with a slash.
- #LATER: this can have all sorts of intelligent logic added
- #Suggested: Check if the files are actually the right ones, if not, tell the user what's wrong with them.
- if path.endswith("/"): return False
- if path.endswith("\\"): return False
- return True
- except:
- _, value, _ = sys.exc_info()
- logger.error(u"Path validation failed: " + unicode(value))
- return False
- def setPathInSettings(self, path):
- '''
- Stores the new path for Forged Alliance in the app settings
- '''
- settings = QtCore.QSettings("ForgedAllianceEditor", "FA Editor")
- settings.beginGroup("ForgedAllianceEditor")
- settings.setValue("app/path", path)
- settings.endGroup()
- settings.sync()
- def getPathFromSettings(self):
- '''
- Retrieves the Path as configured in the settings
- '''
- settings = QtCore.QSettings("ForgedAllianceEditor", "FA Editor")
- settings.beginGroup("ForgedAllianceEditor")
- path = unicode(settings.value("app/path"))
- settings.endGroup()
- return path
- if __name__ == '__main__':
- import sys
- app = QtCore.QCoreApplication(sys.argv)
- server = start()
- app.exec_()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement