Skip to content

Commit edff4c4

Browse files
0.0.23a_01
1 parent ba8df99 commit edff4c4

33 files changed

+665
-236
lines changed

README.md

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
_**Minecraft: Python Edition**_ is a project that strives to recreate each and every old Minecraft version in Python 3 using the **Pyglet** multimedia library and **Cython** for performance.
66

7-
This project is currently recreating the **Multiplayer Classic** versions of Minecraft. The latest version is **Classic 0.0.22a_05** as released on _**June 29, 2009**_.
7+
This project is currently recreating the **Multiplayer Classic** versions of Minecraft. The latest version is **Classic 0.0.23a_01** as released on _**July 11, 2009**_.
88

9-
Learn more about this version [here](https://minecraft.fandom.com/wiki/Java_Edition_Classic_0.0.22a_05).
9+
Learn more about this version [here](https://minecraft.fandom.com/wiki/Java_Edition_Classic_0.0.23a_01).
1010

1111
Or the server version [here](https://minecraft.fandom.com/wiki/Java_Edition_Classic_server_1.8.2).
1212

@@ -22,7 +22,7 @@ you can play it just by specifying the Minecraft version you want to play in the
2222
This version features block sounds and music, and for audio to work you need either *PyOgg* which is recommended, or FFmpeg which is installed on the system.
2323
GStreamer is also supported on Linux through the *gst-python* library. PyOgg requires that your system have one of the *Opus*, *FLAC*, or *Vorbis* codecs. OpenAL is required.
2424

25-
To easily install this version of *Minecraft: Python Edition*, just run `python -m pip install minecraft-python==0.0.22a_05`.
25+
To easily install this version of *Minecraft: Python Edition*, just run `python -m pip install minecraft-python==0.0.23a_01`.
2626

2727
Alternatively, for a manual Cython build, run `python setup.py build_ext --inplace`.
2828

@@ -32,12 +32,9 @@ Run with the argument `-fullscreen` to open the window in fullscreen mode.
3232

3333
### Gameplay
3434

35-
This version features multiplayer, chat, caves, beaches, hill terrain, infinite liquid tiles, level saving, and human mobs.
35+
This version features multiplayer, chat, caves, beaches, hill terrain, infinite liquid tiles, level saving, options, and human mobs.
3636

37-
Press *B* to open the inventory menu. Press *Enter* to set your spawn position, *R* to teleport to your spawn position,
38-
*Y* to invert the mouse, *G* to spawn a mob, *F* to toggle render distance, and *M* to mute audio.
39-
40-
*Minecraft: Python Edition* should be compatible with any platform that supports OpenGL, modern Python 3, and Cython.
37+
Press *B* to open the inventory menu, *G* to spawn a human mob. Press *Esc* to pause and see other controls.
4138

4239
### Multiplayer
4340

mc/Resources.py

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

mc/net/minecraft/KeyBinding.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class KeyBinding:
2+
3+
def __init__(self, name, key):
4+
self.name = name
5+
self.key = key

mc/net/minecraft/Minecraft.py

Lines changed: 94 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
pyglet.options['audio'] = ('openal', 'silent')
44

55
from mc.net.minecraft.Timer import Timer
6+
from mc.net.minecraft.Options import Options
67
from mc.net.minecraft.HitResult import HitResult
78
from mc.net.minecraft.ProgressListener import ProgressListener
89
from mc.net.minecraft.level.tile.Tile import Tile
@@ -53,7 +54,7 @@
5354
GL_DEBUG = False
5455

5556
class Minecraft(window.Window):
56-
VERSION_STRING = '0.0.22a_05'
57+
VERSION_STRING = '0.0.23a_01'
5758
__timer = Timer(20.0)
5859
level = None
5960
levelRenderer = None
@@ -64,7 +65,6 @@ class Minecraft(window.Window):
6465
minecraftUri = ''
6566

6667
__active = False
67-
yMouseAxis = 1
6868
editMode = 0
6969
guiScreen = None
7070

@@ -91,6 +91,7 @@ class Minecraft(window.Window):
9191
__prevFrameTime = 0
9292

9393
hitResult = None
94+
options = None
9495

9596
__title = ''
9697
__text = ''
@@ -177,25 +178,24 @@ def on_mouse_press(self, x, y, button, modifiers):
177178
if compat_platform != 'darwin':
178179
return
179180

180-
if not self.guiScreen or (self.guiScreen and self.guiScreen.allowUserInput):
181-
if not self.guiScreen:
182-
if not self.mouseGrabbed:
183-
self.grabMouse()
184-
elif button == window.mouse.LEFT:
185-
self.__clickMouse()
186-
self.__prevFrameTime = self.__ticksRan
187-
elif button == window.mouse.RIGHT:
188-
self.editMode = (self.editMode + 1) % 2
189-
elif button == window.mouse.MIDDLE and self.hitResult:
190-
tile = self.level.getTile(self.hitResult.x, self.hitResult.y, self.hitResult.z)
191-
if tile == tiles.grass.id:
192-
tile = tiles.dirt.id
193-
194-
slot = self.player.inventory.getSlotContainsID(tile)
195-
if slot >= 0:
196-
self.player.inventory.selectedSlot = slot
197-
elif tile > 0 and tiles.tiles[tile] in User.creativeTiles:
198-
self.player.inventory.getSlotContainsTile(tiles.tiles[tile])
181+
if not self.guiScreen:
182+
if not self.mouseGrabbed:
183+
self.grabMouse()
184+
elif button == window.mouse.LEFT:
185+
self.__clickMouse()
186+
self.__prevFrameTime = self.__ticksRan
187+
elif button == window.mouse.RIGHT:
188+
self.editMode = (self.editMode + 1) % 2
189+
elif button == window.mouse.MIDDLE and self.hitResult:
190+
tile = self.level.getTile(self.hitResult.x, self.hitResult.y, self.hitResult.z)
191+
if tile == tiles.grass.id:
192+
tile = tiles.dirt.id
193+
194+
slot = self.player.inventory.containsTileAt(tile)
195+
if slot >= 0:
196+
self.player.inventory.selectedSlot = slot
197+
elif tile > 0 and tiles.tiles[tile] in User.creativeTiles:
198+
self.player.inventory.setTile(tiles.tiles[tile])
199199
except Exception as e:
200200
print(traceback.format_exc())
201201
self.setScreen(ErrorScreen('Client error', 'The game broke! [' + str(e) + ']'))
@@ -214,7 +214,11 @@ def on_mouse_motion(self, x, y, dx, dy):
214214
self.mouseY = y
215215
if self.mouseGrabbed:
216216
xo = dx
217-
yo = dy * self.yMouseAxis
217+
if self.options.invertMouse:
218+
yo = dy * -1
219+
else:
220+
yo = dy
221+
218222
self.player.turn(xo, yo)
219223
except Exception as e:
220224
print(traceback.format_exc())
@@ -231,35 +235,31 @@ def on_key_press(self, symbol, modifiers):
231235
return
232236

233237
if not self.guiScreen or (self.guiScreen and self.guiScreen.allowUserInput):
234-
self.player.setKey(symbol, True)
235-
236-
if not self.guiScreen:
237-
if symbol == window.key.ESCAPE:
238-
self.pauseGame()
239-
elif symbol == window.key.R:
240-
self.player.resetPos()
241-
elif symbol == window.key.M:
242-
self.soundPlayer.enabled = not self.soundPlayer.enabled
243-
elif symbol == window.key.RETURN:
244-
self.level.setSpawnPos(int(self.player.x), int(self.player.y), int(self.player.z), self.player.yRot)
245-
self.player.resetPos()
246-
elif symbol == window.key.G and self.connectionManager is None and len(self.level.entities) < 256:
247-
self.level.entities.add(Zombie(self.level, self.player.x, self.player.y, self.player.z))
248-
elif symbol == window.key.B:
249-
self.setScreen(InventoryScreen())
250-
elif symbol == window.key.T and self.connectionManager and self.connectionManager.isConnected():
251-
self.player.releaseAllKeys()
252-
self.setScreen(ChatScreen())
253-
254-
for i in range(9):
255-
if symbol == getattr(window.key, '_' + str(i + 1)):
256-
self.player.inventory.selectedSlot = i
257-
258-
if symbol == window.key.Y:
259-
self.yMouseAxis = -self.yMouseAxis
260-
elif symbol == window.key.F:
238+
if symbol != self.options.toggleFog.key:
239+
self.player.setKey(symbol, True)
240+
241+
if not self.guiScreen:
242+
if symbol == window.key.ESCAPE:
243+
self.pauseGame()
244+
elif symbol == self.options.load.key:
245+
self.player.resetPos()
246+
elif symbol == self.options.save.key:
247+
self.level.setSpawnPos(int(self.player.x), int(self.player.y), int(self.player.z), self.player.yRot)
248+
self.player.resetPos()
249+
elif symbol == window.key.G and self.connectionManager is None and len(self.level.entities) < 256:
250+
self.level.entities.add(Zombie(self.level, self.player.x, self.player.y, self.player.z))
251+
elif symbol == self.options.build.key:
252+
self.setScreen(InventoryScreen())
253+
elif symbol == self.options.chat.key and self.connectionManager and self.connectionManager.isConnected():
254+
self.player.releaseAllKeys()
255+
self.setScreen(ChatScreen())
256+
257+
for i in range(9):
258+
if symbol == getattr(window.key, '_' + str(i + 1)):
259+
self.player.inventory.selectedSlot = i
260+
else:
261261
z15 = modifiers & window.key.MOD_SHIFT
262-
self.levelRenderer.drawDistance = self.levelRenderer.drawDistance + (-1 if z15 else 1) & 3
262+
self.options.setOption(4, -1 if z15 else 1)
263263
except Exception as e:
264264
print(traceback.format_exc())
265265
self.setScreen(ErrorScreen('Client error', 'The game broke! [' + str(e) + ']'))
@@ -338,9 +338,14 @@ def on_draw(self):
338338
self.__displayActive = self.__active
339339

340340
if not self.hideGui:
341+
screenWidth = self.width * 240 // self.height
342+
screenHeight = self.height * 240 // self.height
343+
xMouse = self.mouseX * screenWidth // self.width
344+
yMouse = screenHeight - self.mouseY * screenHeight // self.height - 1
345+
341346
if self.level:
342347
self.__render(self.__timer.a)
343-
self.hud.render()
348+
self.hud.render(self.guiScreen is not None, xMouse, yMouse)
344349
self.__checkGlError('Rendered gui')
345350
else:
346351
#gl.glViewport(0, 0, self.width, self.height)
@@ -353,10 +358,6 @@ def on_draw(self):
353358
self.renderHelper.initGui()
354359

355360
if self.guiScreen:
356-
screenWidth = self.width * 240 // self.height
357-
screenHeight = self.height * 240 // self.height
358-
xMouse = self.mouseX * screenWidth // self.width
359-
yMouse = screenHeight - self.mouseY * screenHeight // self.height - 1
360361
self.guiScreen.render(xMouse, yMouse)
361362

362363
self.__checkGlError('Post render')
@@ -425,12 +426,12 @@ def run(self):
425426
success = self.loadLevel(self.loadMapUser, self.loadMapId)
426427
else:
427428
level = self.levelIo.load(self.level, gzip.open('level.dat', 'rb'))
428-
success = level != None
429+
success = level is not None
429430
if not success:
430431
level = self.levelIo.loadLegacy(self.level, gzip.open('level.dat', 'rb'))
431-
success = level != None
432-
433-
self.setLevel(level)
432+
success = level is not None
433+
else:
434+
self.setLevel(level)
434435
except Exception as e:
435436
print(traceback.format_exc())
436437
success = False
@@ -440,16 +441,38 @@ def run(self):
440441

441442
self.levelRenderer = LevelRenderer(self.textures)
442443
self.particleEngine = ParticleEngine(self.level, self.textures)
443-
self.player = Player(self.level, MovementInputFromOptions())
444+
445+
name = 'minecraft'
446+
home = os.path.expanduser('~') or '.'
447+
if 'unix' in sys.platform or 'linux' in sys.platform or \
448+
'solaris' in sys.platform or 'sunos' in sys.platform:
449+
file = os.path.join(home, '.' + name)
450+
elif 'win' in sys.platform:
451+
if 'APPDATA' in os.environ:
452+
file = os.path.join(os.environ['APPDATA'], '.' + name)
453+
else:
454+
file = os.path.join(home, '.' + name)
455+
elif 'mac' in sys.platform or 'darwin' in sys.platform:
456+
file = os.path.join(home, 'Library', 'Application Support', name)
457+
else:
458+
file = os.path.join(home, name)
459+
460+
if not os.path.isdir(file):
461+
os.mkdir(file)
462+
463+
if not os.path.isdir(file):
464+
raise RuntimeError(f'The working directory could not be created: {file}')
465+
466+
self.options = Options(self, file)
467+
self.player = Player(self.level, MovementInputFromOptions(self.options))
444468
self.player.resetPos()
445469
if self.level:
446470
self.setLevel(self.level)
447471

448472
try:
449-
self.soundPlayer = SoundPlayer()
473+
self.soundPlayer = SoundPlayer(self.options)
450474
self.soundPlayer.player = media.Player()
451475
self.soundPlayer.listener = media.get_audio_driver().get_listener()
452-
self.soundPlayer.entity = self.player
453476
except:
454477
print(traceback.format_exc())
455478

@@ -540,9 +563,12 @@ def __clickMouse(self):
540563

541564
def __tick(self):
542565
if self.soundPlayer:
543-
if getMillis() > self.soundManager.lastMusic and \
544-
self.soundManager.playMusic(self.soundPlayer, 'calm'):
545-
self.soundManager.lastMusic = getMillis() + math.floor(self.soundManager.random.random() * 900000) + 300000
566+
if self.options.music:
567+
if getMillis() > self.soundManager.lastMusic and \
568+
self.soundManager.playMusic(self.soundPlayer, 'calm'):
569+
self.soundManager.lastMusic = getMillis() + math.floor(self.soundManager.random.random() * 900000) + 300000
570+
else:
571+
self.soundManager.stopMusic()
546572

547573
for message in self.hud.messages.copy():
548574
message.counter += 1
@@ -642,7 +668,7 @@ def __pick(self, a):
642668
def __render(self, a):
643669
#gl.glViewport(0, 0, self.width, self.height)
644670

645-
f4 = pow(1.0 / (4 - self.levelRenderer.drawDistance), 0.25)
671+
f4 = pow(1.0 / (4 - self.options.renderDistance), 0.25)
646672
self.renderHelper.fogColorRed = 0.6 * (1.0 - f4) + f4
647673
self.renderHelper.fogColorGreen = 0.8 * (1.0 - f4) + f4
648674
self.renderHelper.fogColorBlue = 1.0 * (1.0 - f4) + f4
@@ -663,12 +689,11 @@ def __render(self, a):
663689

664690
gl.glClearColor(self.renderHelper.fogColorRed, self.renderHelper.fogColorGreen, self.renderHelper.fogColorBlue, 0.0)
665691
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
666-
self.__checkGlError('Set viewport')
667692

668693
self.__pick(a)
669694

670695
self.renderHelper.fogColorMultiplier = 1.0
671-
self.renderHelper.renderDistance = float(512 >> (self.levelRenderer.drawDistance << 1))
696+
self.renderHelper.renderDistance = float(512 >> (self.options.renderDistance << 1))
672697
self.__setupCamera(a)
673698

674699
gl.glEnable(gl.GL_CULL_FACE)
@@ -790,7 +815,7 @@ def setLevel(self, level):
790815
elif arg == '-mppass':
791816
mpPass = sys.argv[i + 1]
792817

793-
game = Minecraft(fullScreen, width=854, height=480, caption='Minecraft 0.0.22a_05')
818+
game = Minecraft(fullScreen, width=854, height=480, caption='Minecraft 0.0.23a_01')
794819
game.user = User(name, 0, mpPass)
795820
if server and port:
796821
game.setServer(server, int(port))

0 commit comments

Comments
 (0)