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.
Files changed (116) hide show
  1. {pyboy-2.2.2/pyboy.egg-info → pyboy-2.3.0}/PKG-INFO +1 -1
  2. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/__main__.py +5 -0
  3. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/api/__init__.py +1 -0
  4. pyboy-2.3.0/pyboy/api/gameshark.pxd +24 -0
  5. pyboy-2.3.0/pyboy/api/gameshark.py +153 -0
  6. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/base_plugin.pxd +2 -1
  7. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/base_plugin.py +11 -1
  8. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/window_null.py +2 -0
  9. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/window_open_gl.pxd +0 -1
  10. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/window_open_gl.py +1 -11
  11. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/window_sdl2.pxd +0 -1
  12. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/window_sdl2.py +0 -12
  13. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/pyboy.pxd +2 -0
  14. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/pyboy.py +20 -6
  15. {pyboy-2.2.2 → pyboy-2.3.0/pyboy.egg-info}/PKG-INFO +1 -1
  16. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy.egg-info/SOURCES.txt +2 -0
  17. {pyboy-2.2.2 → pyboy-2.3.0}/pyproject.toml +1 -1
  18. {pyboy-2.2.2 → pyboy-2.3.0}/LICENSE.md +0 -0
  19. {pyboy-2.2.2 → pyboy-2.3.0}/MANIFEST.in +0 -0
  20. {pyboy-2.2.2 → pyboy-2.3.0}/README.md +0 -0
  21. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/__init__.py +0 -0
  22. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/api/constants.py +0 -0
  23. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/api/memory_scanner.pxd +0 -0
  24. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/api/memory_scanner.py +0 -0
  25. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/api/screen.pxd +0 -0
  26. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/api/screen.py +0 -0
  27. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/api/sprite.pxd +0 -0
  28. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/api/sprite.py +0 -0
  29. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/api/tile.pxd +0 -0
  30. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/api/tile.py +0 -0
  31. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/api/tilemap.pxd +0 -0
  32. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/api/tilemap.py +0 -0
  33. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/conftest.py +0 -0
  34. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/__init__.py +0 -0
  35. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/bootrom.pxd +0 -0
  36. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/bootrom.py +0 -0
  37. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/bootrom_cgb.bin +0 -0
  38. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/bootrom_dmg.bin +0 -0
  39. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/__init__.py +0 -0
  40. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/base_mbc.pxd +0 -0
  41. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/base_mbc.py +0 -0
  42. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/cartridge.pxd +0 -0
  43. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/cartridge.py +0 -0
  44. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/mbc1.pxd +0 -0
  45. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/mbc1.py +0 -0
  46. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/mbc2.pxd +0 -0
  47. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/mbc2.py +0 -0
  48. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/mbc3.pxd +0 -0
  49. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/mbc3.py +0 -0
  50. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/mbc5.pxd +0 -0
  51. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/mbc5.py +0 -0
  52. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/rtc.pxd +0 -0
  53. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cartridge/rtc.py +0 -0
  54. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cpu.pxd +0 -0
  55. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/cpu.py +0 -0
  56. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/interaction.pxd +0 -0
  57. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/interaction.py +0 -0
  58. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/lcd.pxd +0 -0
  59. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/lcd.py +0 -0
  60. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/mb.pxd +0 -0
  61. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/mb.py +0 -0
  62. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/opcodes.pxd +0 -0
  63. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/opcodes.py +0 -0
  64. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/opcodes_gen.py +0 -0
  65. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/ram.pxd +0 -0
  66. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/ram.py +0 -0
  67. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/sound.pxd +0 -0
  68. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/sound.py +0 -0
  69. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/timer.pxd +0 -0
  70. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/core/timer.py +0 -0
  71. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/default_rom.gb +0 -0
  72. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/logging/__init__.py +0 -0
  73. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/logging/_logging.py +0 -0
  74. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/logging/logging.pxd +0 -0
  75. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/logging/logging.pyx +0 -0
  76. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/__init__.py +0 -0
  77. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/auto_pause.pxd +0 -0
  78. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/auto_pause.py +0 -0
  79. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/debug.pxd +0 -0
  80. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/debug.py +0 -0
  81. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/debug_prompt.pxd +0 -0
  82. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/debug_prompt.py +0 -0
  83. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/disable_input.pxd +0 -0
  84. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/disable_input.py +0 -0
  85. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/font.txt +0 -0
  86. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/game_wrapper_kirby_dream_land.pxd +0 -0
  87. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/game_wrapper_kirby_dream_land.py +0 -0
  88. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/game_wrapper_pokemon_gen1.pxd +0 -0
  89. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/game_wrapper_pokemon_gen1.py +0 -0
  90. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/game_wrapper_pokemon_pinball.pxd +0 -0
  91. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/game_wrapper_pokemon_pinball.py +0 -0
  92. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/game_wrapper_super_mario_land.pxd +0 -0
  93. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/game_wrapper_super_mario_land.py +0 -0
  94. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/game_wrapper_tetris.pxd +0 -0
  95. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/game_wrapper_tetris.py +0 -0
  96. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/manager.pxd +0 -0
  97. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/manager.py +0 -0
  98. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/manager_gen.py +0 -0
  99. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/record_replay.pxd +0 -0
  100. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/record_replay.py +0 -0
  101. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/rewind.pxd +0 -0
  102. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/rewind.py +0 -0
  103. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/screen_recorder.pxd +0 -0
  104. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/screen_recorder.py +0 -0
  105. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/screenshot_recorder.pxd +0 -0
  106. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/screenshot_recorder.py +0 -0
  107. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/plugins/window_null.pxd +0 -0
  108. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/utils.pxd +0 -0
  109. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy/utils.py +0 -0
  110. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy.egg-info/dependency_links.txt +0 -0
  111. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy.egg-info/entry_points.txt +0 -0
  112. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy.egg-info/not-zip-safe +0 -0
  113. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy.egg-info/requires.txt +0 -0
  114. {pyboy-2.2.2 → pyboy-2.3.0}/pyboy.egg-info/top_level.txt +0 -0
  115. {pyboy-2.2.2 → pyboy-2.3.0}/setup.cfg +0 -0
  116. {pyboy-2.2.2 → pyboy-2.3.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyboy
3
- Version: 2.2.2
3
+ Version: 2.3.0
4
4
  Summary: Game Boy emulator written in Python
5
5
  Author-email: Mads Ynddal <mads@ynddal.dk>
6
6
  License: GNU Lesser General Public License
@@ -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(
@@ -7,6 +7,7 @@ Tools to help interfacing with the Game Boy hardware
7
7
  """
8
8
 
9
9
  from . import constants
10
+ from .gameshark import GameShark
10
11
  from .screen import Screen
11
12
  from .sprite import Sprite
12
13
  from .tile import Tile
@@ -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
- return False
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
 
@@ -22,7 +22,6 @@ cdef int ROWS, COLS
22
22
  cdef class WindowOpenGL(PyBoyWindowPlugin):
23
23
  cdef list events
24
24
 
25
- cdef int64_t _ftime
26
25
  cdef void _glkeyboard(self, str, int, int, bint) noexcept
27
26
  cdef void _glkeyboardspecial(self, char, int, int, bint) noexcept
28
27
 
@@ -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
- self._ftime = time.perf_counter_ns()
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:
@@ -25,7 +25,6 @@ cpdef list sdl2_event_pump(list) noexcept
25
25
 
26
26
  cdef class WindowSDL2(PyBoyWindowPlugin):
27
27
 
28
- cdef int64_t _ftime
29
28
  cdef dict _key_down
30
29
  cdef dict _key_up
31
30
  cdef bint fullscreen
@@ -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
- Some window types do not implement a frame-limiter, and will always run at full speed.
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyboy
3
- Version: 2.2.2
3
+ Version: 2.3.0
4
4
  Summary: Game Boy emulator written in Python
5
5
  Author-email: Mads Ynddal <mads@ynddal.dk>
6
6
  License: GNU Lesser General Public License
@@ -20,6 +20,8 @@ pyboy.egg-info/requires.txt
20
20
  pyboy.egg-info/top_level.txt
21
21
  pyboy/api/__init__.py
22
22
  pyboy/api/constants.py
23
+ pyboy/api/gameshark.pxd
24
+ pyboy/api/gameshark.py
23
25
  pyboy/api/memory_scanner.pxd
24
26
  pyboy/api/memory_scanner.py
25
27
  pyboy/api/screen.pxd
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "pyboy"
3
- version = "2.2.2"
3
+ version = "2.3.0"
4
4
  authors = [
5
5
  {name = "Mads Ynddal", email = "mads@ynddal.dk"}
6
6
  ]
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