pyboy 2.2.2__tar.gz → 2.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyboy-2.2.2/pyboy.egg-info → pyboy-2.3.0}/PKG-INFO +1 -1
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/__main__.py +5 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/api/__init__.py +1 -0
- pyboy-2.3.0/pyboy/api/gameshark.pxd +24 -0
- pyboy-2.3.0/pyboy/api/gameshark.py +153 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/base_plugin.pxd +2 -1
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/base_plugin.py +11 -1
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/window_null.py +2 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/window_open_gl.pxd +0 -1
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/window_open_gl.py +1 -11
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/window_sdl2.pxd +0 -1
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/window_sdl2.py +0 -12
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/pyboy.pxd +2 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/pyboy.py +20 -6
- {pyboy-2.2.2 → pyboy-2.3.0/pyboy.egg-info}/PKG-INFO +1 -1
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy.egg-info/SOURCES.txt +2 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyproject.toml +1 -1
- {pyboy-2.2.2 → pyboy-2.3.0}/LICENSE.md +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/MANIFEST.in +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/README.md +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/__init__.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/api/constants.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/api/memory_scanner.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/api/memory_scanner.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/api/screen.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/api/screen.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/api/sprite.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/api/sprite.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/api/tile.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/api/tile.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/api/tilemap.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/api/tilemap.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/conftest.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/__init__.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/bootrom.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/bootrom.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/bootrom_cgb.bin +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/bootrom_dmg.bin +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/__init__.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/base_mbc.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/base_mbc.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/cartridge.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/cartridge.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/mbc1.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/mbc1.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/mbc2.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/mbc2.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/mbc3.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/mbc3.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/mbc5.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/mbc5.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/rtc.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/rtc.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cpu.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cpu.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/interaction.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/interaction.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/lcd.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/lcd.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/mb.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/mb.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/opcodes.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/opcodes.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/opcodes_gen.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/ram.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/ram.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/sound.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/sound.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/timer.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/timer.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/default_rom.gb +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/logging/__init__.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/logging/_logging.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/logging/logging.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/logging/logging.pyx +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/__init__.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/auto_pause.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/auto_pause.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/debug.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/debug.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/debug_prompt.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/debug_prompt.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/disable_input.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/disable_input.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/font.txt +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/game_wrapper_kirby_dream_land.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/game_wrapper_kirby_dream_land.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/game_wrapper_pokemon_gen1.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/game_wrapper_pokemon_gen1.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/game_wrapper_pokemon_pinball.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/game_wrapper_pokemon_pinball.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/game_wrapper_super_mario_land.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/game_wrapper_super_mario_land.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/game_wrapper_tetris.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/game_wrapper_tetris.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/manager.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/manager.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/manager_gen.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/record_replay.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/record_replay.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/rewind.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/rewind.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/screen_recorder.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/screen_recorder.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/screenshot_recorder.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/screenshot_recorder.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/window_null.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/utils.pxd +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/utils.py +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy.egg-info/dependency_links.txt +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy.egg-info/entry_points.txt +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy.egg-info/not-zip-safe +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy.egg-info/requires.txt +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/pyboy.egg-info/top_level.txt +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/setup.cfg +0 -0
- {pyboy-2.2.2 → pyboy-2.3.0}/setup.py +0 -0
|
@@ -87,6 +87,11 @@ parser.add_argument(
|
|
|
87
87
|
parser.add_argument("-s", "--scale", default=defaults["scale"], type=int, help="The scaling multiplier for the window")
|
|
88
88
|
parser.add_argument("--sound", action="store_true", help="Enable sound (beta)")
|
|
89
89
|
parser.add_argument("--no-renderer", action="store_true", help="Disable rendering (internal use)")
|
|
90
|
+
parser.add_argument(
|
|
91
|
+
"--gameshark",
|
|
92
|
+
type=str,
|
|
93
|
+
help="Add GameShark cheats on start-up. Add multiple by comma separation (i.e. '010138CD, 01033CD1')"
|
|
94
|
+
)
|
|
90
95
|
|
|
91
96
|
gameboy_type_parser = parser.add_mutually_exclusive_group()
|
|
92
97
|
gameboy_type_parser.add_argument(
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#
|
|
2
|
+
# License: See LICENSE.md file
|
|
3
|
+
# GitHub: https://github.com/Baekalfen/PyBoy
|
|
4
|
+
#
|
|
5
|
+
|
|
6
|
+
from libc.stdint cimport uint8_t
|
|
7
|
+
|
|
8
|
+
from pyboy.logging.logging cimport Logger
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
cdef Logger logger
|
|
12
|
+
|
|
13
|
+
cdef class GameShark:
|
|
14
|
+
cdef object memory
|
|
15
|
+
cdef dict cheats
|
|
16
|
+
cdef bint enabled
|
|
17
|
+
|
|
18
|
+
cdef uint8_t _get_value(self, int, int) noexcept
|
|
19
|
+
cdef void _set_value(self, int, int, int) noexcept
|
|
20
|
+
cdef tuple _convert_cheat(self, str code) noexcept
|
|
21
|
+
cpdef void add(self, str code) noexcept
|
|
22
|
+
cpdef void remove(self, str code, bint restore_value=*) noexcept
|
|
23
|
+
cpdef void clear_all(self, bint restore_value=*) noexcept
|
|
24
|
+
cdef void tick(self) noexcept
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
#
|
|
2
|
+
# License: See LICENSE.md file
|
|
3
|
+
# GitHub: https://github.com/Baekalfen/PyBoy
|
|
4
|
+
#
|
|
5
|
+
|
|
6
|
+
from pyboy.logging import get_logger
|
|
7
|
+
|
|
8
|
+
logger = get_logger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class GameShark:
|
|
12
|
+
def __init__(self, memory):
|
|
13
|
+
self.memory = memory
|
|
14
|
+
self.cheats = {}
|
|
15
|
+
self.enabled = False
|
|
16
|
+
|
|
17
|
+
def _convert_cheat(self, gameshark_code):
|
|
18
|
+
'''
|
|
19
|
+
A GameShark code for these consoles is written in the format ttvvaaaa. tt specifies the type, which is usually 01.
|
|
20
|
+
vv specifies the hexadecimal value the code will write into the game's memory. aaaa specifies the memory address
|
|
21
|
+
that will be modified, with the low byte first (e.g. address C056 is written as 56C0).
|
|
22
|
+
Example 011556C0 would output:
|
|
23
|
+
type = 01
|
|
24
|
+
value = 0x15
|
|
25
|
+
address = 0x56C0
|
|
26
|
+
|
|
27
|
+
For more details:
|
|
28
|
+
https://doc.kodewerx.org/hacking_gb.html
|
|
29
|
+
|
|
30
|
+
There seems to be conflicting information about the presence of other types than 01.
|
|
31
|
+
'''
|
|
32
|
+
# Check if the input cheat code has the correct length (8 characters)
|
|
33
|
+
if len(gameshark_code) != 8:
|
|
34
|
+
raise ValueError("Invalid cheat code length. Cheat code must be 8 characters long.")
|
|
35
|
+
|
|
36
|
+
# Extract components from the cheat code
|
|
37
|
+
_type = int(gameshark_code[:2], 16)
|
|
38
|
+
value = int(gameshark_code[2:4], 16) # Convert hexadecimal value to an integer
|
|
39
|
+
unconverted_address = gameshark_code[4:] # Ex: 1ED1
|
|
40
|
+
lower = unconverted_address[:2] # Ex: 1E
|
|
41
|
+
upper = unconverted_address[2:] # Ex: D1
|
|
42
|
+
address_converted = upper + lower # Ex: 0xD11E # Converting to Ram Readable address
|
|
43
|
+
address = int(address_converted, 16)
|
|
44
|
+
|
|
45
|
+
if not 0x8000 <= address:
|
|
46
|
+
raise ValueError("Invalid GameShark code provided. Address not in the RAM range")
|
|
47
|
+
|
|
48
|
+
return (_type, value, address)
|
|
49
|
+
|
|
50
|
+
def _get_value(self, _type, address):
|
|
51
|
+
if _type == 0x01:
|
|
52
|
+
# 8-bit RAM write
|
|
53
|
+
# Writes the byte xx to the address zzyy.
|
|
54
|
+
return self.memory[address]
|
|
55
|
+
# elif (_type & 0xF0) == 0x80:
|
|
56
|
+
# # 8-bit RAM write (with bank change)
|
|
57
|
+
# # Changes the RAM bank to b, then writes the byte xx to the address zzyy.
|
|
58
|
+
# bank = _type & 0xF
|
|
59
|
+
# pass
|
|
60
|
+
# elif (_type & 0xF0) == 0x90:
|
|
61
|
+
# # 8-bit RAM write (with WRAM bank change)
|
|
62
|
+
# # Changes the WRAM bank to b and then writes the byte xx to the address zzyy. GBC only.
|
|
63
|
+
# bank = _type & 0xF
|
|
64
|
+
# pass
|
|
65
|
+
else:
|
|
66
|
+
raise ValueError("Invalid GameShark type", _type)
|
|
67
|
+
|
|
68
|
+
def _set_value(self, _type, value, address):
|
|
69
|
+
if _type == 0x01:
|
|
70
|
+
# 8-bit RAM write
|
|
71
|
+
# Writes the byte xx to the address zzyy.
|
|
72
|
+
self.memory[address] = value
|
|
73
|
+
# elif (_type & 0xF0) == 0x80:
|
|
74
|
+
# # 8-bit RAM write (with bank change)
|
|
75
|
+
# # Changes the RAM bank to b, then writes the byte xx to the address zzyy.
|
|
76
|
+
# bank = _type & 0xF
|
|
77
|
+
# pass
|
|
78
|
+
# elif (_type & 0xF0) == 0x90:
|
|
79
|
+
# # 8-bit RAM write (with WRAM bank change)
|
|
80
|
+
# # Changes the WRAM bank to b and then writes the byte xx to the address zzyy. GBC only.
|
|
81
|
+
# bank = _type & 0xF
|
|
82
|
+
# pass
|
|
83
|
+
else:
|
|
84
|
+
raise ValueError("Invalid GameShark type", _type)
|
|
85
|
+
|
|
86
|
+
def add(self, code):
|
|
87
|
+
"""
|
|
88
|
+
Add a GameShark cheat to the emulator.
|
|
89
|
+
|
|
90
|
+
Example:
|
|
91
|
+
```python
|
|
92
|
+
>>> pyboy.gameshark.add("01FF16D0")
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
code (str): GameShark code to add
|
|
97
|
+
"""
|
|
98
|
+
self.enabled = True
|
|
99
|
+
_type, value, address = self._convert_cheat(code)
|
|
100
|
+
if code not in self.cheats:
|
|
101
|
+
self.cheats[code] = (self._get_value(_type, address), (_type, value, address))
|
|
102
|
+
else:
|
|
103
|
+
logger.error("GameShark code already applied!")
|
|
104
|
+
|
|
105
|
+
def remove(self, code, restore_value=True):
|
|
106
|
+
"""
|
|
107
|
+
Remove a GameShark cheat from the emulator.
|
|
108
|
+
|
|
109
|
+
Example:
|
|
110
|
+
```python
|
|
111
|
+
>>> pyboy.gameshark.add("01FF16D0")
|
|
112
|
+
>>> pyboy.gameshark.remove("01FF16D0")
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
code (str): GameShark code to remove
|
|
117
|
+
restore_value (bool): True to restore original value at address, otherwise don't restore
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
if not code in self.cheats:
|
|
121
|
+
raise ValueError("GameShark code cannot be removed. Hasn't been applied.")
|
|
122
|
+
|
|
123
|
+
original_value, (_type, _, address) = self.cheats.pop(code)
|
|
124
|
+
if restore_value:
|
|
125
|
+
self._set_value(_type, original_value, address)
|
|
126
|
+
|
|
127
|
+
if len(self.cheats) == 0:
|
|
128
|
+
self.enabled = False
|
|
129
|
+
|
|
130
|
+
def clear_all(self, restore_value=True):
|
|
131
|
+
"""
|
|
132
|
+
Remove all GameShark cheats from the emulator.
|
|
133
|
+
|
|
134
|
+
Example:
|
|
135
|
+
```python
|
|
136
|
+
>>> pyboy.gameshark.clear_all()
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
restore_value (bool): Restore the original values of the memory addresses that were modified by the cheats.
|
|
141
|
+
"""
|
|
142
|
+
# NOTE: Create a list so we don't remove from the iterator we are going through
|
|
143
|
+
for code in list(self.cheats.keys()):
|
|
144
|
+
self.remove(code, restore_value)
|
|
145
|
+
|
|
146
|
+
def tick(self):
|
|
147
|
+
if not self.enabled:
|
|
148
|
+
return
|
|
149
|
+
# https://gbdev.io/pandocs/Shark_Cheats.html
|
|
150
|
+
# "As far as it is understood, patching is implemented by hooking the original VBlank interrupt handler, and
|
|
151
|
+
# re-writing RAM values each frame."
|
|
152
|
+
for _, (_, (_type, value, address)) in self.cheats.items():
|
|
153
|
+
self._set_value(_type, value, address)
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
cimport cython
|
|
7
7
|
cimport numpy as cnp
|
|
8
8
|
from cpython.array cimport array
|
|
9
|
-
from libc.stdint cimport uint8_t, uint16_t, uint32_t
|
|
9
|
+
from libc.stdint cimport uint8_t, uint16_t, uint32_t, int64_t
|
|
10
10
|
|
|
11
11
|
from pyboy.core.lcd cimport Renderer
|
|
12
12
|
from pyboy.core.mb cimport Motherboard
|
|
@@ -38,6 +38,7 @@ cdef class PyBoyWindowPlugin(PyBoyPlugin):
|
|
|
38
38
|
cdef bint enable_title
|
|
39
39
|
cdef Renderer renderer
|
|
40
40
|
|
|
41
|
+
cdef int64_t _ftime
|
|
41
42
|
cdef bint frame_limiter(self, int) noexcept
|
|
42
43
|
cdef void set_title(self, str) noexcept
|
|
43
44
|
|
|
@@ -13,6 +13,7 @@ __pdoc__ = {
|
|
|
13
13
|
|
|
14
14
|
import io
|
|
15
15
|
import random
|
|
16
|
+
import time
|
|
16
17
|
from array import array
|
|
17
18
|
|
|
18
19
|
import numpy as np
|
|
@@ -65,6 +66,8 @@ class PyBoyWindowPlugin(PyBoyPlugin):
|
|
|
65
66
|
def __init__(self, pyboy, mb, pyboy_argv, *args, **kwargs):
|
|
66
67
|
super().__init__(pyboy, mb, pyboy_argv, *args, **kwargs)
|
|
67
68
|
|
|
69
|
+
self._ftime = time.perf_counter_ns()
|
|
70
|
+
|
|
68
71
|
if not self.enabled():
|
|
69
72
|
return
|
|
70
73
|
|
|
@@ -83,7 +86,14 @@ class PyBoyWindowPlugin(PyBoyPlugin):
|
|
|
83
86
|
self.renderer = self.mb.lcd.renderer
|
|
84
87
|
|
|
85
88
|
def frame_limiter(self, speed):
|
|
86
|
-
|
|
89
|
+
self._ftime += int((1.0 / (60.0*speed)) * 1_000_000_000)
|
|
90
|
+
now = time.perf_counter_ns()
|
|
91
|
+
if (self._ftime > now):
|
|
92
|
+
delay = (self._ftime - now) // 1_000_000
|
|
93
|
+
time.sleep(delay / 1000)
|
|
94
|
+
else:
|
|
95
|
+
self._ftime = now
|
|
96
|
+
return True
|
|
87
97
|
|
|
88
98
|
def set_title(self, title):
|
|
89
99
|
pass
|
|
@@ -22,6 +22,8 @@ class WindowNull(PyBoyWindowPlugin):
|
|
|
22
22
|
'Deprecated use of "headless" or "dummy" window. Change to "null" window instead. https://github.com/Baekalfen/PyBoy/wiki/Migrating-from-v1.x.x-to-v2.0.0'
|
|
23
23
|
)
|
|
24
24
|
|
|
25
|
+
pyboy.set_emulation_speed(0)
|
|
26
|
+
|
|
25
27
|
def enabled(self):
|
|
26
28
|
return self.pyboy_argv.get("window") in ["null", "headless", "dummy"]
|
|
27
29
|
|
|
@@ -50,7 +50,7 @@ class WindowOpenGL(PyBoyWindowPlugin):
|
|
|
50
50
|
glPixelZoom(self.scale, self.scale)
|
|
51
51
|
glutReshapeFunc(self._glreshape)
|
|
52
52
|
glutDisplayFunc(self._gldraw)
|
|
53
|
-
|
|
53
|
+
|
|
54
54
|
|
|
55
55
|
# Cython does not cooperate with lambdas
|
|
56
56
|
def _key(self, c, x, y):
|
|
@@ -139,16 +139,6 @@ class WindowOpenGL(PyBoyWindowPlugin):
|
|
|
139
139
|
glDrawPixels(COLS, ROWS, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, buf)
|
|
140
140
|
glFlush()
|
|
141
141
|
|
|
142
|
-
def frame_limiter(self, speed):
|
|
143
|
-
self._ftime += int((1.0 / (60.0*speed)) * 1_000_000_000)
|
|
144
|
-
now = time.perf_counter_ns()
|
|
145
|
-
if (self._ftime > now):
|
|
146
|
-
delay = (self._ftime - now) // 1_000_000
|
|
147
|
-
time.sleep(delay / 1000)
|
|
148
|
-
else:
|
|
149
|
-
self._ftime = now
|
|
150
|
-
return True
|
|
151
|
-
|
|
152
142
|
def enabled(self):
|
|
153
143
|
if self.pyboy_argv.get("window") == "OpenGL":
|
|
154
144
|
if opengl_enabled:
|
|
@@ -157,9 +157,7 @@ class WindowSDL2(PyBoyWindowPlugin):
|
|
|
157
157
|
|
|
158
158
|
if not self.enabled():
|
|
159
159
|
return
|
|
160
|
-
|
|
161
160
|
sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO | sdl2.SDL_INIT_GAMECONTROLLER)
|
|
162
|
-
self._ftime = time.perf_counter_ns()
|
|
163
161
|
|
|
164
162
|
self._window = sdl2.SDL_CreateWindow(
|
|
165
163
|
b"PyBoy", sdl2.SDL_WINDOWPOS_CENTERED, sdl2.SDL_WINDOWPOS_CENTERED, self._scaledresolution[0],
|
|
@@ -205,16 +203,6 @@ class WindowSDL2(PyBoyWindowPlugin):
|
|
|
205
203
|
else:
|
|
206
204
|
return False
|
|
207
205
|
|
|
208
|
-
def frame_limiter(self, speed):
|
|
209
|
-
self._ftime += int((1.0 / (60.0*speed)) * 1_000_000_000)
|
|
210
|
-
now = time.perf_counter_ns()
|
|
211
|
-
if (self._ftime > now):
|
|
212
|
-
delay = (self._ftime - now) // 1_000_000
|
|
213
|
-
sdl2.SDL_Delay(delay)
|
|
214
|
-
else:
|
|
215
|
-
self._ftime = now
|
|
216
|
-
return True
|
|
217
|
-
|
|
218
206
|
def stop(self):
|
|
219
207
|
sdl2.SDL_DestroyWindow(self._window)
|
|
220
208
|
for _ in range(10): # At least 2 to close
|
|
@@ -8,6 +8,7 @@ cimport cython
|
|
|
8
8
|
from libc cimport time
|
|
9
9
|
from libc.stdint cimport int64_t, uint64_t
|
|
10
10
|
|
|
11
|
+
from pyboy.api.gameshark cimport GameShark
|
|
11
12
|
from pyboy.api.memory_scanner cimport MemoryScanner
|
|
12
13
|
from pyboy.api.screen cimport Screen
|
|
13
14
|
from pyboy.api.tilemap cimport TileMap
|
|
@@ -59,6 +60,7 @@ cdef class PyBoy:
|
|
|
59
60
|
cdef readonly TileMap tilemap_window
|
|
60
61
|
cdef readonly object game_wrapper
|
|
61
62
|
cdef readonly MemoryScanner memory_scanner
|
|
63
|
+
cdef readonly GameShark gameshark
|
|
62
64
|
cdef readonly str cartridge_title
|
|
63
65
|
|
|
64
66
|
cdef bint limit_emulationspeed
|
|
@@ -13,6 +13,7 @@ import time
|
|
|
13
13
|
|
|
14
14
|
import numpy as np
|
|
15
15
|
|
|
16
|
+
from pyboy.api.gameshark import GameShark
|
|
16
17
|
from pyboy.api.memory_scanner import MemoryScanner
|
|
17
18
|
from pyboy.api.screen import Screen
|
|
18
19
|
from pyboy.api.tilemap import TileMap
|
|
@@ -50,6 +51,7 @@ class PyBoy:
|
|
|
50
51
|
sound=False,
|
|
51
52
|
sound_emulated=False,
|
|
52
53
|
cgb=None,
|
|
54
|
+
gameshark=None,
|
|
53
55
|
log_level=defaults["log_level"],
|
|
54
56
|
**kwargs
|
|
55
57
|
):
|
|
@@ -355,6 +357,21 @@ class PyBoy:
|
|
|
355
357
|
A game-specific wrapper object.
|
|
356
358
|
"""
|
|
357
359
|
|
|
360
|
+
self.gameshark = GameShark(self.memory)
|
|
361
|
+
"""
|
|
362
|
+
Provides an instance of the `pyboy.api.gameshark.GameShark` handler. This allows you to inject GameShark-based cheat codes.
|
|
363
|
+
|
|
364
|
+
Example:
|
|
365
|
+
```python
|
|
366
|
+
>>> pyboy.gameshark.add("010138CD")
|
|
367
|
+
>>> pyboy.gameshark.remove("010138CD")
|
|
368
|
+
>>> pyboy.gameshark.clear_all()
|
|
369
|
+
```
|
|
370
|
+
"""
|
|
371
|
+
if gameshark:
|
|
372
|
+
for code in gameshark.split(","):
|
|
373
|
+
self.gameshark.add(code.strip())
|
|
374
|
+
|
|
358
375
|
self.initialized = True
|
|
359
376
|
|
|
360
377
|
def _tick(self, render):
|
|
@@ -365,6 +382,7 @@ class PyBoy:
|
|
|
365
382
|
self._handle_events(self.events)
|
|
366
383
|
t_pre = time.perf_counter_ns()
|
|
367
384
|
if not self.paused:
|
|
385
|
+
self.gameshark.tick()
|
|
368
386
|
self.__rendering(render)
|
|
369
387
|
# Reenter mb.tick until we eventually get a clean exit without breakpoints
|
|
370
388
|
while self.mb.tick():
|
|
@@ -970,7 +988,8 @@ class PyBoy:
|
|
|
970
988
|
|
|
971
989
|
A `target_speed` of `0` means unlimited. I.e. fastest possible execution.
|
|
972
990
|
|
|
973
|
-
|
|
991
|
+
Due to backwards compatibility, the null window starts at unlimited speed (i.e. `target_speed=0`), while
|
|
992
|
+
others start at realtime (i.e. `target_speed=1`).
|
|
974
993
|
|
|
975
994
|
Example:
|
|
976
995
|
```python
|
|
@@ -984,11 +1003,6 @@ class PyBoy:
|
|
|
984
1003
|
Args:
|
|
985
1004
|
target_speed (int): Target emulation speed as multiplier of real-time.
|
|
986
1005
|
"""
|
|
987
|
-
if self.initialized and self._plugin_manager.window_null_enabled:
|
|
988
|
-
logger.warning(
|
|
989
|
-
'This window type does not support frame-limiting. `pyboy.set_emulation_speed(...)` will have no effect, as it\'s always running at full speed.'
|
|
990
|
-
)
|
|
991
|
-
|
|
992
1006
|
if target_speed > 5:
|
|
993
1007
|
logger.warning("The emulation speed might not be accurate when speed-target is higher than 5")
|
|
994
1008
|
self.target_emulationspeed = target_speed
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|