diff --git a/src/scon/analyze.py b/src/scon/analyze.py
index 43f92ed..f0438d6 100644
--- a/src/scon/analyze.py
+++ b/src/scon/analyze.py
@@ -1,90 +1,90 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-"""
- Tool to analyze Logs in general.
-"""
-import os, sys, logging
-from logs.logfiles import LogFileResolver as LogFile
-from logs import combat, game, chat
-from logs.session import LogSessionCollector
-from logs.game import ClientInfo
-
-# for windows its kinda this:
-settings = {'root_path': os.path.join(os.path.expanduser('~'),
- 'Documents',
- 'My Games',
- 'StarConflict',),
- 'logfiles': os.path.join(os.path.expanduser('~'),
- 'Documents',
- 'My Games',
- 'StarConflict',
- 'logs'
- )}
-
-
-if __name__ == '__main__':
- import logging
- logging.basicConfig(level=logging.DEBUG,
- format='%(asctime)s - %(message)s',
- datefmt='%Y-%m-%d %H:%M:%S')
- coll = LogSessionCollector(os.path.join(os.path.expanduser('~'),
- 'Documents', 'My Games', 'sc'))
- coll.collect_unique()
- #f = open('output.txt', 'w')
- rex_combat = {}
- rex_game = {}
- rex_chat = {}
- LOG_GOOD = True # Log good packets.
- for logf in coll.sessions:
- logf.parse_files(['game.log', 'combat.log', 'chat.log'])
-
- print "----- Log %s -----" % logf.idstr
- if logf.combat_log:
- for l in logf.combat_log.lines:
- if isinstance(l, dict):
- #print l
- rex_combat['dict'] = rex_combat.get('dict', 0) + 1
- else:
- if not l.unpack() or LOG_GOOD:
- rex_combat[l.__class__.__name__] = rex_combat.get(l.__class__.__name__, 0) + 1
- if not isinstance(l, combat.UserEvent):
- if not LOG_GOOD:
- print l.values['log']
- if logf.game_log:
- for l in logf.game_log.lines:
- if isinstance(l, dict):
- rex_game['dict'] = rex_game.get('dict', 0) + 1
- elif isinstance(l, str):
- print l
- else:
- if l.unpack() and not LOG_GOOD:
- pass
- else:
- rex_game[l.__class__.__name__] = rex_game.get(l.__class__.__name__, 0) + 1
- if not LOG_GOOD:
- print l.values['log']
- if logf.chat_log:
- for l in logf.chat_log.lines:
- if isinstance(l, dict):
- rex_chat['dict'] = rex_chat.get('dict', 0) + 1
- elif isinstance(l, str):
- print l
- else:
- if l.unpack() and not LOG_GOOD:
- pass
- else:
- rex_chat[l.__class__.__name__] = rex_chat.get(l.__class__.__name__, 0) + 1
- if not LOG_GOOD:
- print l.values['log']
- logf.clean(True)
- # additional cleanup:
- logf.chat_log.lines = []
- logf.game_log.lines = []
- logf.combat_log.lines = []
- print 'Analysis complete:'
- print '#'*20+' RexCombat ' + '#' *20
- print rex_combat
- print '#'*20+' RexGame ' + '#' *20
- print rex_game
- print '#'*20+' RexChat ' + '#' *20
- print rex_chat
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+"""
+ Tool to analyze Logs in general.
+"""
+import os, sys, logging
+from .logs.logfiles import LogFileResolver as LogFile
+from .logs import combat, game, chat
+from .logs.session import LogSessionCollector
+from .logs.game import ClientInfo
+
+# for windows its kinda this:
+settings = {'root_path': os.path.join(os.path.expanduser('~'),
+ 'Documents',
+ 'My Games',
+ 'StarConflict',),
+ 'logfiles': os.path.join(os.path.expanduser('~'),
+ 'Documents',
+ 'My Games',
+ 'StarConflict',
+ 'logs'
+ )}
+
+
+if __name__ == '__main__':
+ import logging
+ logging.basicConfig(level=logging.DEBUG,
+ format='%(asctime)s - %(message)s',
+ datefmt='%Y-%m-%d %H:%M:%S')
+ coll = LogSessionCollector(os.path.join(os.path.expanduser('~'),
+ 'Documents', 'My Games', 'sc'))
+ coll.collect_unique()
+ #f = open('output.txt', 'w')
+ rex_combat = {}
+ rex_game = {}
+ rex_chat = {}
+ LOG_GOOD = True # Log good packets.
+ for logf in coll.sessions:
+ logf.parse_files(['game.log', 'combat.log', 'chat.log'])
+
+ print(("----- Log %s -----" % logf.idstr))
+ if logf.combat_log:
+ for l in logf.combat_log.lines:
+ if isinstance(l, dict):
+ #print l
+ rex_combat['dict'] = rex_combat.get('dict', 0) + 1
+ else:
+ if not l.unpack() or LOG_GOOD:
+ rex_combat[l.__class__.__name__] = rex_combat.get(l.__class__.__name__, 0) + 1
+ if not isinstance(l, combat.UserEvent):
+ if not LOG_GOOD:
+ print((l.values['log']))
+ if logf.game_log:
+ for l in logf.game_log.lines:
+ if isinstance(l, dict):
+ rex_game['dict'] = rex_game.get('dict', 0) + 1
+ elif isinstance(l, str):
+ print(l)
+ else:
+ if l.unpack() and not LOG_GOOD:
+ pass
+ else:
+ rex_game[l.__class__.__name__] = rex_game.get(l.__class__.__name__, 0) + 1
+ if not LOG_GOOD:
+ print((l.values['log']))
+ if logf.chat_log:
+ for l in logf.chat_log.lines:
+ if isinstance(l, dict):
+ rex_chat['dict'] = rex_chat.get('dict', 0) + 1
+ elif isinstance(l, str):
+ print(l)
+ else:
+ if l.unpack() and not LOG_GOOD:
+ pass
+ else:
+ rex_chat[l.__class__.__name__] = rex_chat.get(l.__class__.__name__, 0) + 1
+ if not LOG_GOOD:
+ print((l.values['log']))
+ logf.clean(True)
+ # additional cleanup:
+ logf.chat_log.lines = []
+ logf.game_log.lines = []
+ logf.combat_log.lines = []
+ print('Analysis complete:')
+ print(('#'*20+' RexCombat ' + '#' *20))
+ print(rex_combat)
+ print(('#'*20+' RexGame ' + '#' *20))
+ print(rex_game)
+ print(('#'*20+' RexChat ' + '#' *20))
+ print(rex_chat)
diff --git a/src/scon/archive/localbrowser.py b/src/scon/archive/localbrowser.py
index 31a995b..ba51a03 100644
--- a/src/scon/archive/localbrowser.py
+++ b/src/scon/archive/localbrowser.py
@@ -1,142 +1,142 @@
-import os, logging
-from PyQt4 import QtCore, QtGui, QtWebKit, QtNetwork
-from treeview import TreeViewModel, Node
-from django.test import Client
-
-class DebugPage(QtWebKit.QWebPage):
- def sayMyName(self):
- return 'DebugPage'
-
-class LocalWebView(QtWebKit.QWebView):
- def __init__(self, *args, **kwargs):
- basedir = kwargs.pop('basedir', None)
- QtWebKit.QWebView.__init__(self, *args, **kwargs)
- oldManager = self.page().networkAccessManager()
- self.setPage(DebugPage())
- self.page().setNetworkAccessManager(LocalNetworkAccessManager(self, basedir))
-
- def set_basedir(self, basedir):
- self.page().setNetworkAccessManager(LocalNetworkAccessManager(self, basedir))
-
-class LocalNetworkAccessManager(QtNetwork.QNetworkAccessManager):
- USE_NETWORK = False
- def __init__(self, parent=None, basedir=None):
- QtNetwork.QNetworkAccessManager.__init__(self, parent=None)
- if not basedir:
- # take current dir as basedir.
- self.basedir = os.path.dirname(os.path.abspath(__file__))
- else:
- self.basedir = basedir
-
- def createRequest(self, operation, request, data):
- scheme = request.url().scheme()
- if scheme != 'page' and scheme != 'image':
- if self.USE_NETWORK:
- return QtNetwork.QNetworkAccessManager.createRequest(self, operation, request, data)
- elif scheme == 'page':
- if operation == self.GetOperation:
- # Handle page:// URLs separately by creating custom
- # QNetworkReply objects.
- reply = PageReply(self, request.url(), self.GetOperation)
- #print('here')
- #print reply
- return reply
- elif operation == self.PostOperation:
- #print data.readAll()
- #print request
- reply = PageReply(self, request.url(), self.PostOperation)
- return reply
- elif scheme == 'image':
- if operation == self.GetOperation:
- return ImageReply(self, request.url(), self.GetOperation, self.basedir)
- else:
- if self.USE_NETWORK:
- return QtNetwork.QNetworkAccessManager.createRequest(self, operation, request, data)
- return NoNetworkReply(self, request.url(), self.GetOperation)
-
-class BasePageReply(QtNetwork.QNetworkReply):
- content_type = 'text/html; charset=utf-8'
- def __init__(self, parent, url, operation):
- QtNetwork.QNetworkReply.__init__(self, parent)
- self.content = self.initialize_content(url, operation)
- self.offset = 0
- self.setHeader(QtNetwork.QNetworkRequest.ContentTypeHeader, self.get_content_type())
- self.setHeader(QtNetwork.QNetworkRequest.ContentLengthHeader, len(self.content))
- QtCore.QTimer.singleShot(0, self, QtCore.SIGNAL('readyRead()'))
- QtCore.QTimer.singleShot(0, self, QtCore.SIGNAL('finished()'))
- self.open(self.ReadOnly | self.Unbuffered)
- self.setUrl(url)
-
- def get_content_type(self):
- return self.content_type
-
- def initialize_content(self, url, operation):
- return '''
-
-
Test
-
-
- '''
-
- def abort(self):
- pass
-
- def bytesAvailable(self):
- return len(self.content) - self.offset + QtNetwork.QNetworkReply.bytesAvailable(self)
-
- def isSequential(self):
- return True
-
- def readData(self, maxSize):
- if self.offset < len(self.content):
- end = min(self.offset + maxSize, len(self.content))
- data = self.content[self.offset:end]
- self.offset = end
- return data
-
-class PageReply(BasePageReply):
- def initialize_content(self, url, operation):
- c = Client()
- print "Response for %s, method %s" % (url.path(), operation)
- if operation == LocalNetworkAccessManager.GetOperation:
- response = c.get(unicode(url.path()), )
- elif operation == LocalNetworkAccessManager.PostOperation:
- response = c.post(unicode(url.path()))
- # response code
- print "Response Status: %s" % response.status_code
- # note: on a 404, we might need to trigger file response.
- return response.content
-
-class NoNetworkReply(BasePageReply):
- def initialize_content(self, url, operation):
- return '''
-
- No Network Access.
-
- Internal access to the network has been disabled.
-
-
- '''
-
-class ImageReply(BasePageReply):
- content_type = 'image/png'
- def __init__(self, parent, url, operation, basedir):
- self.basedir = basedir
- BasePageReply.__init__(self, parent, url, operation)
-
- def initialize_content(self, url, operation):
- path = os.path.join(self.basedir, unicode(url.path()).lstrip('/'))
- if not os.path.exists(path):
- logging.error('Image does not exist: %s' % path)
- return ''
- h = url.host()
- try:
- f = open(path, 'rb')
- return f.read()
- finally:
- f.close()
+import os, logging
+from PyQt4 import QtCore, QtGui, QtWebKit, QtNetwork
+from treeview import TreeViewModel, Node
+from django.test import Client
+
+class DebugPage(QtWebKit.QWebPage):
+ def sayMyName(self):
+ return 'DebugPage'
+
+class LocalWebView(QtWebKit.QWebView):
+ def __init__(self, *args, **kwargs):
+ basedir = kwargs.pop('basedir', None)
+ QtWebKit.QWebView.__init__(self, *args, **kwargs)
+ oldManager = self.page().networkAccessManager()
+ self.setPage(DebugPage())
+ self.page().setNetworkAccessManager(LocalNetworkAccessManager(self, basedir))
+
+ def set_basedir(self, basedir):
+ self.page().setNetworkAccessManager(LocalNetworkAccessManager(self, basedir))
+
+class LocalNetworkAccessManager(QtNetwork.QNetworkAccessManager):
+ USE_NETWORK = False
+ def __init__(self, parent=None, basedir=None):
+ QtNetwork.QNetworkAccessManager.__init__(self, parent=None)
+ if not basedir:
+ # take current dir as basedir.
+ self.basedir = os.path.dirname(os.path.abspath(__file__))
+ else:
+ self.basedir = basedir
+
+ def createRequest(self, operation, request, data):
+ scheme = request.url().scheme()
+ if scheme != 'page' and scheme != 'image':
+ if self.USE_NETWORK:
+ return QtNetwork.QNetworkAccessManager.createRequest(self, operation, request, data)
+ elif scheme == 'page':
+ if operation == self.GetOperation:
+ # Handle page:// URLs separately by creating custom
+ # QNetworkReply objects.
+ reply = PageReply(self, request.url(), self.GetOperation)
+ #print('here')
+ #print reply
+ return reply
+ elif operation == self.PostOperation:
+ #print data.readAll()
+ #print request
+ reply = PageReply(self, request.url(), self.PostOperation)
+ return reply
+ elif scheme == 'image':
+ if operation == self.GetOperation:
+ return ImageReply(self, request.url(), self.GetOperation, self.basedir)
+ else:
+ if self.USE_NETWORK:
+ return QtNetwork.QNetworkAccessManager.createRequest(self, operation, request, data)
+ return NoNetworkReply(self, request.url(), self.GetOperation)
+
+class BasePageReply(QtNetwork.QNetworkReply):
+ content_type = 'text/html; charset=utf-8'
+ def __init__(self, parent, url, operation):
+ QtNetwork.QNetworkReply.__init__(self, parent)
+ self.content = self.initialize_content(url, operation)
+ self.offset = 0
+ self.setHeader(QtNetwork.QNetworkRequest.ContentTypeHeader, self.get_content_type())
+ self.setHeader(QtNetwork.QNetworkRequest.ContentLengthHeader, len(self.content))
+ QtCore.QTimer.singleShot(0, self, QtCore.SIGNAL('readyRead()'))
+ QtCore.QTimer.singleShot(0, self, QtCore.SIGNAL('finished()'))
+ self.open(self.ReadOnly | self.Unbuffered)
+ self.setUrl(url)
+
+ def get_content_type(self):
+ return self.content_type
+
+ def initialize_content(self, url, operation):
+ return '''
+
+ Test
+
+
+ '''
+
+ def abort(self):
+ pass
+
+ def bytesAvailable(self):
+ return len(self.content) - self.offset + QtNetwork.QNetworkReply.bytesAvailable(self)
+
+ def isSequential(self):
+ return True
+
+ def readData(self, maxSize):
+ if self.offset < len(self.content):
+ end = min(self.offset + maxSize, len(self.content))
+ data = self.content[self.offset:end]
+ self.offset = end
+ return data
+
+class PageReply(BasePageReply):
+ def initialize_content(self, url, operation):
+ c = Client()
+ print(("Response for %s, method %s" % (url.path(), operation)))
+ if operation == LocalNetworkAccessManager.GetOperation:
+ response = c.get(str(url.path()), )
+ elif operation == LocalNetworkAccessManager.PostOperation:
+ response = c.post(str(url.path()))
+ # response code
+ print(("Response Status: %s" % response.status_code))
+ # note: on a 404, we might need to trigger file response.
+ return response.content
+
+class NoNetworkReply(BasePageReply):
+ def initialize_content(self, url, operation):
+ return '''
+
+ No Network Access.
+
+ Internal access to the network has been disabled.
+
+
+ '''
+
+class ImageReply(BasePageReply):
+ content_type = 'image/png'
+ def __init__(self, parent, url, operation, basedir):
+ self.basedir = basedir
+ BasePageReply.__init__(self, parent, url, operation)
+
+ def initialize_content(self, url, operation):
+ path = os.path.join(self.basedir, str(url.path()).lstrip('/'))
+ if not os.path.exists(path):
+ logging.error('Image does not exist: %s' % path)
+ return ''
+ h = url.host()
+ try:
+ f = open(path, 'rb')
+ return f.read()
+ finally:
+ f.close()
\ No newline at end of file
diff --git a/src/scon/backup.py b/src/scon/backup.py
index 29bb191..5ee21be 100644
--- a/src/scon/backup.py
+++ b/src/scon/backup.py
@@ -1,71 +1,71 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-"""
- Backup Directories, Handle Files...
-"""
-
-import os, logging, zipfile
-
-def make_zipfile(output_filename, source_dir):
- relroot = os.path.abspath(os.path.join(source_dir, os.pardir))
- with zipfile.ZipFile(output_filename, "w", zipfile.ZIP_DEFLATED) as zip:
- for root, dirs, files in os.walk(source_dir):
- # add directory (needed for empty dirs)
- zip.write(root, os.path.relpath(root, relroot))
- for file in files:
- filename = os.path.join(root, file)
- if os.path.isfile(filename): # regular files only
- arcname = os.path.join(os.path.relpath(root, relroot), file)
- zip.write(filename, arcname)
-
-def backup_log_directory(log_directory, backup_directory, compress=True,
- ommit_level=2, verbose=False):
- # @todo: raw copy
- # ommit_level 0: overwrite.
- # ommit_level 1: write if selected compression method not backuped yet
- # ommit_level 2: write only if neither method contains directory.
- nothing_found = True
- # get all directory names in log_directory.
- # zip them into backup_directory
- for directory in os.listdir(log_directory):
- full_dir = os.path.join(log_directory, directory)
- nothing_found = False
- if os.path.isdir(full_dir):
- if os.path.exists(os.path.join(full_dir, 'combat.log'))\
- and os.path.exists(os.path.join(full_dir, 'game.log'))\
- and os.path.exists(os.path.join(full_dir, 'chat.log'))\
- and os.path.exists(os.path.join(full_dir, 'game.net.log')):
- output_filename = '%s.zip' % directory
- if os.path.exists(os.path.join(backup_directory, output_filename))\
- and ((ommit_level >= 1 and compress) or (ommit_level==2 and not compress)):
- logging.warning('Log %s exists as zip backup, ommited.' % output_filename)
- elif os.path.exists(os.path.join(backup_directory, directory))\
- and ((ommit_level == 2 and compress) or (ommit_level>=1 and not compress)):
- logging.warning('Log %s exists as directory backup, ommited.' % directory)
- else:
- # do the backup
- if compress:
- make_zipfile(os.path.join(backup_directory, output_filename),
- full_dir)
- logging.info('Backed up %s' % directory)
- if verbose:
- print "Backed up %s" % directory
- else:
- if verbose:
- print "Directory Raw Backup not implemented yet."
- raise NotImplementedError
- else:
- if verbose:
- print "%s is not a directory." % full_dir
- if verbose and nothing_found:
- print "Nothing to backup found in %s" % log_directory
-
-
-if __name__ == '__main__':
- print "Performing Log Backup (Dev)"
- log_source = os.path.join(os.path.expanduser('~'),
- 'Documents', 'My Games', 'StarConflict', 'logs')
- log_dest = os.path.join(os.path.expanduser('~'),
- 'Documents', 'My Games', 'sc')
- backup_log_directory(log_source, log_dest, verbose=True, compress=True)
-
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+"""
+ Backup Directories, Handle Files...
+"""
+
+import os, logging, zipfile
+
+def make_zipfile(output_filename, source_dir):
+ relroot = os.path.abspath(os.path.join(source_dir, os.pardir))
+ with zipfile.ZipFile(output_filename, "w", zipfile.ZIP_DEFLATED) as zip:
+ for root, dirs, files in os.walk(source_dir):
+ # add directory (needed for empty dirs)
+ zip.write(root, os.path.relpath(root, relroot))
+ for file in files:
+ filename = os.path.join(root, file)
+ if os.path.isfile(filename): # regular files only
+ arcname = os.path.join(os.path.relpath(root, relroot), file)
+ zip.write(filename, arcname)
+
+def backup_log_directory(log_directory, backup_directory, compress=True,
+ ommit_level=2, verbose=False):
+ # @todo: raw copy
+ # ommit_level 0: overwrite.
+ # ommit_level 1: write if selected compression method not backuped yet
+ # ommit_level 2: write only if neither method contains directory.
+ nothing_found = True
+ # get all directory names in log_directory.
+ # zip them into backup_directory
+ for directory in os.listdir(log_directory):
+ full_dir = os.path.join(log_directory, directory)
+ nothing_found = False
+ if os.path.isdir(full_dir):
+ if os.path.exists(os.path.join(full_dir, 'combat.log'))\
+ and os.path.exists(os.path.join(full_dir, 'game.log'))\
+ and os.path.exists(os.path.join(full_dir, 'chat.log'))\
+ and os.path.exists(os.path.join(full_dir, 'game.net.log')):
+ output_filename = '%s.zip' % directory
+ if os.path.exists(os.path.join(backup_directory, output_filename))\
+ and ((ommit_level >= 1 and compress) or (ommit_level==2 and not compress)):
+ logging.warning('Log %s exists as zip backup, ommited.' % output_filename)
+ elif os.path.exists(os.path.join(backup_directory, directory))\
+ and ((ommit_level == 2 and compress) or (ommit_level>=1 and not compress)):
+ logging.warning('Log %s exists as directory backup, ommited.' % directory)
+ else:
+ # do the backup
+ if compress:
+ make_zipfile(os.path.join(backup_directory, output_filename),
+ full_dir)
+ logging.info('Backed up %s' % directory)
+ if verbose:
+ print(("Backed up %s" % directory))
+ else:
+ if verbose:
+ print("Directory Raw Backup not implemented yet.")
+ raise NotImplementedError
+ else:
+ if verbose:
+ print(("%s is not a directory." % full_dir))
+ if verbose and nothing_found:
+ print(("Nothing to backup found in %s" % log_directory))
+
+
+if __name__ == '__main__':
+ print("Performing Log Backup (Dev)")
+ log_source = os.path.join(os.path.expanduser('~'),
+ 'Documents', 'My Games', 'StarConflict', 'logs')
+ log_dest = os.path.join(os.path.expanduser('~'),
+ 'Documents', 'My Games', 'sc')
+ backup_log_directory(log_source, log_dest, verbose=True, compress=True)
+
diff --git a/src/scon/battle.py b/src/scon/battle.py
index 8b81c05..c88f37b 100644
--- a/src/scon/battle.py
+++ b/src/scon/battle.py
@@ -1,33 +1,33 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-"""
- Tool to analyze Logs in general.
-"""
-import os, sys, logging
-from logs.logfiles import LogFileResolver as LogFile
-from logs import combat, game, chat
-from logs.session import LogSessionCollector
-from logs.game import ClientInfo
-
-# for windows its kinda this:
-settings = {'root_path': os.path.join(os.path.expanduser('~'),
- 'Documents',
- 'My Games',
- 'StarConflict',),
- 'logfiles': os.path.join(os.path.expanduser('~'),
- 'Documents',
- 'My Games',
- 'StarConflict',
- 'logs'
- )}
-if __name__ == '__main__':
- coll = LogSessionCollector(os.path.join(os.path.expanduser('~'),
- 'Documents', 'My Games', 'sc'))
- coll.collect_unique()
- for logf in coll.sessions:
- logf.parse_files(['game.log', 'combat.log'])
- logf.clean()
- if logf.combat_log:
- print 'length combat log ', len(logf.combat_log.lines)
- if logf.game_log:
- print 'length game log ', len(logf.game_log.lines)
\ No newline at end of file
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+"""
+ Tool to analyze Logs in general.
+"""
+import os, sys, logging
+from .logs.logfiles import LogFileResolver as LogFile
+from .logs import combat, game, chat
+from .logs.session import LogSessionCollector
+from .logs.game import ClientInfo
+
+# for windows its kinda this:
+settings = {'root_path': os.path.join(os.path.expanduser('~'),
+ 'Documents',
+ 'My Games',
+ 'StarConflict',),
+ 'logfiles': os.path.join(os.path.expanduser('~'),
+ 'Documents',
+ 'My Games',
+ 'StarConflict',
+ 'logs'
+ )}
+if __name__ == '__main__':
+ coll = LogSessionCollector(os.path.join(os.path.expanduser('~'),
+ 'Documents', 'My Games', 'sc'))
+ coll.collect_unique()
+ for logf in coll.sessions:
+ logf.parse_files(['game.log', 'combat.log'])
+ logf.clean()
+ if logf.combat_log:
+ print(('length combat log ', len(logf.combat_log.lines)))
+ if logf.game_log:
+ print(('length game log ', len(logf.game_log.lines)))
\ No newline at end of file
diff --git a/src/scon/brainstorm.py b/src/scon/brainstorm.py
index df6fcda..f908b89 100644
--- a/src/scon/brainstorm.py
+++ b/src/scon/brainstorm.py
@@ -1,85 +1,85 @@
-"""
- Brainstorm File for Star Conflict Log Parsing
-
- Needed
- - find steam/scon folder on windows
- - find steam/scon folder on mac
- - find steam/scon folder on linux
- - what about steamless installs?
-
- Elaborate
- - which GUI to use? wx? PyQt4? PySide?
- - take over the database stuff from weltenfall.starconflict?
-
- Investigate
- - language based log files?
-"""
-#from win32com.shell import shell, shellcon
-import os, sys, logging
-from logs.logfiles import LogFileResolver as LogFile
-from logs import combat
-
-# for windows its kinda this:
-settings = {'root_path': os.path.join(os.path.expanduser('~'),
- 'Documents',
- 'My Games',
- 'StarConflict',),
- 'logfiles': os.path.join(os.path.expanduser('~'),
- 'Documents',
- 'My Games',
- 'StarConflict',
- 'logs'
- )}
-
-def find_log_files(logpath):
- ''' returns a list of 4-tuples representing
- (combat.log, game.log, chat.log, game.net.log)
- for each directory in the logpath
- '''
- ret = []
- for directory in os.listdir(logpath):
- full_dir = os.path.join(logpath, directory)
- if os.path.isdir(full_dir):
- if os.path.exists(os.path.join(full_dir, 'combat.log'))\
- and os.path.exists(os.path.join(full_dir, 'game.log'))\
- and os.path.exists(os.path.join(full_dir, 'chat.log'))\
- and os.path.exists(os.path.join(full_dir, 'game.net.log')):
- ret.append((
- os.path.join(full_dir, 'combat.log'),
- os.path.join(full_dir, 'game.log'),
- os.path.join(full_dir, 'chat.log'),
- os.path.join(full_dir, 'game.net.log')
- ))
- return ret
-
-def parse_games(logfiles):
- _logfiles = []
- for logpack in logfiles:
- combatlog, gamelog, chatlog, gamenetlog = logpack
- _logfiles.append(LogFile(combatlog))
- #_logfiles.append(LogFile(gamelog))
- #_logfiles.append(LogFile(chatlog))
- #_logfiles.append(LogFile(gamenetlog))
- return _logfiles
-
-if __name__ == '__main__':
- logfiles = find_log_files(settings['logfiles'])
- logfiles = parse_games(logfiles)
- #f = open('output.txt', 'w')
- rex = {}
- for logf in logfiles:
- logf.read()
- logf.parse()
- for l in logf.lines:
- if isinstance(l, dict):
- #print l
- pass
- else:
- if not l.unpack():
- rex[l.__class__.__name__] = rex.get(l.__class__.__name__, 0) + 1
- if not isinstance(l, combat.UserEvent):
- print l.values['log']
- #f.write(l.values['log'] + '\n')
- #f.close()
- #print type(l)
- print rex
\ No newline at end of file
+"""
+ Brainstorm File for Star Conflict Log Parsing
+
+ Needed
+ - find steam/scon folder on windows
+ - find steam/scon folder on mac
+ - find steam/scon folder on linux
+ - what about steamless installs?
+
+ Elaborate
+ - which GUI to use? wx? PyQt4? PySide?
+ - take over the database stuff from weltenfall.starconflict?
+
+ Investigate
+ - language based log files?
+"""
+#from win32com.shell import shell, shellcon
+import os, sys, logging
+from .logs.logfiles import LogFileResolver as LogFile
+from .logs import combat
+
+# for windows its kinda this:
+settings = {'root_path': os.path.join(os.path.expanduser('~'),
+ 'Documents',
+ 'My Games',
+ 'StarConflict',),
+ 'logfiles': os.path.join(os.path.expanduser('~'),
+ 'Documents',
+ 'My Games',
+ 'StarConflict',
+ 'logs'
+ )}
+
+def find_log_files(logpath):
+ ''' returns a list of 4-tuples representing
+ (combat.log, game.log, chat.log, game.net.log)
+ for each directory in the logpath
+ '''
+ ret = []
+ for directory in os.listdir(logpath):
+ full_dir = os.path.join(logpath, directory)
+ if os.path.isdir(full_dir):
+ if os.path.exists(os.path.join(full_dir, 'combat.log'))\
+ and os.path.exists(os.path.join(full_dir, 'game.log'))\
+ and os.path.exists(os.path.join(full_dir, 'chat.log'))\
+ and os.path.exists(os.path.join(full_dir, 'game.net.log')):
+ ret.append((
+ os.path.join(full_dir, 'combat.log'),
+ os.path.join(full_dir, 'game.log'),
+ os.path.join(full_dir, 'chat.log'),
+ os.path.join(full_dir, 'game.net.log')
+ ))
+ return ret
+
+def parse_games(logfiles):
+ _logfiles = []
+ for logpack in logfiles:
+ combatlog, gamelog, chatlog, gamenetlog = logpack
+ _logfiles.append(LogFile(combatlog))
+ #_logfiles.append(LogFile(gamelog))
+ #_logfiles.append(LogFile(chatlog))
+ #_logfiles.append(LogFile(gamenetlog))
+ return _logfiles
+
+if __name__ == '__main__':
+ logfiles = find_log_files(settings['logfiles'])
+ logfiles = parse_games(logfiles)
+ #f = open('output.txt', 'w')
+ rex = {}
+ for logf in logfiles:
+ logf.read()
+ logf.parse()
+ for l in logf.lines:
+ if isinstance(l, dict):
+ #print l
+ pass
+ else:
+ if not l.unpack():
+ rex[l.__class__.__name__] = rex.get(l.__class__.__name__, 0) + 1
+ if not isinstance(l, combat.UserEvent):
+ print((l.values['log']))
+ #f.write(l.values['log'] + '\n')
+ #f.close()
+ #print type(l)
+ print(rex)
\ No newline at end of file
diff --git a/src/scon/config/display_config.py b/src/scon/config/display_config.py
index b26c4b4..e43f371 100644
--- a/src/scon/config/display_config.py
+++ b/src/scon/config/display_config.py
@@ -1,119 +1,119 @@
-"""
- Simple brainstorm to display a config file.
-"""
-import os, logging
-from settings import settings
-logging.basicConfig(level=logging.INFO)
-# import ET:
-try:
- ET = None
- import lxml.etree as ET
- logging.info('Using LXML.')
-except ImportError:
- try:
- import cElementTree as ET
- logging.info('Using cElementTree')
- except ImportError:
- try:
- import elementtree.ElementTree as ET
- logging.info('Using ElementTree')
- except ImportError:
- import xml.etree.ElementTree as ET # python 2.5
- logging.info('Using xml.ElementTree')
-finally:
- if not ET:
- raise NotImplementedError, "XML Parser not found in your Python."
-##################################################################################################
-
-class ConfigFile(object):
- def __init__(self, config_file=None):
- self.cvars = []
- if config_file:
- self.config_file = config_file
- elif settings:
- # settings based loading.
- self.config_file = os.path.join(settings.get_path(), 'user_config.xml')
-
- def open(self, filename = None):
- # reads a config file.
- filename = filename or self.config_file
- self.tree = ET.parse(filename)
- doc = self.tree.getroot()
- if doc.tag == 'UserConfig' \
- and len(doc) == 1\
- and doc[0].tag == 'CVars'\
- and doc[0].attrib['version'] == '4':
- logging.info( "Found valid config file." )
- # save my cvars
- self.cvars = doc[0]
- else:
- logging.info( "Config File not supported." )
- return self
-
- def pprint(self):
- # print out my cvars
- for child in self.cvars:
- print '%s = %s' % (child.tag, child.attrib['val'])
-
- def write(self, filename):
- output = '\n'
- doc = self.tree.getroot()
- # we manually serialize it to keep it exactly the same
- # like original SC to avoid problems with their software.
- def append_node(node, depth=0):
- # xml serializing helper function...
- s = ['%s<%s' % (' '*depth*2, node.tag),]
- for key, val in node.attrib.items():
- s.append(' %s="%s"' % (key, val))
- if len(node):
- s.append('>\n')
- # append children
- for child in node:
- s.extend(append_node(child, depth+1))
- s.append('%s%s>\n' % (' '*depth*2, node.tag))
- else:
- s.append(' />\n')
- return s
- l = append_node(doc)
- output = output + ''.join( l )
- if filename is None:
- # dev.
- assert output[-1], '\n'
- else:
- try:
- f = open(filename, 'w')
- f.write(output)
- finally:
- f.close()
- return output
-
- def debug_serializing(self):
- # detects if output would result in the same data as input
- input, output = None, None
- try:
- f = open(self.config_file, 'r')
- input = f.read()
- finally:
- f.close()
- output = self.write(None)
- return output == input
-
-
-def read_config(config_file):
- tree = ET.parse(config_file)
- # doc = tree.getroot()
- return tree
-
-if __name__ == '__main__':
- # Read the config
- settings.autodetect()
- c = ConfigFile().open()
- print '#' * 80
- print "Output File would be:"
- print c.write(None)
- print '#' * 80
- print "Detected Settings:"
- c.pprint()
- print '#' * 80
- print 'Serializing Test successful: %s' % c.debug_serializing()
+"""
+ Simple brainstorm to display a config file.
+"""
+import os, logging
+from .settings import settings
+logging.basicConfig(level=logging.INFO)
+# import ET:
+try:
+ ET = None
+ import lxml.etree as ET
+ logging.info('Using LXML.')
+except ImportError:
+ try:
+ import cElementTree as ET
+ logging.info('Using cElementTree')
+ except ImportError:
+ try:
+ import elementtree.ElementTree as ET
+ logging.info('Using ElementTree')
+ except ImportError:
+ import xml.etree.ElementTree as ET # python 2.5
+ logging.info('Using xml.ElementTree')
+finally:
+ if not ET:
+ raise NotImplementedError("XML Parser not found in your Python.")
+##################################################################################################
+
+class ConfigFile(object):
+ def __init__(self, config_file=None):
+ self.cvars = []
+ if config_file:
+ self.config_file = config_file
+ elif settings:
+ # settings based loading.
+ self.config_file = os.path.join(settings.get_path(), 'user_config.xml')
+
+ def open(self, filename = None):
+ # reads a config file.
+ filename = filename or self.config_file
+ self.tree = ET.parse(filename)
+ doc = self.tree.getroot()
+ if doc.tag == 'UserConfig' \
+ and len(doc) == 1\
+ and doc[0].tag == 'CVars'\
+ and doc[0].attrib['version'] == '4':
+ logging.info( "Found valid config file." )
+ # save my cvars
+ self.cvars = doc[0]
+ else:
+ logging.info( "Config File not supported." )
+ return self
+
+ def pprint(self):
+ # print out my cvars
+ for child in self.cvars:
+ print(('%s = %s' % (child.tag, child.attrib['val'])))
+
+ def write(self, filename):
+ output = '\n'
+ doc = self.tree.getroot()
+ # we manually serialize it to keep it exactly the same
+ # like original SC to avoid problems with their software.
+ def append_node(node, depth=0):
+ # xml serializing helper function...
+ s = ['%s<%s' % (' '*depth*2, node.tag),]
+ for key, val in list(node.attrib.items()):
+ s.append(' %s="%s"' % (key, val))
+ if len(node):
+ s.append('>\n')
+ # append children
+ for child in node:
+ s.extend(append_node(child, depth+1))
+ s.append('%s%s>\n' % (' '*depth*2, node.tag))
+ else:
+ s.append(' />\n')
+ return s
+ l = append_node(doc)
+ output = output + ''.join( l )
+ if filename is None:
+ # dev.
+ assert output[-1], '\n'
+ else:
+ try:
+ f = open(filename, 'w')
+ f.write(output)
+ finally:
+ f.close()
+ return output
+
+ def debug_serializing(self):
+ # detects if output would result in the same data as input
+ input, output = None, None
+ try:
+ f = open(self.config_file, 'r')
+ input = f.read()
+ finally:
+ f.close()
+ output = self.write(None)
+ return output == input
+
+
+def read_config(config_file):
+ tree = ET.parse(config_file)
+ # doc = tree.getroot()
+ return tree
+
+if __name__ == '__main__':
+ # Read the config
+ settings.autodetect()
+ c = ConfigFile().open()
+ print(('#' * 80))
+ print("Output File would be:")
+ print((c.write(None)))
+ print(('#' * 80))
+ print("Detected Settings:")
+ c.pprint()
+ print(('#' * 80))
+ print(('Serializing Test successful: %s' % c.debug_serializing()))
\ No newline at end of file
diff --git a/src/scon/config/settings.py b/src/scon/config/settings.py
index 62984b2..6f1053b 100644
--- a/src/scon/config/settings.py
+++ b/src/scon/config/settings.py
@@ -1,31 +1,31 @@
-import os
-import platform
-
-class Settings(dict):
- def autodetect(self, path=None):
- # autodetect settings.
- d = path
- system = platform.system()
- if system == 'Windows' or system.startswith('CYGWIN_NT'):
- # try to find user folder:
- d = d or os.path.join(os.path.expanduser('~'),
- 'Documents',
- 'My Games',
- 'StarConflict',)
- elif system == 'Linux':
- raise NotImplementedError, "Implement Linux!"
- elif system == 'Darwin':
- raise NotImplementedError, "Implement Mac!"
- else:
- raise NotImplementedError, "Unknown System! %s" % platform.system()
- if not os.path.exists(d) or not os.path.isdir(d):
- raise Exception, "Configuration Autodetection failed. "
- self['root_path'] = d
-
- def get_path(self):
- return self.get('root_path', None)
-
- def get_logs_path(self):
- return os.path.join(self.get_path, 'logs')
-
-settings = Settings()
+import os
+import platform
+
+class Settings(dict):
+ def autodetect(self, path=None):
+ # autodetect settings.
+ d = path
+ system = platform.system()
+ if system == 'Windows' or system.startswith('CYGWIN_NT'):
+ # try to find user folder:
+ d = d or os.path.join(os.path.expanduser('~'),
+ 'Documents',
+ 'My Games',
+ 'StarConflict',)
+ elif system == 'Linux':
+ raise NotImplementedError("Implement Linux!")
+ elif system == 'Darwin':
+ raise NotImplementedError("Implement Mac!")
+ else:
+ raise NotImplementedError("Unknown System! %s" % platform.system())
+ if not os.path.exists(d) or not os.path.isdir(d):
+ raise Exception("Configuration Autodetection failed. ")
+ self['root_path'] = d
+
+ def get_path(self):
+ return self.get('root_path', None)
+
+ def get_logs_path(self):
+ return os.path.join(self.get_path, 'logs')
+
+settings = Settings()
diff --git a/src/scon/dejaqt/folders.py b/src/scon/dejaqt/folders.py
index bbc5d7f..fd44e3e 100644
--- a/src/scon/dejaqt/folders.py
+++ b/src/scon/dejaqt/folders.py
@@ -1,84 +1,84 @@
-
-import logging, os
-try:
- from django.conf import settings
-except:
- logging.error('Django Settings could not be loaded. Maybe Django has not been initialized?')
- settings = None
-
-class FolderLibrary(object):
- def __init__(self, folders=None):
- self._folders = {}
- try:
- if settings:
- self.folders.update( getattr(settings, 'DEJAQT_DIRS', {}) )
- except:
- logging.error('DEJAQT_DIRS in django settings threw error.')
- import traceback
- traceback.print_exc()
- if folders:
- # no try here: if this fails, you got yourself a programming error.
- self.folders.update(folders)
- self._keys = []
- self.build_keycache()
-
- def get_folders(self):
- return self._folders
-
- def set_folders(self, folders):
- self._folders = folders
- self.build_keycache()
- folders = property(get_folders, set_folders)
-
- def build_keycache(self):
- self._keys = self._folders.keys()
- self._keys.sort(key=lambda item: (-len(item), item))
-
- def add_folder(self, url, folder):
- if not url:
- url = ''
- self._folders[url] = folder
- self.build_keycache()
-
- def match(self, url):
- # run down our keycache, first match wins.
- for key in self._keys:
- if url.startswith(key):
- return key
-
- def matched_folder(self, url):
- m = self.match(url)
- if m is not None:
- folder = self._folders[m]
- #heading, rest = url[:len(m)], url[len(m):]
- rest = url[len(m):]
- real_folder = os.path.abspath( os.path.join(folder, rest) )
- if real_folder.startswith(os.path.abspath(folder)):
- return real_folder
- else:
- logging.error('%s does not seem to be a subpath of %s' % (real_folder, folder))
-
- def print_folders(self):
- print '{'
- for k in self._keys:
- print "'%s': '%s'," % (k, self._folders[k])
- print '}'
-
-
-if __name__ == "__main__":
- # test this:
- import os
- os.environ['DJANGO_SETTINGS_MODULE'] = 'scon.dj.settings'
- f = FolderLibrary({'abc/dab/': 'c:/media',
- 'abc': 'd:/abc',
- 'abc/dab/tmp': '/tmp',
- 'uiuiui': 'x:/',
- 'abc/vul/no': 'x:/2',
- 'abc/vul': 'x:/3',
- 'abc/vul/yes': 'x:/1',
- })
- f.add_folder('abc/dub/', 'c:/dubdub')
- f.print_folders()
-
- print f.matched_folder('abc/dab/okokok/some.png')
+
+import logging, os
+try:
+ from django.conf import settings
+except:
+ logging.error('Django Settings could not be loaded. Maybe Django has not been initialized?')
+ settings = None
+
+class FolderLibrary(object):
+ def __init__(self, folders=None):
+ self._folders = {}
+ try:
+ if settings:
+ self.folders.update( getattr(settings, 'DEJAQT_DIRS', {}) )
+ except:
+ logging.error('DEJAQT_DIRS in django settings threw error.')
+ import traceback
+ traceback.print_exc()
+ if folders:
+ # no try here: if this fails, you got yourself a programming error.
+ self.folders.update(folders)
+ self._keys = []
+ self.build_keycache()
+
+ def get_folders(self):
+ return self._folders
+
+ def set_folders(self, folders):
+ self._folders = folders
+ self.build_keycache()
+ folders = property(get_folders, set_folders)
+
+ def build_keycache(self):
+ self._keys = list(self._folders.keys())
+ self._keys.sort(key=lambda item: (-len(item), item))
+
+ def add_folder(self, url, folder):
+ if not url:
+ url = ''
+ self._folders[url] = folder
+ self.build_keycache()
+
+ def match(self, url):
+ # run down our keycache, first match wins.
+ for key in self._keys:
+ if url.startswith(key):
+ return key
+
+ def matched_folder(self, url):
+ m = self.match(url)
+ if m is not None:
+ folder = self._folders[m]
+ #heading, rest = url[:len(m)], url[len(m):]
+ rest = url[len(m):]
+ real_folder = os.path.abspath( os.path.join(folder, rest) )
+ if real_folder.startswith(os.path.abspath(folder)):
+ return real_folder
+ else:
+ logging.error('%s does not seem to be a subpath of %s' % (real_folder, folder))
+
+ def print_folders(self):
+ print('{')
+ for k in self._keys:
+ print(("'%s': '%s'," % (k, self._folders[k])))
+ print('}')
+
+
+if __name__ == "__main__":
+ # test this:
+ import os
+ os.environ['DJANGO_SETTINGS_MODULE'] = 'scon.dj.settings'
+ f = FolderLibrary({'abc/dab/': 'c:/media',
+ 'abc': 'd:/abc',
+ 'abc/dab/tmp': '/tmp',
+ 'uiuiui': 'x:/',
+ 'abc/vul/no': 'x:/2',
+ 'abc/vul': 'x:/3',
+ 'abc/vul/yes': 'x:/1',
+ })
+ f.add_folder('abc/dub/', 'c:/dubdub')
+ f.print_folders()
+
+ print((f.matched_folder('abc/dab/okokok/some.png')))
\ No newline at end of file
diff --git a/src/scon/dejaqt/qweb.py b/src/scon/dejaqt/qweb.py
index 2d1f29d..dd93a15 100644
--- a/src/scon/dejaqt/qweb.py
+++ b/src/scon/dejaqt/qweb.py
@@ -1,198 +1,198 @@
-"""
- Qt WebKit Browser for local access to internal Django Views.
-"""
-import os, logging
-from PyQt4 import QtCore, QtGui, QtWebKit, QtNetwork
-from django.test import Client
-from folders import FolderLibrary
-from django.http.request import QueryDict
-from urlparse import urlparse, parse_qs
-import cgi
-from io import BytesIO
-from django.http.multipartparser import MultiPartParser
-
-class DebugPage(QtWebKit.QWebPage):
- def sayMyName(self):
- return 'DebugPage'
-
-class DejaWebView(QtWebKit.QWebView):
- '''
- Optional:
- * folders: FolderLibrary() Instance.
- * page: Initialized QWebPage instance for initial page (default DebugPage())
- '''
- def __init__(self, *args, **kwargs):
- self.folders = kwargs.pop('folders', FolderLibrary())
- page = kwargs.pop('page', DebugPage())
- QtWebKit.QWebView.__init__(self, *args, **kwargs)
- #self.oldManager = self.page().networkAccessManager()
- self.setPage(page)
- self.page().setNetworkAccessManager(DejaNetworkAccessManager(self))
- self.client = Client()
- #self.client.login(username='admin', password='admin')
-
-class DejaNetworkAccessManager(QtNetwork.QNetworkAccessManager):
- '''
- The Deja Network Access Manager provides access to two new protocols:
- - page:/// tries to resolve a page internally via a django test client.
- - res:/// direct access to a resource.
-
- USE_NETWORK delegates to other network access manager protocols, if False, it will not
- allow any requests outside these two protocols
- (hopefully disabling network access for your internal browser)
-
- Note, if page does not find the page, a res:/// attempt is made automatically.
- This has to be expanded!
-
- Note2: not sure if cookies and sessions will work this way!
- '''
- USE_NETWORK = False
- def __init__(self, parent=None):
- QtNetwork.QNetworkAccessManager.__init__(self, parent=parent)
- if parent:
- self.folders = getattr(parent, 'folders', FolderLibrary())
-
- def createRequest(self, operation, request, data):
- scheme = request.url().scheme()
- if scheme != 'page' and scheme != 'res':
- if self.USE_NETWORK:
- return QtNetwork.QNetworkAccessManager.createRequest(self, operation, request, data)
- elif scheme == 'page':
- if operation == self.GetOperation:
- # Handle page:// URLs separately by creating custom
- # QNetworkReply objects.
- reply = PageReply(self, request.url(), self.GetOperation)
- #print('here')
- #print reply
- return reply
- elif operation == self.PostOperation:
- reply = PageReply(self, request.url(), self.PostOperation, request, data)
- return reply
- elif scheme == 'res':
- if operation == self.GetOperation:
- return ResourceReply(self, request.url(), self.GetOperation)
- else:
- if self.USE_NETWORK:
- return QtNetwork.QNetworkAccessManager.createRequest(self, operation, request, data)
- return NoNetworkReply(self, request.url(), self.GetOperation)
-
-class BasePageReply(QtNetwork.QNetworkReply):
- content_type = 'text/html; charset=utf-8'
- def __init__(self, parent, url, operation, request=None, data=None):
- QtNetwork.QNetworkReply.__init__(self, parent)
- self.data = data
- self.request = request
- self.content = self.initialize_content(url, operation)
- self.offset = 0
- self.setHeader(QtNetwork.QNetworkRequest.ContentTypeHeader, self.get_content_type())
- self.setHeader(QtNetwork.QNetworkRequest.ContentLengthHeader, len(self.content))
- QtCore.QTimer.singleShot(0, self, QtCore.SIGNAL('readyRead()'))
- QtCore.QTimer.singleShot(0, self, QtCore.SIGNAL('finished()'))
- self.open(self.ReadOnly | self.Unbuffered)
- self.setUrl(url)
-
- def get_content_type(self):
- return self.content_type
-
- def initialize_content(self, url, operation):
- return '''
-
- Empty Page
- This is an empty page. If you see this, you need to subclass BasePageReply.
-
- '''
-
- def abort(self):
- pass
-
- def bytesAvailable(self):
- return len(self.content) - self.offset + QtNetwork.QNetworkReply.bytesAvailable(self)
-
- def isSequential(self):
- return True
-
- def readData(self, maxSize):
- if self.offset < len(self.content):
- end = min(self.offset + maxSize, len(self.content))
- data = self.content[self.offset:end]
- self.offset = end
- return data
-
-class ResourceReply(BasePageReply):
- content_type = 'image/png'
-
- def determine_content_type(self, path):
- return self.content_type
-
- def initialize_content(self, url, operation):
- # determine folder:
- path = unicode(url.path()).lstrip('/')
- folders = getattr(self.parent(), 'folders')
- if folders:
- path = folders.matched_folder(path)
- if path:
- if os.path.exists(path):
- try:
- f = open(path, 'rb')
- return f.read()
- finally:
- f.close()
- else:
- logging.warning('Path does not exist: %s' % path)
- else:
- logging.error('Containing Folder not found for %s' % path)
- else:
- logging.error('Configuration Error: No Folders found.')
- return ''
-
-class PageReply(ResourceReply):
- content_type = 'text/html'
-
- def initialize_content(self, url, operation):
- try:
- c = self.parent().parent().client
- except:
- logging.error('Internal HTTP Client not found. Creating new.')
- c = Client()
- logging.info( "Response for %s, method %s" % (url.path(), operation) )
- if operation == DejaNetworkAccessManager.GetOperation:
- response = c.get(unicode(url.path()), follow=True )
- elif operation == DejaNetworkAccessManager.PostOperation:
- ct = str(self.request.rawHeader('Content-Type'))
- cl = str(self.request.rawHeader('Content-Length'))
- s = str(self.data.readAll())
- if ct.startswith('multipart/form-data'):
- # multipart parsing
- logging.error('Multipart Parsing Try...')
- b = BytesIO(s)
- q, files = MultiPartParser({'CONTENT_TYPE': ct,
- 'CONTENT_LENGTH': cl,
- },
- b,
- []).parse()
- response = c.post(unicode(url.path()), q, follow=True)
- else:
- # assume post data.
- q = QueryDict( s )
- response = c.post(unicode(url.path()), q, follow=True)
- self.content_type = response.get('Content-Type', self.content_type)
- # response code
- #print "Response Status: %s" % response.status_code
- # note: on a 404, we might need to trigger file response.
- if response.status_code == 404:
- return ResourceReply.initialize_content(self, url, DejaNetworkAccessManager.GetOperation)
- if hasattr(response, 'streaming_content'):
- return ''.join(response.streaming_content)
- return response.content
-
-class NoNetworkReply(BasePageReply):
- def initialize_content(self, url, operation):
- return '''
-
- No Network Access.
-
- Internal access to the network has been disabled.
-
-
- '''
-
+"""
+ Qt WebKit Browser for local access to internal Django Views.
+"""
+import os, logging
+from PyQt4 import QtCore, QtGui, QtWebKit, QtNetwork
+from django.test import Client
+from .folders import FolderLibrary
+from django.http.request import QueryDict
+from urllib.parse import urlparse, parse_qs
+import cgi
+from io import BytesIO
+from django.http.multipartparser import MultiPartParser
+
+class DebugPage(QtWebKit.QWebPage):
+ def sayMyName(self):
+ return 'DebugPage'
+
+class DejaWebView(QtWebKit.QWebView):
+ '''
+ Optional:
+ * folders: FolderLibrary() Instance.
+ * page: Initialized QWebPage instance for initial page (default DebugPage())
+ '''
+ def __init__(self, *args, **kwargs):
+ self.folders = kwargs.pop('folders', FolderLibrary())
+ page = kwargs.pop('page', DebugPage())
+ QtWebKit.QWebView.__init__(self, *args, **kwargs)
+ #self.oldManager = self.page().networkAccessManager()
+ self.setPage(page)
+ self.page().setNetworkAccessManager(DejaNetworkAccessManager(self))
+ self.client = Client()
+ #self.client.login(username='admin', password='admin')
+
+class DejaNetworkAccessManager(QtNetwork.QNetworkAccessManager):
+ '''
+ The Deja Network Access Manager provides access to two new protocols:
+ - page:/// tries to resolve a page internally via a django test client.
+ - res:/// direct access to a resource.
+
+ USE_NETWORK delegates to other network access manager protocols, if False, it will not
+ allow any requests outside these two protocols
+ (hopefully disabling network access for your internal browser)
+
+ Note, if page does not find the page, a res:/// attempt is made automatically.
+ This has to be expanded!
+
+ Note2: not sure if cookies and sessions will work this way!
+ '''
+ USE_NETWORK = False
+ def __init__(self, parent=None):
+ QtNetwork.QNetworkAccessManager.__init__(self, parent=parent)
+ if parent:
+ self.folders = getattr(parent, 'folders', FolderLibrary())
+
+ def createRequest(self, operation, request, data):
+ scheme = request.url().scheme()
+ if scheme != 'page' and scheme != 'res':
+ if self.USE_NETWORK:
+ return QtNetwork.QNetworkAccessManager.createRequest(self, operation, request, data)
+ elif scheme == 'page':
+ if operation == self.GetOperation:
+ # Handle page:// URLs separately by creating custom
+ # QNetworkReply objects.
+ reply = PageReply(self, request.url(), self.GetOperation)
+ #print('here')
+ #print reply
+ return reply
+ elif operation == self.PostOperation:
+ reply = PageReply(self, request.url(), self.PostOperation, request, data)
+ return reply
+ elif scheme == 'res':
+ if operation == self.GetOperation:
+ return ResourceReply(self, request.url(), self.GetOperation)
+ else:
+ if self.USE_NETWORK:
+ return QtNetwork.QNetworkAccessManager.createRequest(self, operation, request, data)
+ return NoNetworkReply(self, request.url(), self.GetOperation)
+
+class BasePageReply(QtNetwork.QNetworkReply):
+ content_type = 'text/html; charset=utf-8'
+ def __init__(self, parent, url, operation, request=None, data=None):
+ QtNetwork.QNetworkReply.__init__(self, parent)
+ self.data = data
+ self.request = request
+ self.content = self.initialize_content(url, operation)
+ self.offset = 0
+ self.setHeader(QtNetwork.QNetworkRequest.ContentTypeHeader, self.get_content_type())
+ self.setHeader(QtNetwork.QNetworkRequest.ContentLengthHeader, len(self.content))
+ QtCore.QTimer.singleShot(0, self, QtCore.SIGNAL('readyRead()'))
+ QtCore.QTimer.singleShot(0, self, QtCore.SIGNAL('finished()'))
+ self.open(self.ReadOnly | self.Unbuffered)
+ self.setUrl(url)
+
+ def get_content_type(self):
+ return self.content_type
+
+ def initialize_content(self, url, operation):
+ return '''
+
+ Empty Page
+ This is an empty page. If you see this, you need to subclass BasePageReply.
+
+ '''
+
+ def abort(self):
+ pass
+
+ def bytesAvailable(self):
+ return len(self.content) - self.offset + QtNetwork.QNetworkReply.bytesAvailable(self)
+
+ def isSequential(self):
+ return True
+
+ def readData(self, maxSize):
+ if self.offset < len(self.content):
+ end = min(self.offset + maxSize, len(self.content))
+ data = self.content[self.offset:end]
+ self.offset = end
+ return data
+
+class ResourceReply(BasePageReply):
+ content_type = 'image/png'
+
+ def determine_content_type(self, path):
+ return self.content_type
+
+ def initialize_content(self, url, operation):
+ # determine folder:
+ path = str(url.path()).lstrip('/')
+ folders = getattr(self.parent(), 'folders')
+ if folders:
+ path = folders.matched_folder(path)
+ if path:
+ if os.path.exists(path):
+ try:
+ f = open(path, 'rb')
+ return f.read()
+ finally:
+ f.close()
+ else:
+ logging.warning('Path does not exist: %s' % path)
+ else:
+ logging.error('Containing Folder not found for %s' % path)
+ else:
+ logging.error('Configuration Error: No Folders found.')
+ return ''
+
+class PageReply(ResourceReply):
+ content_type = 'text/html'
+
+ def initialize_content(self, url, operation):
+ try:
+ c = self.parent().parent().client
+ except:
+ logging.error('Internal HTTP Client not found. Creating new.')
+ c = Client()
+ logging.info( "Response for %s, method %s" % (url.path(), operation) )
+ if operation == DejaNetworkAccessManager.GetOperation:
+ response = c.get(str(url.path()), follow=True )
+ elif operation == DejaNetworkAccessManager.PostOperation:
+ ct = str(self.request.rawHeader('Content-Type'))
+ cl = str(self.request.rawHeader('Content-Length'))
+ s = str(self.data.readAll())
+ if ct.startswith('multipart/form-data'):
+ # multipart parsing
+ logging.error('Multipart Parsing Try...')
+ b = BytesIO(s)
+ q, files = MultiPartParser({'CONTENT_TYPE': ct,
+ 'CONTENT_LENGTH': cl,
+ },
+ b,
+ []).parse()
+ response = c.post(str(url.path()), q, follow=True)
+ else:
+ # assume post data.
+ q = QueryDict( s )
+ response = c.post(str(url.path()), q, follow=True)
+ self.content_type = response.get('Content-Type', self.content_type)
+ # response code
+ #print "Response Status: %s" % response.status_code
+ # note: on a 404, we might need to trigger file response.
+ if response.status_code == 404:
+ return ResourceReply.initialize_content(self, url, DejaNetworkAccessManager.GetOperation)
+ if hasattr(response, 'streaming_content'):
+ return ''.join(response.streaming_content)
+ return response.content
+
+class NoNetworkReply(BasePageReply):
+ def initialize_content(self, url, operation):
+ return '''
+
+ No Network Access.
+
+ Internal access to the network has been disabled.
+
+
+ '''
+
diff --git a/src/scon/dj/scon/admin.py b/src/scon/dj/scon/admin.py
index 1c94f0c..b5cac14 100644
--- a/src/scon/dj/scon/admin.py
+++ b/src/scon/dj/scon/admin.py
@@ -1,5 +1,5 @@
from django.contrib import admin
-import models
+from . import models
# Register your models here.
admin.site.register(models.Crafting)
admin.site.register(models.CraftingInput)
diff --git a/src/scon/dj/scon/generate_fixtures.py b/src/scon/dj/scon/generate_fixtures.py
index 9b5714a..efa23f2 100644
--- a/src/scon/dj/scon/generate_fixtures.py
+++ b/src/scon/dj/scon/generate_fixtures.py
@@ -1,592 +1,592 @@
-"""
- Generate Fixtures for Crafting.
- Simple generator, does not integrate well into existing stuff, so please use
- only for bootstrapping.
-"""
-import os, json
-BASE_DIR = os.path.dirname(os.path.dirname(__file__))
-DIR = os.path.join(BASE_DIR, 'scon', 'fixtures')
-
-def write_fixture(data):
- f = open(os.path.join(DIR, 'generated.json'), 'w')
- f.write(json.dumps(data))
- f.close()
-
-def build_pk_cache(data, models=None):
- pk_cache = {}
- # fill cache from existing
- for d in data:
- if 'pk' in d.keys():
- # has pk
- pk_cache[d['model']] = max(pk_cache.get('model', 0), d['pk'])
- for d in data:
- m = d['model']
- if models:
- if m not in models:
- continue
- if 'pk' in d.keys():
- #print "PK was already in there! %s" % d
- pass
- else:
- if m not in pk_cache.keys():
- pk_cache[m] = 1
- i = 1
- else:
- i = pk_cache[m] + 1
- pk_cache[m] = i
- d['pk'] = i
- return data
-
-def lookup_pk(data, name, mdl='scon.item', kwargs=None):
- for d in data:
- if d['model'] == mdl:
- if d['fields'].get('name', '').lower() == name.lower():
- found = True
- if kwargs is not None:
- for key, val in kwargs.items():
- if not d['fields'].get(key, None) == val:
- found = False
- if found:
- return d['pk']
-
-def generate_fixtures():
- data = []
-
- ORES = [
- {'name': 'Impure tungsten', 'sell_price': 6600, 'icon': 'resource_tungsten_ore'},
- {'name': 'Impure osmium', 'sell_price': 4500, 'icon': 'resource_osmium_ore'},
- {'name': 'Impure silicon', 'sell_price': 600, 'icon': 'resource_silicon_ore'},
- {'name': 'Vanadium', 'sell_price': 500, 'icon': 'resource_vanadium'},
- {'name': 'Crystal shard', 'sell_price': 3500, 'icon': 'resource_crystal_shard'},
- ]
- MATERIALS = [
- {'name': 'Tungsten plate',
- 'description': 'Durable tungsten plate',
- 'sell_price': 20000,
- 'icon': 'component_tungsten_plate'},
- {'name': 'Screened battery', 'sell_price': 42000,
- 'icon': 'component_screened_battery'},
- {'name': 'Osmium crystals', 'sell_price': 5500,
- 'icon': 'component_osmium_crystals'},
- {'name': 'Pure Silicon', 'sell_price': 2500,
- 'icon': 'component_pure_silicon'},
- {'name': 'Processing block', 'sell_price': 22000,
- 'icon': 'component_processing_block'},
- {'name': 'Metal blank', 'sell_price': 1600,
- 'icon': 'component_metal_blank'},
- {'name': 'Alien Monocrystal', 'sell_price': 25000,
- 'icon': 'component_alien_monocrystal'},
- {'name': 'Computing chip', 'sell_price': 4500,
- 'icon': 'component_computing_chip'},
- ]
- AMMOS = [
- {'name': 'Explosive Shells',
- 'quality': 4,
- 'sell_price': 1000,
- 'icon': 'ammo_explosive_shells_mk4',
- },
- {'name': 'Double Deflector',
- 'quality': 4,
- 'sell_price': 1000,
- 'icon': 'ammo_double_deflector_mk4',
- },
- {'name': 'Xenon Lamp',
- 'quality': 4,
- 'sell_price': 1000,
- 'icon': 'ammo_xenon_lamp_mk4',
- },
- {'name': 'Attack Drone',
- 'quality': 10,
- 'sell_price': 1092,
- 'icon': 'ammo_attack_drone',
- },
- {'name': 'Focusing Lens',
- 'quality': 4,
- 'sell_price': 1000,
- 'icon': 'ammo_focusing_lens',
- },
- {'name': 'Iridium Slugs',
- 'quality': 4,
- 'sell_price': 1000,
- 'icon': 'ammo_iridium_slugs',
- },
- {'name': 'Supercooled Charges',
- 'quality': 4,
- 'sell_price': 1000,
- 'icon': 'ammo_supercooled_charges',
- },
- {'name': 'Doomsday Missile',
- 'quality': 1,
- 'sell_price': 1000,
- #'tech': 5,
- 'icon': 'ammo_doomsday_missile',
- }
- ]
-
- ITEMS_NON_CRAFTING = [
- {'name': 'Target Tracking Coprocessor III',
- 'typ': 5, # cpu
- 'tech': 3,
- 'sell_price': 20188,
- 'description': 'Increases Critical Damage',
- 'icon': 'cpu_target_tracking_coprocessor',
- },
- {'name': 'Plasma Gun III',
- 'typ': 7, # weap
- 'quality': 4,
- 'tech': 3,
- 'icon': 'weapon_plasma_gun',
- },
- {'name': 'Plasma Gun IV',
- 'typ': 7, # weap
- 'quality': 4,
- 'tech': 4,
- 'icon': 'weapon_plasma_gun',
- },
- {'name': 'Plasma Gun V',
- 'typ': 7, # weap
- 'quality': 4,
- 'tech': 5,
- 'icon': 'weapon_plasma_gun',
- },
- # assault rails:
- {'name': 'Assault Railgun III',
- 'typ': 7, # weap
- 'quality': 4,
- 'tech': 3,
- 'icon': 'weapon_assault_railgun',
- },
- {'name': 'Assault Railgun IV',
- 'typ': 7, # weap
- 'quality': 4,
- 'tech': 4,
- 'icon': 'weapon_assault_railgun',
- },
- {'name': 'Assault Railgun V',
- 'typ': 7, # weap
- 'quality': 4,
- 'tech': 5,
- 'icon': 'weapon_assault_railgun',
- },
- # beam cannon:
- {'name': 'Beam Cannon III',
- 'typ': 7, # weap
- 'quality': 4,
- 'tech': 3,
- 'icon': 'weapon_beam_cannon',
- },
- {'name': 'Beam Cannon IV',
- 'typ': 7, # weap
- 'quality': 4,
- 'tech': 4,
- 'icon': 'weapon_beam_cannon',
- },
- {'name': 'Beam Cannon V',
- 'typ': 7, # weap
- 'quality': 4,
- 'tech': 5,
- 'icon': 'weapon_beam_cannon',
- },
- ]
-
- ITEMS = [
- {'name': 'Duplicator',
- 'typ': 0,
- 'sell_price': 8000,
- 'buy_price_premium': 200,
- 'description': 'Revives in Invasion with Cargo once.',
- 'icon': 'duplicator',
- },
- {'name': 'A1MA IV',
- 'quality': 1,
- 'tech': 4,
- 'typ': 8, # active.
- 'role': 0, # multipurp.
- 'sell_price': 26910,
- 'icon': 'active_a1ma',
- },
- {'name': 'Pirate "Orion" Targeting Complex V',
- 'quality': 14,
- 'tech': 5,
- 'typ': 8, # active.
- 'role': 3, # covops
- 'icon': 'active_t5_orion_targeting_complex_pirate',
- },
- {'name': 'Pirate Engine Overcharge V',
- 'quality': 14,
- 'tech': 5,
- 'typ': 8, # active.
- 'role': 6, # gunship
- 'icon': 'active_t5_engine_overcharge_pirate',
- },
- {'name': 'Pirate Mass Shield Generator V',
- 'quality': 14,
- 'tech': 5,
- 'typ': 8, # active.
- 'role': 7, # engi
- 'icon': 'active_t5_mass_shield_generator_pirate',
- },
- {'name': 'Reverse Thruster III',
- 'quality': 1,
- 'tech': 3,
- 'typ': 8, # active.
- 'role': 9, # LRF
- 'icon': 'active_reverse_thruster',
- },
- {'name': 'Reverse Thruster IV',
- 'quality': 1,
- 'tech': 4,
- 'typ': 8, # active.
- 'role': 9, # LRF
- 'icon': 'active_reverse_thruster',
- },
- {'name': 'Reverse Thruster V',
- 'quality': 1,
- 'tech': 5,
- 'typ': 8, # active.
- 'role': 9, # LRF
- 'icon': 'active_reverse_thruster',
- },
- {'name': 'Plasma Gun III',
- 'quality': 5,
- 'tech': 3,
- 'typ': 7, # weap
- 'icon': 'weapon_plasma_gun_mk5',
- },
- {'name': 'Plasma Gun IV',
- 'quality': 5,
- 'tech': 4,
- 'typ': 7, # weap
- 'icon': 'weapon_plasma_gun_mk5',
- },
- {'name': 'Plasma Gun V',
- 'quality': 5,
- 'tech': 5,
- 'typ': 7, # weap
- 'icon': 'weapon_plasma_gun_mk5',
- },
- {'name': 'Assault Railgun III',
- 'quality': 5,
- 'tech': 3,
- 'typ': 7, # weap
- 'icon': 'weapon_assault_rail_mk5',
- },
- {'name': 'Assault Railgun IV',
- 'quality': 5,
- 'tech': 4,
- 'typ': 7, # weap
- 'icon': 'weapon_assault_rail_mk5',
- },
- {'name': 'Assault Railgun V',
- 'quality': 5,
- 'tech': 5,
- 'typ': 7, # weap
- 'icon': 'weapon_assault_rail_mk5',
- },
- {'name': 'Beam Cannon III',
- 'quality': 5,
- 'tech': 3,
- 'typ': 7, # weap
- 'icon': 'weapon_beam_cannon_mk5',
- },
- {'name': 'Beam Cannon IV',
- 'quality': 5,
- 'tech': 4,
- 'typ': 7, # weap
- 'icon': 'weapon_beam_cannon_mk5',
- },
- {'name': 'Beam Cannon V',
- 'quality': 5,
- 'tech': 5,
- 'typ': 7, # weap
- 'icon': 'weapon_beam_cannon_mk5',
- },
- ]
- BLUEPRINTS = [
- {'name': 'Focusing Lens Blueprint'},
- {'name': 'Iridium Slugs Blueprint'},
- {'name': 'Supercooled Charges Blueprint'},
- {'name': 'A1MA T4 Blueprint'},
- {'name': 'Orion-2 Targeting Complex Blueprint',
- 'description': 'Module works twice as long but much weaker.'},
- {'name': 'Engine Warp Overcharge Blueprint'},
- {'name': 'Mass Shield Energizer Blueprint'},
- {'name': 'Reverse Thruster T3 Blueprint'},
- {'name': 'Reverse Thruster T4 Blueprint'},
- {'name': 'Reverse Thruster T5 Blueprint'},
- {'name': 'Beam Cannon Prototype T3 Blueprint'},
- {'name': 'Beam Cannon Prototype T4 Blueprint'},
- {'name': 'Beam Cannon Prototype T5 Blueprint'},
- {'name': 'Assault Railgun Prototype T3 Blueprint'},
- {'name': 'Assault Railgun Prototype T4 Blueprint'},
- {'name': 'Assault Railgun Prototype T5 Blueprint'},
- {'name': 'Plasma Gun Prototype T3 Blueprint'},
- {'name': 'Plasma Gun Prototype T4 Blueprint'},
- {'name': 'Plasma Gun Prototype T5 Blueprint'},
- {'name': 'Doomsday Missile Blueprint'},
- ]
- CRAFTING = [
- {'item': 'Duplicator',
- 'recipee': [(1, 'Processing Block'), (2,'Computing chip'), (2, 'Metal blank')]},
- {'item': 'Tungsten plate',
- 'recipee': [(2, 'Impure tungsten'),]},
- {'item': 'Screened battery',
- 'recipee': [(1, 'Tungsten plate'), (2, 'Computing chip')]},
- {'item': 'Osmium crystals',
- 'recipee': [(1, 'Impure osmium'),]},
- {'item': 'Pure Silicon',
- 'recipee': [(1, 'Impure silicon'),]},
- {'item': 'Computing chip',
- 'recipee': [(1, 'Crystal shard'),]},
- {'item': 'Processing block',
- 'recipee': [(4, 'Pure Silicon'), (2, 'Computing chip')]},
- {'item': 'Metal blank',
- 'recipee': [(2, 'Vanadium'),]},
- {'item': 'Target Tracking Coprocessor III',
- 'recipee': [(1, 'Screened battery'), (7, 'Metal blank'), (5, 'Pure silicon')]},
- {'item': 'Explosive Shells',
- 'amount': 2,
- 'recipee': [(1, 'Metal blank'),(2, 'Pure Silicon')]},
- {'item': 'Attack drone',
- 'recipee': [(1, 'Alien Monocrystal'), (1,'Computing chip')]},
- {'item': 'Double Deflector',
- 'amount': 2,
- 'recipee': [(1, 'Osmium crystals'),]},
- {'item': 'Xenon Lamp',
- 'amount': 2,
- 'recipee': [(1, 'Computing chip'), (1, 'Pure Silicon')]},
-
- {'item': 'Focusing Lens',
- 'amount': 2,
- 'recipee': [(1, 'Focusing Lens Blueprint'), (1, 'Osmium crystals')]},
- {'item': 'Supercooled Charges',
- 'amount': 2,
- 'recipee': [(1, 'Supercooled Charges Blueprint'), (1, 'Computing chip')]},
- {'item': 'Iridium Slugs',
- 'amount': 2,
- 'recipee': [(1, 'Iridium Slugs Blueprint'), (1, 'Metal blank')]},
- {'item': 'A1MA IV',
- 'recipee': [(1, 'A1MA T4 Blueprint'), (2, 'Processing block'),
- (14, 'Metal blank'), (2, 'Screened battery'),
- (20, 'Alien Monocrystal')]},
- {'item': 'Pirate "Orion" Targeting Complex V',
- 'recipee': [(1, 'Orion-2 Targeting Complex Blueprint'),
- (3, 'Tungsten plate'),
- (4, 'Computing chip'),
- (2, 'Processing block'),
- (30, 'Alien Monocrystal')
- ]},
- {'item': 'Pirate Engine Overcharge V',
- 'recipee': [(1, 'Engine Warp Overcharge Blueprint'),
- (3, 'Tungsten plate'),
- (2, 'Osmium crystals'),
- (2, 'Processing block'),
- (30, 'Alien Monocrystal')
- ]},
- {'item': 'Pirate Mass Shield Generator V',
- 'recipee': [(1, 'Mass Shield Energizer Blueprint'),
- (10, 'Metal blank'),
- (3, 'Computing chip'),
- (3, 'Processing block'),
- (30, 'Alien Monocrystal')
- ]},
- # lrf reverse blink:
- {'item': 'Reverse Thruster III',
- 'recipee': [(1, 'Reverse Thruster T3 Blueprint'),
- (7, 'Metal blank'),
- (1, 'Screened battery'),
- (4, 'Computing chip'),
- (15, 'Alien Monocrystal')
- ]},
- {'item': 'Reverse Thruster IV',
- 'recipee': [(1, 'Reverse Thruster T4 Blueprint'),
- (12, 'Metal blank'),
- (2, 'Screened battery'),
- (5, 'Computing chip'),
- (20, 'Alien Monocrystal')
- ]},
- {'item': 'Reverse Thruster V',
- 'recipee': [(1, 'Reverse Thruster T5 Blueprint'),
- (7, 'Tungsten plate'),
- (3, 'Screened battery'),
- (6, 'Computing chip'),
- (30, 'Alien Monocrystal')
- ]},
-
- # plasma
- {'item': ('Plasma Gun III', {'quality': 5}),
- 'recipee': [(1, 'Plasma Gun Prototype T3 Blueprint'),
- (1, ('Plasma Gun III', {'quality': 4})),
- (6, 'Metal blank'),
- (3, 'Screened battery'),
- (30, 'Alien Monocrystal')
- ]},
- {'item': ('Plasma Gun IV', {'quality': 5}),
- 'recipee': [(1, 'Plasma Gun Prototype T4 Blueprint'),
- (1, ('Plasma Gun IV', {'quality': 4})),
- (1, 'Tungsten plate'),
- (4, 'Screened battery'),
- (50, 'Alien Monocrystal')
- ]},
- {'item': ('Plasma Gun V', {'quality': 5}),
- 'recipee': [(1, 'Plasma Gun Prototype T5 Blueprint'),
- (1, ('Plasma Gun V', {'quality': 4})),
- (3, 'Tungsten plate'),
- (5, 'Screened battery'),
- (70, 'Alien Monocrystal')
- ]},
- # assault
- {'item': ('Assault Railgun III', {'quality': 5}),
- 'recipee': [(1, 'Assault Railgun Prototype T3 Blueprint'),
- (1, ('Assault Railgun III', {'quality': 4})),
- (6, 'Metal blank'),
- (3, 'Screened battery'),
- (30, 'Alien Monocrystal')
- ]},
- {'item': ('Assault Railgun IV', {'quality': 5}),
- 'recipee': [(1, 'Assault Railgun Prototype T4 Blueprint'),
- (1, ('Assault Railgun IV', {'quality': 4})),
- (1, 'Tungsten plate'),
- (4, 'Screened battery'),
- (50, 'Alien Monocrystal')
- ]},
- {'item': ('Assault Railgun V', {'quality': 5}),
- 'recipee': [(1, 'Assault Railgun Prototype T5 Blueprint'),
- (1, ('Assault Railgun V', {'quality': 4})),
- (3, 'Tungsten plate'),
- (5, 'Screened battery'),
- (70, 'Alien Monocrystal')
- ]},
- # beam
- {'item': ('Beam Cannon III', {'quality': 5}),
- 'recipee': [(1, 'Beam Cannon Prototype T3 Blueprint'),
- (1, ('Beam Cannon III', {'quality': 4})),
- (6, 'Metal blank'),
- (3, 'Screened battery'),
- (30, 'Alien Monocrystal')
- ]},
- {'item': ('Beam Cannon IV', {'quality': 5}),
- 'recipee': [(1, 'Beam Cannon Prototype T4 Blueprint'),
- (1, ('Beam Cannon IV', {'quality': 4})),
- (1, 'Tungsten plate'),
- (4, 'Screened battery'),
- (50, 'Alien Monocrystal')
- ]},
- {'item': ('Beam Cannon V', {'quality': 5}),
- 'recipee': [(1, 'Beam Cannon Prototype T5 Blueprint'),
- (1, ('Beam Cannon V', {'quality': 4})),
- (3, 'Tungsten plate'),
- (5, 'Screened battery'),
- (70, 'Alien Monocrystal')
- ]},
- # missiles
- {'item': 'Doomsday Missile',
- 'recipee': [(1, 'Doomsday Missile Blueprint'),
- (2, 'Osmium crystals'),
- (1, 'Computing chip'),
- (1, 'Metal blank'),
- ]},
- ]
-
- for ore in ORES:
- fields = {'typ': 12,
- 'tech': 0,
- 'craftable': True,
- }
- fields.update(ore)
- data.append({'model': 'scon.item', 'fields': fields})
- for mat in MATERIALS:
- fields = {'typ': 13,
- 'tech': 0,
- 'craftable': True,
- }
- fields.update(mat)
- data.append({'model': 'scon.item', 'fields': fields})
-
- for ammo in AMMOS:
- fields = {'typ': 8,
- 'tech': 0,
- 'craftable': True,
- }
- fields.update(ammo)
- data.append({'model': 'scon.item', 'fields': fields})
-
- for item in ITEMS:
- fields = {
- # items define typ and tech!
- 'craftable': True,
- }
- fields.update(item)
- data.append({'model': 'scon.item', 'fields': fields})
-
- for item in ITEMS_NON_CRAFTING:
- fields = {
- # items define typ and tech!
- 'craftable': False,
- }
- fields.update(item)
- data.append({'model': 'scon.item', 'fields': fields})
-
- for bluep in BLUEPRINTS:
- fields = {
- 'typ': 11, # blueprint
- 'tech': 0,
- 'craftable': True,
- 'icon': 'blueprint',
- }
- fields.update(bluep)
- data.append({'model': 'scon.item', 'fields': fields})
-
-
- build_pk_cache(data)
- # now to the crafting recipees:
- i = 1 # counter for crafting
- j = 1 # counter for input
- for craft in CRAFTING:
- try:
- item = craft['item']
- kwargs = None
- if isinstance(item, tuple) or isinstance(item, list):
- kwargs = item[1]
- item = item[0]
- crafting = {'model': 'scon.crafting',
- 'pk': i,
- 'fields': { 'output': lookup_pk(data, item, kwargs=kwargs ),
- 'amount': craft.get('amount', 1) }}
- data.append(crafting)
- primary = True
- for amount, recipee in craft['recipee']:
- item = recipee
- kwargs = None
- if isinstance(item, tuple) or isinstance(item, list):
- print item
- kwargs = item[1]
- item = item[0]
-
- crafting_input = {'model': 'scon.craftinginput',
- 'pk': j,
- 'fields': {'crafting': i,
- 'item': lookup_pk(data, item, kwargs=kwargs),
- 'amount': amount,
- 'primary': primary}
- }
- primary = False
- j = j + 1
- data.append(crafting_input)
- i = i + 1
- except:
- raise
-
- build_pk_cache(data)
- return data
-
-if __name__ == "__main__":
- fixes = generate_fixtures()
- from pprint import pprint
- pprint( fixes )
- # check pks:
- for d in fixes:
- if d.get('pk', None) is None:
- print "%s is fail." % d
-
+"""
+ Generate Fixtures for Crafting.
+ Simple generator, does not integrate well into existing stuff, so please use
+ only for bootstrapping.
+"""
+import os, json
+BASE_DIR = os.path.dirname(os.path.dirname(__file__))
+DIR = os.path.join(BASE_DIR, 'scon', 'fixtures')
+
+def write_fixture(data):
+ f = open(os.path.join(DIR, 'generated.json'), 'w')
+ f.write(json.dumps(data))
+ f.close()
+
+def build_pk_cache(data, models=None):
+ pk_cache = {}
+ # fill cache from existing
+ for d in data:
+ if 'pk' in list(d.keys()):
+ # has pk
+ pk_cache[d['model']] = max(pk_cache.get('model', 0), d['pk'])
+ for d in data:
+ m = d['model']
+ if models:
+ if m not in models:
+ continue
+ if 'pk' in list(d.keys()):
+ #print "PK was already in there! %s" % d
+ pass
+ else:
+ if m not in list(pk_cache.keys()):
+ pk_cache[m] = 1
+ i = 1
+ else:
+ i = pk_cache[m] + 1
+ pk_cache[m] = i
+ d['pk'] = i
+ return data
+
+def lookup_pk(data, name, mdl='scon.item', kwargs=None):
+ for d in data:
+ if d['model'] == mdl:
+ if d['fields'].get('name', '').lower() == name.lower():
+ found = True
+ if kwargs is not None:
+ for key, val in list(kwargs.items()):
+ if not d['fields'].get(key, None) == val:
+ found = False
+ if found:
+ return d['pk']
+
+def generate_fixtures():
+ data = []
+
+ ORES = [
+ {'name': 'Impure tungsten', 'sell_price': 6600, 'icon': 'resource_tungsten_ore'},
+ {'name': 'Impure osmium', 'sell_price': 4500, 'icon': 'resource_osmium_ore'},
+ {'name': 'Impure silicon', 'sell_price': 600, 'icon': 'resource_silicon_ore'},
+ {'name': 'Vanadium', 'sell_price': 500, 'icon': 'resource_vanadium'},
+ {'name': 'Crystal shard', 'sell_price': 3500, 'icon': 'resource_crystal_shard'},
+ ]
+ MATERIALS = [
+ {'name': 'Tungsten plate',
+ 'description': 'Durable tungsten plate',
+ 'sell_price': 20000,
+ 'icon': 'component_tungsten_plate'},
+ {'name': 'Screened battery', 'sell_price': 42000,
+ 'icon': 'component_screened_battery'},
+ {'name': 'Osmium crystals', 'sell_price': 5500,
+ 'icon': 'component_osmium_crystals'},
+ {'name': 'Pure Silicon', 'sell_price': 2500,
+ 'icon': 'component_pure_silicon'},
+ {'name': 'Processing block', 'sell_price': 22000,
+ 'icon': 'component_processing_block'},
+ {'name': 'Metal blank', 'sell_price': 1600,
+ 'icon': 'component_metal_blank'},
+ {'name': 'Alien Monocrystal', 'sell_price': 25000,
+ 'icon': 'component_alien_monocrystal'},
+ {'name': 'Computing chip', 'sell_price': 4500,
+ 'icon': 'component_computing_chip'},
+ ]
+ AMMOS = [
+ {'name': 'Explosive Shells',
+ 'quality': 4,
+ 'sell_price': 1000,
+ 'icon': 'ammo_explosive_shells_mk4',
+ },
+ {'name': 'Double Deflector',
+ 'quality': 4,
+ 'sell_price': 1000,
+ 'icon': 'ammo_double_deflector_mk4',
+ },
+ {'name': 'Xenon Lamp',
+ 'quality': 4,
+ 'sell_price': 1000,
+ 'icon': 'ammo_xenon_lamp_mk4',
+ },
+ {'name': 'Attack Drone',
+ 'quality': 10,
+ 'sell_price': 1092,
+ 'icon': 'ammo_attack_drone',
+ },
+ {'name': 'Focusing Lens',
+ 'quality': 4,
+ 'sell_price': 1000,
+ 'icon': 'ammo_focusing_lens',
+ },
+ {'name': 'Iridium Slugs',
+ 'quality': 4,
+ 'sell_price': 1000,
+ 'icon': 'ammo_iridium_slugs',
+ },
+ {'name': 'Supercooled Charges',
+ 'quality': 4,
+ 'sell_price': 1000,
+ 'icon': 'ammo_supercooled_charges',
+ },
+ {'name': 'Doomsday Missile',
+ 'quality': 1,
+ 'sell_price': 1000,
+ #'tech': 5,
+ 'icon': 'ammo_doomsday_missile',
+ }
+ ]
+
+ ITEMS_NON_CRAFTING = [
+ {'name': 'Target Tracking Coprocessor III',
+ 'typ': 5, # cpu
+ 'tech': 3,
+ 'sell_price': 20188,
+ 'description': 'Increases Critical Damage',
+ 'icon': 'cpu_target_tracking_coprocessor',
+ },
+ {'name': 'Plasma Gun III',
+ 'typ': 7, # weap
+ 'quality': 4,
+ 'tech': 3,
+ 'icon': 'weapon_plasma_gun',
+ },
+ {'name': 'Plasma Gun IV',
+ 'typ': 7, # weap
+ 'quality': 4,
+ 'tech': 4,
+ 'icon': 'weapon_plasma_gun',
+ },
+ {'name': 'Plasma Gun V',
+ 'typ': 7, # weap
+ 'quality': 4,
+ 'tech': 5,
+ 'icon': 'weapon_plasma_gun',
+ },
+ # assault rails:
+ {'name': 'Assault Railgun III',
+ 'typ': 7, # weap
+ 'quality': 4,
+ 'tech': 3,
+ 'icon': 'weapon_assault_railgun',
+ },
+ {'name': 'Assault Railgun IV',
+ 'typ': 7, # weap
+ 'quality': 4,
+ 'tech': 4,
+ 'icon': 'weapon_assault_railgun',
+ },
+ {'name': 'Assault Railgun V',
+ 'typ': 7, # weap
+ 'quality': 4,
+ 'tech': 5,
+ 'icon': 'weapon_assault_railgun',
+ },
+ # beam cannon:
+ {'name': 'Beam Cannon III',
+ 'typ': 7, # weap
+ 'quality': 4,
+ 'tech': 3,
+ 'icon': 'weapon_beam_cannon',
+ },
+ {'name': 'Beam Cannon IV',
+ 'typ': 7, # weap
+ 'quality': 4,
+ 'tech': 4,
+ 'icon': 'weapon_beam_cannon',
+ },
+ {'name': 'Beam Cannon V',
+ 'typ': 7, # weap
+ 'quality': 4,
+ 'tech': 5,
+ 'icon': 'weapon_beam_cannon',
+ },
+ ]
+
+ ITEMS = [
+ {'name': 'Duplicator',
+ 'typ': 0,
+ 'sell_price': 8000,
+ 'buy_price_premium': 200,
+ 'description': 'Revives in Invasion with Cargo once.',
+ 'icon': 'duplicator',
+ },
+ {'name': 'A1MA IV',
+ 'quality': 1,
+ 'tech': 4,
+ 'typ': 8, # active.
+ 'role': 0, # multipurp.
+ 'sell_price': 26910,
+ 'icon': 'active_a1ma',
+ },
+ {'name': 'Pirate "Orion" Targeting Complex V',
+ 'quality': 14,
+ 'tech': 5,
+ 'typ': 8, # active.
+ 'role': 3, # covops
+ 'icon': 'active_t5_orion_targeting_complex_pirate',
+ },
+ {'name': 'Pirate Engine Overcharge V',
+ 'quality': 14,
+ 'tech': 5,
+ 'typ': 8, # active.
+ 'role': 6, # gunship
+ 'icon': 'active_t5_engine_overcharge_pirate',
+ },
+ {'name': 'Pirate Mass Shield Generator V',
+ 'quality': 14,
+ 'tech': 5,
+ 'typ': 8, # active.
+ 'role': 7, # engi
+ 'icon': 'active_t5_mass_shield_generator_pirate',
+ },
+ {'name': 'Reverse Thruster III',
+ 'quality': 1,
+ 'tech': 3,
+ 'typ': 8, # active.
+ 'role': 9, # LRF
+ 'icon': 'active_reverse_thruster',
+ },
+ {'name': 'Reverse Thruster IV',
+ 'quality': 1,
+ 'tech': 4,
+ 'typ': 8, # active.
+ 'role': 9, # LRF
+ 'icon': 'active_reverse_thruster',
+ },
+ {'name': 'Reverse Thruster V',
+ 'quality': 1,
+ 'tech': 5,
+ 'typ': 8, # active.
+ 'role': 9, # LRF
+ 'icon': 'active_reverse_thruster',
+ },
+ {'name': 'Plasma Gun III',
+ 'quality': 5,
+ 'tech': 3,
+ 'typ': 7, # weap
+ 'icon': 'weapon_plasma_gun_mk5',
+ },
+ {'name': 'Plasma Gun IV',
+ 'quality': 5,
+ 'tech': 4,
+ 'typ': 7, # weap
+ 'icon': 'weapon_plasma_gun_mk5',
+ },
+ {'name': 'Plasma Gun V',
+ 'quality': 5,
+ 'tech': 5,
+ 'typ': 7, # weap
+ 'icon': 'weapon_plasma_gun_mk5',
+ },
+ {'name': 'Assault Railgun III',
+ 'quality': 5,
+ 'tech': 3,
+ 'typ': 7, # weap
+ 'icon': 'weapon_assault_rail_mk5',
+ },
+ {'name': 'Assault Railgun IV',
+ 'quality': 5,
+ 'tech': 4,
+ 'typ': 7, # weap
+ 'icon': 'weapon_assault_rail_mk5',
+ },
+ {'name': 'Assault Railgun V',
+ 'quality': 5,
+ 'tech': 5,
+ 'typ': 7, # weap
+ 'icon': 'weapon_assault_rail_mk5',
+ },
+ {'name': 'Beam Cannon III',
+ 'quality': 5,
+ 'tech': 3,
+ 'typ': 7, # weap
+ 'icon': 'weapon_beam_cannon_mk5',
+ },
+ {'name': 'Beam Cannon IV',
+ 'quality': 5,
+ 'tech': 4,
+ 'typ': 7, # weap
+ 'icon': 'weapon_beam_cannon_mk5',
+ },
+ {'name': 'Beam Cannon V',
+ 'quality': 5,
+ 'tech': 5,
+ 'typ': 7, # weap
+ 'icon': 'weapon_beam_cannon_mk5',
+ },
+ ]
+ BLUEPRINTS = [
+ {'name': 'Focusing Lens Blueprint'},
+ {'name': 'Iridium Slugs Blueprint'},
+ {'name': 'Supercooled Charges Blueprint'},
+ {'name': 'A1MA T4 Blueprint'},
+ {'name': 'Orion-2 Targeting Complex Blueprint',
+ 'description': 'Module works twice as long but much weaker.'},
+ {'name': 'Engine Warp Overcharge Blueprint'},
+ {'name': 'Mass Shield Energizer Blueprint'},
+ {'name': 'Reverse Thruster T3 Blueprint'},
+ {'name': 'Reverse Thruster T4 Blueprint'},
+ {'name': 'Reverse Thruster T5 Blueprint'},
+ {'name': 'Beam Cannon Prototype T3 Blueprint'},
+ {'name': 'Beam Cannon Prototype T4 Blueprint'},
+ {'name': 'Beam Cannon Prototype T5 Blueprint'},
+ {'name': 'Assault Railgun Prototype T3 Blueprint'},
+ {'name': 'Assault Railgun Prototype T4 Blueprint'},
+ {'name': 'Assault Railgun Prototype T5 Blueprint'},
+ {'name': 'Plasma Gun Prototype T3 Blueprint'},
+ {'name': 'Plasma Gun Prototype T4 Blueprint'},
+ {'name': 'Plasma Gun Prototype T5 Blueprint'},
+ {'name': 'Doomsday Missile Blueprint'},
+ ]
+ CRAFTING = [
+ {'item': 'Duplicator',
+ 'recipee': [(1, 'Processing Block'), (2,'Computing chip'), (2, 'Metal blank')]},
+ {'item': 'Tungsten plate',
+ 'recipee': [(2, 'Impure tungsten'),]},
+ {'item': 'Screened battery',
+ 'recipee': [(1, 'Tungsten plate'), (2, 'Computing chip')]},
+ {'item': 'Osmium crystals',
+ 'recipee': [(1, 'Impure osmium'),]},
+ {'item': 'Pure Silicon',
+ 'recipee': [(1, 'Impure silicon'),]},
+ {'item': 'Computing chip',
+ 'recipee': [(1, 'Crystal shard'),]},
+ {'item': 'Processing block',
+ 'recipee': [(4, 'Pure Silicon'), (2, 'Computing chip')]},
+ {'item': 'Metal blank',
+ 'recipee': [(2, 'Vanadium'),]},
+ {'item': 'Target Tracking Coprocessor III',
+ 'recipee': [(1, 'Screened battery'), (7, 'Metal blank'), (5, 'Pure silicon')]},
+ {'item': 'Explosive Shells',
+ 'amount': 2,
+ 'recipee': [(1, 'Metal blank'),(2, 'Pure Silicon')]},
+ {'item': 'Attack drone',
+ 'recipee': [(1, 'Alien Monocrystal'), (1,'Computing chip')]},
+ {'item': 'Double Deflector',
+ 'amount': 2,
+ 'recipee': [(1, 'Osmium crystals'),]},
+ {'item': 'Xenon Lamp',
+ 'amount': 2,
+ 'recipee': [(1, 'Computing chip'), (1, 'Pure Silicon')]},
+
+ {'item': 'Focusing Lens',
+ 'amount': 2,
+ 'recipee': [(1, 'Focusing Lens Blueprint'), (1, 'Osmium crystals')]},
+ {'item': 'Supercooled Charges',
+ 'amount': 2,
+ 'recipee': [(1, 'Supercooled Charges Blueprint'), (1, 'Computing chip')]},
+ {'item': 'Iridium Slugs',
+ 'amount': 2,
+ 'recipee': [(1, 'Iridium Slugs Blueprint'), (1, 'Metal blank')]},
+ {'item': 'A1MA IV',
+ 'recipee': [(1, 'A1MA T4 Blueprint'), (2, 'Processing block'),
+ (14, 'Metal blank'), (2, 'Screened battery'),
+ (20, 'Alien Monocrystal')]},
+ {'item': 'Pirate "Orion" Targeting Complex V',
+ 'recipee': [(1, 'Orion-2 Targeting Complex Blueprint'),
+ (3, 'Tungsten plate'),
+ (4, 'Computing chip'),
+ (2, 'Processing block'),
+ (30, 'Alien Monocrystal')
+ ]},
+ {'item': 'Pirate Engine Overcharge V',
+ 'recipee': [(1, 'Engine Warp Overcharge Blueprint'),
+ (3, 'Tungsten plate'),
+ (2, 'Osmium crystals'),
+ (2, 'Processing block'),
+ (30, 'Alien Monocrystal')
+ ]},
+ {'item': 'Pirate Mass Shield Generator V',
+ 'recipee': [(1, 'Mass Shield Energizer Blueprint'),
+ (10, 'Metal blank'),
+ (3, 'Computing chip'),
+ (3, 'Processing block'),
+ (30, 'Alien Monocrystal')
+ ]},
+ # lrf reverse blink:
+ {'item': 'Reverse Thruster III',
+ 'recipee': [(1, 'Reverse Thruster T3 Blueprint'),
+ (7, 'Metal blank'),
+ (1, 'Screened battery'),
+ (4, 'Computing chip'),
+ (15, 'Alien Monocrystal')
+ ]},
+ {'item': 'Reverse Thruster IV',
+ 'recipee': [(1, 'Reverse Thruster T4 Blueprint'),
+ (12, 'Metal blank'),
+ (2, 'Screened battery'),
+ (5, 'Computing chip'),
+ (20, 'Alien Monocrystal')
+ ]},
+ {'item': 'Reverse Thruster V',
+ 'recipee': [(1, 'Reverse Thruster T5 Blueprint'),
+ (7, 'Tungsten plate'),
+ (3, 'Screened battery'),
+ (6, 'Computing chip'),
+ (30, 'Alien Monocrystal')
+ ]},
+
+ # plasma
+ {'item': ('Plasma Gun III', {'quality': 5}),
+ 'recipee': [(1, 'Plasma Gun Prototype T3 Blueprint'),
+ (1, ('Plasma Gun III', {'quality': 4})),
+ (6, 'Metal blank'),
+ (3, 'Screened battery'),
+ (30, 'Alien Monocrystal')
+ ]},
+ {'item': ('Plasma Gun IV', {'quality': 5}),
+ 'recipee': [(1, 'Plasma Gun Prototype T4 Blueprint'),
+ (1, ('Plasma Gun IV', {'quality': 4})),
+ (1, 'Tungsten plate'),
+ (4, 'Screened battery'),
+ (50, 'Alien Monocrystal')
+ ]},
+ {'item': ('Plasma Gun V', {'quality': 5}),
+ 'recipee': [(1, 'Plasma Gun Prototype T5 Blueprint'),
+ (1, ('Plasma Gun V', {'quality': 4})),
+ (3, 'Tungsten plate'),
+ (5, 'Screened battery'),
+ (70, 'Alien Monocrystal')
+ ]},
+ # assault
+ {'item': ('Assault Railgun III', {'quality': 5}),
+ 'recipee': [(1, 'Assault Railgun Prototype T3 Blueprint'),
+ (1, ('Assault Railgun III', {'quality': 4})),
+ (6, 'Metal blank'),
+ (3, 'Screened battery'),
+ (30, 'Alien Monocrystal')
+ ]},
+ {'item': ('Assault Railgun IV', {'quality': 5}),
+ 'recipee': [(1, 'Assault Railgun Prototype T4 Blueprint'),
+ (1, ('Assault Railgun IV', {'quality': 4})),
+ (1, 'Tungsten plate'),
+ (4, 'Screened battery'),
+ (50, 'Alien Monocrystal')
+ ]},
+ {'item': ('Assault Railgun V', {'quality': 5}),
+ 'recipee': [(1, 'Assault Railgun Prototype T5 Blueprint'),
+ (1, ('Assault Railgun V', {'quality': 4})),
+ (3, 'Tungsten plate'),
+ (5, 'Screened battery'),
+ (70, 'Alien Monocrystal')
+ ]},
+ # beam
+ {'item': ('Beam Cannon III', {'quality': 5}),
+ 'recipee': [(1, 'Beam Cannon Prototype T3 Blueprint'),
+ (1, ('Beam Cannon III', {'quality': 4})),
+ (6, 'Metal blank'),
+ (3, 'Screened battery'),
+ (30, 'Alien Monocrystal')
+ ]},
+ {'item': ('Beam Cannon IV', {'quality': 5}),
+ 'recipee': [(1, 'Beam Cannon Prototype T4 Blueprint'),
+ (1, ('Beam Cannon IV', {'quality': 4})),
+ (1, 'Tungsten plate'),
+ (4, 'Screened battery'),
+ (50, 'Alien Monocrystal')
+ ]},
+ {'item': ('Beam Cannon V', {'quality': 5}),
+ 'recipee': [(1, 'Beam Cannon Prototype T5 Blueprint'),
+ (1, ('Beam Cannon V', {'quality': 4})),
+ (3, 'Tungsten plate'),
+ (5, 'Screened battery'),
+ (70, 'Alien Monocrystal')
+ ]},
+ # missiles
+ {'item': 'Doomsday Missile',
+ 'recipee': [(1, 'Doomsday Missile Blueprint'),
+ (2, 'Osmium crystals'),
+ (1, 'Computing chip'),
+ (1, 'Metal blank'),
+ ]},
+ ]
+
+ for ore in ORES:
+ fields = {'typ': 12,
+ 'tech': 0,
+ 'craftable': True,
+ }
+ fields.update(ore)
+ data.append({'model': 'scon.item', 'fields': fields})
+ for mat in MATERIALS:
+ fields = {'typ': 13,
+ 'tech': 0,
+ 'craftable': True,
+ }
+ fields.update(mat)
+ data.append({'model': 'scon.item', 'fields': fields})
+
+ for ammo in AMMOS:
+ fields = {'typ': 8,
+ 'tech': 0,
+ 'craftable': True,
+ }
+ fields.update(ammo)
+ data.append({'model': 'scon.item', 'fields': fields})
+
+ for item in ITEMS:
+ fields = {
+ # items define typ and tech!
+ 'craftable': True,
+ }
+ fields.update(item)
+ data.append({'model': 'scon.item', 'fields': fields})
+
+ for item in ITEMS_NON_CRAFTING:
+ fields = {
+ # items define typ and tech!
+ 'craftable': False,
+ }
+ fields.update(item)
+ data.append({'model': 'scon.item', 'fields': fields})
+
+ for bluep in BLUEPRINTS:
+ fields = {
+ 'typ': 11, # blueprint
+ 'tech': 0,
+ 'craftable': True,
+ 'icon': 'blueprint',
+ }
+ fields.update(bluep)
+ data.append({'model': 'scon.item', 'fields': fields})
+
+
+ build_pk_cache(data)
+ # now to the crafting recipees:
+ i = 1 # counter for crafting
+ j = 1 # counter for input
+ for craft in CRAFTING:
+ try:
+ item = craft['item']
+ kwargs = None
+ if isinstance(item, tuple) or isinstance(item, list):
+ kwargs = item[1]
+ item = item[0]
+ crafting = {'model': 'scon.crafting',
+ 'pk': i,
+ 'fields': { 'output': lookup_pk(data, item, kwargs=kwargs ),
+ 'amount': craft.get('amount', 1) }}
+ data.append(crafting)
+ primary = True
+ for amount, recipee in craft['recipee']:
+ item = recipee
+ kwargs = None
+ if isinstance(item, tuple) or isinstance(item, list):
+ print(item)
+ kwargs = item[1]
+ item = item[0]
+
+ crafting_input = {'model': 'scon.craftinginput',
+ 'pk': j,
+ 'fields': {'crafting': i,
+ 'item': lookup_pk(data, item, kwargs=kwargs),
+ 'amount': amount,
+ 'primary': primary}
+ }
+ primary = False
+ j = j + 1
+ data.append(crafting_input)
+ i = i + 1
+ except:
+ raise
+
+ build_pk_cache(data)
+ return data
+
+if __name__ == "__main__":
+ fixes = generate_fixtures()
+ from pprint import pprint
+ pprint( fixes )
+ # check pks:
+ for d in fixes:
+ if d.get('pk', None) is None:
+ print(("%s is fail." % d))
+
write_fixture(fixes)
\ No newline at end of file
diff --git a/src/scon/dj/scon/views.py b/src/scon/dj/scon/views.py
index 022d568..f7bc75c 100644
--- a/src/scon/dj/scon/views.py
+++ b/src/scon/dj/scon/views.py
@@ -2,8 +2,8 @@
from django.shortcuts import render
from django.http import HttpResponse
from django.template import RequestContext, loader
-import logic
-import models
+from . import logic
+from . import models
def config(request):
t = loader.get_template('scon/config.html')
diff --git a/src/scon/game/pieces.py b/src/scon/game/pieces.py
index 22d47b9..880f4bb 100644
--- a/src/scon/game/pieces.py
+++ b/src/scon/game/pieces.py
@@ -1,100 +1,100 @@
-
-def res_to_red(res):
- ''' calculates reduction % of damage from base resistance
- incoming damage is assumed to be 100.0 to get percentages.
- '''
- if res >= 0:
- fd = 100 / (1.0+res/100.0)
- else:
- fd = 100 / (1.0-res/100.0)
- return 100.0 - fd
-
-def dam_res(dam, res):
- ''' calculates damage modified by resistance.
- '''
- if res >= 0:
- fd = dam / (1.0+res/100.0)
- else:
- fd = dam / (1.0-res/100.0)
- return fd
-
-class ShipInstance(object):
- # just testin something.
- def __init__(self,
- shields=None,
- hulls=None,
- shield_resis=None,
- hull_resis=None ):
- self.shield_max = shields or 5000
- self.hull_max = hulls or 5000
- shield_resis = shield_resis or (100,100,100)
- hull_resis = hull_resis or (100,100,100)
- self.set_shield_res(*shield_resis)
- self.set_hull_res(*hull_resis)
-
-
- def set_shield_res(self, kn, em, th):
- self.shield_res_kn = kn
- self.shield_res_em = em
- self.shield_res_th = th
-
- def set_hull_res(self, kn, em, th):
- self.hull_res_kn = kn
- self.hull_res_em = em
- self.hull_res_th = th
-
- def survivability(self):
- # i have no clue how they calc this.
- # multiple attempts shows, they are using base pts as measure, but how exactly the calc is?
- krs = (self.shield_max/100.0 * self.shield_res_kn)
- ers = (self.shield_max/100.0 * self.shield_res_em)
- trs = (self.shield_max/100.0 * self.shield_res_th)
- print "Shield.", krs, ers, trs
-
- krh = (self.hull_max/100.0 * self.hull_res_kn)
- erh = (self.hull_max/100.0 * self.hull_res_em)
- trh = (self.hull_max/100.0 * self.hull_res_th)
- print "Hull.", krh, erh, trh
-
- #print "?1", ((krs+ers+trs+krh+erh+trh)/6.0)+self.shield_max + self.hull_max
- print "?2", ((krs+ers+trs+3*self.shield_max)/3.0)+((krh+erh+trh+3*self.hull_max)/3.0)
-
-
- # another try:
- """
- lets assume survivability is really measured through applying 1000 dps for 10 secs.
-
- """
- print "Assuming dps..."
- shield = self.shield_max
- hull = self.hull_max
- r1s = shield / (1.0*dam_res(1000, self.shield_res_kn))
- r2s = shield / (1.0*dam_res(1000, self.shield_res_em))
- r3s = shield / (1.0*dam_res(1000, self.shield_res_th))
- print r1s, r2s, r3s
- rXs = (r1s+r2s+r3s) / 3.0
- print "Shield survival time at 1kdps", rXs
-
- r1h = hull / (1.0*dam_res(1000, self.hull_res_kn))
- r2h = hull / (1.0*dam_res(1000, self.hull_res_em))
- r3h = hull / (1.0*dam_res(1000, self.hull_res_th))
- print r1h, r2h, r3h
- rXh = (r1h+r2h+r3h) / 3.0
- print "Hull survival time at 1kdps", rXh
-
- print "Total survival time ", rXs + rXh, " sec"
- print "Surv should be ", int(round((rXs+rXh) * 1000))
-
-
-
- return ((krs+ers+trs)/3.0)+self.shield_max + self.hull_max + ((krh+erh+trh)/3.0)
-
-
-
-ship = ShipInstance()
-print ship.survivability()
-
-print "#" * 80
-mykatanas=ShipInstance(7664, 4296, (70,61,100), (20,80,50))
-print "We know its 19736... but own calcs say..."
-print mykatanas.survivability()
\ No newline at end of file
+
+def res_to_red(res):
+ ''' calculates reduction % of damage from base resistance
+ incoming damage is assumed to be 100.0 to get percentages.
+ '''
+ if res >= 0:
+ fd = 100 / (1.0+res/100.0)
+ else:
+ fd = 100 / (1.0-res/100.0)
+ return 100.0 - fd
+
+def dam_res(dam, res):
+ ''' calculates damage modified by resistance.
+ '''
+ if res >= 0:
+ fd = dam / (1.0+res/100.0)
+ else:
+ fd = dam / (1.0-res/100.0)
+ return fd
+
+class ShipInstance(object):
+ # just testin something.
+ def __init__(self,
+ shields=None,
+ hulls=None,
+ shield_resis=None,
+ hull_resis=None ):
+ self.shield_max = shields or 5000
+ self.hull_max = hulls or 5000
+ shield_resis = shield_resis or (100,100,100)
+ hull_resis = hull_resis or (100,100,100)
+ self.set_shield_res(*shield_resis)
+ self.set_hull_res(*hull_resis)
+
+
+ def set_shield_res(self, kn, em, th):
+ self.shield_res_kn = kn
+ self.shield_res_em = em
+ self.shield_res_th = th
+
+ def set_hull_res(self, kn, em, th):
+ self.hull_res_kn = kn
+ self.hull_res_em = em
+ self.hull_res_th = th
+
+ def survivability(self):
+ # i have no clue how they calc this.
+ # multiple attempts shows, they are using base pts as measure, but how exactly the calc is?
+ krs = (self.shield_max/100.0 * self.shield_res_kn)
+ ers = (self.shield_max/100.0 * self.shield_res_em)
+ trs = (self.shield_max/100.0 * self.shield_res_th)
+ print(("Shield.", krs, ers, trs))
+
+ krh = (self.hull_max/100.0 * self.hull_res_kn)
+ erh = (self.hull_max/100.0 * self.hull_res_em)
+ trh = (self.hull_max/100.0 * self.hull_res_th)
+ print(("Hull.", krh, erh, trh))
+
+ #print "?1", ((krs+ers+trs+krh+erh+trh)/6.0)+self.shield_max + self.hull_max
+ print(("?2", ((krs+ers+trs+3*self.shield_max)/3.0)+((krh+erh+trh+3*self.hull_max)/3.0)))
+
+
+ # another try:
+ """
+ lets assume survivability is really measured through applying 1000 dps for 10 secs.
+
+ """
+ print("Assuming dps...")
+ shield = self.shield_max
+ hull = self.hull_max
+ r1s = shield / (1.0*dam_res(1000, self.shield_res_kn))
+ r2s = shield / (1.0*dam_res(1000, self.shield_res_em))
+ r3s = shield / (1.0*dam_res(1000, self.shield_res_th))
+ print((r1s, r2s, r3s))
+ rXs = (r1s+r2s+r3s) / 3.0
+ print(("Shield survival time at 1kdps", rXs))
+
+ r1h = hull / (1.0*dam_res(1000, self.hull_res_kn))
+ r2h = hull / (1.0*dam_res(1000, self.hull_res_em))
+ r3h = hull / (1.0*dam_res(1000, self.hull_res_th))
+ print((r1h, r2h, r3h))
+ rXh = (r1h+r2h+r3h) / 3.0
+ print(("Hull survival time at 1kdps", rXh))
+
+ print(("Total survival time ", rXs + rXh, " sec"))
+ print(("Surv should be ", int(round((rXs+rXh) * 1000))))
+
+
+
+ return ((krs+ers+trs)/3.0)+self.shield_max + self.hull_max + ((krh+erh+trh)/3.0)
+
+
+
+ship = ShipInstance()
+print((ship.survivability()))
+
+print(("#" * 80))
+mykatanas=ShipInstance(7664, 4296, (70,61,100), (20,80,50))
+print("We know its 19736... but own calcs say...")
+print((mykatanas.survivability()))
\ No newline at end of file
diff --git a/src/scon/gui/treeview.py b/src/scon/gui/treeview.py
index e42a9c2..6e551ce 100644
--- a/src/scon/gui/treeview.py
+++ b/src/scon/gui/treeview.py
@@ -1,444 +1,444 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-## FROM:
-# https://github.com/cloudformdesign/cloudtb/blob/master/extra/PyQt/treeview.py
-# ****** The Cloud Toolbox v0.1.2******
-# This is the cloud toolbox -- a single module used in several packages
-# found at
-# For more information see
-#
-# This module may be a part of a python package, and may be out of date.
-# This behavior is intentional, do NOT update it.
-#
-# You are encouraged to use this pacakge, or any code snippets in it, in
-# your own projects. Hopefully they will be helpful to you!
-#
-# This project is Licenced under The MIT License (MIT)
-#
-# Copyright (c) 2013 Garrett Berg cloudformdesign.com
-# An updated version of this file can be found at:
-#
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the "Software"),
-# to deal in the Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish, distribute, sublicense,
-# and/or sell copies of the Software, and to permit persons to whom the
-# Software is furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-# DEALINGS IN THE SOFTWARE.
-#
-# http://opensource.org/licenses/MIT
-
-# import pdb
-import os
-
-from PyQt4 import QtCore, QtGui
-import sys
-#import icons_rc
-
-
-# from cloudtb import dbe
-
-class Node(object):
- '''A general node stucture to be used in treeview
-the attrib_dict can store any information your overall treeview
-needs it to store.
-'''
- def __init__(self, name, parent=None, icon = None,
- attrib_dict = None):
-
- self._name = name
- self._attrib = attrib_dict
- self._children = []
- self._parent = parent
- self.icon = icon
-
- if parent is not None:
- parent.addChild(self)
-
- def addChild(self, child):
- self._children.append(child)
-
- def insertChild(self, position, child):
-
- if position < 0 or position > len(self._children):
- return False
-
- self._children.insert(position, child)
- child._parent = self
- return True
-
- def removeChild(self, position):
-
- if position < 0 or position > len(self._children):
- return False
- child = self._children.pop(position)
- child._parent = None
-
- return True
-
- def name(self):
- return self._name
-
- def setName(self, name):
- self._name = name
-
- def child(self, row):
- return self._children[row]
-
- def childCount(self):
- return len(self._children)
-
- def parent(self):
- return self._parent
-
- def row(self):
- if self._parent is not None:
- return self._parent._children.index(self)
-
-
- def log(self, tabLevel=-1):
-
- output = ""
- tabLevel += 1
-
- for i in range(tabLevel):
- output += " "
-
- output += "|-" + self._name + "\n"
-
- for child in self._children:
- output += child.log(tabLevel)
-
- tabLevel -= 1
-# output += "\n"
-
- return output
-
- def __repr__(self):
- return self.log()
-
-class TreeViewModel(QtCore.QAbstractItemModel):
- """INPUTS: Node, QObject"""
- def __init__(self, root, parent=None, header_title = None):
- super(TreeViewModel, self).__init__(parent)
- self.is_editable = False
- self.is_selectable = True
- self.is_enabled = True
- self.set_flags()
- self._rootNode = root
- self.header_title = header_title
-
- # The following are created functions called in "data" -- which is a
- # Qt defined funciton. This way of doing things is FAR more pythonic
- # and allows classes to inherit this one and not have to rewrite the
- # entire data method
- # all of them recieve an index and a node
-
- def role_display(self, index, node):
- if index.column() == 0:
- return node.name()
-
- def role_edit(self, index, node):
- return self.role_display(index, node)
-
- def role_tool_tip(self, index, node):
- return
-
- def role_check_state(self, index, node):
- return
-
- def role_decoration(self, index, node):
- if index.column() == 0:
- icon = node.icon
- if icon == None:
- return False
- else:
- return icon
-
- def role_flags(self, index, node):
- '''While not technically a "role" it behaves in much the same way.
-This method is called by the "flags" method for all indexes with
-a node'''
- return self.BASE_FLAGS
-
- def set_flags(self, is_editable = None, is_selectable = None,
- is_enabled = None):
- ''' Sets new flags to the BASE_FLAGS variable'''
- if is_editable != None:
- self.is_editable = is_editable
- if is_selectable != None:
- self.is_selectable = is_selectable
- if is_enabled != None:
- self.is_enabled = is_enabled
- self.BASE_FLAGS = QtCore.Qt.ItemFlags(
- (QtCore.Qt.ItemIsEnabled * bool(self.is_enabled))
- | (QtCore.Qt.ItemIsSelectable * bool(self.is_selectable))
- | (QtCore.Qt.ItemIsEditable * bool(self.is_editable))
- )
-
- """INPUTS: QModelIndex"""
- """OUTPUT: int"""
- def rowCount(self, parent):
- if not parent.isValid():
- parentNode = self._rootNode
- else:
- parentNode = parent.internalPointer()
-
- return parentNode.childCount()
-
- """INPUTS: QModelIndex"""
- """OUTPUT: int"""
- def columnCount(self, parent):
- return 1
-
- """INPUTS: QModelIndex, int"""
- """OUTPUT: QVariant, strings are cast to QString which is a QVariant"""
- def data(self, index, role):
- '''index is an object that contains a pointer to the item inside
-internPointer(). Note that this was set during the insertRows
-method call, so you don't need to track them!
-'''
- if not index.isValid():
- return None
-
- node = index.internalPointer()
-
- if role == QtCore.Qt.EditRole:
- return self.role_edit(index, node)
-
- if role == QtCore.Qt.ToolTipRole:
- return self.role_tool_tip(index, node)
-
- if role == QtCore.Qt.CheckStateRole:
- return self.role_check_state(index, node)
-
- if role == QtCore.Qt.DisplayRole:
- return self.role_display(index, node)
-
- if role == QtCore.Qt.DecorationRole:
- return self.role_decoration(index, node)
-
- """INPUTS: QModelIndex, QVariant, int (flag)"""
- def setData(self, index, value, role=QtCore.Qt.EditRole):
- if index.isValid():
- if role == QtCore.Qt.EditRole:
- node = index.internalPointer()
- node.setName(value)
- return True
- return False
-
- """INPUTS: int, Qt::Orientation, int"""
- """OUTPUT: QVariant, strings are cast to QString which is a QVariant"""
- def headerData(self, section, orientation, role):
- if role == QtCore.Qt.DisplayRole:
- if self.header_title != None:
- return self.header_title
- if section == 0:
- return "Scenegraph"
- else:
- return "Typeinfo"
-
- """INPUTS: QModelIndex"""
- """OUTPUT: int (flag)"""
-# def flags(self, index):
-# return (QtCore.Qt.ItemIsEnabled |
-# QtCore.Qt.ItemIsSelectable #|
-## QtCore.Qt.ItemIsEditable
-# )
- def flags(self, index):
- if not index.isValid():
- return self.BASE_FLAGS
-
- node = index.internalPointer()
- return self.role_flags(index, node)
-
- """INPUTS: QModelIndex"""
- """OUTPUT: QModelIndex"""
- """Should return the parent of the node with the given QModelIndex"""
- def parent(self, index):
- node = self.getNode(index)
- parentNode = node.parent()
-
- if parentNode == self._rootNode:
- return QtCore.QModelIndex()
- return self.createIndex(parentNode.row(), 0, parentNode)
-
- """INPUTS: int, int, QModelIndex"""
- """OUTPUT: QModelIndex"""
- """Should return a QModelIndex that corresponds to the given row,
-column and parent node"""
- def index(self, row, column, parent):
- # This is how Qt creates the nested (tree) list. It knows how many
- # rows it has because of insertRows, and it uses index and
- # createIndex to build the tree.
-# print 'Index called', row, column
- parentNode = self.getNode(parent)
- childItem = parentNode.child(row)
- if childItem:
- return self.createIndex(row, column, childItem)
- else:
- return QtCore.QModelIndex()
-
- """CUSTOM"""
- """INPUTS: QModelIndex"""
- def getNode(self, index):
- if index.isValid():
- node = index.internalPointer()
- if node:
- return node
-
- return self._rootNode
-
-
- """INPUTS: int, List of Nodes, QModelIndex"""
- def insertRows(self, position, rows, parent=QtCore.QModelIndex()):
- parentNode = self.getNode(parent)
-
- self.beginInsertRows(parent, position, position + len(rows) - 1)
-
- for i, row in enumerate(rows):
-# childCount = parentNode.childCount()
- childNode = row
- success = parentNode.insertChild(position + i, childNode)
-
- self.endInsertRows()
-
- return success
-
- """INPUTS: int, int, QModelIndex"""
- def removeRows(self, position, rows, parent=QtCore.QModelIndex()):
- if rows == 0:
- return
-
- parentNode = self.getNode(parent)
- self.beginRemoveRows(parent, position, position + rows - 1)
-
- for row in range(rows):
- success = parentNode.removeChild(position)
- # TODO: break if not success?
-
- self.endRemoveRows()
-
- return success
-
- def clear_rows(self):
- return self.removeRows(0, self._rootNode.childCount())
-
-# TODO: doesn't work. Not sure how to get icons
-ICON_FOLDER = QtGui.QIcon.fromTheme('folder')
-
-def _node_compare(a, b):
- return b.isdir - a.isdir
-
-def get_file_folder_node(fdata, parent):
- '''return the node structure of the data.
-[[(dir_name, path),
-[dir_name, path),
-[(file, path),
-(file, path)]]
-]
-]
-'''
- # TODO: set icons correctly
-
- nodes = []
- for fobj in fdata:
- path = fobj[0]
- name = os.path.split(path)[1]
-
- if len(fobj) == 1:
- fileobj = Node(name, parent = parent, icon = None)
- fileobj.full_path = path
- fileobj.isdir = False
- nodes.append(fileobj)
- continue
- folderobj = Node(name, parent = parent, icon = ICON_FOLDER,
- )
- folderobj.full_path = path
- folderobj.isdir = True
-
- get_file_folder_node(fobj[1], parent = folderobj)
- nodes.append(folderobj)
- nodes.sort(cmp = _node_compare)
- return nodes
-import itertools
-
-def _get_filelist_nodes(iter_file_list, dir_path = ''):
- '''Takes a sorted file list iterator and returns the files in a
-format that can be converted'''
- files = []
- dir_path = os.path.join(dir_path, '') # Put into directory syntax
- len_dp = len(dir_path)
- while True:
- try:
- fpath = next(iter_file_list)
- except StopIteration:
- break
- if dir_path != fpath[:len_dp]:
- iter_file_list = itertools.chain((fpath,), iter_file_list)
- break
-
- if os.path.isdir(fpath):
- iter_file_list, new_files = _get_filelist_nodes(iter_file_list,
- dir_path = fpath)
- files.append((fpath, new_files))
- else:
- files.append((fpath,))
- return iter_file_list, files
-
-def get_filelist_nodes(file_list, parent = None):
- file_list = sorted(file_list)
- file_tuples = _get_filelist_nodes(iter(file_list))[1]
- return get_file_folder_node(file_tuples, parent)
-
-def dev_show_file_list(file_objects):
- '''For developemnet'''
-
- app = QtGui.QApplication(sys.argv)
-
- rootNode = Node("Rootdir")
- model = TreeViewModel(rootNode)
-
- treeView = QtGui.QTreeView()
- treeView.show()
-
- treeView.setModel(model)
- model.insertRows(0, file_objects, QtCore.QModelIndex())
- sys.exit(app.exec_())
-
-
-if __name__ == '__main__':
- from pprint import pprint
-
- files = '''/home/user/Projects/Learning/LearningQt/LearningQt.pro.user
-/home/user/Projects/Learning/LearningQt/LearningQt.pro
-/home/user/Projects/Learning/LearningQt/qmlapplicationviewer/qmlapplicationviewer.h
-/home/user/Projects/Learning/LearningQt/qmlapplicationviewer/qmlapplicationviewer.cpp
-/home/user/Projects/Learning/LearningQt/qmlapplicationviewer/qmlapplicationviewer.pri
-/home/user/Projects/Learning/LearningQt/qmlapplicationviewer
-/home/user/Projects/Learning/LearningQt/LearningQt64.png
-/home/user/Projects/Learning/LearningQt/LearningQt_harmattan.desktop
-/home/user/Projects/Learning/LearningQt/LearningQt.svg
-/home/user/Projects/Learning/LearningQt/main.cpp
-/home/user/Projects/Learning/LearningQt/LearningQt.desktop
-/home/user/Projects/Learning/LearningQt/qml/LearningQt/main.qml
-/home/user/Projects/Learning/LearningQt/qml/LearningQt
-/home/user/Projects/Learning/LearningQt/qml
-/home/user/Projects/Learning/LearningQt/LearningQt80.png'''
- nodes = get_filelist_nodes(files.split('\n'))
- for n in nodes:
- print n
- dev_show_file_list(nodes)
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+## FROM:
+# https://github.com/cloudformdesign/cloudtb/blob/master/extra/PyQt/treeview.py
+# ****** The Cloud Toolbox v0.1.2******
+# This is the cloud toolbox -- a single module used in several packages
+# found at
+# For more information see
+#
+# This module may be a part of a python package, and may be out of date.
+# This behavior is intentional, do NOT update it.
+#
+# You are encouraged to use this pacakge, or any code snippets in it, in
+# your own projects. Hopefully they will be helpful to you!
+#
+# This project is Licenced under The MIT License (MIT)
+#
+# Copyright (c) 2013 Garrett Berg cloudformdesign.com
+# An updated version of this file can be found at:
+#
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+#
+# http://opensource.org/licenses/MIT
+
+# import pdb
+import os
+
+from PyQt4 import QtCore, QtGui
+import sys
+#import icons_rc
+
+
+# from cloudtb import dbe
+
+class Node(object):
+ '''A general node stucture to be used in treeview
+the attrib_dict can store any information your overall treeview
+needs it to store.
+'''
+ def __init__(self, name, parent=None, icon = None,
+ attrib_dict = None):
+
+ self._name = name
+ self._attrib = attrib_dict
+ self._children = []
+ self._parent = parent
+ self.icon = icon
+
+ if parent is not None:
+ parent.addChild(self)
+
+ def addChild(self, child):
+ self._children.append(child)
+
+ def insertChild(self, position, child):
+
+ if position < 0 or position > len(self._children):
+ return False
+
+ self._children.insert(position, child)
+ child._parent = self
+ return True
+
+ def removeChild(self, position):
+
+ if position < 0 or position > len(self._children):
+ return False
+ child = self._children.pop(position)
+ child._parent = None
+
+ return True
+
+ def name(self):
+ return self._name
+
+ def setName(self, name):
+ self._name = name
+
+ def child(self, row):
+ return self._children[row]
+
+ def childCount(self):
+ return len(self._children)
+
+ def parent(self):
+ return self._parent
+
+ def row(self):
+ if self._parent is not None:
+ return self._parent._children.index(self)
+
+
+ def log(self, tabLevel=-1):
+
+ output = ""
+ tabLevel += 1
+
+ for i in range(tabLevel):
+ output += " "
+
+ output += "|-" + self._name + "\n"
+
+ for child in self._children:
+ output += child.log(tabLevel)
+
+ tabLevel -= 1
+# output += "\n"
+
+ return output
+
+ def __repr__(self):
+ return self.log()
+
+class TreeViewModel(QtCore.QAbstractItemModel):
+ """INPUTS: Node, QObject"""
+ def __init__(self, root, parent=None, header_title = None):
+ super(TreeViewModel, self).__init__(parent)
+ self.is_editable = False
+ self.is_selectable = True
+ self.is_enabled = True
+ self.set_flags()
+ self._rootNode = root
+ self.header_title = header_title
+
+ # The following are created functions called in "data" -- which is a
+ # Qt defined funciton. This way of doing things is FAR more pythonic
+ # and allows classes to inherit this one and not have to rewrite the
+ # entire data method
+ # all of them recieve an index and a node
+
+ def role_display(self, index, node):
+ if index.column() == 0:
+ return node.name()
+
+ def role_edit(self, index, node):
+ return self.role_display(index, node)
+
+ def role_tool_tip(self, index, node):
+ return
+
+ def role_check_state(self, index, node):
+ return
+
+ def role_decoration(self, index, node):
+ if index.column() == 0:
+ icon = node.icon
+ if icon == None:
+ return False
+ else:
+ return icon
+
+ def role_flags(self, index, node):
+ '''While not technically a "role" it behaves in much the same way.
+This method is called by the "flags" method for all indexes with
+a node'''
+ return self.BASE_FLAGS
+
+ def set_flags(self, is_editable = None, is_selectable = None,
+ is_enabled = None):
+ ''' Sets new flags to the BASE_FLAGS variable'''
+ if is_editable != None:
+ self.is_editable = is_editable
+ if is_selectable != None:
+ self.is_selectable = is_selectable
+ if is_enabled != None:
+ self.is_enabled = is_enabled
+ self.BASE_FLAGS = QtCore.Qt.ItemFlags(
+ (QtCore.Qt.ItemIsEnabled * bool(self.is_enabled))
+ | (QtCore.Qt.ItemIsSelectable * bool(self.is_selectable))
+ | (QtCore.Qt.ItemIsEditable * bool(self.is_editable))
+ )
+
+ """INPUTS: QModelIndex"""
+ """OUTPUT: int"""
+ def rowCount(self, parent):
+ if not parent.isValid():
+ parentNode = self._rootNode
+ else:
+ parentNode = parent.internalPointer()
+
+ return parentNode.childCount()
+
+ """INPUTS: QModelIndex"""
+ """OUTPUT: int"""
+ def columnCount(self, parent):
+ return 1
+
+ """INPUTS: QModelIndex, int"""
+ """OUTPUT: QVariant, strings are cast to QString which is a QVariant"""
+ def data(self, index, role):
+ '''index is an object that contains a pointer to the item inside
+internPointer(). Note that this was set during the insertRows
+method call, so you don't need to track them!
+'''
+ if not index.isValid():
+ return None
+
+ node = index.internalPointer()
+
+ if role == QtCore.Qt.EditRole:
+ return self.role_edit(index, node)
+
+ if role == QtCore.Qt.ToolTipRole:
+ return self.role_tool_tip(index, node)
+
+ if role == QtCore.Qt.CheckStateRole:
+ return self.role_check_state(index, node)
+
+ if role == QtCore.Qt.DisplayRole:
+ return self.role_display(index, node)
+
+ if role == QtCore.Qt.DecorationRole:
+ return self.role_decoration(index, node)
+
+ """INPUTS: QModelIndex, QVariant, int (flag)"""
+ def setData(self, index, value, role=QtCore.Qt.EditRole):
+ if index.isValid():
+ if role == QtCore.Qt.EditRole:
+ node = index.internalPointer()
+ node.setName(value)
+ return True
+ return False
+
+ """INPUTS: int, Qt::Orientation, int"""
+ """OUTPUT: QVariant, strings are cast to QString which is a QVariant"""
+ def headerData(self, section, orientation, role):
+ if role == QtCore.Qt.DisplayRole:
+ if self.header_title != None:
+ return self.header_title
+ if section == 0:
+ return "Scenegraph"
+ else:
+ return "Typeinfo"
+
+ """INPUTS: QModelIndex"""
+ """OUTPUT: int (flag)"""
+# def flags(self, index):
+# return (QtCore.Qt.ItemIsEnabled |
+# QtCore.Qt.ItemIsSelectable #|
+## QtCore.Qt.ItemIsEditable
+# )
+ def flags(self, index):
+ if not index.isValid():
+ return self.BASE_FLAGS
+
+ node = index.internalPointer()
+ return self.role_flags(index, node)
+
+ """INPUTS: QModelIndex"""
+ """OUTPUT: QModelIndex"""
+ """Should return the parent of the node with the given QModelIndex"""
+ def parent(self, index):
+ node = self.getNode(index)
+ parentNode = node.parent()
+
+ if parentNode == self._rootNode:
+ return QtCore.QModelIndex()
+ return self.createIndex(parentNode.row(), 0, parentNode)
+
+ """INPUTS: int, int, QModelIndex"""
+ """OUTPUT: QModelIndex"""
+ """Should return a QModelIndex that corresponds to the given row,
+column and parent node"""
+ def index(self, row, column, parent):
+ # This is how Qt creates the nested (tree) list. It knows how many
+ # rows it has because of insertRows, and it uses index and
+ # createIndex to build the tree.
+# print 'Index called', row, column
+ parentNode = self.getNode(parent)
+ childItem = parentNode.child(row)
+ if childItem:
+ return self.createIndex(row, column, childItem)
+ else:
+ return QtCore.QModelIndex()
+
+ """CUSTOM"""
+ """INPUTS: QModelIndex"""
+ def getNode(self, index):
+ if index.isValid():
+ node = index.internalPointer()
+ if node:
+ return node
+
+ return self._rootNode
+
+
+ """INPUTS: int, List of Nodes, QModelIndex"""
+ def insertRows(self, position, rows, parent=QtCore.QModelIndex()):
+ parentNode = self.getNode(parent)
+
+ self.beginInsertRows(parent, position, position + len(rows) - 1)
+
+ for i, row in enumerate(rows):
+# childCount = parentNode.childCount()
+ childNode = row
+ success = parentNode.insertChild(position + i, childNode)
+
+ self.endInsertRows()
+
+ return success
+
+ """INPUTS: int, int, QModelIndex"""
+ def removeRows(self, position, rows, parent=QtCore.QModelIndex()):
+ if rows == 0:
+ return
+
+ parentNode = self.getNode(parent)
+ self.beginRemoveRows(parent, position, position + rows - 1)
+
+ for row in range(rows):
+ success = parentNode.removeChild(position)
+ # TODO: break if not success?
+
+ self.endRemoveRows()
+
+ return success
+
+ def clear_rows(self):
+ return self.removeRows(0, self._rootNode.childCount())
+
+# TODO: doesn't work. Not sure how to get icons
+ICON_FOLDER = QtGui.QIcon.fromTheme('folder')
+
+def _node_compare(a, b):
+ return b.isdir - a.isdir
+
+def get_file_folder_node(fdata, parent):
+ '''return the node structure of the data.
+[[(dir_name, path),
+[dir_name, path),
+[(file, path),
+(file, path)]]
+]
+]
+'''
+ # TODO: set icons correctly
+
+ nodes = []
+ for fobj in fdata:
+ path = fobj[0]
+ name = os.path.split(path)[1]
+
+ if len(fobj) == 1:
+ fileobj = Node(name, parent = parent, icon = None)
+ fileobj.full_path = path
+ fileobj.isdir = False
+ nodes.append(fileobj)
+ continue
+ folderobj = Node(name, parent = parent, icon = ICON_FOLDER,
+ )
+ folderobj.full_path = path
+ folderobj.isdir = True
+
+ get_file_folder_node(fobj[1], parent = folderobj)
+ nodes.append(folderobj)
+ nodes.sort(cmp = _node_compare)
+ return nodes
+import itertools
+
+def _get_filelist_nodes(iter_file_list, dir_path = ''):
+ '''Takes a sorted file list iterator and returns the files in a
+format that can be converted'''
+ files = []
+ dir_path = os.path.join(dir_path, '') # Put into directory syntax
+ len_dp = len(dir_path)
+ while True:
+ try:
+ fpath = next(iter_file_list)
+ except StopIteration:
+ break
+ if dir_path != fpath[:len_dp]:
+ iter_file_list = itertools.chain((fpath,), iter_file_list)
+ break
+
+ if os.path.isdir(fpath):
+ iter_file_list, new_files = _get_filelist_nodes(iter_file_list,
+ dir_path = fpath)
+ files.append((fpath, new_files))
+ else:
+ files.append((fpath,))
+ return iter_file_list, files
+
+def get_filelist_nodes(file_list, parent = None):
+ file_list = sorted(file_list)
+ file_tuples = _get_filelist_nodes(iter(file_list))[1]
+ return get_file_folder_node(file_tuples, parent)
+
+def dev_show_file_list(file_objects):
+ '''For developemnet'''
+
+ app = QtGui.QApplication(sys.argv)
+
+ rootNode = Node("Rootdir")
+ model = TreeViewModel(rootNode)
+
+ treeView = QtGui.QTreeView()
+ treeView.show()
+
+ treeView.setModel(model)
+ model.insertRows(0, file_objects, QtCore.QModelIndex())
+ sys.exit(app.exec_())
+
+
+if __name__ == '__main__':
+ from pprint import pprint
+
+ files = '''/home/user/Projects/Learning/LearningQt/LearningQt.pro.user
+/home/user/Projects/Learning/LearningQt/LearningQt.pro
+/home/user/Projects/Learning/LearningQt/qmlapplicationviewer/qmlapplicationviewer.h
+/home/user/Projects/Learning/LearningQt/qmlapplicationviewer/qmlapplicationviewer.cpp
+/home/user/Projects/Learning/LearningQt/qmlapplicationviewer/qmlapplicationviewer.pri
+/home/user/Projects/Learning/LearningQt/qmlapplicationviewer
+/home/user/Projects/Learning/LearningQt/LearningQt64.png
+/home/user/Projects/Learning/LearningQt/LearningQt_harmattan.desktop
+/home/user/Projects/Learning/LearningQt/LearningQt.svg
+/home/user/Projects/Learning/LearningQt/main.cpp
+/home/user/Projects/Learning/LearningQt/LearningQt.desktop
+/home/user/Projects/Learning/LearningQt/qml/LearningQt/main.qml
+/home/user/Projects/Learning/LearningQt/qml/LearningQt
+/home/user/Projects/Learning/LearningQt/qml
+/home/user/Projects/Learning/LearningQt/LearningQt80.png'''
+ nodes = get_filelist_nodes(files.split('\n'))
+ for n in nodes:
+ print(n)
+ dev_show_file_list(nodes)
\ No newline at end of file
diff --git a/src/scon/gui/viewer.py b/src/scon/gui/viewer.py
index ff59fa6..1f88023 100644
--- a/src/scon/gui/viewer.py
+++ b/src/scon/gui/viewer.py
@@ -13,7 +13,7 @@ import sys
from PyQt4 import QtCore, QtGui, QtWebKit, QtNetwork
from scon.dejaqt.folders import FolderLibrary
from scon.dejaqt.qweb import DejaWebView
-from treeview import TreeViewModel, Node
+from .treeview import TreeViewModel, Node
class MenuTree(QtGui.QTreeView):
def __init__(self, *args, **kwargs):
diff --git a/src/scon/logs/base.py b/src/scon/logs/base.py
index 8415e91..439de57 100644
--- a/src/scon/logs/base.py
+++ b/src/scon/logs/base.py
@@ -1,89 +1,89 @@
-import logging
-"""
- Base Class for a Logentry is Log. Stacktrace is an exception, which gets injected if a stacktrace
- is assumed, and swallows all following unrecognized logs.
-
- -> It gets parsed by a Logstream, like the Logfile, but might also be used to be feeded
- by live-streams of currently open log files.
-
- -> Logfiles is responsible to read whole packs of files, and
- -> Sessions are responsible for reading whole directories.
-
- A Log object usually will expand itself containing "values", and is responsible to retain all dynamic data needed to describe it in unpack()
- The classmethod is_handler should pre-scan a log, which is usually a dict containing the actual log in log['log']
- but it could be a string aswell.
-
- clean is called to make a log object independent of its source information, and delete all incoming data, so it becomes sleek.
- reviewed is an internal boolean, which supposed to be saved on successful unpack, unpack should ignore already unpacked logs.
- matcher is a regex object to match, or a list of them.
- trash is a boolean flag to indicate, this log is possibly unknown information or unneeded, and should be removed or ignored.
-
- -> Note for anyone creating new subclasses for parsing:
- All classes are to be __slot__-ed so they can be created more efficiently by python.
- A class without __slot__ will slow down parsing exponentially in CPython.
- __slots__ hinder you to add new properties on the fly in the code, but having this immutable class optimizes memory allocation.
-
- This is the reason, the base layout of the log object is explained here.
-"""
-
-
-L_CMBT = 'CMBT'
-L_WARNING = 'WARNING'
-L_NET = 'NET' # Not supported in near future.
-L_CHAT = 'CHAT'
-
-class Log(object):
- __slots__ = ['matcher', 'trash', 'reviewed']
- matcher = None
- trash = False
- reviewed = False
-
- @classmethod
- def is_handler(cls, log):
- return False
-
- def unpack(self, force=False):
- ''' unpacks this log from its data and saves values '''
- pass
-
- def explain(self):
- ''' returns a String readable by humans explaining this Log '''
- return ''
-
- def clean(self):
- ''' tell the log to forget all non-essential data '''
- pass
-
- def append(self, something):
- ''' returns true if this logfile wants an unrecognized log appended to it. '''
- return False
-
-class Stacktrace(Log):
- ''' Special Log to catch error reports '''
- def __init__(self, values=None):
- super(Stacktrace, self).__init__()
- self.message = values or ''
- if isinstance(self.message, dict):
- self.message = self.message.get('log', '')
- #self.trash = True
-
- @classmethod
- def is_handler(cls, log):
- # do i have a system crash report beginning here?
- if isinstance(log, basestring):
- l = log.strip()
- elif isinstance(log, dict):
- l = log.get('log', '').strip()
- else:
- return False
- if l.startswith('Stack trace:') or l.startswith('BitStream::DbgLog'):
- return True
-
- def clean(self):
- self.message = ''
-
- def append(self, something):
- ''' I take anything! '''
- logging.debug( "EXC: %s" % something )
- self.message = '%s\n%s' % (self.message, something)
+import logging
+"""
+ Base Class for a Logentry is Log. Stacktrace is an exception, which gets injected if a stacktrace
+ is assumed, and swallows all following unrecognized logs.
+
+ -> It gets parsed by a Logstream, like the Logfile, but might also be used to be feeded
+ by live-streams of currently open log files.
+
+ -> Logfiles is responsible to read whole packs of files, and
+ -> Sessions are responsible for reading whole directories.
+
+ A Log object usually will expand itself containing "values", and is responsible to retain all dynamic data needed to describe it in unpack()
+ The classmethod is_handler should pre-scan a log, which is usually a dict containing the actual log in log['log']
+ but it could be a string aswell.
+
+ clean is called to make a log object independent of its source information, and delete all incoming data, so it becomes sleek.
+ reviewed is an internal boolean, which supposed to be saved on successful unpack, unpack should ignore already unpacked logs.
+ matcher is a regex object to match, or a list of them.
+ trash is a boolean flag to indicate, this log is possibly unknown information or unneeded, and should be removed or ignored.
+
+ -> Note for anyone creating new subclasses for parsing:
+ All classes are to be __slot__-ed so they can be created more efficiently by python.
+ A class without __slot__ will slow down parsing exponentially in CPython.
+ __slots__ hinder you to add new properties on the fly in the code, but having this immutable class optimizes memory allocation.
+
+ This is the reason, the base layout of the log object is explained here.
+"""
+
+
+L_CMBT = 'CMBT'
+L_WARNING = 'WARNING'
+L_NET = 'NET' # Not supported in near future.
+L_CHAT = 'CHAT'
+
+class Log(object):
+ __slots__ = ['matcher', 'trash', 'reviewed']
+ matcher = None
+ trash = False
+ reviewed = False
+
+ @classmethod
+ def is_handler(cls, log):
+ return False
+
+ def unpack(self, force=False):
+ ''' unpacks this log from its data and saves values '''
+ pass
+
+ def explain(self):
+ ''' returns a String readable by humans explaining this Log '''
+ return ''
+
+ def clean(self):
+ ''' tell the log to forget all non-essential data '''
+ pass
+
+ def append(self, something):
+ ''' returns true if this logfile wants an unrecognized log appended to it. '''
+ return False
+
+class Stacktrace(Log):
+ ''' Special Log to catch error reports '''
+ def __init__(self, values=None):
+ super(Stacktrace, self).__init__()
+ self.message = values or ''
+ if isinstance(self.message, dict):
+ self.message = self.message.get('log', '')
+ #self.trash = True
+
+ @classmethod
+ def is_handler(cls, log):
+ # do i have a system crash report beginning here?
+ if isinstance(log, str):
+ l = log.strip()
+ elif isinstance(log, dict):
+ l = log.get('log', '').strip()
+ else:
+ return False
+ if l.startswith('Stack trace:') or l.startswith('BitStream::DbgLog'):
+ return True
+
+ def clean(self):
+ self.message = ''
+
+ def append(self, something):
+ ''' I take anything! '''
+ logging.debug( "EXC: %s" % something )
+ self.message = '%s\n%s' % (self.message, something)
return True
\ No newline at end of file
diff --git a/src/scon/logs/chat.py b/src/scon/logs/chat.py
index bf31589..18768fc 100644
--- a/src/scon/logs/chat.py
+++ b/src/scon/logs/chat.py
@@ -1,206 +1,206 @@
-# -*- coding: utf-8 -*-
-from logs.base import Log, L_WARNING, Stacktrace
-import re
-"""
- Responsible for Chat Log.
-
- Anything related to chat gets logged here, basicly interesting for chat related stuff mainly.
- Channel leaving and joining and connection to the chat server get logged here too.
-
--------------------------------
-Maybe add something to create a ColorChart of usernames?
-between 33-33-33 and FF-33 FF-33 FF-33
-
-"""
-
-class ChatLog(Log):
- __slots__ = ['matcher', 'trash', '_match_id', 'values']
-
- @classmethod
- def is_handler(cls, log):
- if log.get('logtype', None) == 'CHAT':
- return cls._is_handler(log)
- return False
-
- @classmethod
- def _is_handler(cls, log):
- return False
-
- def __init__(self, values=None):
- self.values = values or {}
- self.reviewed = False
-
- def unpack(self, force=False):
- if self.reviewed and not force:
- return True
- self._match_id = None
- # unpacks the data from the values.
- if hasattr(self, 'matcher') and self.matcher:
- matchers = self.matcher
- if not isinstance(matchers, list):
- matchers = [matchers,]
- for i, matcher in enumerate(matchers):
- m = matcher.match(self.values.get('log', ''))
- if m:
- self.values.update(m.groupdict())
- self._match_id = i
- self.reviewed = True
- return True
- # unknown?
- self.trash = True
-
- def explain(self):
- ''' returns a String readable by humans explaining this Log '''
- return self.values.get('log', 'Unknown Chat Log')
-
- def clean(self):
- if 'log' in self.values.keys():
- del self.values['log']
-
-class SystemMessage(ChatLog):
- matcher = re.compile(r"^<\s+SYSTEM>\s(?P.*)")
-
- @classmethod
- def _is_handler(cls, log):
- if log.get('log', '').lstrip().startswith('< SYSTEM>'):
- return True
- return False
-
- def explain(self):
- return '[SYSTEM]: %(message)s' % self.values
-
- def append(self, something):
- ''' System Messages accept appends '''
- if 'message' in self.values.keys():
- self.values['message'] = '%s\n%s' % (self.values['message'], something)
- return True
-
-
-
-class PrivateMessageReceived(ChatLog):
- matcher = re.compile(r"^<\s\s\s\sPRIVATE From>\[\s*(?P[^\]]+)\]\s(?P.*)")
-
- @classmethod
- def _is_handler(cls, log):
- if log.get('log', '').lstrip().startswith('< PRIVATE From>'):
- return True
- return False
-
- def explain(self):
- return '[From %(nickname)s]: %(message)s' % self.values
-
- def append(self, something):
- ''' Private Messages accept appends '''
- if 'message' in self.values.keys():
- self.values['message'] = '%s\n%s' % (self.values['message'], something)
- return True
-
-class PrivateMessageSent(ChatLog):
- matcher = re.compile(r"^<\s\s\s\sPRIVATE To\s\s>\[\s*(?P[^\]]+)\]\s(?P.*)")
-
- @classmethod
- def _is_handler(cls, log):
- if log.get('log', '').lstrip().startswith('< PRIVATE To >'):
- return True
- return False
-
- def explain(self):
- return '[To %(nickname)s]: %(message)s' % self.values
-
- def append(self, something):
- ''' Private Messages accept appends '''
- if 'message' in self.values.keys():
- self.values['message'] = '%s\n%s' % (self.values['message'], something)
- return True
-
-class ChatMessage(ChatLog):
- matcher = re.compile(r"^<\s*#(?P[^>]+)>\[\s*(?P[^\]]+)\]\s(?P.*)")
-
- @classmethod
- def _is_handler(cls, log):
- if log.get('log', '').lstrip().startswith('<'):
- return True
- return False
-
- def explain(self):
- return '[%(channel)s] <%(nickname)s>: %(message)s' % self.values
-
- def append(self, something):
- ''' ChatMessages accept appends '''
- if not 'message' in self.values.keys():
- print "Missing message? %s" % self.values
- self.values['message'] = ''
- self.values['message'] = '%s\n%s' % (self.values['message'], something)
- return True
-
-class ChatJoinChannel(ChatLog):
- matcher = re.compile(r"^Join\schannel\s<\s*#(?P[^>]+)>")
-
- @classmethod
- def _is_handler(cls, log):
- if log.get('log', '').lstrip().startswith('Join channel'):
- return True
- return False
-
- def explain(self):
- return '[joined %(channel)s]' % self.values
-
-class ChatLeaveChannel(ChatLog):
- matcher = re.compile(r"^Leave\schannel\s<\s*#(?P[^>]+)>")
-
- @classmethod
- def _is_handler(cls, log):
- if log.get('log', '').lstrip().startswith('Leave channel'):
- return True
- return False
-
- def explain(self):
- return '[left %(channel)s]' % self.values
-
-
-class ChatServerConnect(ChatLog):
- # 00:12:47.668 CHAT| Connection to chat-server established
- matcher = []
-
- @classmethod
- def _is_handler(cls, log):
- if log.get('log', '').lstrip().startswith('Connection to'):
- return True
- return False
-
- def unpack(self, force=False):
- self.reviewed = True
- return True
-
- def explain(self):
- return '[connected]'
-
-
-class ChatServerDisconnect(ChatLog):
- # 00:53:03.738 CHAT| Disconnect form chat-server (reason 0)
- matcher = []
-
- @classmethod
- def _is_handler(cls, log):
- if log.get('log', '').lstrip().startswith('Disconnect'):
- return True
- return False
-
- def unpack(self, force=False):
- self.reviewed = True
- return True
-
- def explain(self):
- return '[disconnected]'
-
-CHAT_LOGS = [
- SystemMessage,
- PrivateMessageReceived,
- PrivateMessageSent,
- ChatMessage, # private messages need to be before chatmessage.
- ChatServerConnect,
- ChatServerDisconnect,
- ChatJoinChannel,
- ChatLeaveChannel,
- Stacktrace,
- ]
+# -*- coding: utf-8 -*-
+from logs.base import Log, L_WARNING, Stacktrace
+import re
+"""
+ Responsible for Chat Log.
+
+ Anything related to chat gets logged here, basicly interesting for chat related stuff mainly.
+ Channel leaving and joining and connection to the chat server get logged here too.
+
+-------------------------------
+Maybe add something to create a ColorChart of usernames?
+between 33-33-33 and FF-33 FF-33 FF-33
+
+"""
+
+class ChatLog(Log):
+ __slots__ = ['matcher', 'trash', '_match_id', 'values']
+
+ @classmethod
+ def is_handler(cls, log):
+ if log.get('logtype', None) == 'CHAT':
+ return cls._is_handler(log)
+ return False
+
+ @classmethod
+ def _is_handler(cls, log):
+ return False
+
+ def __init__(self, values=None):
+ self.values = values or {}
+ self.reviewed = False
+
+ def unpack(self, force=False):
+ if self.reviewed and not force:
+ return True
+ self._match_id = None
+ # unpacks the data from the values.
+ if hasattr(self, 'matcher') and self.matcher:
+ matchers = self.matcher
+ if not isinstance(matchers, list):
+ matchers = [matchers,]
+ for i, matcher in enumerate(matchers):
+ m = matcher.match(self.values.get('log', ''))
+ if m:
+ self.values.update(m.groupdict())
+ self._match_id = i
+ self.reviewed = True
+ return True
+ # unknown?
+ self.trash = True
+
+ def explain(self):
+ ''' returns a String readable by humans explaining this Log '''
+ return self.values.get('log', 'Unknown Chat Log')
+
+ def clean(self):
+ if 'log' in list(self.values.keys()):
+ del self.values['log']
+
+class SystemMessage(ChatLog):
+ matcher = re.compile(r"^<\s+SYSTEM>\s(?P.*)")
+
+ @classmethod
+ def _is_handler(cls, log):
+ if log.get('log', '').lstrip().startswith('< SYSTEM>'):
+ return True
+ return False
+
+ def explain(self):
+ return '[SYSTEM]: %(message)s' % self.values
+
+ def append(self, something):
+ ''' System Messages accept appends '''
+ if 'message' in list(self.values.keys()):
+ self.values['message'] = '%s\n%s' % (self.values['message'], something)
+ return True
+
+
+
+class PrivateMessageReceived(ChatLog):
+ matcher = re.compile(r"^<\s\s\s\sPRIVATE From>\[\s*(?P[^\]]+)\]\s(?P.*)")
+
+ @classmethod
+ def _is_handler(cls, log):
+ if log.get('log', '').lstrip().startswith('< PRIVATE From>'):
+ return True
+ return False
+
+ def explain(self):
+ return '[From %(nickname)s]: %(message)s' % self.values
+
+ def append(self, something):
+ ''' Private Messages accept appends '''
+ if 'message' in list(self.values.keys()):
+ self.values['message'] = '%s\n%s' % (self.values['message'], something)
+ return True
+
+class PrivateMessageSent(ChatLog):
+ matcher = re.compile(r"^<\s\s\s\sPRIVATE To\s\s>\[\s*(?P[^\]]+)\]\s(?P.*)")
+
+ @classmethod
+ def _is_handler(cls, log):
+ if log.get('log', '').lstrip().startswith('< PRIVATE To >'):
+ return True
+ return False
+
+ def explain(self):
+ return '[To %(nickname)s]: %(message)s' % self.values
+
+ def append(self, something):
+ ''' Private Messages accept appends '''
+ if 'message' in list(self.values.keys()):
+ self.values['message'] = '%s\n%s' % (self.values['message'], something)
+ return True
+
+class ChatMessage(ChatLog):
+ matcher = re.compile(r"^<\s*#(?P[^>]+)>\[\s*(?P[^\]]+)\]\s(?P.*)")
+
+ @classmethod
+ def _is_handler(cls, log):
+ if log.get('log', '').lstrip().startswith('<'):
+ return True
+ return False
+
+ def explain(self):
+ return '[%(channel)s] <%(nickname)s>: %(message)s' % self.values
+
+ def append(self, something):
+ ''' ChatMessages accept appends '''
+ if not 'message' in list(self.values.keys()):
+ print(("Missing message? %s" % self.values))
+ self.values['message'] = ''
+ self.values['message'] = '%s\n%s' % (self.values['message'], something)
+ return True
+
+class ChatJoinChannel(ChatLog):
+ matcher = re.compile(r"^Join\schannel\s<\s*#(?P[^>]+)>")
+
+ @classmethod
+ def _is_handler(cls, log):
+ if log.get('log', '').lstrip().startswith('Join channel'):
+ return True
+ return False
+
+ def explain(self):
+ return '[joined %(channel)s]' % self.values
+
+class ChatLeaveChannel(ChatLog):
+ matcher = re.compile(r"^Leave\schannel\s<\s*#(?P[^>]+)>")
+
+ @classmethod
+ def _is_handler(cls, log):
+ if log.get('log', '').lstrip().startswith('Leave channel'):
+ return True
+ return False
+
+ def explain(self):
+ return '[left %(channel)s]' % self.values
+
+
+class ChatServerConnect(ChatLog):
+ # 00:12:47.668 CHAT| Connection to chat-server established
+ matcher = []
+
+ @classmethod
+ def _is_handler(cls, log):
+ if log.get('log', '').lstrip().startswith('Connection to'):
+ return True
+ return False
+
+ def unpack(self, force=False):
+ self.reviewed = True
+ return True
+
+ def explain(self):
+ return '[connected]'
+
+
+class ChatServerDisconnect(ChatLog):
+ # 00:53:03.738 CHAT| Disconnect form chat-server (reason 0)
+ matcher = []
+
+ @classmethod
+ def _is_handler(cls, log):
+ if log.get('log', '').lstrip().startswith('Disconnect'):
+ return True
+ return False
+
+ def unpack(self, force=False):
+ self.reviewed = True
+ return True
+
+ def explain(self):
+ return '[disconnected]'
+
+CHAT_LOGS = [
+ SystemMessage,
+ PrivateMessageReceived,
+ PrivateMessageSent,
+ ChatMessage, # private messages need to be before chatmessage.
+ ChatServerConnect,
+ ChatServerDisconnect,
+ ChatJoinChannel,
+ ChatLeaveChannel,
+ Stacktrace,
+ ]
diff --git a/src/scon/logs/combat.py b/src/scon/logs/combat.py
index d39c450..a75fde8 100644
--- a/src/scon/logs/combat.py
+++ b/src/scon/logs/combat.py
@@ -1,304 +1,304 @@
-# -*- coding: utf-8 -*-
-"""
- Primary Packets for Combat.Log Files.
-
- This is the most important part for dealing with actual statistics, since every action taken
- in a combat instance gets logged here.
-
-
- ------------------------------------
- Note:
- All logs start with something like
- 23:53:29.137 | LOGDATA
-
- LOGDATA can be quite different depending on the logfile.
-
- other forms encountered:
- 23:54:00.600 WARNING|
-
- combat logs:
- 01:04:38.805 CMBT |
-"""
-import re
-from base import Log, L_CMBT, Stacktrace
-import logging
-
-class CombatLog(Log):
- __slots__ = Log.__slots__ + [ '_match_id', 'values']
- @classmethod
- def _log_handler(cls, log):
- if log.startswith(cls.__name__):
- return True
- return False
-
- @classmethod
- def is_handler(cls, log):
- if log.get('logtype', None) == L_CMBT:
- return cls._log_handler(log.get('log', '').strip())
- return False
-
- def __init__(self, values=None):
- self.values = values or {}
- self.reviewed = False
-
- def unpack(self, force=False):
- if self.reviewed and not force:
- return True
- self._match_id = None
- # unpacks the data from the values.
- if hasattr(self, 'matcher') and self.matcher:
- matchers = self.matcher
- if not isinstance(matchers, list):
- matchers = [matchers,]
- for i, matcher in enumerate(matchers):
- m = matcher.match(self.values.get('log', ''))
- if m:
- self.values.update(m.groupdict())
- self._match_id = i
- self.reviewed = True
- return True
- # unknown?
- if not isinstance(self, UserEvent):
- logging.warning('Unknown Packet for %s:\n%s' % (self.__class__.__name__,
- self.values.get('log', '')))
- # trash if unknown or no matcher.
- self.trash = True
-
- def explain(self):
- ''' returns a String readable by humans explaining this Log '''
- return self.values.get('log', 'Unknown Combat Log')
-
- def clean(self):
- if 'log' in self.values.keys():
- del self.values['log']
-
-
-# @todo: where does this come from?
-class Action(CombatLog):
- __slots__ = CombatLog.__slots__
- pass
-
-class Gameplay(CombatLog):
- __slots__ = CombatLog.__slots__
- matcher = [
- # usual: team(reason). explained reason.
- re.compile(r"^Gameplay\sfinished\.\sWinner\steam\:\s+(?P\d+)\((?P\w+)\)\.\sFinish\sreason\:\s'(?P[^']+)'\.\sActual\sgame\stime\s+(?P\d+|\d+\.\d+)\ssec"),
- # team, unexplained reason (unknown, Timeout)
- re.compile(r"^Gameplay\sfinished\.\sWinner\steam\:\s+(?P\d+).\sFinish\sreason\:\s'(?P[^']+)'\.\sActual\sgame\stime\s+(?P\d+|\d+\.\d+)\ssec"),
- ]
-
-class Apply(CombatLog): # Apply Aura.
- __slots__ = CombatLog.__slots__
- matcher = re.compile(r"^Apply\saura\s'(?P\w+)'\sid\s(?P\d+)\stype\s(?P\w+)\sto\s'(?P[^\']+)'")
-
-class Damage(CombatLog):
- __slots__ = CombatLog.__slots__
- matcher = re.compile(r"^Damage\s+(?P[^\s]+)\s\->\s+(?P[^\s]+)\s+(?P(?:\d+|\d+\.\d+))(?:\s(?P[^\s]+)\s|\s{2,2})(?P(?:\w|\|)+)")
-
-class Spawn(CombatLog):
- __slots__ = CombatLog.__slots__
- matcher = re.compile(r"^Spawn\sSpaceShip\sfor\splayer(?P\d+)\s\((?P[^,]+),\s+(?P#\w+)\)\.\s+'(?P\w+)'")
-
-class Spell(CombatLog):
- __slots__ = CombatLog.__slots__
- matcher = re.compile(r"^Spell\s'(?P\w+)'\sby\s+(?P.*)(?:\((?P\w+)\)|)\stargets\((?P\d+)\)\:(?:\s(?P.+)|\s*)")
-
-class Reward(CombatLog):
- __slots__ = CombatLog.__slots__
- matcher = [
- # ordinary reward:
- re.compile(r"^Reward\s+(?P[^\s]+)(?:\s(?P\w+)\s+|\s+)(?P\d+)\s(?P.*)\s+for\s(?P.*)"),
- # openspace reward (karma):
- re.compile(r"^Reward\s+(?P[^\s]+)(?:\s(?P\w+)\s+|\s+)\s+(?P[\+\-]\d+)\skarma\spoints\s+for\s(?P.*)"),
- ]
-
-class Participant(CombatLog):
- __slots__ = CombatLog.__slots__
- matcher = re.compile(r"^\s+Participant\s+(?P[^\s]+)(?:\s+(?P\w+)|\s{30,})\s+(?:totalDamage\s(?P(?:\d+|\d+\.\d+));\s+|\s+)(?:mostDamageWith\s'(?P[^']+)';\s*(?P.*)|<(?P\w+)>)")
-
-"""
-2017-03-29 13:25:49 - Unknown Packet for Rocket:
-Rocket launch 18912, owner 'LOSNAR', def 'SpaceMissile_Barrage_T5_Mk3', target 'white213mouse' (17894)
-2017-03-29 13:25:49 - Unknown Packet for Rocket:
-Rocket detonation 18912, owner 'LOSNAR', def 'SpaceMissile_Barrage_T5_Mk3', reason 'auto_detonate', directHit 'white213mouse'
-2017-03-29 13:25:49 - Unknown Packet for Rocket:
-Rocket launch 18966, owner 'LOSNAR', def 'SpaceMissile_Barrage_T5_Mk3', target 'white213mouse' (17894)
-2017-03-29 13:25:49 - Unknown Packet for Rocket:
-Rocket detonation 18966, owner 'LOSNAR', def 'SpaceMissile_Barrage_T5_Mk3', reason 'auto_detonate', directHit 'white213mouse'
-2017-03-29 13:25:49 - Unknown Packet for Rocket:
-Rocket detonation 18892, owner 'LOSNAR', def 'SpaceMissile_Barrage_T5_Mk3', reason 'ttl'
-2017-03-29 13:25:49 - Unknown Packet for Rocket:
-Rocket detonation 18931, owner 'optimistik', def 'Weapon_Railgun_Heavy_T5_Epic', reason 'hit'
-2017-03-29 13:25:49 - Unknown Packet for Participant:
- Participant white213mouse Ship_Race5_M_ATTACK_Rank15
-"""
-
-class Rocket(CombatLog):
- __slots__ = CombatLog.__slots__
- matcher = re.compile(r"^Rocket\s(?Plaunch|detonation)\.\sowner\s'(?P[^']+)'(?:,\s(?:def\s'(?P\w+)'|target\s'(?P[^']+)'|reason\s'(?P\w+)'|directHit\s'(?P[^']+)'))+")
-
-class Heal(CombatLog):
- __slots__ = CombatLog.__slots__
- matcher = [
- # heal by module
- re.compile(r"^Heal\s+(?P[^\s]+)\s\->\s+(?P[^\s]+)\s+(?P(?:\d+|\d+\.\d+))\s(?P[^\s]+)"),
- # direct heal by source or n/a (global buff)
- re.compile(r"^Heal\s+(?:n/a|(?P\w+))\s+\->\s+(?P[^\s]+)\s+(?P(?:\d+|\d+\.\d+))"),
- ]
-
-class Killed(CombatLog):
- __slots__ = CombatLog.__slots__
- matcher = [
- re.compile(r"^Killed\s(?P[^\s]+)\s+(?P\w+);\s+killer\s(?P[^\s]+)\s*"),
- re.compile(r"^Killed\s(?P