diff --git a/.gitignore b/.gitignore index 27541f05..ea5b23fc 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ *.core *.log .vscode -*.ogg \ No newline at end of file +*.ogg +community/logs diff --git a/community/controller.py b/community/controller.py index 7972e38c..c08d2d06 100644 --- a/community/controller.py +++ b/community/controller.py @@ -57,8 +57,13 @@ def misc(self, mode): elif mode == self.MiscMode.SAVE: self.game.world.save.save() elif mode == self.MiscMode.ESCAPE: - self.game.mouse_captured = False - self.game.set_exclusive_mouse(False) + self.game.window.mouse_captured = False + self.game.window.set_exclusive_mouse(False) + self.game.show_pause = True + self.end_move(self.MoveMode.RIGHT) + self.end_move(self.MoveMode.LEFT) + self.end_move(self.MoveMode.FORWARD) + self.end_move(self.MoveMode.BACKWARD) elif mode == self.MiscMode.SPEED_TIME: self.game.world.speed_daytime() elif mode == self.MiscMode.FULLSCREEN: @@ -116,9 +121,9 @@ def end_move(self, mode): self.update_move(axis) def start_modifier(self, mode): - if mode == self.ModifierMode.SPRINT: + if mode == self.ModifierMode.SPRINT and not self.game.show_pause: self.game.player.target_speed = player.SPRINTING_SPEED def end_modifier(self, mode): - if mode == self.ModifierMode.SPRINT: + if mode == self.ModifierMode.SPRINT and not self.game.show_pause: self.game.player.target_speed = player.WALKING_SPEED \ No newline at end of file diff --git a/community/gamemain.py b/community/gamemain.py new file mode 100644 index 00000000..9b5a15f5 --- /dev/null +++ b/community/gamemain.py @@ -0,0 +1,312 @@ +import platform +import ctypes +import logging +import random +import time +import os + +import pyglet +from scene import Scene +from gui import GuiButton + +pyglet.options["shadow_window"] = False +pyglet.options["debug_gl"] = False +pyglet.options["search_local_libs"] = True +pyglet.options["audio"] = ("openal", "pulse", "directsound", "xaudio2", "silent") + +import pyglet.gl as gl +import shader +import player +import texture_manager + +import world + +import options +import time + +import joystick +import keyboard_mouse +from collections import deque + +class GameMain(Scene): + def __init__(self, window): + super(GameMain, self).__init__(window, texture=None, color='#000000') + + self.config = gl.Config(double_buffer = True, + major_version = 3, minor_version = 3, + depth_size = 16, sample_buffers=bool(options.ANTIALIASING), samples=options.ANTIALIASING) + + # Options + self.options = window.options + + if self.options.INDIRECT_RENDERING and not gl.gl_info.have_version(4, 2): + raise RuntimeError("""Indirect Rendering is not supported on your hardware + This feature is only supported on OpenGL 4.2+, but your driver doesnt seem to support it, + Please disable "INDIRECT_RENDERING" in options.py""") + + # Pause menu + self.show_pause = False + self.back_to_game = GuiButton(self.on_back_to_game, self.window, self.window.width/2, self.window.height/2+35, 'Back to game') + self.save_game = GuiButton(self.on_save_game, self.window, self.window.width/2, self.window.height/2, 'Save and quit to title') + + # F3 Debug Screen + + self.show_f3 = False + self.f3 = pyglet.text.Label("", x = 10, y = self.height - 10, + font_size = 16, + color = (255, 255, 255, 255), + width = self.width // 3, + multiline = True + ) + self.system_info = f"""Python: {platform.python_implementation()} {platform.python_version()} +System: {platform.machine()} {platform.system()} {platform.release()} {platform.version()} +CPU: {platform.processor()} +Display: {gl.gl_info.get_renderer()} +{gl.gl_info.get_version()}""" + + logging.info(f"System Info: {self.system_info}") + # create shader + + logging.info("Compiling Shaders") + if not self.options.COLORED_LIGHTING: + self.shader = shader.Shader("shaders/alpha_lighting/vert.glsl", "shaders/alpha_lighting/frag.glsl") + else: + self.shader = shader.Shader("shaders/colored_lighting/vert.glsl", "shaders/colored_lighting/frag.glsl") + self.shader_sampler_location = self.shader.find_uniform(b"u_TextureArraySampler") + self.shader.use() + + # create textures + logging.info("Creating Texture Array") + self.texture_manager = texture_manager.TextureManager(16, 16, 256) + + # create world + + self.world = world.World(self.shader, None, self.texture_manager, self.options) + + # player stuff + + logging.info("Setting up player & camera") + self.player = player.Player(self.world, self.shader, self.width, self.height) + self.world.player = self.player + + # pyglet stuff + pyglet.clock.schedule(self.player.update_interpolation) + pyglet.clock.schedule_interval(self.update, 1 / 600) + self.window.mouse_captured = False + + # misc stuff + + self.holding = 50 + + # bind textures + + gl.glActiveTexture(gl.GL_TEXTURE0) + gl.glBindTexture(gl.GL_TEXTURE_2D_ARRAY, self.world.texture_manager.texture_array) + gl.glUniform1i(self.shader_sampler_location, 0) + + # enable cool stuff + + gl.glEnable(gl.GL_DEPTH_TEST) + gl.glEnable(gl.GL_CULL_FACE) + gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) + + if self.options.ANTIALIASING: + gl.glEnable(gl.GL_MULTISAMPLE) + gl.glEnable(gl.GL_SAMPLE_ALPHA_TO_COVERAGE) + gl.glSampleCoverage(0.5, gl.GL_TRUE) + + # controls stuff + self.controls = [0, 0, 0] + + # joystick stuff + self.joystick_controller = joystick.Joystick_controller(self) + + # mouse and keyboard stuff + self.keyboard_mouse = keyboard_mouse.Keyboard_Mouse(self) + + # music stuff + logging.info("Loading audio") + try: + self.music = [pyglet.media.load(os.path.join("audio/music", file)) for file in os.listdir("audio/music") if os.path.isfile(os.path.join("audio/music", file))] + except: + self.music = [] + + self.media_player = pyglet.media.Player() + self.media_player.volume = 0.5 + + if len(self.music) > 0: + self.media_player.queue(random.choice(self.music)) + self.media_player.play() + self.media_player.standby = False + else: + self.media_player.standby = True + + self.media_player.next_time = 0 + + # GPU command syncs + self.fences = deque() + + def on_save_game(self): + self.window.mouse_captured = False + self.window.set_exclusive_mouse(False) + self.show_pause = True + self.media_player.delete() + for fence in self.fences: + gl.glDeleteSync(fence) + self.world.save.save() + self.window.show_menu() + + def on_back_to_game(self): + self.window.mouse_captured = True + self.window.set_exclusive_mouse(True) + self.show_pause = False + + def toggle_fullscreen(self): + self.window.set_fullscreen(not self.window.fullscreen) + + def on_close(self): + logging.info("Deleting media player") + self.media_player.delete() + for fence in self.fences: + gl.glDeleteSync(fence) + + pyglet.app.exit() + + def update_f3(self, delta_time): + """Update the F3 debug screen content""" + + player_chunk_pos = world.get_chunk_position(self.player.position) + player_local_pos = world.get_local_position(self.player.position) + chunk_count = len(self.world.chunks) + visible_chunk_count = len(self.world.visible_chunks) + quad_count = sum(chunk.mesh_quad_count for chunk in self.world.chunks.values()) + visible_quad_count = sum(chunk.mesh_quad_count for chunk in self.world.visible_chunks) + self.f3.text = \ +f""" +{round(pyglet.clock.get_fps())} FPS ({self.world.chunk_update_counter} Chunk Updates) {"inf" if not self.options.VSYNC else "vsync"}{"ao" if self.options.SMOOTH_LIGHTING else ""} +C: {visible_chunk_count} / {chunk_count} pC: {self.world.pending_chunk_update_count} pU: {len(self.world.chunk_building_queue)} aB: {chunk_count} +Client Singleplayer @{round(delta_time * 1000)} ms tick {round(1 / delta_time)} TPS + +XYZ: ( X: {round(self.player.position[0], 3)} / Y: {round(self.player.position[1], 3)} / Z: {round(self.player.position[2], 3)} ) +Block: {self.player.rounded_position[0]} {self.player.rounded_position[1]} {self.player.rounded_position[2]} +Chunk: {player_local_pos[0]} {player_local_pos[1]} {player_local_pos[2]} in {player_chunk_pos[0]} {player_chunk_pos[1]} {player_chunk_pos[2]} +Light: {max(self.world.get_light(self.player.rounded_position), self.world.get_skylight(self.player.rounded_position))} ({self.world.get_skylight(self.player.rounded_position)} sky, {self.world.get_light(self.player.rounded_position)} block) + +{self.system_info} + +Renderer: {"OpenGL 3.3 VAOs" if not self.options.INDIRECT_RENDERING else "OpenGL 4.0 VAOs Indirect"} {"Conditional" if self.options.ADVANCED_OPENGL else ""} +Buffers: {chunk_count} +Vertex Data: {round(quad_count * 28 * ctypes.sizeof(gl.GLfloat) / 1048576, 3)} MiB ({quad_count} Quads) +Visible Quads: {visible_quad_count} +Buffer Uploading: Direct (glBufferSubData) +""" + + def update(self, delta_time): + """Every tick""" + + if self.show_f3: + self.update_f3(delta_time) + + if not self.media_player.source and len(self.music) > 0: + if not self.media_player.standby: + self.media_player.standby = True + self.media_player.next_time = time.time() + random.randint(240, 360) + elif time.time() >= self.media_player.next_time: + self.media_player.standby = False + self.media_player.queue(random.choice(self.music)) + self.media_player.play() + + if not self.window.mouse_captured: + self.player.input = [0, 0, 0] + + self.joystick_controller.update_controller() + self.player.update(delta_time) + + self.world.tick(delta_time) + + def on_draw(self): + gl.glEnable(gl.GL_DEPTH_TEST) + self.shader.use() + self.player.update_matrices() + + while len(self.fences) > self.options.MAX_CPU_AHEAD_FRAMES: + fence = self.fences.popleft() + gl.glClientWaitSync(fence, gl.GL_SYNC_FLUSH_COMMANDS_BIT, 2147483647) + gl.glDeleteSync(fence) + + self.window.clear() + self.world.prepare_rendering() + self.world.draw() + + # Draw the F3 Debug screen + if self.show_f3: + self.draw_f3() + + # Draw pause menu + if self.show_pause: + self.draw_pause() + + # CPU - GPU Sync + if not self.options.SMOOTH_FPS: + self.fences.append(gl.glFenceSync(gl.GL_SYNC_GPU_COMMANDS_COMPLETE, 0)) + else: + gl.glFinish() + + def draw_pause(self): + """Draws the pause screen. Current uses the fixed-function pipeline since pyglet labels uses it""" + gl.glDisable(gl.GL_DEPTH_TEST) + gl.glUseProgram(0) + gl.glBindVertexArray(0) + gl.glMatrixMode(gl.GL_MODELVIEW) + gl.glPushMatrix() + gl.glLoadIdentity() + + gl.glMatrixMode(gl.GL_PROJECTION) + gl.glPushMatrix() + gl.glLoadIdentity() + gl.glOrtho(0, self.width, 0, self.height, -1, 1) + + self.back_to_game.draw() + self.save_game.draw() + + gl.glPopMatrix() + + gl.glMatrixMode(gl.GL_MODELVIEW) + gl.glPopMatrix() + + def draw_f3(self): + """Draws the f3 debug screen. Current uses the fixed-function pipeline since pyglet labels uses it""" + gl.glDisable(gl.GL_DEPTH_TEST) + gl.glUseProgram(0) + gl.glBindVertexArray(0) + gl.glMatrixMode(gl.GL_MODELVIEW) + gl.glPushMatrix() + gl.glLoadIdentity() + + gl.glMatrixMode(gl.GL_PROJECTION) + gl.glPushMatrix() + gl.glLoadIdentity() + gl.glOrtho(0, self.width, 0, self.height, -1, 1) + + self.f3.draw() + + gl.glPopMatrix() + + gl.glMatrixMode(gl.GL_MODELVIEW) + gl.glPopMatrix() + + + # input functions + + def on_resize(self, width, height): + super(GameMain, self).on_resize(width, height) + logging.info(f"Resize {width} * {height}") + gl.glViewport(0, 0, width, height) + + self.player.view_width = width + self.player.view_height = height + self.f3.y = self.height - 10 + self.f3.width = self.width // 3 + + self.back_to_game = GuiButton(self.on_back_to_game, self.window, self.window.width/2, self.window.height/2+25, 'Back to game') + self.save_game = GuiButton(self.on_back_to_game, self.window, self.window.width/2, self.window.height/2, 'Save and quit to title') \ No newline at end of file diff --git a/community/gui.py b/community/gui.py new file mode 100644 index 00000000..9e5ccbf4 --- /dev/null +++ b/community/gui.py @@ -0,0 +1,62 @@ +import pyglet + +class GuiButton(): + def __init__(self, on_click_func, window, x, y, text, locked=False): + self.locked = locked + self.func = on_click_func + self.window = window + self.text = text + self.hovered=False + + self.button_texture = pyglet.image.load('textures/button.png') + self.button_texture_hover = pyglet.image.load('textures/button_hover.png') + self.button_texture_locked = pyglet.image.load('textures/button_locked.png') + + H_ratio = 1.5 + W_ratio = 1.2 + + self.font_size = self.button_texture.height/2 + self.x = x-self.button_texture.width/2 + self.y = y-self.button_texture.height/2 + + self.button_sprite = pyglet.sprite.Sprite(self.button_texture, x=self.x, y=self.y) + self.button_sprite.scale_x = W_ratio + self.button_sprite.scale_y = H_ratio + self.font_size = self.button_sprite.height/2 + self.x = x-self.button_sprite.width/2 + self.y = y-self.button_sprite.height/2 + self.button_sprite.x = self.x + self.button_sprite.y = self.y + + self.button_sprite_hover = pyglet.sprite.Sprite(self.button_texture_hover, x=self.x, y=self.y) + self.button_sprite_hover.scale_x = W_ratio + self.button_sprite_hover.scale_y = H_ratio + + self.button_sprite_locked = pyglet.sprite.Sprite(self.button_texture_locked, x=self.x, y=self.y) + self.button_sprite_locked.scale_x = W_ratio + self.button_sprite_locked.scale_y = H_ratio + + self.button_text = pyglet.text.Label(text, font_size=self.font_size, font_name=('Verdana', 'Calibri', 'Arial'), x=self.button_sprite.x+self.button_sprite.width/2, y=(self.button_sprite.y+self.button_sprite.height/2)-self.font_size/2, multiline=False, width=self.button_sprite.width, height=self.button_sprite.height, color=(255, 255, 255, 255), anchor_x='center') + + def draw(self): + if not self.locked: + if self.hovered: + self.button_sprite_hover.draw() + else: + self.button_sprite.draw() + else: + self.button_sprite_locked.draw() + self.button_text.draw() + + def on_mouse_press(self, x, y, button, modifiers): + if not self.locked: + if x > self.button_sprite.x and x < (self.button_sprite.x + self.button_sprite.width): + if y > self.button_sprite.y and y < (self.button_sprite.y + self.button_sprite.height): + self.func() + + def on_mouse_motion(self, x, y, delta_x, delta_y): + if not self.locked: + self.hovered = False + if x > self.button_sprite.x and x < (self.button_sprite.x + self.button_sprite.width): + if y > self.button_sprite.y and y < (self.button_sprite.y + self.button_sprite.height): + self.hovered = True \ No newline at end of file diff --git a/community/joystick.py b/community/joystick.py index 455b136a..76057c45 100644 --- a/community/joystick.py +++ b/community/joystick.py @@ -41,7 +41,7 @@ def init_joysticks(self, joysticks): joystick.open(exclusive=True) def update_controller(self): - if not self.game.mouse_captured or not self.joysticks: + if not self.game.window.mouse_captured or not self.joysticks: return self.game.player.rotation[0] += self.joystick_look[0] * self.camera_sensitivity diff --git a/community/keyboard_mouse.py b/community/keyboard_mouse.py index c1146707..de078c99 100644 --- a/community/keyboard_mouse.py +++ b/community/keyboard_mouse.py @@ -15,60 +15,67 @@ def __init__(self, game): self.game.on_key_release = self.on_key_release def on_mouse_press(self, x, y, button, modifiers): - if not self.game.mouse_captured: - self.game.mouse_captured = True - self.game.set_exclusive_mouse(True) + if not self.game.window.mouse_captured and not self.game.show_pause: + self.game.window.mouse_captured = True + self.game.window.set_exclusive_mouse(True) + self.game.show_pause = False return - - if button == pyglet.window.mouse.RIGHT: self.interact(self.InteractMode.PLACE) - elif button == pyglet.window.mouse.LEFT: self.interact(self.InteractMode.BREAK) - elif button == pyglet.window.mouse.MIDDLE: self.interact(self.InteractMode.PICK) + elif self.game.show_pause: + self.game.back_to_game.on_mouse_press(x, y, button, modifiers) + self.game.save_game.on_mouse_press(x, y, button, modifiers) + else: + if button == pyglet.window.mouse.RIGHT: self.interact(self.InteractMode.PLACE) + elif button == pyglet.window.mouse.LEFT: self.interact(self.InteractMode.BREAK) + elif button == pyglet.window.mouse.MIDDLE: self.interact(self.InteractMode.PICK) def on_mouse_motion(self, x, y, delta_x, delta_y): - if self.game.mouse_captured: + if self.game.window.mouse_captured and not self.game.show_pause: sensitivity = 0.004 self.game.player.rotation[0] += delta_x * sensitivity self.game.player.rotation[1] += delta_y * sensitivity self.game.player.rotation[1] = max(-math.tau / 4, min(math.tau / 4, self.game.player.rotation[1])) + elif self.game.show_pause: + self.game.back_to_game.on_mouse_motion(x, y, delta_x, delta_y) + self.game.save_game.on_mouse_motion(x, y, delta_x, delta_y) def on_mouse_drag(self, x, y, delta_x, delta_y, buttons, modifiers): self.on_mouse_motion(x, y, delta_x, delta_y) def on_key_press(self, key, modifiers): - if not self.game.mouse_captured: + if not self.game.window.mouse_captured and not self.game.show_pause: return - - if key == pyglet.window.key.D: self.start_move(self.MoveMode.RIGHT) - elif key == pyglet.window.key.A: self.start_move(self.MoveMode.LEFT) - elif key == pyglet.window.key.W: self.start_move(self.MoveMode.FORWARD) - elif key == pyglet.window.key.S: self.start_move(self.MoveMode.BACKWARD) - elif key == pyglet.window.key.SPACE : self.start_move(self.MoveMode.UP) - elif key == pyglet.window.key.LSHIFT: self.start_move(self.MoveMode.DOWN) - - elif key == pyglet.window.key.LCTRL : self.start_modifier(self.ModifierMode.SPRINT) - - elif key == pyglet.window.key.F: self.misc(self.MiscMode.FLY) - elif key == pyglet.window.key.G: self.misc(self.MiscMode.RANDOM) - elif key == pyglet.window.key.O: self.misc(self.MiscMode.SAVE) - elif key == pyglet.window.key.R: self.misc(self.MiscMode.TELEPORT) - elif key == pyglet.window.key.ESCAPE: self.misc(self.MiscMode.ESCAPE) - elif key == pyglet.window.key.F6: self.misc(self.MiscMode.SPEED_TIME) - elif key == pyglet.window.key.F11: self.misc(self.MiscMode.FULLSCREEN) - elif key == pyglet.window.key.F3: self.misc(self.MiscMode.TOGGLE_F3) - elif key == pyglet.window.key.F10: self.misc(self.MiscMode.TOGGLE_AO) + else: + if key == pyglet.window.key.D: self.start_move(self.MoveMode.RIGHT) + elif key == pyglet.window.key.A: self.start_move(self.MoveMode.LEFT) + elif key == pyglet.window.key.W: self.start_move(self.MoveMode.FORWARD) + elif key == pyglet.window.key.S: self.start_move(self.MoveMode.BACKWARD) + elif key == pyglet.window.key.SPACE : self.start_move(self.MoveMode.UP) + elif key == pyglet.window.key.LSHIFT: self.start_move(self.MoveMode.DOWN) + + elif key == pyglet.window.key.LCTRL : self.start_modifier(self.ModifierMode.SPRINT) + + elif key == pyglet.window.key.F: self.misc(self.MiscMode.FLY) + elif key == pyglet.window.key.G: self.misc(self.MiscMode.RANDOM) + elif key == pyglet.window.key.O: self.misc(self.MiscMode.SAVE) + elif key == pyglet.window.key.R: self.misc(self.MiscMode.TELEPORT) + elif key == pyglet.window.key.ESCAPE: self.misc(self.MiscMode.ESCAPE) + elif key == pyglet.window.key.F6: self.misc(self.MiscMode.SPEED_TIME) + elif key == pyglet.window.key.F11: self.misc(self.MiscMode.FULLSCREEN) + elif key == pyglet.window.key.F3: self.misc(self.MiscMode.TOGGLE_F3) + elif key == pyglet.window.key.F10: self.misc(self.MiscMode.TOGGLE_AO) def on_key_release(self, key, modifiers): - if not self.game.mouse_captured: + if not self.game.window.mouse_captured and not self.game.show_pause: return - - if key == pyglet.window.key.D: self.end_move(self.MoveMode.RIGHT) - elif key == pyglet.window.key.A: self.end_move(self.MoveMode.LEFT) - elif key == pyglet.window.key.W: self.end_move(self.MoveMode.FORWARD) - elif key == pyglet.window.key.S: self.end_move(self.MoveMode.BACKWARD) - elif key == pyglet.window.key.SPACE : self.end_move(self.MoveMode.UP) - elif key == pyglet.window.key.LSHIFT: self.end_move(self.MoveMode.DOWN) - - elif key == pyglet.window.key.LCTRL : self.end_modifier(self.ModifierMode.SPRINT) \ No newline at end of file + else: + if key == pyglet.window.key.D: self.end_move(self.MoveMode.RIGHT) + elif key == pyglet.window.key.A: self.end_move(self.MoveMode.LEFT) + elif key == pyglet.window.key.W: self.end_move(self.MoveMode.FORWARD) + elif key == pyglet.window.key.S: self.end_move(self.MoveMode.BACKWARD) + elif key == pyglet.window.key.SPACE : self.end_move(self.MoveMode.UP) + elif key == pyglet.window.key.LSHIFT: self.end_move(self.MoveMode.DOWN) + + elif key == pyglet.window.key.LCTRL : self.end_modifier(self.ModifierMode.SPRINT) \ No newline at end of file diff --git a/community/main.py b/community/main.py index 40743f3e..cf9f91a9 100644 --- a/community/main.py +++ b/community/main.py @@ -1,30 +1,30 @@ -import platform -import ctypes -import logging -import random -import time -import os - +from re import I, S import pyglet +from scene import Scene +from scene import __WIDTH__ +from scene import __HEIGHT__ +from scene import convert_hashColor_to_RGBA +from time import time, sleep +from gamemain import GameMain +from gui import GuiButton +import options +import os +import logging -pyglet.options["shadow_window"] = False -pyglet.options["debug_gl"] = False -pyglet.options["search_local_libs"] = True -pyglet.options["audio"] = ("openal", "pulse", "directsound", "xaudio2", "silent") +def init_logger(): + log_folder = "logs/" + log_filename = f"{time()}.logs" + log_path = os.path.join(log_folder, log_filename) -import pyglet.gl as gl -import shader -import player -import texture_manager + if not os.path.isdir(log_folder): + os.mkdir(log_folder) -import world + with open(log_path, 'x') as file: + file.write("[LOGS]\n") -import options -import time + logging.basicConfig(level=logging.INFO, filename=log_path, + format="[%(asctime)s] [%(processName)s/%(threadName)s/%(levelname)s] (%(module)s.py/%(funcName)s) %(message)s") -import joystick -import keyboard_mouse -from collections import deque class InternalConfig: def __init__(self, options): @@ -42,268 +42,128 @@ def __init__(self, options): self.COLORED_LIGHTING = options.COLORED_LIGHTING self.ANTIALIASING = options.ANTIALIASING +class IntroScreen(Scene): + def __init__(self, window): + super(IntroScreen, self).__init__(window, texture=None, color='#FFFFFF') -class Window(pyglet.window.Window): - def __init__(self, **args): - super().__init__(**args) + self.intro_text = pyglet.text.Label('Probably can\'t show the', font_size=40, font_name=('Verdana', 'Calibri', 'Arial'), x=self.window.width/2, y=self.window.height/2, multiline=False, width=self.window.width, height=self.window.height, color=(255, 165, 0, 255), anchor_x='center') + self.has_been_visible_since = time() - # Options - self.options = InternalConfig(options) - - if self.options.INDIRECT_RENDERING and not gl.gl_info.have_version(4, 2): - raise RuntimeError("""Indirect Rendering is not supported on your hardware - This feature is only supported on OpenGL 4.2+, but your driver doesnt seem to support it, - Please disable "INDIRECT_RENDERING" in options.py""") - - # F3 Debug Screen - - self.show_f3 = False - self.f3 = pyglet.text.Label("", x = 10, y = self.height - 10, - font_size = 16, - color = (255, 255, 255, 255), - width = self.width // 3, - multiline = True - ) - self.system_info = f"""Python: {platform.python_implementation()} {platform.python_version()} -System: {platform.machine()} {platform.system()} {platform.release()} {platform.version()} -CPU: {platform.processor()} -Display: {gl.gl_info.get_renderer()} -{gl.gl_info.get_version()}""" - - logging.info(f"System Info: {self.system_info}") - # create shader - - logging.info("Compiling Shaders") - if not self.options.COLORED_LIGHTING: - self.shader = shader.Shader("shaders/alpha_lighting/vert.glsl", "shaders/alpha_lighting/frag.glsl") - else: - self.shader = shader.Shader("shaders/colored_lighting/vert.glsl", "shaders/colored_lighting/frag.glsl") - self.shader_sampler_location = self.shader.find_uniform(b"u_TextureArraySampler") - self.shader.use() - - # create textures - logging.info("Creating Texture Array") - self.texture_manager = texture_manager.TextureManager(16, 16, 256) - - # create world - - self.world = world.World(self.shader, None, self.texture_manager, self.options) - - # player stuff - - logging.info("Setting up player & camera") - self.player = player.Player(self.world, self.shader, self.width, self.height) - self.world.player = self.player - - # pyglet stuff - pyglet.clock.schedule(self.player.update_interpolation) - pyglet.clock.schedule_interval(self.update, 1 / 60) - self.mouse_captured = False - - # misc stuff - - self.holding = 50 - - # bind textures - - gl.glActiveTexture(gl.GL_TEXTURE0) - gl.glBindTexture(gl.GL_TEXTURE_2D_ARRAY, self.world.texture_manager.texture_array) - gl.glUniform1i(self.shader_sampler_location, 0) + def on_draw(self): + self.draw() + self.intro_text.draw() + if time() - 2 > self.has_been_visible_since: + self.intro_text.text = 'Mojang Logo due to copyright.' + +class MenuScreen(Scene): + def __init__(self, window): + image = pyglet.image.load("textures/dirt.png").get_texture() + self.window = window + image.height = self.window.height + image.width = self.window.width + + super(MenuScreen, self).__init__(window, texture=image, color='#000000') + + image = pyglet.image.load("textures/logo.png") + self.logo = pyglet.sprite.Sprite(image, x=0, y=0) + H_ratio = 1.5 + W_ratio = 1.2 + self.logo.scale_x = W_ratio + self.logo.scale_y = H_ratio + self.logo.x = (self.window.width/2)-self.logo.width/2 + self.logo.y = self.window.height-100 + + self.singleplayer = GuiButton(self.on_singleplayer, self.window, self.window.width/2, self.window.height/2+35, 'Singleplayer') + self.multiplayer = GuiButton(None, self.window, self.window.width/2, self.window.height/2, 'Multiplayer', locked=True) + self.options = GuiButton(None, self.window, self.window.width/2, self.window.height/2-35, 'Options', locked=True) + + def on_singleplayer(self): + self.window.set_scene(GameMain(self.window)) + + def on_mouse_press(self, x, y, button, modifiers): + self.singleplayer.on_mouse_press(x, y, button, modifiers) + self.multiplayer.on_mouse_press(x, y, button, modifiers) + self.options.on_mouse_press(x, y, button, modifiers) + + def on_mouse_motion(self, x, y, delta_x, delta_y): + self.singleplayer.on_mouse_motion(x, y, delta_x, delta_y) + self.multiplayer.on_mouse_motion(x, y, delta_x, delta_y) + self.options.on_mouse_motion(x, y, delta_x, delta_y) - # enable cool stuff + def on_draw(self): + self.draw() + self.logo.draw() + self.singleplayer.draw() + self.multiplayer.draw() + self.options.draw() - gl.glEnable(gl.GL_DEPTH_TEST) - gl.glEnable(gl.GL_CULL_FACE) - gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) +class Window(pyglet.window.Window): + def __init__(self, refreshrate, **args): + super().__init__(**args) + self.refreshrate = refreshrate - if self.options.ANTIALIASING: - gl.glEnable(gl.GL_MULTISAMPLE) - gl.glEnable(gl.GL_SAMPLE_ALPHA_TO_COVERAGE) - gl.glSampleCoverage(0.5, gl.GL_TRUE) - - # controls stuff - self.controls = [0, 0, 0] - - # joystick stuff - self.joystick_controller = joystick.Joystick_controller(self) - - # mouse and keyboard stuff - self.keyboard_mouse = keyboard_mouse.Keyboard_Mouse(self) - - # music stuff - logging.info("Loading audio") - try: - self.music = [pyglet.media.load(os.path.join("audio/music", file)) for file in os.listdir("audio/music") if os.path.isfile(os.path.join("audio/music", file))] - except: - self.music = [] - - self.media_player = pyglet.media.Player() - self.media_player.volume = 0.5 + # Options + self.options = InternalConfig(options) - if len(self.music) > 0: - self.media_player.queue(random.choice(self.music)) - self.media_player.play() - self.media_player.standby = False - else: - self.media_player.standby = True + self.alive = 1 - self.media_player.next_time = 0 + self.currentScreen = IntroScreen(self) + self.screen_has_been_shown_since = time() + self.not_first = 0 - # GPU command syncs - self.fences = deque() - - def toggle_fullscreen(self): - self.set_fullscreen(not self.fullscreen) + def show_menu(self): + self.currentScreen = MenuScreen(self) - def on_close(self): - logging.info("Deleting media player") - self.media_player.delete() - for fence in self.fences: - gl.glDeleteSync(fence) - - pyglet.app.exit() - - def update_f3(self, delta_time): - """Update the F3 debug screen content""" - - player_chunk_pos = world.get_chunk_position(self.player.position) - player_local_pos = world.get_local_position(self.player.position) - chunk_count = len(self.world.chunks) - visible_chunk_count = len(self.world.visible_chunks) - quad_count = sum(chunk.mesh_quad_count for chunk in self.world.chunks.values()) - visible_quad_count = sum(chunk.mesh_quad_count for chunk in self.world.visible_chunks) - self.f3.text = \ -f""" -{round(pyglet.clock.get_fps())} FPS ({self.world.chunk_update_counter} Chunk Updates) {"inf" if not self.options.VSYNC else "vsync"}{"ao" if self.options.SMOOTH_LIGHTING else ""} -C: {visible_chunk_count} / {chunk_count} pC: {self.world.pending_chunk_update_count} pU: {len(self.world.chunk_building_queue)} aB: {chunk_count} -Client Singleplayer @{round(delta_time * 1000)} ms tick {round(1 / delta_time)} TPS - -XYZ: ( X: {round(self.player.position[0], 3)} / Y: {round(self.player.position[1], 3)} / Z: {round(self.player.position[2], 3)} ) -Block: {self.player.rounded_position[0]} {self.player.rounded_position[1]} {self.player.rounded_position[2]} -Chunk: {player_local_pos[0]} {player_local_pos[1]} {player_local_pos[2]} in {player_chunk_pos[0]} {player_chunk_pos[1]} {player_chunk_pos[2]} -Light: {max(self.world.get_light(self.player.rounded_position), self.world.get_skylight(self.player.rounded_position))} ({self.world.get_skylight(self.player.rounded_position)} sky, {self.world.get_light(self.player.rounded_position)} block) - -{self.system_info} - -Renderer: {"OpenGL 3.3 VAOs" if not self.options.INDIRECT_RENDERING else "OpenGL 4.0 VAOs Indirect"} {"Conditional" if self.options.ADVANCED_OPENGL else ""} -Buffers: {chunk_count} -Vertex Data: {round(quad_count * 28 * ctypes.sizeof(gl.GLfloat) / 1048576, 3)} MiB ({quad_count} Quads) -Visible Quads: {visible_quad_count} -Buffer Uploading: Direct (glBufferSubData) -""" - - def update(self, delta_time): - """Every tick""" - if self.show_f3: - self.update_f3(delta_time) - - if not self.media_player.source and len(self.music) > 0: - if not self.media_player.standby: - self.media_player.standby = True - self.media_player.next_time = time.time() + random.randint(240, 360) - elif time.time() >= self.media_player.next_time: - self.media_player.standby = False - self.media_player.queue(random.choice(self.music)) - self.media_player.play() - - if not self.mouse_captured: - self.player.input = [0, 0, 0] - - self.joystick_controller.update_controller() - self.player.update(delta_time) - - self.world.tick(delta_time) + def set_scene(self, scene): + self.currentScreen = scene def on_draw(self): - gl.glEnable(gl.GL_DEPTH_TEST) - self.shader.use() - self.player.update_matrices() - - while len(self.fences) > self.options.MAX_CPU_AHEAD_FRAMES: - fence = self.fences.popleft() - gl.glClientWaitSync(fence, gl.GL_SYNC_FLUSH_COMMANDS_BIT, 2147483647) - gl.glDeleteSync(fence) - - self.clear() - self.world.prepare_rendering() - self.world.draw() - - # Draw the F3 Debug screen - if self.show_f3: - self.draw_f3() - - # CPU - GPU Sync - if not self.options.SMOOTH_FPS: - self.fences.append(gl.glFenceSync(gl.GL_SYNC_GPU_COMMANDS_COMPLETE, 0)) - else: - gl.glFinish() - - def draw_f3(self): - """Draws the f3 debug screen. Current uses the fixed-function pipeline since pyglet labels uses it""" - gl.glDisable(gl.GL_DEPTH_TEST) - gl.glUseProgram(0) - gl.glBindVertexArray(0) - gl.glMatrixMode(gl.GL_MODELVIEW) - gl.glPushMatrix() - gl.glLoadIdentity() - - gl.glMatrixMode(gl.GL_PROJECTION) - gl.glPushMatrix() - gl.glLoadIdentity() - gl.glOrtho(0, self.width, 0, self.height, -1, 1) - - self.f3.draw() + self.render() - gl.glPopMatrix() + def on_key_press(self, symbol, mod): + self.currentScreen.on_key_press(symbol, mod) - gl.glMatrixMode(gl.GL_MODELVIEW) - gl.glPopMatrix() + def on_key_release(self, key, modifiers): + self.currentScreen.on_key_release(key, modifiers) + def on_mouse_motion(self, x, y, delta_x, delta_y): + self.currentScreen.on_mouse_motion(x, y, delta_x, delta_y) - # input functions + def on_mouse_drag(self, x, y, delta_x, delta_y, buttons, modifiers): + self.currentScreen.on_mouse_drag(x, y, delta_x, delta_y, buttons, modifiers) - def on_resize(self, width, height): - logging.info(f"Resize {width} * {height}") - gl.glViewport(0, 0, width, height) + def on_mouse_press(self, x, y, button, modifiers): + self.currentScreen.on_mouse_press(x, y, button, modifiers) - self.player.view_width = width - self.player.view_height = height - self.f3.y = self.height - 10 - self.f3.width = self.width // 3 -class Game: - def __init__(self): - self.config = gl.Config(double_buffer = True, - major_version = 3, minor_version = 3, - depth_size = 16, sample_buffers=bool(options.ANTIALIASING), samples=options.ANTIALIASING) - self.window = Window(config = self.config, width = 852, height = 480, caption = "Minecraft clone", resizable = True, vsync = options.VSYNC) - - def run(self): - pyglet.app.run() - - - -def init_logger(): - log_folder = "logs/" - log_filename = f"{time.time()}.log" - log_path = os.path.join(log_folder, log_filename) - - if not os.path.isdir(log_folder): - os.mkdir(log_folder) + def render(self): + self.clear() - with open(log_path, 'x') as file: - file.write("[LOGS]\n") + if time() - 5 > self.screen_has_been_shown_since and type(self.currentScreen) is not MenuScreen and type(self.currentScreen) is not GameMain: + self.currentScreen = MenuScreen(self) - logging.basicConfig(level=logging.INFO, filename=log_path, - format="[%(asctime)s] [%(processName)s/%(threadName)s/%(levelname)s] (%(module)s.py/%(funcName)s) %(message)s") + self.currentScreen.on_draw() + self.flip() + def on_close(self): + self.currentScreen.on_close() + self.alive = 0 + # def on_resize(self, width, height): + # if self.not_first > 5: + # print("s") + # self.not_first = 0 + # self.currentScreen.on_resize(width, height) + # self.not_first += 1 + def run(self): + while self.alive: + self.render() + self.dispatch_events() + pyglet.clock.tick() -def main(): - init_logger() - game = Game() - game.run() if __name__ == "__main__": - main() + init_logger() + win = Window(900, width = __WIDTH__, height = __HEIGHT__, caption = "Minecraft clone", resizable = True, vsync = options.VSYNC) + win.run() \ No newline at end of file diff --git a/community/save/0/1r/c.0.-1.dat b/community/save/0/1r/c.0.-1.dat index a1e4b255..3e945b60 100644 Binary files a/community/save/0/1r/c.0.-1.dat and b/community/save/0/1r/c.0.-1.dat differ diff --git a/community/save/1/1r/c.1.-1.dat b/community/save/1/1r/c.1.-1.dat index 84fe36b0..7c13f2b4 100644 Binary files a/community/save/1/1r/c.1.-1.dat and b/community/save/1/1r/c.1.-1.dat differ diff --git a/community/save/2/2/c.2.2.dat b/community/save/2/2/c.2.2.dat index 8bc0fc85..63ce93b7 100644 Binary files a/community/save/2/2/c.2.2.dat and b/community/save/2/2/c.2.2.dat differ diff --git a/community/scene.py b/community/scene.py new file mode 100644 index 00000000..f7e5b543 --- /dev/null +++ b/community/scene.py @@ -0,0 +1,61 @@ +import pyglet + +__WIDTH__ = 852 +__HEIGHT__ = 480 + +def convert_hashColor_to_RGBA(color): + if '#' in color: + c = color.lstrip("#") + c = max(6-len(c),0)*"0" + c + r = int(c[:2], 16) + g = int(c[2:4], 16) + b = int(c[4:], 16) + color = (r,g,b,255) + return color + +class Scene(pyglet.sprite.Sprite): + def __init__(self, window, texture=None, color="#000000"): + self.window = window + width = window.width + height = window.height + x = width/2 + y = height/2 + if texture is None: + self.texture = pyglet.image.SolidColorImagePattern(convert_hashColor_to_RGBA(color)).create_image(width,height) + else: + self.texture = texture + super(Scene, self).__init__(self.texture) + + self.image.anchor_x = self.image.width / 2 + self.image.anchor_y = self.image.height / 2 + self.x = x + self.y = y + + def on_draw(self): + self.draw() + + def on_close(self): + pass + + def on_key_press(self, symbol, mod): + pass + + def on_key_release(self, key, modifiers): + pass + + def on_mouse_motion(self, x, y, delta_x, delta_y): + pass + + def on_mouse_drag(self, x, y, delta_x, delta_y, buttons, modifiers): + pass + + def on_mouse_press(self, x, y, button, modifiers): + pass + + def on_resize(self, width, height): + self.image.width = width + self.image.height = height + self.image.anchor_x = self.image.width / 2 + self.image.anchor_y = self.image.height / 2 + self.x = width/2 + self.y = height/2 \ No newline at end of file diff --git a/community/textures/button.png b/community/textures/button.png new file mode 100644 index 00000000..f46300c9 Binary files /dev/null and b/community/textures/button.png differ diff --git a/community/textures/button_hover.png b/community/textures/button_hover.png new file mode 100644 index 00000000..8cb9fb77 Binary files /dev/null and b/community/textures/button_hover.png differ diff --git a/community/textures/button_locked.png b/community/textures/button_locked.png new file mode 100644 index 00000000..f2016b14 Binary files /dev/null and b/community/textures/button_locked.png differ diff --git a/community/textures/logo.png b/community/textures/logo.png new file mode 100644 index 00000000..41cd6e68 Binary files /dev/null and b/community/textures/logo.png differ