This commit is contained in:
Gergely Polonkai 2015-11-04 13:46:33 +01:00
parent b180214152
commit 1dfc4601d7
7 changed files with 321 additions and 27 deletions

View File

@ -1,2 +1,10 @@
class Buffer(object): class Buffer(object):
pass def __init__(self):
self.__size = 0
self.__data = ''
def setSize(self, size):
self.__size = size
def getData(self):
return self.__data

97
einsteingame/formatter.py Normal file
View File

@ -0,0 +1,97 @@
import struct
from enum import Enum
class Formatter(object):
class CmdType(Enum):
EMPTY_CMD = 0
TEXT_COMMAND = 1
INT_ARG = 2
STRING_ARG = 3
DOUBLE_ARG = 4
FLOAT_ARG = 5
def __init__(self, data, offset):
cnt = struct.unpack('i', data[offset:offset + 4])[0]
if cnt == 0:
commandsCnt = argsCnt = 0
commands = NULL
args = NULL
offset += 4
commands = []
commandsCnt = 0
maxArg = 0
argNo = None
for i in range(0, cnt):
typ = data[offset]
offset += 1
size = struct.unpack('i', data[offset:offset + 4])[0]
offset += 4
if typ == 1:
commands.append({
"type": self.CmdType.TEXT_COMMAND,
"data": data[offset:offset + size].decode('utf-8'),
})
elif typ == 2:
argNo = struct.unapack('i', data[offset:offset + 4])[0]
if argNo > maxArg:
maxArg = argNo
commands.append({
"type": self.CmdType.INT_ARG,
"data": argNo,
})
elif typ == 3:
argNo = struct.unapack('i', data[offset:offset + 4])[0]
if argNo > maxArg:
maxArg = argNo
commands.append({
"type": self.CmdType.STRING_ARG,
"data": argNo,
})
elif typ == 3:
argNo = struct.unapack('i', data[offset:offset + 4])[0]
if argNo > maxArg:
maxArg = argNo
commands.append({
"type": self.CmdType.FLOAT_ARG,
"data": argNo,
})
elif typ == 3:
argNo = struct.unapack('i', data[offset:offset + 4])[0]
if argNo > maxArg:
maxArg = argNo
commands.append({
"type": self.CmdType.DOUBLE_ARG,
"data": argNo,
})
offset += size;
argsCnt = maxArg
if argsCnt == 0:
args = None
else:
args = []
for i in range(0, len(commands)):
args.append[0]
for i in range(0, len(commands)):
c = commands[i]
if c.type == INT_ARG or c.type == STRING_ARG or c.type == FLOAT_ARG or c.type == DOUBLE_ARG:
no = c.data
args[no - 1] = c.type

View File

@ -2,10 +2,21 @@ from locale import setlocale, LC_ALL, LC_NUMERIC
class Locale(object): class Locale(object):
def __init__(self): def __init__(self):
self.__country = None
self.__language = None
self.parseLocale(setlocale(LC_ALL, "")) self.parseLocale(setlocale(LC_ALL, ""))
# hack because of numbers in Lua # hack because of numbers in Lua
setlocale(LC_NUMERIC, "C") setlocale(LC_NUMERIC, "C")
@property
def country(self):
return self.__country
@property
def language(self):
return self.__language
def parseLocale(self, name): def parseLocale(self, name):
pos = name.find('.') pos = name.find('.')
@ -21,17 +32,16 @@ class Locale(object):
pos = langAndCountry.find('_') pos = langAndCountry.find('_')
if pos < 0: if pos < 0:
language = langAndCountry self.__language = langAndCountry
country = "" self.__country = ''
else: else:
language = langAndCountry[0:pos] self.__language = langAndCountry[0:pos]
country = langAndCountry[pos + 1:] self.__country = langAndCountry[pos + 1:]
language = language.lower() self.__language = self.__language.lower()
country = country.lower() self.__country = self.__country.lower()
encoding = encoding.upper() encoding = encoding.upper()
def splitFileName(fileName): def splitFileName(fileName):
""" """
Returns tuple of name, extension, lang, country Returns tuple of name, extension, lang, country
@ -87,10 +97,10 @@ def getScore(lang, country, locale):
score = 0 score = 0
if locale.getCountry() == country: if locale.country == country:
score += 2 score += 2
if locale.getLanguage() == lang: if locale.language == lang:
score += 4 score += 4
return score return score

View File

@ -11,7 +11,8 @@ gi.require_version('Clutter', '1.0')
from gi.repository import Clutter from gi.repository import Clutter
from gi.repository import GLib from gi.repository import GLib
from .resources import ResourcesCollection from .messages import msg
from .resources import ResourcesCollection, resources
from .utils import ensureDirExists from .utils import ensureDirExists
win32 = False win32 = False
@ -19,8 +20,7 @@ apple = False
developer = True developer = True
PREFIX = '/usr' PREFIX = '/usr'
# Clutter.init()
#
# stage = Clutter.Stage() # stage = Clutter.Stage()
# stage.connect('destroy', lambda x: Clutter.main_quit()) # stage.connect('destroy', lambda x: Clutter.main_quit())
# stage.title = 'Test' # stage.title = 'Test'
@ -48,6 +48,21 @@ PREFIX = '/usr'
# stage.show() # stage.show()
# Clutter.main() # Clutter.main()
stage = None
sound = None
def initScreen():
Clutter.init()
stage = Clutter.Stage()
stage.connect('destroy', lambda x: Clutter.main_quit())
stage.set_size(800, 600)
stage.title = 'Einstein'
def initAudio():
# sound = Sound()
pass
def loadResources(selfPath): def loadResources(selfPath):
dirs = [] dirs = []
@ -65,7 +80,7 @@ def loadResources(selfPath):
dirs.append("res") dirs.append("res")
dirs.append(".") dirs.append(".")
resources = ResourcesCollection(dirs) resources = ResourcesCollection(dirs)
msg.load() msg.load(resources)
def main(script, *args): def main(script, *args):
ensureDirExists(os.environ["HOME"] + "/.einstein") ensureDirExists(os.environ["HOME"] + "/.einstein")
@ -73,7 +88,5 @@ def main(script, *args):
loadResources(sys.argv[0]) loadResources(sys.argv[0])
initScreen() initScreen()
initAudio() initAudio()
menu() # menu()
getStorage().flush() # getStorage().flush()
# screen.doneCursors();

66
einsteingame/messages.py Normal file
View File

@ -0,0 +1,66 @@
import struct
from .buffer import Buffer
from .formatter import Formatter
class Messages(object):
def __init__(self):
self.__messages = {}
def load(self, resources):
buf = Buffer()
resources.forEachInGroup('messages', lambda res: self.loadFromResource(res, buf))
def loadFromResource(self, resource, buf):
if not resource:
return
cnt = resource.getVariantsCount()
for variant in resource.variants:
if variant:
try:
score = variant.i18nScore
data = variant.getData()
self.loadBundle(score, data)
except Exception as e:
print("Error loading text bundle {}: {}".format(resource.getName(), e))
raise
def loadBundle(self, score, data):
if data[0:3] != b"CMF":
raise Exception("Invalid format of message file!")
version = struct.unpack('i', data[3:7])[0]
if version != 1:
raise Exception("Unknown version of message file!")
offset = struct.unpack('i', data[len(data) - 4:])[0]
cnt = struct.unpack('i', data[offset:offset + 4])[0]
offset += 4
for i in range(0, cnt):
sz = struct.unpack('i', data[offset:offset + 4])[0]
offset += 4;
if sz > 0:
name = data[offset:offset + sz].decode('utf-8')
msgOffset = struct.unpack('i', data[offset + sz:offset + sz + 4])[0]
if name in self.__messages:
ss = self.__messages[name]
if ss['score'] <= score:
ss['score'] = score
ss['message'] = Formatter(data, msgOffset)
else:
self.__messages[name] = {
"score": score,
"message": Formatter(data, msgOffset),
}
offset += sz + 4
msg = Messages()

View File

@ -1,6 +1,7 @@
from os import listdir from os import listdir
import struct import struct
import io import io
import zlib
from .buffer import Buffer from .buffer import Buffer
from .i18n import splitFileName, getScore, locale from .i18n import splitFileName, getScore, locale
@ -9,16 +10,73 @@ class ResourceError(Exception):
def __init__(self, code=None): def __init__(self, code=None):
self.code = code self.code = code
class ResVariant(object):
def __init__(self, resFile, i18nScore, dirEntry):
self.__file = resFile
self.__i18nScore = i18nScore
self.__offset = dirEntry['offset']
self.__unpackedSize = dirEntry['unpackedSize']
self.__packedSize = dirEntry['packedSize']
self.__level = dirEntry['level']
self.__refCnt = 0
self.__data = None
@property
def i18nScore(self):
return self.__i18nScore
def getData(self):
buf = Buffer()
buf.setSize(self.__unpackedSize)
if self.__refCnt == 0:
self.__data = self.__file.load(self.__offset, self.__packedSize, self.__unpackedSize, self.__level)
return self.__data
class Resource(object):
def __init__(self, file, i18nScore, entry, name):
self.__variants = []
self.__name = name
self.addVariant(file, i18nScore, entry)
def addVariant(self, file, i18nScore, entry):
if len(self.__variants) == 0:
self.__variants.append(ResVariant(file, i18nScore, entry))
return
try:
best_variant = [idx for idx, variant in enumerate(self.__variants) \
if variant.i18nScore == i18nScore][0]
self.__variants[best_variant] = ResVariant(file, i18nScore, entry)
except KeyError:
self.__variants.append(ResVariant(file, i18nScore, entry))
self.__variants.sort(key=lambda variant: variant.getI18nScore())
def getVariantsCount(self):
return len(self.__variants)
@property
def variants(self):
return self.__variants
def getName(self):
return self.__name
class ResourceFile(object): class ResourceFile(object):
def __init__(self, fileName, buf=None): def __init__(self, fileName, buf=None):
self.__name = fileName self.__name = fileName
if buf is not None: if buf is not None:
buffer = buf self.__buffer = buf
ownBuffer = False self.__ownBuffer = False
else: else:
buffer = Buffer() self.__buffer = Buffer()
ownBuffer = True self.__ownBuffer = True
try: try:
self.__stream = open(self.__name, 'rb') self.__stream = open(self.__name, 'rb')
@ -37,6 +95,27 @@ class ResourceFile(object):
except IOError as e: except IOError as e:
raise Exception("Error loading resource file '{}': {}".format(self.__name, e.message)) raise Exception("Error loading resource file '{}': {}".format(self.__name, e.message))
def load(self, offset, packedSize, unpackedSize, level):
try:
if level == 0:
self.__stream.seek(offset, io.SEEK_SET)
self.__stream.read()
return self.__stream.read(unpackedSize)
self.__stream.seek(offset, io.SEEK_SET)
data = self.__stream.read(packedSize)
return self.unpack(data)
except Exception as e:
print("Eror loading resource: {}".format(e))
raise
# void ResourceFile::unpack(char *in, int inSize, char *out, int outSize)
def unpack(self, data):
return zlib.decompress(data)
def readInt(self): def readInt(self):
return struct.unpack('i', self.__stream.read(4))[0] return struct.unpack('i', self.__stream.read(4))[0]
@ -55,7 +134,7 @@ class ResourceFile(object):
def getDirectory(self): def getDirectory(self):
try: try:
self.__stream.seek(-8, io.SEEK_END); self.__stream.seek(-8, io.SEEK_END)
except IOError: except IOError:
raise Exception("Error reading {} directory".format(self.__name)) raise Exception("Error reading {} directory".format(self.__name))
@ -63,7 +142,7 @@ class ResourceFile(object):
count = self.readInt() count = self.readInt()
try: try:
self.__stream.seek(start, io.SEEK_SET); self.__stream.seek(start, io.SEEK_SET)
except IOError: except IOError:
raise Exception("Error reading {} directory".format(self.__name)) raise Exception("Error reading {} directory".format(self.__name))
@ -89,9 +168,13 @@ class ResourcesCollection:
self.__files = [] self.__files = []
self.__buffer = None self.__buffer = None
self.__resources = {} self.__resources = {}
self.__groups = {}
self.loadResourceFiles(directories) self.loadResourceFiles(directories)
self.processFiles() self.processFiles()
def __iter__(self):
return iter(self.__resources.values())
def loadResourceFiles(self, directories): def loadResourceFiles(self, directories):
for directory in directories: for directory in directories:
try: try:
@ -119,9 +202,18 @@ class ResourcesCollection:
res = Resource(res_file, score, de, resName) res = Resource(res_file, score, de, resName)
self.__resources[resName] = res self.__resources[resName] = res
if len(de.group) > 0: if len(de['group']) > 0:
groups[de.group].append(res) if de['group'] not in self.__groups:
self.__groups[de['group']] = []
self.__groups[de['group']].append(res)
else: else:
res.addVariant(file, score, de) res.addVariant(res_file, score, de)
directory.clear() directory.clear()
def forEachInGroup(self, group, func):
for resource in self.__groups[group]:
func(resource)
resources = None

8
einsteingame/screen.py Normal file
View File

@ -0,0 +1,8 @@
class Screen(object):
def __init__(self):
self.__screen = None
self.__mouseImage = None
self.__mouseSave = None
self.__mouseVisible = None
self.__regionsList = None
self.__maxRegionsList = 0