Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import pygame
- from pygame.locals import *
- from OpenGL.GL import *
- from OpenGL.GLU import *
- import numpy as np
- import random
- import os
- import pickle
- import time
- from collections import OrderedDict
- import zipfile
- import io
- import json
- import shutil
- import math
- import noise
- import traceback
- pygame.init()
- pygame.font.init()
- info = pygame.display.Info() # Pobieranie informacji o ekranie
- screen_width = info.current_w # Szerokość ekranu
- screen_height = info.current_h # Wysokość ekranu
- display = (screen_width, screen_height) # Ustawienie rozdzielczości okna gry na rozdzielczość ekranu
- print(f"Gra uruchomiona w {screen_width}x{screen_height}")
- pygame.display.set_mode(display, DOUBLEBUF | OPENGL | RESIZABLE) # Ustawienie okna gry
- # Ustawienia OpenGL
- glClearColor(0.5, 0.7, 1.0, 1.0) # Jasne niebo jako tło
- glEnable(GL_DEPTH_TEST)
- glEnable(GL_CULL_FACE)
- glEnable(GL_BLEND)
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
- glEnable(GL_TEXTURE_2D)
- WORLD_SIZES = OrderedDict([
- ("Mały (8x8x8)", 8),
- ("Średni (16x16x16)", 16),
- ("Duży (32x32x32)", 32),
- ("Ogromny (64x64x64)", 64),
- ("Nieskończony", None)
- ])
- DEFAULT_SETTINGS = {
- "mouse_sensitivity": 0.1,
- "move_speed": 0.1,
- "jump_force": 0.3,
- "gravity": 0.01,
- "fov": 70,
- "render_distance": 8,
- "resource_pack": "Brak",
- "invert_mouse_x": False,
- "invert_mouse_y": False
- }
- BLOCK_TEXTURE_PATHS = {
- 1: "blocks/grass.png",
- 2: "blocks/dirt.png",
- 3: "blocks/stone.png",
- }
- BLOCK_TYPES_TO_INV_NAMES = {
- 1: "Trawa",
- 2: "Ziemia",
- 3: "Kamień",
- }
- BLOCK_AIR = 0
- CHUNK_SIZE = 16
- font_small = None
- font_medium = None
- font_large = None
- font_height = 0
- settings = DEFAULT_SETTINGS.copy()
- class ResourceManager:
- def __init__(self, base_asset_dir="assets", rp_dir="resourcepacks"):
- self.base_asset_dir = base_asset_dir
- self.rp_dir = rp_dir
- self.available_packs = ["Brak"]
- self.active_pack_name = "Brak"
- self.active_pack_zip = None
- self._texture_cache = {}
- self.scan_resource_packs()
- def scan_resource_packs(self):
- self.available_packs = ["Brak"]
- if not os.path.exists(self.rp_dir):
- os.makedirs(self.rp_dir)
- return
- for item_name in os.listdir(self.rp_dir):
- item_path = os.path.join(self.rp_dir, item_name)
- if os.path.isfile(item_path) and item_name.endswith(".zip"):
- try:
- with zipfile.ZipFile(item_path, 'r') as zf:
- if any(name.startswith('assets/minecraft/textures/') for name in zf.namelist()) or 'pack.mcmeta' in zf.namelist():
- self.available_packs.append(item_name)
- else:
- print(f"'{item_name}' nie jest resource packiem, pomijam.")
- except zipfile.BadZipFile:
- print(f"'{item_name}' nie jest prawidłowym ZIP, pomijam.")
- except Exception as e:
- print(f"Błąd skanowania '{item_name}': {e}")
- def activate_resource_pack(self, pack_name):
- if pack_name not in self.available_packs:
- print(f"Nieznany pack: {pack_name}. Używam 'Brak'.")
- pack_name = "Brak"
- if self.active_pack_name == pack_name:
- return
- print(f"Aktywacja: {pack_name}")
- self.clear_texture_cache()
- if self.active_pack_zip:
- try:
- self.active_pack_zip.close()
- except Exception as e:
- print(f"Błąd zamykania ZIP '{self.active_pack_name}': {e}")
- self.active_pack_zip = None
- self.active_pack_name = pack_name
- if pack_name != "Brak":
- item_path = os.path.join(self.rp_dir, pack_name)
- try:
- self.active_pack_zip = zipfile.ZipFile(item_path, 'r')
- except FileNotFoundError:
- print(f"Pack '{pack_name}' nie znaleziono.")
- self.active_pack_name = "Brak"
- except zipfile.BadZipFile:
- print(f"'{pack_name}' nie jest prawidłowym ZIP.")
- self.active_pack_name = "Brak"
- except Exception as e:
- print(f"Błąd otwierania '{pack_name}': {e}")
- self.active_pack_name = "Brak"
- def clear_texture_cache(self):
- texture_ids = [tid for tid in self._texture_cache.values() if tid > 0 and glIsTexture(tid)]
- if texture_ids:
- try:
- glDeleteTextures(texture_ids)
- except Exception as e:
- print(f"Błąd usuwania tekstur: {e}")
- self._texture_cache = {}
- def _load_texture_opengl_from_surface(self, texture_surface, is_game_asset=True):
- if texture_surface is None:
- return 0
- try:
- texture_surface = texture_surface.convert_alpha()
- texture_data = pygame.image.tobytes(texture_surface, "RGBA", False)
- width, height = texture_surface.get_size()
- if width == 0 or height == 0:
- return 0
- tex_id = glGenTextures(1)
- glBindTexture(GL_TEXTURE_2D, tex_id)
- filter_type = GL_NEAREST if is_game_asset else GL_LINEAR
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter_type)
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter_type)
- wrap_mode = GL_REPEAT if is_game_asset else GL_CLAMP_TO_EDGE
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_mode)
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_mode)
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture_data)
- return tex_id
- except Exception as e:
- print(f"Błąd tworzenia tekstury: {e}")
- return 0
- def load_texture_game_asset(self, path_in_textures_folder):
- cache_key = (self.active_pack_name, path_in_textures_folder)
- if cache_key in self._texture_cache:
- print(f"Tekstura z cache: {path_in_textures_folder}, tex_id={self._texture_cache[cache_key]}")
- return self._texture_cache[cache_key]
- tex_id = 0
- texture_surface = None
- if self.active_pack_zip:
- rp_internal_path = f"assets/minecraft/textures/{path_in_textures_folder}"
- print(f"Próba ładowania z resource pack: {rp_internal_path}")
- try:
- with self.active_pack_zip.open(rp_internal_path) as texture_file:
- texture_bytes = io.BytesIO(texture_file.read())
- texture_surface = pygame.image.load(texture_bytes)
- print(f"Załadowano z resource pack: {rp_internal_path}")
- except KeyError:
- print(f"Brak tekstury w resource pack: {rp_internal_path}")
- except Exception as e:
- print(f"Błąd ładowania '{rp_internal_path}' z '{self.active_pack_name}': {e}")
- if texture_surface is None:
- default_path = os.path.join(self.base_asset_dir, "textures", path_in_textures_folder)
- print(f"Próba ładowania domyślnej tekstury: {default_path}")
- if os.path.exists(default_path):
- try:
- texture_surface = pygame.image.load(default_path)
- print(f"Załadowano domyślną teksturę: {default_path}")
- except pygame.error as e:
- print(f"Błąd Pygame dla '{default_path}': {e}")
- except Exception as e:
- print(f"Nieznany błąd dla '{default_path}': {e}")
- else:
- print(f"Plik nie istnieje: {default_path}")
- if texture_surface is not None:
- tex_id = self._load_texture_opengl_from_surface(texture_surface, is_game_asset=True)
- if tex_id > 0:
- self._texture_cache[cache_key] = tex_id
- print(f"Utworzono teksturę: {path_in_textures_folder}, tex_id={tex_id}")
- return tex_id
- else:
- print(f"Nie udało się utworzyć tekstury dla '{path_in_textures_folder}'.")
- else:
- print(f"Brak powierzchni tekstury dla: {path_in_textures_folder}")
- # Fallback na dummy.png
- dummy_path = os.path.join(self.base_asset_dir, "textures", "dummy.png")
- print(f"Próba ładowania dummy: {dummy_path}")
- if os.path.exists(dummy_path):
- cache_key_dummy = ("UI", dummy_path)
- if cache_key_dummy in self._texture_cache:
- print(f"Dummy z cache: {dummy_path}, tex_id={self._texture_cache[cache_key_dummy]}")
- return self._texture_cache[cache_key_dummy]
- try:
- dummy_surface = pygame.image.load(dummy_path)
- dummy_tex_id = self._load_texture_opengl_from_surface(dummy_surface, is_game_asset=False)
- if dummy_tex_id > 0:
- self._texture_cache[cache_key_dummy] = dummy_tex_id
- self._texture_cache[cache_key] = dummy_tex_id
- print(f"Użyto dummy tekstury dla '{path_in_textures_folder}', tex_id={dummy_tex_id}")
- return dummy_tex_id
- except Exception as e:
- print(f"Błąd ładowania zastępczej '{dummy_path}': {e}")
- else:
- print(f"Brak dummy tekstury: {dummy_path}")
- print(f"Nie udało się załadować '{path_in_textures_folder}' ani dummy.")
- return 0
- def load_texture_ui_asset(self, path_in_base_asset_dir):
- cache_key = ("UI", path_in_base_asset_dir)
- if cache_key in self._texture_cache:
- print(f"Tekstura UI z cache: {path_in_base_asset_dir}, tex_id={self._texture_cache[cache_key]}")
- return self._texture_cache[cache_key]
- default_path = os.path.join(self.base_asset_dir, path_in_base_asset_dir)
- print(f"Pełna ścieżka do pliku: {default_path}")
- tex_id = 0
- if os.path.exists(default_path):
- try:
- texture_surface = pygame.image.load(default_path)
- print(f"Załadowano teksturę UI: {default_path}")
- tex_id = self._load_texture_opengl_from_surface(texture_surface, is_game_asset=False)
- if tex_id > 0:
- self._texture_cache[cache_key] = tex_id
- print(f"Utworzono teksturę UI: {default_path}, tex_id={tex_id}")
- return tex_id
- else:
- print(f"Błąd tworzenia tekstury UI z {default_path}.")
- except pygame.error as e:
- print(f"Błąd Pygame przy ładowaniu {default_path}: {e}")
- except Exception as e:
- print(f"Nieznany błąd dla {default_path}: {e}")
- else:
- print(f"Plik UI nie istnieje: {default_path}")
- return 0
- def load_text_texture(text, font, color):
- if not text:
- return 0, 0, 0
- try:
- # Renderowanie tekstu
- text_surface = font.render(text, True, color).convert_alpha()
- # Odwracamy tylko powierzchnię tekstu w pionie, aby naprawić efekt lustra (w osi Y)
- text_surface = pygame.transform.flip(text_surface, False, True) # False dla osi X, True dla osi Y
- text_data = pygame.image.tobytes(text_surface, "RGBA", False)
- width, height = text_surface.get_size()
- if width == 0 or height == 0:
- return 0, 0, 0
- # Tworzenie tekstury OpenGL
- tex_id = glGenTextures(1)
- glBindTexture(GL_TEXTURE_2D, tex_id)
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
- # Przypisanie danych tekstury
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, text_data)
- glBindTexture(GL_TEXTURE_2D, 0)
- return tex_id, width, height
- except Exception as e:
- print(f"Błąd tworzenia tekstury tekstu '{text}': {e}")
- return 0, 0, 0
- class ChunkManager:
- def __init__(self, seed=0, render_distance_chunks=8, world_name_dir="infinite_world_default"):
- self.seed = seed
- self.render_distance_chunks = render_distance_chunks
- self.world_name_dir = world_name_dir
- self.chunks = {}
- self._chunks_to_save = set()
- self.world_dir = os.path.join("worlds", world_name_dir)
- self.region_dir = os.path.join(self.world_dir, "region")
- os.makedirs(self.region_dir, exist_ok=True)
- def get_block(self, x, y, z):
- BUILD_HEIGHT_LIMIT = 256
- if y < 0 or y >= BUILD_HEIGHT_LIMIT:
- return BLOCK_AIR
- cx, cy, cz = x // CHUNK_SIZE, y // CHUNK_SIZE, z // CHUNK_SIZE
- lx, ly, lz = x % CHUNK_SIZE, y % CHUNK_SIZE, z % CHUNK_SIZE
- lx = lx if lx >= 0 else lx + CHUNK_SIZE
- ly = ly if ly >= 0 else ly + CHUNK_SIZE
- lz = lz if lz >= 0 else lz + CHUNK_SIZE
- chunk_coords = (cx, cy, cz)
- if chunk_coords in self.chunks:
- if 0 <= lx < CHUNK_SIZE and 0 <= ly < CHUNK_SIZE and 0 <= lz < CHUNK_SIZE:
- return self.chunks[chunk_coords][lx][ly][lz]
- else:
- print(f"Nieprawidłowe współrzędne ({lx}, {ly}, {lz}) dla chunka ({cx}, {cy}, {cz}).")
- return BLOCK_AIR
- def set_block(self, x, y, z, block_type):
- BUILD_HEIGHT_LIMIT = 256
- if y < 0 or y >= BUILD_HEIGHT_LIMIT:
- print(f"Blok poza limitem wysokości ({y}).")
- return
- cx, cy, cz = x // CHUNK_SIZE, y // CHUNK_SIZE, z // CHUNK_SIZE
- lx, ly, lz = x % CHUNK_SIZE, y % CHUNK_SIZE, z % CHUNK_SIZE
- lx = lx if lx >= 0 else lx + CHUNK_SIZE
- ly = ly if ly >= 0 else ly + CHUNK_SIZE
- lz = lz if lz >= 0 else lz + CHUNK_SIZE
- chunk_coords = (cx, cy, cz)
- if chunk_coords in self.chunks:
- self.chunks[chunk_coords][lx][ly][lz] = block_type
- self._chunks_to_save.add(chunk_coords)
- if lx == 0: self._chunks_to_save.add((cx-1, cy, cz))
- if lx == CHUNK_SIZE - 1: self._chunks_to_save.add((cx+1, cy, cz))
- if ly == 0: self._chunks_to_save.add((cx, cy-1, cz))
- if ly == CHUNK_SIZE - 1: self._chunks_to_save.add((cx, cy+1, cz))
- if lz == 0: self._chunks_to_save.add((cx, cy, cz-1))
- if lz == CHUNK_SIZE - 1: self._chunks_to_save.add((cx, cy, cz+1))
- else:
- print(f"Próba ustawienia bloku w niezaładowanym chunku: {chunk_coords}")
- def _generate_and_load_chunk(self, cx, cy, cz):
- chunk_coords = (cx, cy, cz)
- if chunk_coords in self.chunks:
- return
- chunk_file = os.path.join(self.region_dir, f"chunk_{cx}_{cy}_{cz}.dat")
- chunk = None
- if os.path.exists(chunk_file):
- try:
- with open(chunk_file, "rb") as f:
- chunk = pickle.load(f)
- except Exception as e:
- print(f"Błąd wczytywania chunka {chunk_coords}: {e}")
- if chunk is None:
- chunk = np.zeros((CHUNK_SIZE, CHUNK_SIZE, CHUNK_SIZE), dtype=int)
- scale = 30.0
- height_multiplier = 20
- ground_level_base = 60
- for x in range(CHUNK_SIZE):
- for z in range(CHUNK_SIZE):
- world_x = cx * CHUNK_SIZE + x
- world_z = cz * CHUNK_SIZE + z
- noise_val = noise.pnoise2(world_x / scale + self.seed*10, world_z / scale + self.seed*10,
- octaves=6, persistence=0.5, lacunarity=2.0, repeatx=100000, repeaty=100000, base=self.seed*1000)
- height = int(noise_val * height_multiplier) + ground_level_base
- height = max(1, min(height, 255))
- for y in range(CHUNK_SIZE):
- world_y = cy * CHUNK_SIZE + y
- if world_y <= height:
- chunk[x][y][z] = 1 if world_y == height else 2 if world_y >= height - random.randint(2, 4) else 3
- try:
- with open(chunk_file, "wb") as f:
- pickle.dump(chunk, f)
- except Exception as e:
- print(f"Błąd zapisywania chunka {chunk_coords}: {e}")
- self.chunks[chunk_coords] = chunk
- def _unload_chunk(self, chunk_coords):
- if chunk_coords in self.chunks and chunk_coords in self._chunks_to_save:
- try:
- chunk_file = os.path.join(self.region_dir, f"chunk_{chunk_coords[0]}_{chunk_coords[1]}_{chunk_coords[2]}.dat")
- with open(chunk_file, "wb") as f:
- pickle.dump(self.chunks[chunk_coords], f)
- self._chunks_to_save.discard(chunk_coords)
- except Exception as e:
- print(f"Błąd zapisywania chunka {chunk_coords}: {e}")
- if chunk_coords in self.chunks:
- del self.chunks[chunk_coords]
- def update_loaded_chunks(self, player_pos):
- px, py, pz = player_pos
- player_chunk_x = int(np.floor(px / CHUNK_SIZE))
- player_chunk_y = int(np.floor(py / CHUNK_SIZE))
- player_chunk_z = int(np.floor(pz / CHUNK_SIZE))
- min_cx = player_chunk_x - self.render_distance_chunks
- max_cx = player_chunk_x + self.render_distance_chunks
- min_cy = player_chunk_y - self.render_distance_chunks
- max_cy = player_chunk_y + self.render_distance_chunks
- min_cz = player_chunk_z - self.render_distance_chunks
- max_cz = player_chunk_z + self.render_distance_chunks
- chunks_to_load_or_keep = set((cx, cy, cz) for cx in range(min_cx, max_cx + 1) for cy in range(min_cy, max_cy + 1) for cz in range(min_cz, max_cz + 1))
- for cc in [cc for cc in self.chunks if cc not in chunks_to_load_or_keep]:
- self._unload_chunk(cc)
- for cc in [cc for cc in chunks_to_load_or_keep if cc not in self.chunks]:
- self._generate_and_load_chunk(*cc)
- def get_loaded_chunks_coords(self):
- return list(self.chunks.keys())
- def save_all_chunks(self):
- print(f"Zapisuję {len(self._chunks_to_save)} chunków...")
- saved_count = 0
- for chunk_coords in list(self._chunks_to_save):
- if chunk_coords in self.chunks:
- try:
- chunk_file = os.path.join(self.region_dir, f"chunk_{chunk_coords[0]}_{chunk_coords[1]}_{chunk_coords[2]}.dat")
- with open(chunk_file, "wb") as f:
- pickle.dump(self.chunks[chunk_coords], f)
- self._chunks_to_save.discard(chunk_coords)
- saved_count += 1
- except Exception as e:
- print(f"Błąd zapisywania chunka {chunk_coords}: {e}")
- else:
- self._chunks_to_save.discard(chunk_coords)
- print(f"Zapisano {saved_count} chunków.")
- def save_fixed_world(world, world_name, size):
- if not world_name:
- print("Brak nazwy świata!")
- return False
- safe_world_name_dir = "".join(c for c in world_name if c.isalnum() or c in (' ', '-', '_')).strip()
- if not safe_world_name_dir:
- safe_world_name_dir = "saved_world_" + str(int(time.time()))
- print(f"Używam domyślnej nazwy: '{safe_world_name_dir}'")
- world_dir = os.path.join("worlds", safe_world_name_dir)
- try:
- os.makedirs(world_dir, exist_ok=True)
- with open(os.path.join(world_dir, "world.dat"), "wb") as f:
- pickle.dump(world, f)
- with open(os.path.join(world_dir, "settings.dat"), "wb") as f:
- pickle.dump({"size": size, "name": world_name, "type": "fixed"}, f)
- print(f"Świat '{world_name}' zapisany jako '{safe_world_name_dir}'!")
- return True
- except Exception as e:
- print(f"Błąd zapisywania '{world_name}': {e}")
- return False
- def load_world(world_name_dir):
- try:
- world_dir = os.path.join("worlds", world_name_dir)
- settings_file = os.path.join(world_dir, "settings.dat")
- if not os.path.exists(settings_file):
- print(f"Brak ustawień dla '{world_name_dir}'.")
- return None, None, None, None
- with open(settings_file, "rb") as f:
- settings_data = pickle.load(f)
- world_type = settings_data.get("type", "fixed")
- world_name_display = settings_data.get("name", world_name_dir)
- size = settings_data.get("size")
- if world_type == "fixed":
- if size is None:
- print("Brak rozmiaru dla świata fixed!")
- return None, world_name_display, None, False
- world_file = os.path.join(world_dir, "world.dat")
- if os.path.exists(world_file):
- with open(world_file, "rb") as f:
- world = pickle.load(f)
- if isinstance(world, np.ndarray) and world.shape == (size, size, size):
- return world, world_name_display, size, False
- else:
- print(f"Niepoprawne dane świata: {getattr(world, 'shape', 'N/A')}")
- return None, world_name_display, None, False
- else:
- print(f"Brak pliku świata '{world_file}'.")
- return None, world_name_display, None, False
- elif world_type == "infinite":
- seed = settings_data.get("seed", 0)
- print(f"Świat '{world_name_display}' wczytany (nieskończony, seed {seed})!")
- return (seed, world_name_dir), world_name_display, None, True
- else:
- print(f"Nieznany typ świata '{world_type}'.")
- return None, world_name_display, None, None
- except Exception as e:
- print(f"Błąd wczytywania '{world_name_dir}': {e}")
- traceback.print_exc()
- return None, None, None, None
- from perlin_noise import PerlinNoise
- def generate_fixed_world(size, seed=0):
- print(f"Generowanie świata {size}x{size}x{size} z seedem {seed}...")
- world = np.zeros((size, size, size), dtype=int)
- np.random.seed(seed)
- random.seed(seed)
- scale = max(10, size / 8.0)
- height_multiplier = max(5, size // 10)
- ground_level_base = size // 4
- noise_gen = PerlinNoise(octaves=4, seed=seed)
- try:
- for x in range(size):
- for z in range(size):
- noise_val = noise_gen([x / scale, z / scale])
- height = int(noise_val * height_multiplier) + ground_level_base
- height = max(1, min(height, size - 1))
- for y in range(height + 1):
- world[x][y][z] = 1 if y == height else 2 if y >= height - random.randint(2, 4) else 3
- if x % (size // 4) == 0 and z == 0:
- print(f"Postęp generowania: x={x}/{size}")
- except Exception as e:
- print(f"Błąd w generowaniu świata: {e}")
- traceback.print_exc()
- return None
- print("Generowanie zakończone.")
- return world
- def is_block_in_render_distance(x, y, z, player_pos, render_distance_blocks):
- px, py, pz = player_pos
- dist_sq = (x + 0.5 - px)**2 + (y + 0.5 - py)**2 + (z + 0.5 - pz)**2
- return dist_sq <= render_distance_blocks**2
- def draw_single_block(x, y, z, block_type, get_neighbor_block_func, resource_manager, block_texture_paths):
- vertices = [
- (0, 0, 0), (1, 0, 0), (1, 1, 0), (0, 1, 0),
- (0, 0, 1), (1, 0, 1), (1, 1, 1), (0, 1, 1)
- ]
- normals = [(0, 0, -1), (0, 0, 1), (0, 1, 0), (0, -1, 0), (1, 0, 0), (-1, 0, 0)]
- faces = [(0, 1, 2, 3), (5, 4, 7, 6), (3, 2, 6, 7), (1, 0, 4, 5), (1, 5, 6, 2), (4, 0, 3, 7)]
- texcoords = [(0, 0), (1, 0), (1, 1), (0, 1)]
- neighbors_offset = [(0, 0, -1), (0, 0, 1), (0, 1, 0), (0, -1, 0), (1, 0, 0), (-1, 0, 0)]
- # Ładowanie tekstury przed renderowaniem
- texture_path = block_texture_paths.get(block_type)
- tex_id = resource_manager.load_texture_game_asset(texture_path) if texture_path else 0
- print(f"Ładowanie tekstury dla bloku {block_type} ({texture_path}): tex_id={tex_id}") # Debug
- # Ustawienie stanu OpenGL przed glBegin()
- glPushAttrib(GL_ENABLE_BIT) # Zachowaj stan
- if tex_id > 0 and glIsTexture(tex_id):
- glEnable(GL_TEXTURE_2D)
- glBindTexture(GL_TEXTURE_2D, tex_id)
- glColor3f(1.0, 1.0, 1.0)
- else:
- glDisable(GL_TEXTURE_2D)
- glColor3f(0.2, 0.8, 0.2) if block_type == 1 else (0.5, 0.3, 0.1) if block_type == 2 else (0.5, 0.5, 0.5)
- # Renderowanie bloku
- glBegin(GL_QUADS)
- for i, face_indices in enumerate(faces):
- if get_neighbor_block_func(x + neighbors_offset[i][0], y + neighbors_offset[i][1], z + neighbors_offset[i][2]) == BLOCK_AIR:
- glNormal3fv(normals[i])
- for j, vertex_index in enumerate(face_indices):
- if tex_id > 0 and glIsTexture(tex_id):
- glTexCoord2fv(texcoords[j])
- vx, vy, vz = vertices[vertex_index]
- glVertex3f(vx + x, vy + y, vz + z)
- glEnd()
- # Przywrócenie stanu
- glPopAttrib() # Oczyść stan
- def draw_world(world_data, player_pos, settings, resource_manager, block_texture_paths, is_infinite):
- print(f"Przed draw_world - tryb macierzy: {glGetIntegerv(GL_MATRIX_MODE)}")
- render_distance_blocks = settings.get("render_distance", DEFAULT_SETTINGS["render_distance"]) * CHUNK_SIZE
- glPushAttrib(GL_ENABLE_BIT | GL_TEXTURE_BIT)
- glEnable(GL_TEXTURE_2D)
- glColor3f(1.0, 1.0, 1.0)
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # Czyszczenie bufora
- vertices = [(0, 0, 0), (1, 0, 0), (1, 1, 0), (0, 1, 0),
- (0, 0, 1), (1, 0, 1), (1, 1, 1), (0, 1, 1)]
- normals = [(0, 0, -1), (0, 0, 1), (0, 1, 0), (0, -1, 0), (1, 0, 0), (-1, 0, 0)]
- faces = [(0, 1, 2, 3), (5, 4, 7, 6), (3, 2, 6, 7), (1, 0, 4, 5), (1, 5, 6, 2), (4, 0, 3, 7)]
- texcoords = [(0, 0), (1, 0), (1, 1), (0, 1)]
- neighbors_offset = [(0, 0, -1), (0, 0, 1), (0, 1, 0), (0, -1, 0), (1, 0, 0), (-1, 0, 0)]
- if is_infinite:
- chunk_manager = world_data
- loaded_chunks = chunk_manager.get_loaded_chunks_coords()
- print(f"Załadowane chunki: {len(loaded_chunks)}: {loaded_chunks}")
- for chunk_coords in loaded_chunks:
- cx, cy, cz = chunk_coords
- chunk = chunk_manager.chunks.get(chunk_coords)
- if chunk is None:
- print(f"Brak danych chunka: {chunk_coords}")
- continue
- glPushAttrib(GL_ENABLE_BIT)
- block_count = 0
- for x in range(CHUNK_SIZE):
- for y in range(CHUNK_SIZE):
- for z in range(CHUNK_SIZE):
- block_type = chunk[x][y][z]
- if block_type != BLOCK_AIR:
- block_world_x = cx * CHUNK_SIZE + x
- block_world_y = cy * CHUNK_SIZE + y
- block_world_z = cz * CHUNK_SIZE + z
- if is_block_in_render_distance(block_world_x, block_world_y, block_world_z, player_pos, render_distance_blocks):
- block_count += 1
- texture_path = block_texture_paths.get(block_type)
- tex_id = resource_manager.load_texture_game_asset(texture_path) if texture_path else 0
- print(f"Renderowanie bloku {block_type} na ({block_world_x}, {block_world_y}, {block_world_z}), tex_id={tex_id}")
- if tex_id > 0 and glIsTexture(tex_id):
- glBindTexture(GL_TEXTURE_2D, tex_id)
- else:
- glBindTexture(GL_TEXTURE_2D, 0)
- glColor3f(0.2, 0.8, 0.2) if block_type == 1 else (0.5, 0.3, 0.1)
- glBegin(GL_QUADS)
- for i, face_indices in enumerate(faces):
- if chunk_manager.get_block(block_world_x + neighbors_offset[i][0], block_world_y + neighbors_offset[i][1], block_world_z + neighbors_offset[i][2]) == BLOCK_AIR:
- glNormal3fv(normals[i])
- for j, vertex_index in enumerate(face_indices):
- if tex_id > 0:
- glTexCoord2fv(texcoords[j])
- vx, vy, vz = vertices[vertex_index]
- glVertex3f(vx + block_world_x, vy + block_world_y, vz + block_world_z)
- glEnd()
- glBindTexture(GL_TEXTURE_2D, 0)
- print(f"Chunek {chunk_coords}: renderowano {block_count} bloków")
- glPopAttrib()
- else:
- world = world_data
- if world is None or not isinstance(world, np.ndarray) or world.ndim != 3:
- print("Nieprawidłowe dane świata fixed.")
- glPopAttrib()
- return
- size = len(world)
- def get_neighbor_block_fixed(nx, ny, nz):
- return world[nx][ny][nz] if 0 <= nx < size and 0 <= ny < size and 0 <= nz < size else BLOCK_AIR
- actual_render_distance_blocks = min(render_distance_blocks, size)
- glPushAttrib(GL_ENABLE_BIT)
- for block_type in block_texture_paths.keys():
- texture_path = block_texture_paths.get(block_type)
- tex_id = resource_manager.load_texture_game_asset(texture_path) if texture_path else 0
- if tex_id > 0:
- glBindTexture(GL_TEXTURE_2D, tex_id)
- else:
- glBindTexture(GL_TEXTURE_2D, 0)
- glColor3f(0.2, 0.8, 0.2) if block_type == 1 else (0.5, 0.3, 0.1)
- glBegin(GL_QUADS)
- for x in range(size):
- for y in range(size):
- for z in range(size):
- if world[x][y][z] == block_type and is_block_in_render_distance(x, y, z, player_pos, actual_render_distance_blocks):
- for i, face_indices in enumerate(faces):
- if get_neighbor_block_fixed(x + neighbors_offset[i][0], y + neighbors_offset[i][1], z + neighbors_offset[i][2]) == BLOCK_AIR:
- glNormal3fv(normals[i])
- for j, vertex_index in enumerate(face_indices):
- if tex_id > 0:
- glTexCoord2fv(texcoords[j])
- vx, vy, vz = vertices[vertex_index]
- glVertex3f(vx + x, vy + y, vz + z)
- glEnd()
- glBindTexture(GL_TEXTURE_2D, 0)
- glPopAttrib()
- glBindTexture(GL_TEXTURE_2D, 0)
- glPopAttrib()
- print(f"Po draw_world - tryb macierzy: {glGetIntegerv(GL_MATRIX_MODE)}")
- def draw_quad_2d(x, y, width, height, color=None, texture_id=None, alpha=1.0, texture_coords=((0,1),(1,1),(1,0),(0,0))):
- if color:
- glDisable(GL_TEXTURE_2D)
- glColor4f(*color, alpha)
- elif texture_id is not None and texture_id > 0:
- glEnable(GL_TEXTURE_2D)
- glBindTexture(GL_TEXTURE_2D, texture_id)
- glColor4f(1.0, 1.0, 1.0, alpha)
- else:
- return
- glBegin(GL_QUADS)
- if texture_id is not None and texture_id > 0:
- for i, (tx, ty) in enumerate(texture_coords):
- glTexCoord2f(tx, ty)
- glVertex2f(x + [0, width, width, 0][i], y + [0, 0, height, height][i])
- else:
- for i in range(4):
- glVertex2f(x + [0, width, width, 0][i], y + [0, 0, height, height][i])
- glEnd()
- def draw_line_loop_2d(x, y, width, height, color, line_width=1.0, alpha=1.0):
- glDisable(GL_TEXTURE_2D)
- glColor4f(*color, alpha)
- glLineWidth(line_width)
- glBegin(GL_LINE_LOOP)
- for vx, vy in [(x, y), (x + width, y), (x + width, y + height), (x, y + height)]:
- glVertex2f(vx, vy)
- glEnd()
- def draw_lines_2d(points, color, line_width=1.0, alpha=1.0):
- glDisable(GL_TEXTURE_2D)
- glColor4f(*color, alpha)
- glLineWidth(line_width)
- glBegin(GL_LINES)
- for point in points:
- glVertex2f(*point)
- glEnd()
- def draw_text_2d(x, y, text, font, color=(255, 255, 255), alpha=1.0):
- text_tex, text_width, text_height = load_text_texture(text, font, color)
- if text_tex > 0:
- # Poprawiamy kolejność współrzędnych tekstury, żeby tekst nie był odwrócony
- text_coords = ((0, 1), (1, 1), (1, 0), (0, 0)) # Poprawione współrzędne UV
- draw_quad_2d(x, y, text_width, text_height, texture_id=text_tex, alpha=alpha, texture_coords=text_coords)
- glDeleteTextures([text_tex])
- return text_width, text_height
- def setup_2d_overlay():
- glDisable(GL_DEPTH_TEST)
- glDisable(GL_CULL_FACE)
- glMatrixMode(GL_PROJECTION)
- glPushMatrix()
- glLoadIdentity()
- glOrtho(0, display[0], display[1], 0, -1, 1)
- glMatrixMode(GL_MODELVIEW)
- glPushMatrix()
- glLoadIdentity()
- glEnable(GL_BLEND)
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
- glDisable(GL_TEXTURE_2D)
- def restore_3d_projection():
- glMatrixMode(GL_MODELVIEW)
- glPopMatrix()
- glMatrixMode(GL_PROJECTION)
- glPopMatrix()
- glEnable(GL_DEPTH_TEST)
- glEnable(GL_CULL_FACE)
- def draw_background(resource_manager, alpha=1.0):
- menu_background_path = os.path.join("textures", "menu", "background.png")
- # Sprawdzamy, czy plik istnieje przed próbą załadowania tekstury
- if not os.path.isfile(menu_background_path):
- print(f"Plik UI nie istnieje: {menu_background_path}")
- # Możesz zainicjować jakąś domyślną teksturę lub inne tło, jeśli plik nie istnieje
- menu_background_tex_id = None
- else:
- menu_background_tex_id = resource_manager.load_texture_ui_asset(menu_background_path)
- print(f"Renderowanie tła, tex_id={menu_background_tex_id}")
- # Jeśli tekstura się nie załadowała (tex_id == 0 lub None), używamy koloru
- if not menu_background_tex_id:
- print(f"Nie udało się załadować {menu_background_path}, używam koloru.")
- # Przekazujemy None lub ID tekstury w zależności od tego, czy tekstura została załadowana
- draw_quad_2d(0, 0, display[0], display[1], texture_id=menu_background_tex_id if menu_background_tex_id else None, color=(0.2, 0.2, 0.2), alpha=alpha)
- def draw_button(x, y, width, height, text, font, mouse_pos, clicked, animation_alpha=1.0):
- is_hovered = x < mouse_pos[0] < x + width and y < mouse_pos[1] < y + height
- btn_color = (0.3, 0.3, 0.3) if is_hovered else (0.2, 0.2, 0.2)
- draw_quad_2d(x + 5, y + 5, width, height, color=(0.1, 0.1, 0.1), alpha=0.5 * animation_alpha)
- draw_quad_2d(x, y, width, height, color=btn_color, alpha=animation_alpha)
- draw_line_loop_2d(x, y, width, height, color=(0.5, 0.5, 0.5), alpha=animation_alpha)
- text_width = font.size(text)[0]
- text_x = x + (width - text_width) // 2
- text_y = y + (height - font_height) // 2
- draw_text_2d(text_x, text_y, text, font, alpha=animation_alpha)
- return is_hovered and clicked
- # Rysuje suwak do ustawień (np. czułość myszy, FOV)
- def draw_slider(x, y, width, height, value, min_val, max_val, font, mouse_pos, mouse_clicked, is_dragging, animation_alpha=1.0):
- # Tło suwaka
- draw_quad_2d(x, y, width, height, color=(0.2, 0.2, 0.2), alpha=animation_alpha)
- draw_line_loop_2d(x, y, width, height, color=(0.5, 0.5, 0.5), alpha=animation_alpha)
- # Wskaźnik suwaka
- slider_width = 10
- norm_value = (value - min_val) / (max_val - min_val) # Normalizacja wartości do 0-1
- slider_x = x + norm_value * (width - slider_width)
- draw_quad_2d(slider_x, y, slider_width, height, color=(0.4, 0.4, 0.4), alpha=animation_alpha)
- # Wyświetl wartość
- value_text = f"{value:.2f}" if isinstance(value, float) else str(value)
- text_width = font.size(value_text)[0]
- draw_text_2d(x + (width - text_width) // 2, y + (height - font.get_linesize()) // 2, value_text, font, alpha=animation_alpha)
- # Obsługa myszy
- is_hovered = x < mouse_pos[0] < x + width and y < mouse_pos[1] < y + height
- if is_hovered and mouse_clicked:
- is_dragging = True
- if not pygame.mouse.get_pressed()[0]:
- is_dragging = False
- if is_dragging:
- norm_pos = (mouse_pos[0] - x) / width
- norm_pos = max(0, min(1, norm_pos)) # Ogranicz do 0-1
- value = min_val + norm_pos * (max_val - min_val)
- if isinstance(min_val, int):
- value = int(round(value))
- return value, is_dragging
- # Rysuje pole tekstowe (np. do nazwy świata, seeda)
- def draw_text_field(x, y, width, height, text, font, is_active, animation_alpha=1.0):
- # Tło pola
- bg_color = (0.3, 0.3, 0.3) if is_active else (0.2, 0.2, 0.2)
- draw_quad_2d(x, y, width, height, color=bg_color, alpha=animation_alpha)
- draw_line_loop_2d(x, y, width, height, color=(0.5, 0.5, 0.5), alpha=animation_alpha)
- # Tekst
- display_text = text if text else "Wpisz..." if not is_active else ""
- text_x = x + 5
- text_y = y + (height - font.get_linesize()) // 2
- draw_text_2d(text_x, text_y, display_text, font, color=(255, 255, 255) if text else (150, 150, 150), alpha=animation_alpha)
- # Rysuje dropdown (np. do wyboru rozmiaru świata)
- def draw_dropdown(x, y, width, height, options, selected_option, font, mouse_pos, mouse_clicked, is_open, animation_alpha=1.0):
- list_spacing = 5
- # Główne pole dropdown
- draw_quad_2d(x, y, width, height, color=(0.2, 0.2, 0.2), alpha=animation_alpha)
- draw_line_loop_2d(x, y, width, height, color=(0.5, 0.5, 0.5), alpha=animation_alpha)
- text_x = x + 5
- text_y = y + (height - font.get_linesize()) // 2
- draw_text_2d(text_x, text_y, selected_option, font, alpha=animation_alpha)
- # Strzałka
- arrow_size = 10
- draw_quad_2d(x + width - arrow_size - 5, y + (height - arrow_size) // 2, arrow_size, arrow_size, color=(0.4, 0.4, 0.4), alpha=animation_alpha)
- was_clicked = False
- is_hovered = x < mouse_pos[0] < x + width and y < mouse_pos[1] < y + height
- if is_hovered and mouse_clicked:
- is_open = not is_open
- was_clicked = True
- # Lista opcji
- if is_open:
- for i, option in enumerate(options):
- item_y = y + height + (i * (height + list_spacing))
- item_color = (0.3, 0.3, 0.3) if option != selected_option else (0.4, 0.4, 0.4)
- is_hovered = x < mouse_pos[0] < x + width and item_y < mouse_pos[1] < item_y + height
- draw_quad_2d(x, item_y, width, height, color=item_color, alpha=animation_alpha)
- if is_hovered:
- draw_line_loop_2d(x, item_y, width, height, color=(0.6, 0.6, 0.6), alpha=animation_alpha)
- draw_text_2d(text_x, item_y + (height - font.get_linesize()) // 2, option, font, alpha=animation_alpha)
- if is_hovered and mouse_clicked:
- selected_option = option
- is_open = False
- was_clicked = True
- return selected_option, is_open, was_clicked
- # Rysuje checkbox (np. do odwracania osi myszy)
- def draw_checkbox(x, y, width, height, label, is_checked, font, mouse_pos, mouse_clicked, animation_alpha=1.0):
- # Pole checkbox
- draw_quad_2d(x, y, width, height, color=(0.2, 0.2, 0.2), alpha=animation_alpha)
- draw_line_loop_2d(x, y, width, height, color=(0.5, 0.5, 0.5), alpha=animation_alpha)
- if is_checked:
- draw_quad_2d(x + 5, y + 5, width - 10, height - 10, color=(0.4, 0.4, 0.4), alpha=animation_alpha)
- # Etykieta
- text_x = x + width + 10
- text_y = y + (height - font.get_linesize()) // 2
- draw_text_2d(text_x, text_y, label, font, alpha=animation_alpha)
- # Obsługa kliknięcia
- is_hovered = x < mouse_pos[0] < x + width and y < mouse_pos[1] < y + height
- if is_hovered and mouse_clicked:
- is_checked = not is_checked
- return is_checked
- # Rysuje okno potwierdzenia (np. do usuwania świata)
- def draw_confirm_window(x, y, width, height, animation_alpha=1.0):
- draw_quad_2d(x, y, width, height, color=(0.2, 0.2, 0.2), alpha=animation_alpha)
- draw_line_loop_2d(x, y, width, height, color=(0.5, 0.5, 0.5), line_width=2, alpha=animation_alpha)
- def show_main_menu(resource_manager):
- global display, settings, font_small, font_medium, font_large, font_height
- pygame.mouse.set_visible(True)
- pygame.event.set_grab(False)
- print("Menu główne: kursor włączony")
- clock = pygame.time.Clock()
- menu_state = "main"
- selected_world = None
- create_world_name_text = ""
- create_world_seed_text = ""
- selected_world_size_key = list(WORLD_SIZES.keys())[0]
- resource_pack_selected_pack = settings.get("resource_pack", "Brak")
- active_text_field = None
- dropdown_open_state = {}
- menu_running = True
- menu_alpha = 0.0
- fade_in = True
- while menu_running:
- mouse_pos = pygame.mouse.get_pos()
- mouse_clicked = False
- for event in pygame.event.get():
- if event.type == QUIT:
- print("Wyjście z aplikacji.")
- return None
- if event.type == VIDEORESIZE:
- display = (event.w, event.h)
- if display[0] > 0 and display[1] > 0:
- pygame.display.set_mode(display, DOUBLEBUF | OPENGL | RESIZABLE)
- else:
- print(f"Niepoprawny rozmiar okna: {display}")
- if event.type == MOUSEBUTTONDOWN and event.button == 1:
- mouse_clicked = True
- if event.type == KEYDOWN:
- if event.key == K_ESCAPE:
- if menu_state == "main":
- print("Wyjście z menu (ESC).")
- return None
- elif menu_state in ("singleplayer", "settings"):
- menu_state = "main"
- dropdown_open_state = {}
- active_text_field = None
- elif menu_state == "create_world":
- menu_state = "singleplayer"
- dropdown_open_state = {}
- active_text_field = None
- elif active_text_field and menu_state == "create_world":
- if event.key == K_BACKSPACE:
- if active_text_field == "name":
- create_world_name_text = create_world_name_text[:-1]
- elif active_text_field == "seed":
- create_world_seed_text = create_world_seed_text[:-1]
- elif event.key == K_RETURN:
- active_text_field = None
- elif event.unicode.isprintable():
- if active_text_field == "name":
- create_world_name_text += event.unicode
- elif active_text_field == "seed":
- if event.unicode.isdigit() or (event.unicode == '-' and not create_world_seed_text):
- create_world_seed_text += event.unicode
- if fade_in:
- menu_alpha = min(menu_alpha + 0.05, 1.0)
- if menu_alpha >= 1.0:
- fade_in = False
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
- draw_background(resource_manager, alpha=menu_alpha)
- setup_2d_overlay()
- center_x = display[0] // 2
- center_y = display[1] // 2
- button_width = 200
- button_height = 50
- button_spacing = 15
- if menu_state == "main":
- title_text = "Minecraft Clone"
- title_width = font_large.size(title_text)[0]
- draw_text_2d(center_x - title_width // 2, center_y - 150, title_text, font_large, alpha=menu_alpha)
- if draw_button(center_x - button_width // 2, center_y - button_height - button_spacing, button_width, button_height, "Gra jednoosobowa", font_medium, mouse_pos, mouse_clicked, animation_alpha=menu_alpha):
- menu_state = "singleplayer"
- dropdown_open_state = {}
- active_text_field = None
- if draw_button(center_x - button_width // 2, center_y, button_width, button_height, "Ustawienia", font_medium, mouse_pos, mouse_clicked, animation_alpha=menu_alpha):
- menu_state = "settings"
- dropdown_open_state = {}
- active_text_field = None
- if draw_button(center_x - button_width // 2, center_y + button_height + button_spacing, button_width, button_height, "Wyjście", font_medium, mouse_pos, mouse_clicked, animation_alpha=menu_alpha):
- print("Wyjście z menu.")
- return None
- elif menu_state == "singleplayer":
- title_text = "Wybierz świat"
- title_width = font_large.size(title_text)[0]
- draw_text_2d(center_x - title_width // 2, center_y - 200, title_text, font_large, alpha=menu_alpha)
- list_x = center_x - button_width // 2
- list_y = center_y - 100
- list_width = button_width + 100
- list_item_height = 40
- list_spacing = 5
- existing_worlds = []
- if os.path.exists("worlds"):
- existing_worlds = [d for d in os.listdir("worlds") if os.path.isdir(os.path.join("worlds", d))]
- max_visible_worlds = 6
- actual_display_worlds = min(max_visible_worlds, len(existing_worlds))
- if existing_worlds:
- for i in range(actual_display_worlds):
- world_dir_name = existing_worlds[i]
- _, world_name_display, _, _ = load_world(world_dir_name)
- display_name = world_name_display or world_dir_name
- item_y = list_y + i * (list_item_height + list_spacing)
- item_color = (0.3, 0.3, 0.3) if world_dir_name != selected_world else (0.4, 0.4, 0.4)
- is_hovered = list_x < mouse_pos[0] < list_x + list_width and item_y < mouse_pos[1] < item_y + list_item_height
- draw_quad_2d(list_x, item_y, list_width, list_item_height, color=item_color, alpha=menu_alpha)
- if is_hovered:
- draw_line_loop_2d(list_x, item_y, list_width, list_item_height, color=(0.6, 0.6, 0.6), alpha=menu_alpha)
- text_x = list_x + 10
- text_y = item_y + (list_item_height - font_small.get_linesize()) // 2
- draw_text_2d(text_x, text_y, display_name, font_small, alpha=menu_alpha)
- if is_hovered and mouse_clicked:
- selected_world = world_dir_name
- else:
- empty_list_y = list_y
- draw_text_2d(list_x, empty_list_y, "Brak zapisanych światów", font_small, color=(150,150,150), alpha=menu_alpha)
- button_y_start = list_y + max_visible_worlds * (list_item_height + list_spacing) + 20
- if draw_button(center_x - button_width // 2, button_y_start, button_width, button_height, "Graj", font_medium, mouse_pos, mouse_clicked and selected_world is not None, animation_alpha=menu_alpha):
- world_data, world_name_display, size, is_infinite = load_world(selected_world)
- if world_data is not None:
- menu_running = False
- dropdown_open_state = {}
- active_text_field = None
- return world_data, world_name_display, size, is_infinite
- if draw_button(center_x - button_width // 2, button_y_start + button_height + button_spacing, button_width, button_height, "Utwórz nowy świat", font_medium, mouse_pos, mouse_clicked, animation_alpha=menu_alpha):
- menu_state = "create_world"
- create_world_name_text = ""
- create_world_seed_text = ""
- selected_world_size_key = list(WORLD_SIZES.keys())[0]
- dropdown_open_state = {}
- active_text_field = None
- if draw_button(center_x - button_width // 2, button_y_start + 2*(button_height + button_spacing), button_width, button_height, "Powrót", font_medium, mouse_pos, mouse_clicked, animation_alpha=menu_alpha):
- menu_state = "main"
- dropdown_open_state = {}
- active_text_field = None
- elif menu_state == "create_world":
- title_text = "Utwórz nowy świat"
- title_width = font_large.size(title_text)[0]
- draw_text_2d(center_x - title_width // 2, center_y - 200, title_text, font_large, alpha=menu_alpha)
- field_width = 300
- field_height = 40
- field_spacing = 15
- field_x = center_x - field_width // 2
- label_height = font_medium.get_linesize()
- name_label_y = center_y - 100 - label_height - 5
- draw_text_2d(field_x, name_label_y, "Nazwa świata:", font_medium, color=(200,200,200), alpha=menu_alpha)
- name_field_y = center_y - 100
- draw_text_field(field_x, name_field_y, field_width, field_height, create_world_name_text, font_medium, active_text_field == "name")
- name_field_rect = (field_x, name_field_y, field_width, field_height)
- if mouse_clicked and name_field_rect[0] < mouse_pos[0] < name_field_rect[0] + name_field_rect[2] and name_field_rect[1] < mouse_pos[1] < name_field_rect[1] + name_field_rect[3]:
- active_text_field = "name"
- size_label_y = center_y - 30 - label_height - 5
- draw_text_2d(field_x, size_label_y, "Rozmiar świata:", font_medium, color=(200,200,200), alpha=menu_alpha)
- size_dropdown_y = center_y - 30
- dropdown_width = field_width
- dropdown_height = field_height
- selected_world_size_key, size_dropdown_is_open, size_dropdown_clicked = draw_dropdown(
- field_x, size_dropdown_y, dropdown_width, dropdown_height, list(WORLD_SIZES.keys()),
- selected_world_size_key, font_medium, mouse_pos, mouse_clicked, dropdown_open_state.get("size_dropdown", False), animation_alpha=menu_alpha
- )
- dropdown_open_state["size_dropdown"] = size_dropdown_is_open
- dropdown_vertical_offset = (len(WORLD_SIZES) * (dropdown_height + list_spacing) if dropdown_open_state.get("size_dropdown", False) else 0)
- seed_label_y = size_dropdown_y + dropdown_height + field_spacing + dropdown_vertical_offset - label_height - 5
- draw_text_2d(field_x, seed_label_y, "Seed (puste = losowy):", font_medium, color=(200,200,200), alpha=menu_alpha)
- seed_field_y = size_dropdown_y + dropdown_height + field_spacing + dropdown_vertical_offset
- draw_text_field(field_x, seed_field_y, field_width, field_height, create_world_seed_text, font_medium, active_text_field == "seed")
- seed_field_rect = (field_x, seed_field_y, field_width, field_height)
- if mouse_clicked and seed_field_rect[0] < mouse_pos[0] < seed_field_rect[0] + seed_field_rect[2] and seed_field_rect[1] < mouse_pos[1] < seed_field_rect[1] + seed_field_rect[3]:
- active_text_field = "seed"
- if mouse_clicked:
- clicked_on_field = (name_field_rect[0] < mouse_pos[0] < name_field_rect[0] + name_field_rect[2] and name_field_rect[1] < mouse_pos[1] < name_field_rect[1] + name_field_rect[3]) or \
- (seed_field_rect[0] < mouse_pos[0] < seed_field_rect[0] + seed_field_rect[2] and seed_field_rect[1] < mouse_pos[1] < seed_field_rect[1] + seed_field_rect[3])
- if not clicked_on_field and not size_dropdown_clicked:
- active_text_field = None
- button_y_start = seed_field_y + field_height + 30
- create_button_enabled = bool(create_world_name_text.strip())
- if draw_button(center_x - button_width // 2, button_y_start, button_width, button_height, "Utwórz świat", font_medium, mouse_pos, mouse_clicked if create_button_enabled else False, animation_alpha=menu_alpha):
- print(f"Utwórz świat '{create_world_name_text}'")
- world_size_val = WORLD_SIZES[selected_world_size_key]
- try:
- seed_input_str = create_world_seed_text.strip()
- world_seed = random.randint(1, 1000000) if seed_input_str == '-' or not seed_input_str else int(seed_input_str)
- create_world_seed_text = str(world_seed)
- except ValueError:
- print("Niepoprawny seed! Losowy.")
- world_seed = random.randint(1, 1000000)
- create_world_seed_text = str(world_seed)
- world_dir_name = create_world_name_text.strip().replace(' ', '_')
- world_dir_name = "".join(c for c in world_dir_name if c.isalnum() or c in ('-', '_')).strip() or "world_" + str(int(time.time()))
- # Sprawdzenie istniejących światów
- existing_worlds_dirs = []
- if os.path.exists("worlds"):
- existing_worlds_dirs = [d for d in os.listdir("worlds") if os.path.isdir(os.path.join("worlds", d))]
- i = 1
- original_dir_name = world_dir_name
- while world_dir_name in existing_worlds_dirs:
- world_dir_name = f"{original_dir_name}_{i}"
- i += 1
- if world_size_val is None:
- world_dir_path = os.path.join("worlds", world_dir_name)
- try:
- os.makedirs(world_dir_path, exist_ok=True)
- with open(os.path.join(world_dir_path, "settings.dat"), "wb") as f:
- pickle.dump({"seed": world_seed, "name": create_world_name_text.strip(), "type": "infinite"}, f)
- print(f"Ustawienia świata zapisane do '{world_dir_path}/settings.dat'")
- menu_running = False
- dropdown_open_state = {}
- active_text_field = None
- return (world_seed, world_dir_name), create_world_name_text.strip(), None, True
- except Exception as e:
- print(f"Błąd zapisywania ustawień: {e}")
- else:
- world_data = generate_fixed_world(world_size_val, world_seed)
- if save_fixed_world(world_data, create_world_name_text.strip(), world_size_val):
- menu_running = False
- dropdown_open_state = {}
- active_text_field = None
- return world_data, create_world_name_text.strip(), world_size_val, False
- if draw_button(center_x - button_width // 2, button_y_start + button_height + field_spacing, button_width, button_height, "Powrót", font_medium, mouse_pos, mouse_clicked, animation_alpha=menu_alpha):
- menu_state = "singleplayer"
- active_text_field = None
- dropdown_open_state = {}
- elif menu_state == "settings":
- title_text = "Ustawienia"
- title_width = font_large.size(title_text)[0]
- draw_text_2d(center_x - title_width // 2, center_y - 200, title_text, font_large, alpha=menu_alpha)
- settings_menu_state = settings_menu_state if 'settings_menu_state' in locals() else "main_settings"
- if settings_menu_state == "main_settings":
- setting_width = 300
- setting_height = 40
- setting_spacing = 15
- setting_x = center_x - setting_width // 2
- setting_y_start = center_y - 100
- label_height = font_medium.get_linesize()
- label_text = "Czułość myszy:"
- label_y = setting_y_start - label_height - 5
- draw_text_2d(setting_x, label_y, label_text, font_medium, color=(200,200,200), alpha=menu_alpha)
- settings["mouse_sensitivity"], mouse_sensitivity_dragging = draw_slider(
- setting_x, setting_y_start, setting_width, setting_height, settings.get("mouse_sensitivity", DEFAULT_SETTINGS["mouse_sensitivity"]),
- 0.01, 1.0, font_medium, mouse_pos, mouse_clicked, mouse_sensitivity_dragging if 'mouse_sensitivity_dragging' in locals() else False, animation_alpha=menu_alpha
- )
- if mouse_sensitivity_dragging or (not mouse_sensitivity_dragging and pygame.mouse.get_pressed()[0] and
- setting_x < mouse_pos[0] < setting_x + setting_width and setting_y_start < mouse_pos[1] < setting_y_start + setting_height):
- mouse_clicked = False
- fov_y = setting_y_start + setting_height + setting_spacing
- label_text = "FOV:"
- label_y = fov_y - label_height - 5
- draw_text_2d(setting_x, label_y, label_text, font_medium, color=(200,200,200), alpha=menu_alpha)
- settings["fov"], fov_dragging = draw_slider(
- setting_x, fov_y, setting_width, setting_height, settings.get("fov", DEFAULT_SETTINGS["fov"]),
- 30.0, 110.0, font_medium, mouse_pos, mouse_clicked, fov_dragging if 'fov_dragging' in locals() else False, animation_alpha=menu_alpha
- )
- if fov_dragging or (not fov_dragging and pygame.mouse.get_pressed()[0] and
- setting_x < mouse_pos[0] < setting_x + setting_width and fov_y < mouse_pos[1] < fov_y + setting_height):
- mouse_clicked = False
- render_dist_y = fov_y + setting_height + setting_spacing
- label_text = "Odległość renderowania (chunks):"
- label_y = render_dist_y - label_height - 5
- draw_text_2d(setting_x, label_y, label_text, font_medium, color=(200,200,200), alpha=menu_alpha)
- current_render_dist = settings.get("render_distance", DEFAULT_SETTINGS["render_distance"])
- rendered_val, render_distance_dragging = draw_slider(
- setting_x, render_dist_y, setting_width, setting_height, current_render_dist,
- 2, 32, font_medium, mouse_pos, mouse_clicked, render_distance_dragging if 'render_distance_dragging' in locals() else False, animation_alpha=menu_alpha
- )
- settings["render_distance"] = int(round(rendered_val))
- if render_distance_dragging or (not render_distance_dragging and pygame.mouse.get_pressed()[0] and
- setting_x < mouse_pos[0] < setting_x + setting_width and render_dist_y < mouse_pos[1] < render_dist_y + setting_height):
- mouse_clicked = False
- checkbox_y_start = render_dist_y + setting_height + setting_spacing * 2
- checkbox_width = 30
- checkbox_height = 30
- settings["invert_mouse_x"] = draw_checkbox(
- setting_x, checkbox_y_start, checkbox_width, checkbox_height, "Odwróć oś X myszy",
- settings.get("invert_mouse_x", DEFAULT_SETTINGS["invert_mouse_x"]), font_medium, mouse_pos, mouse_clicked, animation_alpha=menu_alpha
- )
- invert_y_y = checkbox_y_start + checkbox_height + setting_spacing
- settings["invert_mouse_y"] = draw_checkbox(
- setting_x, invert_y_y, checkbox_width, checkbox_height, "Odwróć oś Y myszy",
- settings.get("invert_mouse_y", DEFAULT_SETTINGS["invert_mouse_y"]), font_medium, mouse_pos, mouse_clicked, animation_alpha=menu_alpha
- )
- button_y_start = invert_y_y + checkbox_height + setting_spacing * 2
- if draw_button(center_x - button_width // 2, button_y_start, button_width, button_height, "Paczki zasobów", font_medium, mouse_pos, mouse_clicked, animation_alpha=menu_alpha):
- settings_menu_state = "resource_packs"
- resource_manager.scan_resource_packs()
- dropdown_open_state = {}
- if draw_button(center_x - button_width // 2, button_y_start + button_height + button_spacing, button_width, button_height, "Gotowe", font_medium, mouse_pos, mouse_clicked, animation_alpha=menu_alpha):
- try:
- with open("settings.dat", "wb") as f:
- pickle.dump(settings, f)
- except Exception as e:
- print(f"Błąd zapisywania ustawień: {e}")
- menu_state = "main"
- dropdown_open_state = {}
- elif settings_menu_state == "resource_packs":
- title_text = "Paczki zasobów"
- title_width = font_large.size(title_text)[0]
- draw_text_2d(center_x - title_width // 2, center_y - 200, title_text, font_large, alpha=menu_alpha)
- list_x = center_x - button_width // 2
- list_y = center_y - 100
- list_width = button_width + 100
- list_item_height = 40
- list_spacing = 5
- draw_text_2d(list_x, list_y - 25, "Dostępne paczki:", font_small, color=(200,200,200), alpha=menu_alpha)
- max_visible_list_items = 6
- actual_display_packs = min(max_visible_list_items, len(resource_manager.available_packs))
- if resource_manager.available_packs:
- for i in range(actual_display_packs):
- pack_name = resource_manager.available_packs[i]
- item_y = list_y + i * (list_item_height + list_spacing)
- item_color = (0.3, 0.3, 0.3) if pack_name != resource_pack_selected_pack else (0.4, 0.4, 0.4)
- is_hovered = list_x < mouse_pos[0] < list_x + list_width and item_y < mouse_pos[1] < item_y + list_item_height
- draw_quad_2d(list_x, item_y, list_width, list_item_height, color=item_color, alpha=menu_alpha)
- if is_hovered:
- draw_line_loop_2d(list_x, item_y, list_width, list_item_height, color=(0.6, 0.6, 0.6), alpha=menu_alpha)
- text_x = list_x + 10
- text_y = item_y + (list_item_height - font_small.get_linesize()) // 2
- draw_text_2d(text_x, text_y, pack_name, font_small, alpha=menu_alpha)
- if is_hovered and mouse_clicked:
- resource_pack_selected_pack = pack_name
- else:
- draw_text_2d(list_x, list_y, "Brak innych paczek zasobów", font_small, color=(150,150,150), alpha=menu_alpha)
- button_y_start = list_y + max_visible_list_items * (list_item_height + list_spacing) + 20
- if draw_button(center_x - button_width // 2, button_y_start, button_width, button_height, "Aktywuj", font_medium, mouse_pos, mouse_clicked, animation_alpha=menu_alpha):
- settings["resource_pack"] = resource_pack_selected_pack
- resource_manager.activate_resource_pack(resource_pack_selected_pack)
- print(f"Aktywowano: {resource_pack_selected_pack}")
- settings_menu_state = "main_settings"
- dropdown_open_state = {}
- try:
- with open("settings.dat", "wb") as f:
- pickle.dump(settings, f)
- except Exception as e:
- print(f"Błąd zapisywania ustawień: {e}")
- if draw_button(center_x - button_width // 2, button_y_start + button_height + button_spacing, button_width, button_height, "Powrót", font_medium, mouse_pos, mouse_clicked, animation_alpha=menu_alpha):
- settings_menu_state = "main_settings"
- dropdown_open_state = {}
- restore_3d_projection()
- pygame.display.flip()
- clock.tick(60)
- return None
- def show_pause_menu(world_data, world_name_display, size, resource_manager, is_infinite):
- global display, settings, font_large, font_medium
- clock = pygame.time.Clock()
- pygame.mouse.set_visible(True)
- pygame.event.set_grab(False)
- pause_menu_state = "main_pause"
- mouse_sensitivity_dragging = False
- fov_dragging = False
- render_distance_dragging = False
- pause_running = True
- while pause_running:
- mouse_pos = pygame.mouse.get_pos()
- mouse_clicked = False
- for event in pygame.event.get():
- if event.type == QUIT:
- print("Wyjście z aplikacji.")
- if is_infinite and isinstance(world_data, ChunkManager):
- world_data.save_all_chunks()
- elif world_data is not None and size is not None:
- save_fixed_world(world_data, world_name_display, size)
- try:
- with open("settings.dat", "wb") as f:
- pickle.dump(settings, f)
- except Exception as e:
- print(f"Błąd zapisywania ustawień: {e}")
- return False
- if event.type == VIDEORESIZE:
- display = (event.w, event.h)
- if display[0] > 0 and display[1] > 0:
- pygame.display.set_mode(display, DOUBLEBUF | OPENGL | RESIZABLE)
- else:
- print(f"Niepoprawny rozmiar okna: {display}")
- if event.type == MOUSEBUTTONDOWN and event.button == 1:
- mouse_clicked = True
- if pause_menu_state == "settings_pause" and (mouse_sensitivity_dragging or fov_dragging or render_distance_dragging):
- mouse_clicked = False
- if event.type == KEYDOWN and event.key == K_ESCAPE:
- if pause_menu_state == "main_pause":
- print("Wznów grę.")
- pause_running = False
- elif pause_menu_state == "settings_pause":
- try:
- with open("settings.dat", "wb") as f:
- pickle.dump(settings, f)
- except Exception as e:
- print(f"Błąd zapisywania ustawień: {e}")
- pause_menu_state = "main_pause"
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
- draw_background(resource_manager, alpha=1.0)
- setup_2d_overlay()
- draw_quad_2d(0, 0, display[0], display[1], color=(0.1, 0.1, 0.1), alpha=0.7)
- center_x = display[0] // 2
- center_y = display[1] // 2
- button_width = 200
- button_height = 50
- button_spacing = 15
- if pause_menu_state == "main_pause":
- title_text = "Gra wstrzymana"
- title_width = font_large.size(title_text)[0]
- draw_text_2d(center_x - title_width // 2, center_y - 150, title_text, font_large)
- if draw_button(center_x - button_width // 2, center_y - button_height - button_spacing // 2, button_width, button_height, "Wznów grę", font_medium, mouse_pos, mouse_clicked):
- pause_running = False
- if draw_button(center_x - button_width // 2, center_y + button_spacing // 2, button_width, button_height, "Ustawienia", font_medium, mouse_pos, mouse_clicked):
- pause_menu_state = "settings_pause"
- if draw_button(center_x - button_width // 2, center_y + button_height + button_spacing * 3 // 2, button_width, button_height, "Zapisz i wyjdź", font_medium, mouse_pos, mouse_clicked):
- print("Zapisz i wróć do menu.")
- if is_infinite and isinstance(world_data, ChunkManager):
- world_data.save_all_chunks()
- elif world_data is not None and size is not None:
- save_fixed_world(world_data, world_name_display, size)
- try:
- with open("settings.dat", "wb") as f:
- pickle.dump(settings, f)
- except Exception as e:
- print(f"Błąd zapisywania ustawień: {e}")
- pause_running = False
- return True
- elif pause_menu_state == "settings_pause":
- title_text = "Ustawienia"
- title_width = font_large.size(title_text)[0]
- draw_text_2d(center_x - title_width // 2, center_y - 200, title_text, font_large)
- setting_width = 300
- setting_height = 40
- setting_spacing = 15
- setting_x = center_x - setting_width // 2
- setting_y_start = center_y - 100
- label_height = font_medium.get_linesize()
- label_text = "Czułość myszy:"
- label_y = setting_y_start - label_height - 5
- draw_text_2d(setting_x, label_y, label_text, font_medium, color=(200,200,200))
- settings["mouse_sensitivity"], mouse_sensitivity_dragging = draw_slider(
- setting_x, setting_y_start, setting_width, setting_height, settings.get("mouse_sensitivity", DEFAULT_SETTINGS["mouse_sensitivity"]),
- 0.01, 1.0, font_medium, mouse_pos, mouse_clicked, mouse_sensitivity_dragging
- )
- if mouse_sensitivity_dragging or (not mouse_sensitivity_dragging and pygame.mouse.get_pressed()[0] and
- setting_x < mouse_pos[0] < setting_x + setting_width and setting_y_start < mouse_pos[1] < setting_y_start + setting_height):
- mouse_clicked = False
- fov_y = setting_y_start + setting_height + setting_spacing
- label_text = "FOV:"
- label_y = fov_y - label_height - 5
- draw_text_2d(setting_x, label_y, label_text, font_medium, color=(200,200,200))
- settings["fov"], fov_dragging = draw_slider(
- setting_x, fov_y, setting_width, setting_height, settings.get("fov", DEFAULT_SETTINGS["fov"]),
- 30.0, 110.0, font_medium, mouse_pos, mouse_clicked, fov_dragging
- )
- if fov_dragging or (not fov_dragging and pygame.mouse.get_pressed()[0] and
- setting_x < mouse_pos[0] < setting_x + setting_width and fov_y < mouse_pos[1] < fov_y + setting_height):
- mouse_clicked = False
- if is_infinite:
- render_dist_y = fov_y + setting_height + setting_spacing
- label_text = "Odległość renderowania (chunks):"
- label_y = render_dist_y - label_height - 5
- draw_text_2d(setting_x, label_y, label_text, font_medium, color=(200,200,200))
- current_render_dist = settings.get("render_distance", DEFAULT_SETTINGS["render_distance"])
- rendered_val, render_distance_dragging = draw_slider(
- setting_x, render_dist_y, setting_width, setting_height, current_render_dist,
- 2, 32, font_medium, mouse_pos, mouse_clicked, render_distance_dragging
- )
- settings["render_distance"] = int(round(rendered_val))
- if render_distance_dragging or (not render_distance_dragging and pygame.mouse.get_pressed()[0] and
- setting_x < mouse_pos[0] < setting_x + setting_width and render_dist_y < mouse_pos[1] < render_dist_y + setting_height):
- mouse_clicked = False
- checkbox_y_start = render_dist_y + setting_height + setting_spacing * 2
- else:
- checkbox_y_start = fov_y + setting_height + setting_spacing * 2
- checkbox_width = 30
- checkbox_height = 30
- settings["invert_mouse_x"] = draw_checkbox(
- setting_x, checkbox_y_start, checkbox_width, checkbox_height, "Odwróć oś X myszy",
- settings.get("invert_mouse_x", DEFAULT_SETTINGS["invert_mouse_x"]), font_medium, mouse_pos, mouse_clicked
- )
- invert_y_y = checkbox_y_start + checkbox_height + setting_spacing
- settings["invert_mouse_y"] = draw_checkbox(
- setting_x, invert_y_y, checkbox_width, checkbox_height, "Odwróć oś Y myszy",
- settings.get("invert_mouse_y", DEFAULT_SETTINGS["invert_mouse_y"]), font_medium, mouse_pos, mouse_clicked
- )
- button_y_start = invert_y_y + checkbox_height + setting_spacing * 2
- if draw_button(center_x - button_width // 2, button_y_start, button_width, button_height, "Powrót", font_medium, mouse_pos, mouse_clicked):
- try:
- with open("settings.dat", "wb") as f:
- pickle.dump(settings, f)
- except Exception as e:
- print(f"Błąd zapisywania ustawień: {e}")
- pause_menu_state = "main_pause"
- restore_3d_projection()
- pygame.display.flip()
- clock.tick(60)
- return False
- def show_delete_confirmation(world_name, resource_manager):
- global display, font_medium
- clock = pygame.time.Clock()
- print(f"POTWIERDZENIE USUWANIA: {world_name}")
- while True:
- mouse_pos = pygame.mouse.get_pos()
- mouse_clicked = False
- for event in pygame.event.get():
- if event.type == QUIT:
- print("Wyjście z aplikacji.")
- return None
- if event.type == VIDEORESIZE:
- display = (event.w, event.h)
- if display[0] > 0 and display[1] > 0:
- pygame.display.set_mode(display, DOUBLEBUF | OPENGL | RESIZABLE)
- else:
- print(f"Niepoprawny rozmiar okna: {display}")
- if event.type == MOUSEBUTTONDOWN and event.button == 1:
- mouse_clicked = True
- if event.type == KEYDOWN and event.key == K_ESCAPE:
- print("Anuluj usuwanie.")
- return False
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
- setup_2d_overlay()
- draw_quad_2d(0, 0, display[0], display[1], color=(0.1, 0.1, 0.1), alpha=0.7)
- window_width = 400
- window_height = 200
- window_x = (display[0] - window_width) // 2
- window_y = (display[1] - window_height) // 2
- draw_confirm_window(window_x, window_y, window_width, window_height)
- question_text = "Czy usunąć świat?"
- question_width = font_medium.size(question_text)[0]
- draw_text_2d(window_x + (window_width - question_width) // 2, window_y + 40, question_text, font_medium)
- max_name_width = window_width - 40
- truncated_world_name = world_name
- if font_medium.size(truncated_world_name)[0] > max_name_width:
- while font_medium.size(truncated_world_name + "...")[0] > max_name_width and len(truncated_world_name) > 0:
- truncated_world_name = truncated_world_name[:-1]
- truncated_world_name += "..."
- name_text = f"'{truncated_world_name}'?"
- name_width = font_medium.size(name_text)[0]
- draw_text_2d(window_x + (window_width - name_width) // 2, window_y + 80, name_text, font_medium)
- button_width = 100
- button_height = 40
- button_spacing = 20
- button_start_x = window_x + (window_width - 2 * button_width - button_spacing) // 2
- button_y = window_y + window_height - 60
- if draw_button(button_start_x, button_y, button_width, button_height, "Tak", font_medium, mouse_pos, mouse_clicked):
- print(f"Usuwam '{world_name}'")
- restore_3d_projection()
- return True
- if draw_button(button_start_x + button_width + button_spacing, button_y, button_width, button_height, "Nie", font_medium, mouse_pos, mouse_clicked):
- print("Anuluj usuwanie")
- restore_3d_projection()
- return False
- restore_3d_projection()
- pygame.display.flip()
- clock.tick(60)
- dropdown_open_state = {}
- def main():
- global settings, display, font_small, font_medium, font_large, font_height, dropdown_open_state
- try:
- font_small = pygame.font.Font(None, 24)
- font_medium = pygame.font.Font(None, 32)
- font_large = pygame.font.Font(None, 48)
- font_height = font_medium.get_linesize()
- except pygame.error as e:
- print(f"Błąd ładowania czcionki: {e}")
- resource_manager = ResourceManager()
- settings_file = "settings.dat"
- if os.path.exists(settings_file):
- try:
- with open(settings_file, "rb") as f:
- loaded_settings = pickle.load(f)
- for key in DEFAULT_SETTINGS:
- if key in loaded_settings:
- expected_type = type(DEFAULT_SETTINGS[key])
- loaded_value = loaded_settings[key]
- if isinstance(loaded_value, expected_type):
- if isinstance(DEFAULT_SETTINGS[key], (int, float)) and loaded_value >= 0:
- settings[key] = loaded_value
- elif isinstance(loaded_value, (int, float)) and isinstance(DEFAULT_SETTINGS[key], (int, float)):
- settings[key] = expected_type(loaded_value)
- except Exception as e:
- print(f"Błąd wczytywania ustawień: {e}")
- for key, default_value in DEFAULT_SETTINGS.items():
- if key not in settings:
- settings[key] = default_value
- resource_pack_name = settings.get("resource_pack", "Brak")
- if resource_pack_name not in resource_manager.available_packs:
- print(f"Pack '{resource_pack_name}' nie znaleziono. Używam 'Brak'.")
- settings["resource_pack"] = "Brak"
- resource_pack_name = "Brak"
- resource_manager.activate_resource_pack(resource_pack_name)
- running = True
- while running:
- dropdown_open_state = {}
- world_data_tuple = show_main_menu(resource_manager)
- if world_data_tuple is None:
- running = False
- break
- world_data, world_name_display, size, is_infinite = world_data_tuple
- if world_data is None:
- print("Nie udało się wczytać świata. Wracam do menu.")
- continue
- # Inicjalizacja gry
- clock = pygame.time.Clock()
- pygame.mouse.set_visible(False)
- pygame.event.set_grab(True)
- # Pozycja i rotacja gracza
- player_pos = [size / 2, size / 2 + 2, size / 2] if not is_infinite else [0, 64, 0]
- player_velocity = [0, 0, 0]
- player_on_ground = False
- yaw, pitch = 0, 0
- selected_block_type = 1 # Domyślny blok do stawiania
- # Ustawienia kamery
- gluPerspective(settings["fov"], display[0] / display[1], 0.1, settings["render_distance"] * CHUNK_SIZE * 2)
- glMatrixMode(GL_MODELVIEW)
- glLoadIdentity()
- # Chunk manager dla światów nieskończonych
- chunk_manager = None
- if is_infinite:
- seed, world_dir_name = world_data
- chunk_manager = ChunkManager(seed=seed, render_distance_chunks=settings["render_distance"], world_name_dir=world_dir_name)
- world_data = chunk_manager
- start_y = 60
- for y in range(255, -1, -1):
- block = chunk_manager.get_block(0, y, 0)
- print(f"Sprawdzam y={y}, block={block}")
- if block != BLOCK_AIR:
- start_y = y + 2
- break
- player_pos = [0, start_y, 0]
- print(f"Pozycja startowa gracza: {player_pos}")
- game_running = True
- while game_running:
- dt = clock.tick(60) / 1000.0 # Delta time w sekundach
- mouse_dx, mouse_dy = pygame.mouse.get_rel()
- mouse_sensitivity = settings["mouse_sensitivity"]
- invert_x = settings["invert_mouse_x"]
- invert_y = settings["invert_mouse_y"]
- yaw -= mouse_dx * mouse_sensitivity * (-1 if invert_x else 1)
- pitch -= mouse_dy * mouse_sensitivity * (-1 if invert_y else 1)
- pitch = max(-89.9, min(89.9, pitch)) # Ogranicz pitch
- # Input gracza
- keys = pygame.key.get_pressed()
- move_dir = [0, 0, 0]
- if keys[pygame.K_w]:
- move_dir[0] -= math.cos(math.radians(yaw)) * settings["move_speed"]
- move_dir[2] -= math.sin(math.radians(yaw)) * settings["move_speed"]
- if keys[pygame.K_s]:
- move_dir[0] += math.cos(math.radians(yaw)) * settings["move_speed"]
- move_dir[2] += math.sin(math.radians(yaw)) * settings["move_speed"]
- if keys[pygame.K_a]:
- move_dir[0] -= math.cos(math.radians(yaw + 90)) * settings["move_speed"]
- move_dir[2] -= math.sin(math.radians(yaw + 90)) * settings["move_speed"]
- if keys[pygame.K_d]:
- move_dir[0] += math.cos(math.radians(yaw + 90)) * settings["move_speed"]
- move_dir[2] += math.sin(math.radians(yaw + 90)) * settings["move_speed"]
- if keys[pygame.K_SPACE] and player_on_ground:
- player_velocity[1] = settings["jump_force"]
- player_on_ground = False
- # Grawitacja i ruch
- player_velocity[1] -= settings["gravity"] * dt * 60
- player_velocity[0] = move_dir[0]
- player_velocity[2] = move_dir[2]
- # Kolizje
- def is_colliding(pos):
- for dx in [-0.3, 0, 0.3]:
- for dy in [0, 1.8]:
- for dz in [-0.3, 0, 0.3]:
- block_x = int(math.floor(pos[0] + dx))
- block_y = int(math.floor(pos[1] + dy))
- block_z = int(math.floor(pos[2] + dz))
- block = chunk_manager.get_block(block_x, block_y, block_z) if is_infinite else \
- world_data[block_x][block_y][block_z] if 0 <= block_x < size and 0 <= block_y < size and 0 <= block_z < size else BLOCK_AIR
- if block != BLOCK_AIR:
- return True
- return False
- for i in range(3):
- new_pos = player_pos.copy()
- new_pos[i] += player_velocity[i] * dt * 60
- if not is_colliding(new_pos):
- player_pos[i] = new_pos[i]
- else:
- player_velocity[i] = 0
- if i == 1 and player_velocity[1] <= 0:
- player_on_ground = True
- # Aktualizacja chunków
- if is_infinite:
- chunk_manager.update_loaded_chunks(player_pos)
- # Raycasting do interakcji z blokami
- def raycast(start_pos, direction, max_distance=5):
- pos = start_pos.copy()
- step = [1 if d > 0 else -1 for d in direction]
- t_delta = [abs(1 / d) if d != 0 else float('inf') for d in direction]
- max_steps = int(max_distance / 0.1)
- block_pos = [int(math.floor(p)) for p in pos]
- t_max = [(1 - (p - block_pos[i])) / direction[i] if direction[i] > 0 else (p - block_pos[i]) / -direction[i] if direction[i] < 0 else float('inf') for i, p in enumerate(pos)]
- for _ in range(max_steps):
- block = chunk_manager.get_block(*block_pos) if is_infinite else \
- world_data[block_pos[0]][block_pos[1]][block_pos[2]] if 0 <= block_pos[0] < size and 0 <= block_pos[1] < size and 0 <= block_pos[2] < size else BLOCK_AIR
- if block != BLOCK_AIR:
- return block_pos, [block_pos[i] + (0 if direction[i] > 0 else 1) for i in range(3)]
- min_t = min(enumerate(t_max), key=lambda x: x[1])[0]
- block_pos[min_t] += step[min_t]
- t_max[min_t] += t_delta[min_t]
- return None, None
- direction = [
- -math.cos(math.radians(yaw)) * math.cos(math.radians(pitch)),
- -math.sin(math.radians(pitch)),
- -math.sin(math.radians(yaw)) * math.cos(math.radians(pitch))
- ]
- # Zdarzenia
- for event in pygame.event.get():
- if event.type == QUIT:
- if is_infinite:
- chunk_manager.save_all_chunks()
- elif size is not None:
- save_fixed_world(world_data, world_name_display, size)
- running = False
- game_running = False
- if event.type == VIDEORESIZE:
- display = (event.w, event.h)
- if display[0] > 0 and display[1] > 0:
- pygame.display.set_mode(display, DOUBLEBUF | OPENGL | RESIZABLE)
- gluPerspective(settings["fov"], display[0] / display[1], 0.1, settings["render_distance"] * CHUNK_SIZE * 2)
- else:
- print(f"Niepoprawny rozmiar okna: {display}")
- if event.type == KEYDOWN:
- if event.key == K_ESCAPE:
- return_to_menu = show_pause_menu(world_data, world_name_display, size, resource_manager, is_infinite)
- if return_to_menu:
- game_running = False
- pygame.mouse.set_visible(True)
- pygame.event.set_grab(False)
- print("Po pauzie: kursor włączony")
- if event.key == K_e:
- print("Otwarto ekwipunek (placeholder).")
- if event.type == MOUSEBUTTONDOWN:
- block_pos, adjacent_pos = raycast(player_pos, direction)
- if event.button == 1 and block_pos: # LPM - usuń blok
- if is_infinite:
- chunk_manager.set_block(*block_pos, BLOCK_AIR)
- elif 0 <= block_pos[0] < size and 0 <= block_pos[1] < size and 0 <= block_pos[2] < size:
- world_data[block_pos[0]][block_pos[1]][block_pos[2]] = BLOCK_AIR
- print(f"Usunięto blok na {block_pos}")
- if event.button == 3 and adjacent_pos: # PPM - postaw blok
- if is_infinite:
- if not is_colliding([adjacent_pos[0] + 0.5, adjacent_pos[1] + 0.5, adjacent_pos[2] + 0.5]):
- chunk_manager.set_block(*adjacent_pos, selected_block_type)
- print(f"Postawiono blok {BLOCK_TYPES_TO_INV_NAMES[selected_block_type]} na {adjacent_pos}")
- elif 0 <= adjacent_pos[0] < size and 0 <= adjacent_pos[1] < size and 0 <= adjacent_pos[2] < size:
- if not is_colliding([adjacent_pos[0] + 0.5, adjacent_pos[1] + 0.5, adjacent_pos[2] + 0.5]):
- world_data[adjacent_pos[0]][adjacent_pos[1]][adjacent_pos[2]] = selected_block_type
- print(f"Postawiono blok {BLOCK_TYPES_TO_INV_NAMES[selected_block_type]} na {adjacent_pos}")
- # Renderowanie
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
- print(f"Stos macierzy przed: {glGetIntegerv(GL_MATRIX_MODE)}")
- glLoadIdentity()
- gluLookAt(
- player_pos[0], player_pos[1] + 1.6, player_pos[2],
- player_pos[0] + direction[0], player_pos[1] + 1.6 + direction[1], player_pos[2] + direction[2],
- 0, 1, 0
- )
- print(f"Stos macierzy po kamery: {glGetIntegerv(GL_MATRIX_MODE)}")
- draw_world(world_data, player_pos, settings, resource_manager, BLOCK_TEXTURE_PATHS, is_infinite)
- # HUD
- setup_2d_overlay()
- crosshair_size = 10
- draw_lines_2d(
- [
- (display[0] / 2 - crosshair_size, display[1] / 2),
- (display[0] / 2 + crosshair_size, display[1] / 2),
- (display[0] / 2, display[1] / 2 - crosshair_size),
- (display[0] / 2, display[1] / 2 + crosshair_size)
- ],
- color=(1, 1, 1), line_width=2
- )
- fps_text = f"FPS: {int(clock.get_fps())}"
- draw_text_2d(10, 10, fps_text, font_small)
- restore_3d_projection()
- pygame.display.flip()
- # Zapis świata przy wyjściu z gry
- if is_infinite:
- chunk_manager.save_all_chunks()
- elif size is not None:
- save_fixed_world(world_data, world_name_display, size)
- try:
- with open("settings.dat", "wb") as f:
- pickle.dump(settings, f)
- except Exception as e:
- print(f"Błąd zapisywania ustawień: {e}")
- # Zamykanie gry
- resource_manager.clear_texture_cache()
- pygame.quit()
- if __name__ == "__main__":
- try:
- main()
- except Exception as e:
- print(f"Błąd: {e}")
- traceback.print_exc()
- pygame.quit()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement