src/platform/python/mgba/core.py (view raw)
1# Copyright (c) 2013-2016 Jeffrey Pfau
2#
3# This Source Code Form is subject to the terms of the Mozilla Public
4# License, v. 2.0. If a copy of the MPL was not distributed with this
5# file, You can obtain one at http://mozilla.org/MPL/2.0/.
6from ._pylib import ffi, lib
7from . import tile
8from cached_property import cached_property
9
10def find(path):
11 core = lib.mCoreFind(path.encode('UTF-8'))
12 if core == ffi.NULL:
13 return None
14 return Core._init(core)
15
16def findVF(vf):
17 core = lib.mCoreFindVF(vf.handle)
18 if core == ffi.NULL:
19 return None
20 return Core._init(core)
21
22def loadPath(path):
23 core = find(path)
24 if not core or not core.loadFile(path):
25 return None
26 return core
27
28def loadVF(vf):
29 core = findVF(vf)
30 if not core or not core.loadROM(vf):
31 return None
32 return core
33
34def needsReset(f):
35 def wrapper(self, *args, **kwargs):
36 if not self._wasReset:
37 raise RuntimeError("Core must be reset first")
38 return f(self, *args, **kwargs)
39 return wrapper
40
41class Core(object):
42 if hasattr(lib, 'PLATFORM_GBA'):
43 PLATFORM_GBA = lib.PLATFORM_GBA
44
45 if hasattr(lib, 'PLATFORM_GB'):
46 PLATFORM_GB = lib.PLATFORM_GB
47
48 def __init__(self, native):
49 self._core = native
50 self._wasReset = False
51
52 @cached_property
53 def tiles(self):
54 return tile.TileView(self)
55
56 @classmethod
57 def _init(cls, native):
58 core = ffi.gc(native, native.deinit)
59 success = bool(core.init(core))
60 if not success:
61 raise RuntimeError("Failed to initialize core")
62 if hasattr(cls, 'PLATFORM_GBA') and core.platform(core) == cls.PLATFORM_GBA:
63 from .gba import GBA
64 return GBA(core)
65 if hasattr(cls, 'PLATFORM_GB') and core.platform(core) == cls.PLATFORM_GB:
66 from .gb import GB
67 return GB(core)
68 return Core(core)
69
70 def _deinit(self):
71 self._core.deinit(self._core)
72
73 def loadFile(self, path):
74 return bool(lib.mCoreLoadFile(self._core, path.encode('UTF-8')))
75
76 def isROM(self, vf):
77 return bool(self._core.isROM(vf.handle))
78
79 def loadROM(self, vf):
80 return bool(self._core.loadROM(self._core, vf.handle))
81
82 def loadSave(self, vf):
83 return bool(self._core.loadSave(self._core, vf.handle))
84
85 def loadTemporarySave(self, vf):
86 return bool(self._core.loadTemporarySave(self._core, vf.handle))
87
88 def loadPatch(self, vf):
89 return bool(self._core.loadPatch(self._core, vf.handle))
90
91 def autoloadSave(self):
92 return bool(lib.mCoreAutoloadSave(self._core))
93
94 def autoloadPatch(self):
95 return bool(lib.mCoreAutoloadPatch(self._core))
96
97 def platform(self):
98 return self._core.platform(self._core)
99
100 def desiredVideoDimensions(self):
101 width = ffi.new("unsigned*")
102 height = ffi.new("unsigned*")
103 self._core.desiredVideoDimensions(self._core, width, height)
104 return width[0], height[0]
105
106 def setVideoBuffer(self, image):
107 self._core.setVideoBuffer(self._core, image.buffer, image.stride)
108
109 def reset(self):
110 self._core.reset(self._core)
111 self._wasReset = True
112
113 @needsReset
114 def runFrame(self):
115 self._core.runFrame(self._core)
116
117 @needsReset
118 def runLoop(self):
119 self._core.runLoop(self._core)
120
121 @needsReset
122 def step(self):
123 self._core.step(self._core)
124
125 @staticmethod
126 def _keysToInt(*args, **kwargs):
127 keys = 0
128 if 'raw' in kwargs:
129 keys = kwargs['raw']
130 for key in args:
131 keys |= 1 << key
132 return keys
133
134 def setKeys(self, *args, **kwargs):
135 self._core.setKeys(self._core, self._keysToInt(*args, **kwargs))
136
137 def addKeys(self, *args, **kwargs):
138 self._core.addKeys(self._core, self._keysToInt(*args, **kwargs))
139
140 def clearKeys(self, *args, **kwargs):
141 self._core.clearKeys(self._core, self._keysToInt(*args, **kwargs))
142
143 @needsReset
144 def frameCounter(self):
145 return self._core.frameCounter(self._core)
146
147 def frameCycles(self):
148 return self._core.frameCycles(self._core)
149
150 def frequency(self):
151 return self._core.frequency(self._core)
152
153 def getGameTitle(self):
154 title = ffi.new("char[16]")
155 self._core.getGameTitle(self._core, title)
156 return ffi.string(title, 16).decode("ascii")
157
158 def getGameCode(self):
159 code = ffi.new("char[12]")
160 self._core.getGameCode(self._core, code)
161 return ffi.string(code, 12).decode("ascii")