def get_pos_delta_on_input(inp, map_, x, y, jump, flight): player_slice = map_[x] feet_y = y head_y = y - 1 below_y = y + 1 above_y = y - 2 dx = -1 * ('a' in inp) + 1 * ('d' in inp) dx, dy = get_pos_delta(dx, x, y, map_) # Jumps if up pressed, block below, no block above if ( 'w' in inp and y > 1 and (not is_solid( player_slice[above_y] ) and ( is_solid( player_slice[below_y] ) or player_slice[feet_y] == '=' ) or flight)): dy = -1 jump = 6 if (flight and 's' in inp and head_y < world_gen['height'] and (not is_solid(player_slice[below_y]))): dy = 1 return dx, dy, jump
def spawn(mobs, players, map_, x_start_range, y_start_range, x_end_range, y_end_range): log("spawning", x_start_range, x_end_range, m='mobs') n_mobs_to_spawn = random.randint(0, 5) if random.random() < mob_rate else 0 new_mobs = {} max_attempts = 100 * n_mobs_to_spawn attempts = 0 while (len(mobs) + len(new_mobs) < mob_limit and len(new_mobs) < n_mobs_to_spawn and attempts < max_attempts): attempts += 1 mx = random.randint(x_start_range, x_end_range - 1) my = random.randint(y_start_range, y_end_range - 1) if mx not in map_ or my < 1 or my > len(map_[mx]) - 2: continue feet = map_[mx][my] head = map_[mx][my - 1] floor = map_[mx][my + 1] closest_player_dist = min( map(lambda p: abs(p['x'] - mx), players.values())) spot_found = (not terrain.is_solid(feet) and not terrain.is_solid(head) and terrain.is_solid(floor) and render_interface.get_light_level( mx, my) < max_spawn_light_level and render_interface.get_light_level( mx, my - 1) < max_spawn_light_level and not closest_player_dist < spawn_player_range_min) if spot_found: new_mobs[str(uuid4())] = { 'x': mx, 'y': my, 'x_vel': 0, 'health': max_mob_health, 'type': 'mob', 'last_attack': 0 } mobs.update(new_mobs) return new_mobs
def get_char(x, y, map_, pixel): left = get_block(x-1, y, map_) right = get_block(x+1, y, map_) below = get_block(x, y+1, map_) char = blocks[pixel]['char'] if below is None or not is_solid(below): if left is not None and is_solid(left) and 'char_left' in blocks[pixel]: char = blocks[pixel]['char_left'] elif right is not None and is_solid(right) and 'char_right' in blocks[pixel]: char = blocks[pixel]['char_right'] return char
def pathfind_towards_delta(entity, delta, map_): updated = False kill_entity = False ex = entity['x'] ey = entity['y'] x_vel = entity['x_vel'] x_vel += delta / 100 if abs(x_vel) > 1: x_vel = x_vel / abs(x_vel) dx = round(x_vel) if (ex + dx - 1 not in map_.keys() or ex + dx not in map_.keys() or ex + dx + 1 not in map_.keys()): kill_entity = True else: dx, dy = player.get_pos_delta(dx, ex, ey, map_) ex, ey = ex + dx, ey + dy if not terrain.is_solid(map_[ex][ey + 1]): ey += 1 entity['x'] = ex entity['y'] = ey entity['x_vel'] = x_vel updated = True return updated, kill_entity
def spawn(mobs, players, map_, x_start_range, y_start_range, x_end_range, y_end_range): log("spawning", x_start_range, x_end_range, m='mobs'); n_mobs_to_spawn = random.randint(0, 5) if random.random() < mob_rate else 0 new_mobs = {} max_attempts = 100 * n_mobs_to_spawn attempts = 0 while (len(mobs) + len(new_mobs) < mob_limit and len(new_mobs) < n_mobs_to_spawn and attempts < max_attempts): attempts += 1 mx = random.randint(x_start_range, x_end_range-1) my = random.randint(y_start_range, y_end_range-1) if mx not in map_ or my < 1 or my > len(map_[mx]) - 2: continue feet = map_[mx][my] head = map_[mx][my - 1] floor = map_[mx][my + 1] closest_player_dist = min(map(lambda p: abs(p['x'] - mx), players.values())) spot_found = (not terrain.is_solid(feet) and not terrain.is_solid(head) and terrain.is_solid(floor) and render_interface.get_light_level(mx, my) < max_spawn_light_level and render_interface.get_light_level(mx, my - 1) < max_spawn_light_level and not closest_player_dist < spawn_player_range_min) if spot_found: new_mobs[str(uuid4())] = { 'x': mx, 'y': my, 'x_vel': 0, 'health': max_mob_health, 'type': 'mob', 'last_attack': 0 } mobs.update(new_mobs) return new_mobs
def get_char(x, y, map_, pixel): left = get_block(x - 1, y, map_) right = get_block(x + 1, y, map_) below = get_block(x, y + 1, map_) char = blocks[pixel]['char'] if below is None or not is_solid(below): if left is not None and is_solid( left) and 'char_left' in blocks[pixel]: char = blocks[pixel]['char_left'] elif right is not None and is_solid( right) and 'char_right' in blocks[pixel]: char = blocks[pixel]['char_right'] return char
def get_pos_delta(dx, x, y, map_): player_slice = map_[x] feet_y = y head_y = y - 1 below_y = y + 1 above_y = y - 2 dy = 0 next_slice = map_[x + dx] checked_dx = 0 if not is_solid(next_slice[head_y]): if is_solid( next_slice[feet_y] ): if ( not is_solid( next_slice[above_y] ) and not is_solid( player_slice[above_y] )): dy = -1 checked_dx = dx else: checked_dx = dx return checked_dx, dy
def get_pos_delta(char, map_, x, y, jump, flight): left_slice = map_[x - 1] player_slice = map_[x] right_slice = map_[x + 1] feet_y = y head_y = y - 1 below_y = y + 1 above_y = y - 2 dy = 0 dx = 0 # Calculate change in x pos for left and right movement for test_char, dir_, next_slice in (('a', -1, left_slice), ('d', 1, right_slice)): if ( char in test_char and not is_solid( next_slice[head_y] )): if is_solid( next_slice[feet_y] ): if ( not is_solid( next_slice[above_y] ) and not is_solid( player_slice[above_y] )): dy = -1 dx = dir_ else: dx = dir_ # Jumps if up pressed, block below, no block above if ( char in 'w' and y > 1 and (not is_solid( player_slice[above_y] ) and ( is_solid( player_slice[below_y] ) or player_slice[feet_y] == '=' ) or flight)): dy = -1 jump = 5 if (flight and char in 's' and head_y < world_gen['height'] and (not is_solid(player_slice[below_y]))): dy = 1 return dx, dy, jump
def get_pos_delta(char, map_, x, y, blocks, jump): left_slice = map_[x - 1] player_slice = map_[x] right_slice = map_[x + 1] feet_y = y head_y = y - 1 below_y = y + 1 above_y = y - 2 dy = 0 dx = 0 is_solid = lambda block: terrain.is_solid(blocks, block) # Calculate change in x pos for left and right movement for test_char, dir_, func in (("a", -1, left_slice), ("d", 1, right_slice)): if char in test_char and not is_solid(func[head_y]): if is_solid(func[feet_y]): if not is_solid(func[above_y]) and not is_solid(player_slice[above_y]): dy = -1 dx = dir_ else: dx = dir_ # Jumps if up pressed, block below, no block above if ( char in "w" and y > 1 and not is_solid(player_slice[above_y]) and (is_solid(player_slice[below_y]) or player_slice[feet_y] == "=") ): dy = -1 jump = 5 return dx, dy, jump
def light_mask(x, y, map_, slice_heights): if is_solid(map_[x][y]) or (world_gen['height'] - y) < slice_heights[x]: z = 0 else: z = -1 return z
def game(server, settings, benchmarks): dt = 0 # Tick df = 0 # Frame dc = 0 # Cursor ds = 0 # Selector dpos = False dinv = False # Inventory dcraft = False # Crafting FPS = 15 # Max MPS = 15 # Movement SPS = 5 # Mob spawns old_bk_objects = None old_edges = None redraw_all = True last_move = time() last_mob_spawn = time() inp = None jump = 0 cursor = 0 crafting = False crafting_sel = 0 crafting_list = [] inv_sel = 0 cursor_hidden = True new_blocks = {} alive = True events = [] crafting_list, crafting_sel = player.get_crafting( server.inv, crafting_list, crafting_sel ) # Game loop with NonBlockingInput() as nbi: while server.game: x, y = server.pos dt = server.dt() frame_start = time() ## Input char = True inp = [] while char: # Receive input if a key is pressed char = nbi.char() if char: char = str(char).lower() if char in 'wasdhkjliuoc-=\n ': inp.append(char) # Hard pause if DEBUG and '\n' in inp: input() inp.remove('\n') # Pause game if ' ' in inp or '\n' in inp: server.redraw = True redraw_all = True if ui.pause(server, settings) == 'exit': server.logout() continue width = settings.get('width') height = settings.get('height') # Update player and mobs position / damage move_period = 1 / MPS while frame_start >= move_period + last_move and x in server.map_: dx, dy, jump = player.get_pos_delta_on_input( inp, server.map_, x, y, jump, settings.get('flight')) if dx or dy: dpos = True x += dx y += dy if x in server.map_ and not settings.get('flight'): # Player falls when no solid block below it and not jumping jump -= dt if jump <= 0: jump = 0 if not terrain.is_solid(server.map_[x][y + 1]): # Fall y += 1 dpos = True if 'h' in inp: item = render.blocks[server.inv[inv_sel]['block']] if len(server.inv) else {} server.player_attack(item.get('attack_radius', 5), item.get('attack_damage', 10)) server.update_items() server.update_mobs() if server.health <= 0: alive = False last_move += move_period ## Update Map # Finds display boundaries edges = (x - int(width / 2), x + int(width / 2)) edges_y = (y - int(height / 2), y + int(height / 2)) if edges_y[1] > data.world_gen['height']: edges_y = (data.world_gen['height'] - height, data.world_gen['height']) elif edges_y[0] < 0: edges_y = (0, height) extended_edges = (edges[0]-render.max_light, edges[1]+render.max_light) slice_list = terrain.detect_edges(server.map_, extended_edges) if slice_list: log('slices to load', slice_list) chunk_list = terrain.get_chunk_list(slice_list) server.get_chunks(chunk_list) server.unload_slices(extended_edges) # Moving view if not edges == old_edges or server.view_change: extended_view = terrain.move_map(server.map_, extended_edges) old_edges = edges server.redraw = True server.view_change = False # Sun has moved bk_objects, sky_colour, day = render.bk_objects(server.time, width, edges[0], settings.get('fancy_lights')) if not bk_objects == old_bk_objects: old_bk_objects = bk_objects server.redraw = True if settings.get('gravity'): blocks = terrain.apply_gravity(server.map_, extended_edges) if blocks: server.set_blocks(blocks) ## Crafting if 'c' in inp: server.redraw = True crafting = not crafting and len(crafting_list) dcraft, dcraftC, dcraftN = False, False, False if dinv: crafting = False if crafting: # Craft if player pressed craft server.inv, inv_sel, crafting_list, dcraftC = \ player.crafting(inp, server.inv, inv_sel, crafting_list, crafting_sel) # Increment/decrement craft no. crafting_list, dcraftN = \ player.craft_num(inp, server.inv, crafting_list, crafting_sel) dcraft = dcraftC or dcraftN # Update crafting list crafting_list, crafting_sel = \ player.get_crafting(server.inv, crafting_list, crafting_sel, dcraftC) if not len(crafting_list): crafting = False dc = player.move_cursor(inp) cursor = (cursor + dc) % 6 ds = player.move_sel(inp) if crafting: crafting_sel = ((crafting_sel + ds) % len(crafting_list) if len(crafting_list) else 0) else: inv_sel = ((inv_sel + ds) % len(server.inv) if len(server.inv) else 0) if any((dpos, dc, ds, dinv, dcraft)): server.redraw = True if dpos: dpos = False server.pos = x, y cursor_hidden = True if dc: cursor_hidden = False ## Eating or placing blocks p_hungry = server.health < player.MAX_PLAYER_HEALTH new_blocks, server.inv, inv_sel, new_events, dhealth, dinv = \ player.cursor_func( inp, server.map_, x, y, cursor, inv_sel, server.inv, p_hungry ) server.add_health(dhealth) if new_blocks: server.set_blocks(new_blocks) ## Process events events += new_events new_blocks = {} for i in range(int(dt)): new_blocks.update(process_events(events, server)) if new_blocks: server.set_blocks(new_blocks) # If no block below, kill player try: block = server.map_[x][y+1] except IndexError: alive = False # Respawn player if dead if not alive: if ui.respawn() == 'exit': server.logout() continue server.redraw = True redraw_all = True alive = True server.respawn() ## Spawning mobs / Generating lighting buffer lights = render.get_lights(extended_view, bk_objects, x) spawn_period = 1 / SPS n_mob_spawn_cycles = int((frame_start - last_mob_spawn) // spawn_period) last_mob_spawn += spawn_period * n_mob_spawn_cycles server.spawn_mobs(n_mob_spawn_cycles, bk_objects, sky_colour, day, lights) ## Render if server.redraw: server.redraw = False # TODO: It would be nice to reuse any of the lighting_buffer generated for the mobs which overlaps with the screen render_interface.create_lighting_buffer(width, height, edges[0], edges_y[0], server.map_, server.slice_heights, bk_objects, sky_colour, day, lights) entities = { 'player': list(server.current_players.values()), 'zombie': list(server.mobs.values()) } objects = player.entities_to_render_objects( entities, x, int(width / 2), edges ) objects += items_to_render_objects(server.items, x, int(width / 2)) if not cursor_hidden: cursor_colour = player.cursor_colour( x, y, cursor, server.map_, server.inv, inv_sel ) objects.append(player.assemble_cursor( int(width / 2), y, cursor, cursor_colour )) render_args = [ server.map_, server.slice_heights, edges, edges_y, objects, bk_objects, sky_colour, day, lights, settings, redraw_all ] render_map = lambda: render_interface.render_map(*render_args) if benchmarks: timer = timeit.Timer(render_map) t = timer.timeit(1) log('Render call time = {}'.format(t), m="benchmarks") else: render_map() redraw_all = False crafting_grid = render.render_grid( player.CRAFT_TITLE, crafting, crafting_list, height, crafting_sel ) inv_grid = render.render_grid( player.INV_TITLE, not crafting, server.inv, height, inv_sel ) label = (player.label(crafting_list, crafting_sel) if crafting else player.label(server.inv, inv_sel)) health = 'Health: {}/{}'.format(round(server.health), player.MAX_PLAYER_HEALTH) render.render_grids( [ [inv_grid, crafting_grid], [[label]], [[health]] ], width, height ) in_game_log('({}, {})'.format(x, y), 0, 0) d_frame = time() - frame_start if d_frame < (1/FPS): sleep((1/FPS) - d_frame)
def game(blocks, meta, map_, save): x = meta['player_x'] y = meta['player_y'] dx = 0 dy = 0 dt = 0 # Tick df = 0 # Frame dc = 0 # Cursor ds = 0 # Selector dinv = False # Inventory dcraft = False # Crafting width = 40 height = terrain.world_gen['height'] - 1 FPS = 15 # Max TPS = 10 # Ticks IPS = 20 # Input MPS = 15 # Movement SUN_TICK = radians(1/32) old_bk_objects = None old_edges = None redraw = False last_frame = [] last_out = time() last_tick = time() last_inp = time() last_move = time() inp = None jump = 0 cursor = 0 crafting = False crafting_sel = 0 crafting_list = [] inv_sel = 0 c_hidden = True new_slices = {} alive = True events = [] crafting_list, crafting_sel = player.get_crafting( meta['inv'], crafting_list, crafting_sel, blocks ) # Game loop game = True with NonBlockingInput() as nbi: while game: # Finds display boundaries edges = (x - int(width / 2), x + int(width / 2)) extended_edges = (edges[0]-render.max_light, edges[1]+render.max_light) # Generates new terrain slice_list = terrain.detect_edges(map_, extended_edges) for pos in slice_list: new_slices[pos] = terrain.gen_slice(pos, meta, blocks) map_[pos] = new_slices[pos] # Save new terrain to file if new_slices: saves.save_map(save, new_slices) new_slices = {} redraw = True # Moving view if not edges == old_edges: view = terrain.move_map(map_, edges) extended_view = terrain.move_map(map_, extended_edges) old_edges = edges redraw = True # Sun has moved bk_objects, sky_colour = render.bk_objects(meta['tick'], width) if not bk_objects == old_bk_objects: old_bk_objects = bk_objects redraw = True # Draw view if redraw and time() >= 1/FPS + last_out: df = 1 redraw = False last_out = time() cursor_colour = player.cursor_colour( x, y, cursor, map_, blocks, meta['inv'], inv_sel ) objects = player.assemble_player( int(width / 2), y, cursor, cursor_colour, c_hidden ) lights = render.get_lights(extended_view, edges[0], blocks, bk_objects) out, last_frame = render.render_map( view, objects, blocks, bk_objects, sky_colour, lights, meta['tick'], last_frame ) crafting_grid = render.render_grid( player.CRAFT_TITLE, crafting, crafting_list, blocks, height, crafting_sel ) inv_grid = render.render_grid( player.INV_TITLE, not crafting, meta['inv'], blocks, height, inv_sel ) label = (player.label(crafting_list, crafting_sel, blocks) if crafting else player.label(meta['inv'], inv_sel, blocks)) out += render.render_grids( [ [inv_grid, crafting_grid], [[label]] ], width, height ) print(out) in_game_debug('({}, {})'.format(x, y), 0, 0) else: df = 0 # Respawn player if dead if not alive and df: alive = True x, y = player.respawn(meta) if dt: # Player falls when no solid block below it if jump > 0: # Countdown till fall jump -= 1 elif not terrain.is_solid(blocks, map_[x][y+1]): # Fall y += 1 redraw = True new_new_slices = process_events(events, map_, blocks) new_slices.update(new_new_slices) map_.update(new_new_slices) # If no block below, kill player try: block = map_[x][y+1] except IndexError: alive = False # Receive input if a key is pressed char = str(nbi.char()).lower() inp = char if char in 'wadkjliuo-=' else None # Input Frame if time() >= (1/IPS) + last_inp and alive and inp: if time() >= (1/MPS) + last_move: # Update player position dx, dy, jump = player.get_pos_delta( str(inp), map_, x, y, blocks, jump) y += dy x += dx last_move = time() new_new_slices, meta['inv'], inv_sel, new_events, dinv = \ player.cursor_func(str(inp), map_, x, y, cursor, inv_sel, meta, blocks) map_.update(new_new_slices) new_slices.update(new_new_slices) events += new_events dcraft, dcraftC, dcraftN = False, False, False if dinv: crafting = False if crafting: # Craft if player pressed craft meta['inv'], inv_sel, crafting_list, dcraftC = \ player.crafting(str(inp), meta['inv'], inv_sel, crafting_list, crafting_sel, blocks) # Increment/decrement craft no. crafting_list, dcraftN = \ player.craft_num(str(inp), meta['inv'], crafting_list, crafting_sel, blocks) dcraft = dcraftC or dcraftN # Update crafting list if dinv or dcraft: crafting_list, crafting_sel = \ player.get_crafting(meta['inv'], crafting_list, crafting_sel, blocks, dcraftC) if not len(crafting_list): crafting = False dc = player.move_cursor(inp) cursor = (cursor + dc) % 6 ds = player.move_sel(inp) if crafting: crafting_sel = ((crafting_sel + ds) % len(crafting_list) if len(crafting_list) else 0) else: inv_sel = ((inv_sel + ds) % len(meta['inv']) if len(meta['inv']) else 0) if any((dx, dy, dc, ds, dinv, dcraft)): meta['player_x'], meta['player_y'] = x, y saves.save_meta(save, meta) redraw = True if dx or dy: c_hidden = True if dc: c_hidden = False last_inp = time() inp = None if char in 'c': redraw = True crafting = not crafting and len(crafting_list) # Hard pause if DEBUG and char in '\n': input() char = '0' # Pause game if char in ' \n': meta['player_x'], meta['player_y'] = x, y saves.save_meta(save, meta) redraw = True last_frame = [] if ui.pause() == 'exit': game = False # Increase tick if time() >= (1/TPS) + last_tick: dt = 1 meta['tick'] += SUN_TICK last_tick = time() else: dt = 0
def game(server, settings, benchmarks): dt = 0 # Tick df = 0 # Frame dc = 0 # Cursor ds = 0 # Selector dpos = False dinv = False # Inventory dcraft = False # Crafting FPS = 15 # Max MPS = 15 # Movement SPS = 5 # Mob spawns old_bk_objects = None old_edges = None redraw_all = True last_move = time() last_mob_spawn = time() inp = None jump = 0 cursor = 0 crafting = False crafting_sel = 0 crafting_list = [] inv_sel = 0 cursor_hidden = True new_blocks = {} alive = True events = [] crafting_list, crafting_sel = player.get_crafting(server.inv, crafting_list, crafting_sel) # Game loop with NonBlockingInput() as nbi: while server.game: x, y = server.pos dt = server.dt() frame_start = time() ## Input char = True inp = [] while char: # Receive input if a key is pressed char = nbi.char() if char: char = str(char).lower() if char in 'wasdhkjliuoc-=\n ': inp.append(char) # Hard pause if DEBUG and '\n' in inp: input() inp.remove('\n') # Pause game if ' ' in inp or '\n' in inp: server.redraw = True redraw_all = True if ui.pause(server, settings) == 'exit': server.logout() continue width = settings.get('width') height = settings.get('height') # Update player and mobs position / damage move_period = 1 / MPS while frame_start >= move_period + last_move and x in server.map_: dx, dy, jump = player.get_pos_delta_on_input( inp, server.map_, x, y, jump, settings.get('flight')) if dx or dy: dpos = True x += dx y += dy if x in server.map_ and not settings.get('flight'): # Player falls when no solid block below it and not jumping jump -= dt if jump <= 0: jump = 0 if not terrain.is_solid(server.map_[x][y + 1]): # Fall y += 1 dpos = True if 'h' in inp: item = render.blocks[server.inv[inv_sel]['block']] if len( server.inv) else {} server.player_attack(item.get('attack_radius', 5), item.get('attack_damage', 10)) server.update_items() server.update_mobs() if server.health <= 0: alive = False last_move += move_period ## Update Map # Finds display boundaries edges = (x - int(width / 2), x + int(width / 2)) edges_y = (y - int(height / 2), y + int(height / 2)) if edges_y[1] > data.world_gen['height']: edges_y = (data.world_gen['height'] - height, data.world_gen['height']) elif edges_y[0] < 0: edges_y = (0, height) extended_edges = (edges[0] - render.max_light, edges[1] + render.max_light) slice_list = terrain.detect_edges(server.map_, extended_edges) if slice_list: log('slices to load', slice_list) chunk_list = terrain.get_chunk_list(slice_list) server.get_chunks(chunk_list) server.unload_slices(extended_edges) # Moving view if not edges == old_edges or server.view_change: extended_view = terrain.move_map(server.map_, extended_edges) old_edges = edges server.redraw = True server.view_change = False # Sun has moved bk_objects, sky_colour, day = render.bk_objects( server.time, width, edges[0], settings.get('fancy_lights')) if not bk_objects == old_bk_objects: old_bk_objects = bk_objects server.redraw = True if settings.get('gravity'): blocks = terrain.apply_gravity(server.map_, extended_edges) if blocks: server.set_blocks(blocks) ## Crafting if 'c' in inp: server.redraw = True crafting = not crafting and len(crafting_list) dcraft, dcraftC, dcraftN = False, False, False if dinv: crafting = False if crafting: # Craft if player pressed craft server.inv, inv_sel, crafting_list, dcraftC = \ player.crafting(inp, server.inv, inv_sel, crafting_list, crafting_sel) # Increment/decrement craft no. crafting_list, dcraftN = \ player.craft_num(inp, server.inv, crafting_list, crafting_sel) dcraft = dcraftC or dcraftN # Update crafting list crafting_list, crafting_sel = \ player.get_crafting(server.inv, crafting_list, crafting_sel, dcraftC) if not len(crafting_list): crafting = False dc = player.move_cursor(inp) cursor = (cursor + dc) % 6 ds = player.move_sel(inp) if crafting: crafting_sel = ((crafting_sel + ds) % len(crafting_list) if len(crafting_list) else 0) else: inv_sel = ((inv_sel + ds) % len(server.inv) if len(server.inv) else 0) if any((dpos, dc, ds, dinv, dcraft)): server.redraw = True if dpos: dpos = False server.pos = x, y cursor_hidden = True if dc: cursor_hidden = False ## Eating or placing blocks p_hungry = server.health < player.MAX_PLAYER_HEALTH new_blocks, server.inv, inv_sel, new_events, dhealth, dinv = \ player.cursor_func( inp, server.map_, x, y, cursor, inv_sel, server.inv, p_hungry ) server.add_health(dhealth) if new_blocks: server.set_blocks(new_blocks) ## Process events events += new_events new_blocks = {} for i in range(int(dt)): new_blocks.update(process_events(events, server)) if new_blocks: server.set_blocks(new_blocks) # If no block below, kill player try: block = server.map_[x][y + 1] except IndexError: alive = False # Respawn player if dead if not alive: if ui.respawn() == 'exit': server.logout() continue server.redraw = True redraw_all = True alive = True server.respawn() ## Spawning mobs / Generating lighting buffer lights = render.get_lights(extended_view, bk_objects, x) spawn_period = 1 / SPS n_mob_spawn_cycles = int( (frame_start - last_mob_spawn) // spawn_period) last_mob_spawn += spawn_period * n_mob_spawn_cycles server.spawn_mobs(n_mob_spawn_cycles, bk_objects, sky_colour, day, lights) ## Render if server.redraw: server.redraw = False # TODO: It would be nice to reuse any of the lighting_buffer generated for the mobs which overlaps with the screen render_interface.create_lighting_buffer( width, height, edges[0], edges_y[0], server.map_, server.slice_heights, bk_objects, sky_colour, day, lights) entities = { 'player': list(server.current_players.values()), 'zombie': list(server.mobs.values()) } objects = player.entities_to_render_objects( entities, x, int(width / 2), edges) objects += items_to_render_objects(server.items, x, int(width / 2)) if not cursor_hidden: cursor_colour = player.cursor_colour( x, y, cursor, server.map_, server.inv, inv_sel) objects.append( player.assemble_cursor(int(width / 2), y, cursor, cursor_colour)) render_args = [ server.map_, server.slice_heights, edges, edges_y, objects, bk_objects, sky_colour, day, lights, settings, redraw_all ] render_map = lambda: render_interface.render_map(*render_args) if benchmarks: timer = timeit.Timer(render_map) t = timer.timeit(1) log('Render call time = {}'.format(t), m="benchmarks") else: render_map() redraw_all = False crafting_grid = render.render_grid(player.CRAFT_TITLE, crafting, crafting_list, height, crafting_sel) inv_grid = render.render_grid(player.INV_TITLE, not crafting, server.inv, height, inv_sel) label = (player.label(crafting_list, crafting_sel) if crafting else player.label(server.inv, inv_sel)) health = 'Health: {}/{}'.format(round(server.health), player.MAX_PLAYER_HEALTH) render.render_grids( [[inv_grid, crafting_grid], [[label]], [[health]]], width, height) in_game_log('({}, {})'.format(x, y), 0, 0) d_frame = time() - frame_start if d_frame < (1 / FPS): sleep((1 / FPS) - d_frame)
def game(server, settings): x, y = server.pos dx = 0 dy = 0 dt = 0 # Tick df = 0 # Frame dc = 0 # Cursor ds = 0 # Selector dinv = False # Inventory dcraft = False # Crafting FPS = 15 # Max IPS = 20 # Input MPS = 15 # Movement old_bk_objects = None old_edges = None last_frame = {} last_out = time() last_inp = time() last_move = time() inp = None jump = 0 cursor = 0 crafting = False crafting_sel = 0 crafting_list = [] inv_sel = 0 c_hidden = True new_blocks = {} alive = True events = [] crafting_list, crafting_sel = player.get_crafting( server.inv, crafting_list, crafting_sel ) # Game loop with NonBlockingInput() as nbi: while server.game: x, y = server.pos width = settings.get('width') height = settings.get('height') sleep(1/1000) # Finds display boundaries edges = (x - int(width / 2), x + int(width / 2)) edges_y = (y - int(height / 2), y + int(height / 2)) if edges_y[1] > data.world_gen['height']: edges_y = (data.world_gen['height'] - height, data.world_gen['height']) elif edges_y[0] < 0: edges_y = (0, height) extended_edges = (edges[0]-render.max_light, edges[1]+render.max_light) slice_list = terrain.detect_edges(server.map_, extended_edges) if slice_list: log('slices to load', slice_list) chunk_list = terrain.get_chunk_list(slice_list) server.get_chunks(chunk_list) server.unload_slices(extended_edges) # Moving view if not edges == old_edges or server.view_change: extended_view = terrain.move_map(server.map_, extended_edges) old_edges = edges server.redraw = True server.view_change = False # Sun has moved bk_objects, sky_colour, day = render.bk_objects(server.time, width, settings.get('fancy_lights')) if not bk_objects == old_bk_objects: old_bk_objects = bk_objects server.redraw = True # Draw view if server.redraw and time() >= 1/FPS + last_out: df = 1 server.redraw = False last_out = time() if settings.get('gravity'): blocks = terrain.apply_gravity(server.map_, edges) if blocks: server.set_blocks(blocks) cursor_colour = player.cursor_colour( x, y, cursor, server.map_, server.inv, inv_sel ) objects = player.assemble_players( server.current_players, x, y, int(width / 2), edges ) if not c_hidden: objects.append(player.assemble_cursor( int(width / 2), y, cursor, cursor_colour )) lights = render.get_lights(extended_view, edges[0], bk_objects) out, last_frame = render.render_map( server.map_, server.slice_heights, edges, edges_y, objects, bk_objects, sky_colour, day, lights, last_frame, settings.get('fancy_lights') ) crafting_grid = render.render_grid( player.CRAFT_TITLE, crafting, crafting_list, height, crafting_sel ) inv_grid = render.render_grid( player.INV_TITLE, not crafting, server.inv, height, inv_sel ) label = (player.label(crafting_list, crafting_sel) if crafting else player.label(server.inv, inv_sel)) out += render.render_grids( [ [inv_grid, crafting_grid], [[label]] ], width, height ) print(out) in_game_log('({}, {})'.format(x, y), 0, 0) else: df = 0 # Respawn player if dead if not alive and df: alive = True server.respawn() if dt and server.chunk_loaded(x): if not settings.get('flight'): # Player falls when no solid block below it if jump > 0: # Countdown till fall jump -= 1 elif not terrain.is_solid(server.map_[x][y+1]): # Fall y += 1 server.pos = x, y server.redraw = True new_blocks = process_events(events, server.map_) if new_blocks: server.set_blocks(new_blocks) # If no block below, kill player try: block = server.map_[x][y+1] except IndexError: alive = False # Receive input if a key is pressed char = str(nbi.char()).lower() inp = char if char in 'wasdkjliuo-=' else None # Input Frame if time() >= (1/IPS) + last_inp and alive and inp: if time() >= (1/MPS) + last_move: # Update player position dx, dy, jump = player.get_pos_delta( str(inp), server.map_, x, y, jump, settings.get('flight')) y += dy x += dx last_move = time() new_blocks, inv, inv_sel, new_events, dinv = \ player.cursor_func( str(inp), server.map_, x, y, cursor, inv_sel, server.inv ) if dinv: server.inv = inv if new_blocks: server.set_blocks(new_blocks) events += new_events dcraft, dcraftC, dcraftN = False, False, False if dinv: crafting = False if crafting: # Craft if player pressed craft inv, inv_sel, crafting_list, dcraftC = \ player.crafting(str(inp), server.inv, inv_sel, crafting_list, crafting_sel) if dcraftC: server.inv = inv # Increment/decrement craft no. crafting_list, dcraftN = \ player.craft_num(str(inp), server.inv, crafting_list, crafting_sel) dcraft = dcraftC or dcraftN # Update crafting list if dinv or dcraft: crafting_list, crafting_sel = \ player.get_crafting(server.inv, crafting_list, crafting_sel, dcraftC) if not len(crafting_list): crafting = False dc = player.move_cursor(inp) cursor = (cursor + dc) % 6 ds = player.move_sel(inp) if crafting: crafting_sel = ((crafting_sel + ds) % len(crafting_list) if len(crafting_list) else 0) else: inv_sel = ((inv_sel + ds) % len(server.inv) if len(server.inv) else 0) if any((dx, dy, dc, ds, dinv, dcraft)): server.pos = x, y server.redraw = True if dx or dy: c_hidden = True if dc: c_hidden = False last_inp = time() inp = None if char in 'c': server.redraw = True crafting = not crafting and len(crafting_list) # Hard pause if DEBUG and char in '\n': input() char = '0' # Pause game if char in ' \n': server.pos = x, y server.redraw = True last_frame = {} if ui.pause(server, settings) == 'exit': server.logout() dt = server.dt()