infinite terrain baby!
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 17 Jan 2022 00:02:52 +0000 (18:02 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 17 Jan 2022 00:02:52 +0000 (18:02 -0600)
src/build.onyx
src/chunk.onyx
src/main.onyx
src/physics.onyx
src/player.onyx
src/utils.onyx [new file with mode: 0644]
src/vecmath.onyx
src/world.onyx
src/worldgen.onyx

index c4562a14778d796c2a6076d14d78968134873e7b..8667782e2dc0ead35da926832e8c22058c15972f 100644 (file)
@@ -18,6 +18,7 @@
 #load "player"
 #load "shader"
 #load "texture"
+#load "utils"
 #load "vecmath"
 #load "world"
 #load "worldgen"
index be71bb2a0ed9b52a3a93acb40e16933cd26ee97f..ef3b5ef359371cf6974f6f4c37e6d482228c6ff6 100644 (file)
@@ -59,6 +59,12 @@ chunk_make :: (x, y, z: i32, allocator := context.allocator) -> ^Chunk {
     return chunk;
 }
 
+chunk_free :: (chunk: ^Chunk) {
+    chunk_destroy_mesh(chunk);
+    memory.free_slice(^chunk.blocks);
+    cfree(chunk);
+}
+
 #local in_chunk_bounds :: macro (x, y, z: i32) -> bool {
     if x < 0 do return false;
     if x >= Chunk_Size do return false;
@@ -171,7 +177,22 @@ chunk_build_mesh :: (use chunk: ^Chunk) {
     mesh_dirty = false;
 }
 
+chunk_destroy_mesh :: (use chunk: ^Chunk) {
+    if mesh == null do return;
+
+    mesh_free(mesh);
+    mesh = null;
+
+    mesh_dirty = true; // Just in case this chunk will be reused later.
+}
+
+#local block_texture: Texture;
 chunk_draw :: (chunk: ^Chunk) {
+    if block_texture.filename.data == null {
+        block_texture = texture_make(#cstr "assets/textures/block.png");
+    }
+
+    texture_use(^block_texture);
     update_model_matrix(chunk.position);
     mesh_draw(chunk.mesh);
 }
index 3da9d418a0afb25627f7cf986cadbd2d95b5c7c0..73fcb8a06cbc62427607a1764040fe936a8768cc 100644 (file)
@@ -75,8 +75,6 @@ toggle_cursor_grabbed :: () {
     }
 }
 
-#local block_texture: Texture;
-
 setup_opengl :: () {
     glInit(glfwGetLoadProcAddress());
 
@@ -99,8 +97,6 @@ setup_opengl :: () {
 
     font = font_lookup(.{"./assets/fonts/calibri.ttf", 32});
 
-    block_texture = texture_make(#cstr "assets/textures/block.png");
-    
     shader_use(world_shader);
     world = world_make();
     player = player_make();
@@ -130,6 +126,9 @@ update :: (dt: f32) {
     }
 
     player_update(^player, dt);
+    player_chunk := world_position_to_chunk(world, player.body.pos);
+    world_move_center(world, player_chunk);
+    world_update(world, dt);
 
     if is_key_just_down(GLFW_KEY_F7) {
         debug_screen = !debug_screen;
@@ -150,7 +149,6 @@ draw :: () {
 
     shader_use(world_shader);
     shader_set_uniform(world_shader, #cstr "u_texture", 0);
-    texture_use(^block_texture);
     world_draw(world);
     
     glLineWidth(2);
@@ -161,10 +159,12 @@ draw :: () {
     font_print(font, ~~(ww / 2), ~~(wh / 2), ".");
 
     if debug_screen {
+        player_chunk := world_position_to_chunk(world, player.body.pos);
         font_print(font, 0, 32, "FPS: {}", game_fps);
         font_print(font, 0, 64, "Position: {}", camera.position);
         font_print(font, 0, 96, "Facing: {}", camera.y_rot * 180 / math.PI);
         font_print(font, 0, 128, "Looking at: {}", selected_block);
+        font_print(font, 0, 160, "Chunk: {}", player_chunk);
     }
 
     glfwSwapBuffers(window);
index 8b89b6ae445d819f03dce1e8f44e1a4f87fd3e0f..746e39da77893e6c9c1c6d54e4ee1027adf89760 100644 (file)
@@ -34,8 +34,6 @@ physics_simulate :: (use body: ^PhysicsBody, dt: f32, world: ^World) {
     aabb_buffer := (cast(^AABB) alloc.from_stack(sizeof [256] AABB))[0..256];
 
     aabbs := world_get_aabbs(world, pos, 3, aabb_buffer);
-    vel += acc * dt;
-
     try_move :: macro (delta: Vector3) -> f32 {
         new_pos := body.pos + delta;
         body_aabb := get_collision_object(new_pos);
@@ -51,14 +49,16 @@ physics_simulate :: (use body: ^PhysicsBody, dt: f32, world: ^World) {
     }
 
     on_ground = false;
-    move_x := try_move(.{vel.x * dt, 0, 0});
-    move_y := try_move(.{0, vel.y * dt, 0});
-    move_z := try_move(.{0, 0, vel.z * dt});
+    move_x := try_move(.{acc.x*0.5*dt*dt + vel.x * dt, 0, 0});
+    move_y := try_move(.{0, acc.y*0.5*dt*dt + vel.y * dt, 0});
+    move_z := try_move(.{0, 0, acc.z*0.5*dt*dt + vel.z * dt});
 
     pos.x += vel.x * dt * move_x;
     pos.y += vel.y * dt * move_y;
     pos.z += vel.z * dt * move_z;
 
+    vel += acc * dt;
+
     if on_ground do vel.y = 0;
 }
 
index 52a1b41f7728332b2cff49108ef2133afc83e995..c10d6d14af9412d7df92f0f315ac202e3fd808b0 100644 (file)
@@ -61,7 +61,7 @@ player_update :: (use player: ^Player, dt: f32) {
     physics_simulate(^body, dt, world);
 
     // Fix falling off the world
-    if body.pos.y < -10 do body.pos = .{0,48,0};
+    if body.pos.y < -100 do body.pos = .{0,48,0};
 
     camera.position = body.pos;
 
diff --git a/src/utils.onyx b/src/utils.onyx
new file mode 100644 (file)
index 0000000..25a9873
--- /dev/null
@@ -0,0 +1,72 @@
+use package core
+
+Ray :: struct {
+    origin, direction: Vector3;
+}
+
+
+ray_cast :: (ray: Ray, max_distance: f32, ctx: rawptr, is_solid: (rawptr, Vector3i) -> bool, out_block: ^Vector3i, out_dir: ^Vector3i) -> bool {
+    pos := Vector3i.{ ~~math.floor(ray.origin.x), ~~math.floor(ray.origin.y), ~~math.floor(ray.origin.z) };
+
+    dir := ray.direction;
+    step := Vector3i.{ ~~math.sign(dir.x), ~~math.sign(dir.y), ~~math.sign(dir.z) };
+
+    tmax: Vector3;
+    tmax.x = ((math.ceil(ray.origin.x) - ray.origin.x) if dir.x > 0 else (ray.origin.x - math.floor(ray.origin.x))) / math.abs(dir.x);
+    tmax.y = ((math.ceil(ray.origin.y) - ray.origin.y) if dir.y > 0 else (ray.origin.y - math.floor(ray.origin.y))) / math.abs(dir.y);
+    tmax.z = ((math.ceil(ray.origin.z) - ray.origin.z) if dir.z > 0 else (ray.origin.z - math.floor(ray.origin.z))) / math.abs(dir.z);
+
+    tdelta := Vector3.{ ~~step.x / dir.x, ~~step.y / dir.y, ~~step.z / dir.z };
+    radius := max_distance / Vector3.mag(dir);
+
+    while true {
+        if is_solid(ctx, pos) {
+            *out_block = pos;
+            return true;
+        }
+
+        if tmax.x < tmax.y {
+            if tmax.x < tmax.z {
+                if tmax.x > radius {
+                    break;
+                }
+
+                pos.x += step.x;
+                tmax.x += tdelta.x;
+                *out_dir = .{ -step.x, 0, 0 };
+
+            } else {
+                if tmax.z > radius {
+                    break;
+                }
+
+                pos.z += step.z;
+                tmax.z += tdelta.z;
+                *out_dir = .{ 0, 0, -step.z };
+            }
+
+        } else {
+            if tmax.y < tmax.z {
+                if tmax.y > radius {
+                    break;
+                }
+
+                pos.y += step.y;
+                tmax.y += tdelta.y;
+                *out_dir = .{ 0, -step.y, 0 };
+
+            } else {
+                if tmax.z > radius {
+                    break;
+                }
+
+                pos.z += step.z;
+                tmax.z += tdelta.z;
+                *out_dir = .{ 0, 0, -step.z };
+            }
+        }
+    }
+
+    return false;
+}
+
index 95abdf10e53c6bf301e37d3efb20e51dce5e9d75..caf6a3f12fc7f3742ffffcee978f743e2eb3de30 100644 (file)
@@ -42,39 +42,25 @@ Vector3 :: struct [conv.Custom_Format.{format_vector3}] {
 #operator + macro (v1, v2: Vector3)    => Vector3.{ v1.x + v2.x, v1.y + v2.y, v1.z + v2.z };
 #operator - macro (v1, v2: Vector3)    => Vector3.{ v1.x - v2.x, v1.y - v2.y, v1.z - v2.z };
 #operator * macro (v: Vector3, s: f32) => Vector3.{ v.x * s,     v.y * s,     v.z * s };
+#operator == macro (v1, v2: Vector3)   => v1.x == v2.x && v1.y == v2.y && v1.z == v2.z;
 
 #operator + macro (v1, v2: Vector3i)    => Vector3i.{ v1.x + v2.x, v1.y + v2.y, v1.z + v2.z };
 #operator - macro (v1, v2: Vector3i)    => Vector3i.{ v1.x - v2.x, v1.y - v2.y, v1.z - v2.z };
 #operator * macro (v: Vector3i, s: i32) => Vector3i.{ v.x * s,     v.y * s,     v.z * s };
+#operator == macro (v1, v2: Vector3i)   => v1.x == v2.x && v1.y == v2.y && v1.z == v2.z;
 
 #local {
     conv :: package core.conv
 
     format_vector2 :: (output: ^conv.Format_Output, format: ^conv.Format, v: ^Vector2) {
-        output->write("(");
-        conv.format_any(output, format, .{^v.x, f32});
-        output->write(", ");
-        conv.format_any(output, format, .{^v.y, f32});
-        output->write(")");
+        conv.format(output, "({}, {})", v.x, v.y);
     }
 
     format_vector3 :: (output: ^conv.Format_Output, format: ^conv.Format, v: ^Vector3) {
-        output->write("(");
-        conv.format_any(output, format, .{^v.x, f32});
-        output->write(", ");
-        conv.format_any(output, format, .{^v.y, f32});
-        output->write(", ");
-        conv.format_any(output, format, .{^v.z, f32});
-        output->write(")");
+        conv.format(output, "({}, {}, {})", v.x, v.y, v.z);
     }
 
     format_vector3i :: (output: ^conv.Format_Output, format: ^conv.Format, v: ^Vector3i) {
-        output->write("(");
-        conv.format_any(output, format, .{^v.x, i32});
-        output->write(", ");
-        conv.format_any(output, format, .{^v.y, i32});
-        output->write(", ");
-        conv.format_any(output, format, .{^v.z, i32});
-        output->write(")");
+        conv.format(output, "({}, {}, {})", v.x, v.y, v.z);
     }
-}
\ No newline at end of file
+}
index 72238b084cfe059fc3441f44a11e02964dcc2b53..4c691b94beb156e6beb740c8abf4b4e4107cf989 100644 (file)
 use package core
 
 World :: struct {
-    chunk_dist: u32;
+    chunk_dist: i32;
     chunks: [] ^Chunk;
+
+    center_chunk: Vector3i;
+
+    chunks_to_load: [..] Vector3i;
 }
 
 world_make :: (allocator := context.allocator) -> ^World {
     world := new(World, allocator);
-    world.chunk_dist = 3;
-    memory.alloc_slice(^world.chunks, world.chunk_dist * world.chunk_dist * world.chunk_dist);
+    world.chunk_dist = 2;
+    world.center_chunk = .{0,0,0};
 
-    for x: 0 .. 3 do for y: 0 .. 3 do for z: 0 .. 3 {
-        chunk := chunk_make(x, y, z);
-        world.chunks[x * world.chunk_dist * world.chunk_dist + y * world.chunk_dist + z] = chunk;
-        generate_chunk(world, chunk);
+    sl := world.chunk_dist * 2 + 1;
+    memory.alloc_slice(^world.chunks, sl * sl * sl);
+    memory.fill_slice(world.chunks, null);
+
+    for x: (world.center_chunk.x-world.chunk_dist) .. world.center_chunk.x+world.chunk_dist+1
+        do for y: (world.center_chunk.y-world.chunk_dist) .. world.center_chunk.y+world.chunk_dist+1
+            do for z: (world.center_chunk.z-world.chunk_dist) .. world.center_chunk.z+world.chunk_dist+1 {
+        world.chunks_to_load << .{x, y, z};
     }
 
     return world;
 }
 
+world_load_chunk :: (world: ^World, chunk_to_load: Vector3i) {
+    //
+    // For now, no persistence will happen to the chunk, so generate a completely new chunk.
+    //
+    chunk := chunk_make(chunk_to_load.x, chunk_to_load.y, chunk_to_load.z);
+    generate_chunk(world, chunk);
+    world_set_chunk(world, chunk_to_load, chunk);
+}
+
+world_unload_chunk :: #match {
+    (world: ^World, chunk_to_unload: Vector3i) {
+        chunk := world_get_chunk(world, chunk_to_unload);
+        world_unload_chunk(world, chunk);
+        world_set_chunk(world, chunk_to_unload, null);
+    },
+
+    (world: ^World, chunk: ^Chunk) {
+        if chunk != null {
+            chunk_free(chunk);
+        }
+    }
+}
+
+world_get_chunk :: #match {
+    @CompilerBug // If I write the following function in quick form:
+    //
+    // (world: ^World, v: Vector3i) => world_get_chunk(world, v.x, v.y, v.z),
+    //
+    // the ',' at the end appears to mean "compound expression", so the following
+    // function defintion gets lumped as the second return result. Maybe there
+    // should be a special case for parsing this? I've always hated how parsing
+    // inside of a #match block works.
+    //
+    (world: ^World, v: Vector3i) -> #auto { return world_get_chunk(world, v.x, v.y, v.z); },
+
+    (world: ^World, x, y, z: i32) -> ^Chunk {
+        d  := world.chunk_dist;
+        sl := d * 2 + 1;
+
+        ix := x - world.center_chunk.x + d;
+        iy := y - world.center_chunk.y + d;
+        iz := z - world.center_chunk.z + d;
+        if ix < 0 || ix > 2 * world.chunk_dist do return null;
+        if iy < 0 || iy > 2 * world.chunk_dist do return null;
+        if iz < 0 || iz > 2 * world.chunk_dist do return null;
+
+        return world.chunks[ix * sl * sl + iy * sl + iz];
+    }
+}
+
+world_set_chunk :: #match {
+    (world: ^World, v: Vector3i, chunk: ^Chunk) -> #auto { return world_set_chunk(world, v.x, v.y, v.z, chunk); },
+
+    (world: ^World, x, y, z: i32, chunk: ^Chunk) -> bool {
+        d  := world.chunk_dist;
+        sl := d * 2 + 1;
+
+        ix := x - world.center_chunk.x + d;
+        iy := y - world.center_chunk.y + d;
+        iz := z - world.center_chunk.z + d;
+        if ix < 0 || ix > 2 * world.chunk_dist do return false;
+        if iy < 0 || iy > 2 * world.chunk_dist do return false;
+        if iz < 0 || iz > 2 * world.chunk_dist do return false;
+
+        world.chunks[ix * sl * sl + iy * sl + iz] = chunk;
+        return true;
+    }
+}
+
+// Getting around the stupidness that is integer arithmetic on modern processors
+#local world_coord_to_chunk_and_block :: (world: ^World, x, y, z: i32) -> (chunk: Vector3i, block: Vector3i) {
+    chunk, block: Vector3i;
+    chunk.x = x / Chunk_Size;
+    chunk.y = y / Chunk_Size;
+    chunk.z = z / Chunk_Size;
+    block.x = x % Chunk_Size;
+    block.y = y % Chunk_Size;
+    block.z = z % Chunk_Size;
+
+    if x < 0 && block.x != 0 { chunk.x -= 1; block.x += Chunk_Size; }
+    if y < 0 && block.y != 0 { chunk.y -= 1; block.y += Chunk_Size; }
+    if z < 0 && block.z != 0 { chunk.z -= 1; block.z += Chunk_Size; }
+
+    return chunk, block;
+}
+
+world_position_to_chunk :: (world: ^World, use pos: Vector3) -> Vector3i {
+    chunk: Vector3i;
+    chunk.x = ~~math.floor(x / ~~Chunk_Size);
+    chunk.y = ~~math.floor(y / ~~Chunk_Size);
+    chunk.z = ~~math.floor(z / ~~Chunk_Size);
+    return chunk;
+}
+
 world_get_block :: (world: ^World, x, y, z: i32) -> Block {
-    @WorldCenter
-    cx := x / Chunk_Size;
-    cy := y / Chunk_Size;
-    cz := z / Chunk_Size;
-    if cx < 0 || cx >= world.chunk_dist do return Block_Empty;
-    if cy < 0 || cy >= world.chunk_dist do return Block_Empty;
-    if cz < 0 || cz >= world.chunk_dist do return Block_Empty;
-    chunk := world.chunks[cx * world.chunk_dist * world.chunk_dist + cy * world.chunk_dist + cz];
-    return chunk_get(chunk, x % Chunk_Size, y % Chunk_Size, z % Chunk_Size);
+    chunk_pos, block_pos := world_coord_to_chunk_and_block(world, x, y, z);
+    chunk := world_get_chunk(world, chunk_pos);
+    if chunk == null do return Block_Empty;
+    return chunk_get(chunk, block_pos.x, block_pos.y, block_pos.z);
 }
 
 world_set_block :: (world: ^World, x, y, z: i32, block: Block) {
-    @WorldCenter
-    cx := x / Chunk_Size;
-    cy := y / Chunk_Size;
-    cz := z / Chunk_Size;
-    if cx < 0 || cx >= world.chunk_dist do return;
-    if cy < 0 || cy >= world.chunk_dist do return;
-    if cz < 0 || cz >= world.chunk_dist do return;
-    chunk := world.chunks[cx * world.chunk_dist * world.chunk_dist + cy * world.chunk_dist + cz];
-    chunk_set(chunk, x % Chunk_Size, y % Chunk_Size, z % Chunk_Size, block);
+    chunk_pos, block_pos := world_coord_to_chunk_and_block(world, x, y, z);
+    chunk := world_get_chunk(world, chunk_pos);
+    if chunk == null do return;
+    chunk_set(chunk, block_pos.x, block_pos.y, block_pos.z, block);
+}
+
+world_move_center :: (use world: ^World, new_center: Vector3i) {
+    if center_chunk == new_center do return;
+
+    sl := world.chunk_dist * 2 + 1;
+    current_chunks := memory.copy_slice(world.chunks);
+    memory.alloc_slice(^world.chunks, sl * sl * sl);
+    memory.fill_slice(world.chunks, null);
+
+    center_chunk = new_center;
+    for current_chunks {
+        if it == null do continue;
+        if !world_set_chunk(world, it.coord, it) {
+            world_unload_chunk(world, it);
+        }
+    }
+
+    for x: (center_chunk.x-world.chunk_dist) .. center_chunk.x+world.chunk_dist+1
+        do for y: (center_chunk.y-world.chunk_dist) .. center_chunk.y+world.chunk_dist+1
+            do for z: (center_chunk.z-world.chunk_dist) .. center_chunk.z+world.chunk_dist+1 {
+        if world_get_chunk(world, x, y, z) == null do world.chunks_to_load << .{x, y, z};
+    }
+
+    memory.free_slice(^current_chunks);
 }
 
 world_get_aabbs :: (use world: ^World, center: Vector3, radius: f32, buffer: [] AABB = .[]) -> [] AABB {
@@ -77,81 +194,19 @@ world_get_aabbs :: (use world: ^World, center: Vector3, radius: f32, buffer: []
     return buffer[0 .. buffer_pos];
 }
 
+world_update :: (use world: ^World, dt: f32) {
+    if chunks_to_load.count > 0 {
+        chunk_to_load := chunks_to_load[0];
+        array.delete(^chunks_to_load, 0);
+        printf("Loading {}\n", chunk_to_load);
 
-@Relocate // to a utils file
-Ray :: struct {
-    origin, direction: Vector3;
-}
-
-@Relocate // to a utils file
-ray_cast :: (ray: Ray, max_distance: f32, ctx: rawptr, is_solid: (rawptr, Vector3i) -> bool, out_block: ^Vector3i, out_dir: ^Vector3i) -> bool {
-    pos := Vector3i.{ ~~math.floor(ray.origin.x), ~~math.floor(ray.origin.y), ~~math.floor(ray.origin.z) };
-
-    dir := ray.direction;
-    step := Vector3i.{ ~~math.sign(dir.x), ~~math.sign(dir.y), ~~math.sign(dir.z) };
-
-    tmax: Vector3;
-    tmax.x = ((math.ceil(ray.origin.x) - ray.origin.x) if dir.x > 0 else (ray.origin.x - math.floor(ray.origin.x))) / math.abs(dir.x);
-    tmax.y = ((math.ceil(ray.origin.y) - ray.origin.y) if dir.y > 0 else (ray.origin.y - math.floor(ray.origin.y))) / math.abs(dir.y);
-    tmax.z = ((math.ceil(ray.origin.z) - ray.origin.z) if dir.z > 0 else (ray.origin.z - math.floor(ray.origin.z))) / math.abs(dir.z);
-
-    tdelta := Vector3.{ ~~step.x / dir.x, ~~step.y / dir.y, ~~step.z / dir.z };
-    radius := max_distance / Vector3.mag(dir);
-
-    while true {
-        if is_solid(ctx, pos) {
-            *out_block = pos;
-            return true;
-        }
-
-        if tmax.x < tmax.y {
-            if tmax.x < tmax.z {
-                if tmax.x > radius {
-                    break;
-                }
-
-                pos.x += step.x;
-                tmax.x += tdelta.x;
-                *out_dir = .{ -step.x, 0, 0 };
-
-            } else {
-                if tmax.z > radius {
-                    break;
-                }
-
-                pos.z += step.z;
-                tmax.z += tdelta.z;
-                *out_dir = .{ 0, 0, -step.z };
-            }
-
-        } else {
-            if tmax.y < tmax.z {
-                if tmax.y > radius {
-                    break;
-                }
-
-                pos.y += step.y;
-                tmax.y += tdelta.y;
-                *out_dir = .{ 0, -step.y, 0 };
-
-            } else {
-                if tmax.z > radius {
-                    break;
-                }
-
-                pos.z += step.z;
-                tmax.z += tdelta.z;
-                *out_dir = .{ 0, 0, -step.z };
-            }
-        }
+        world_load_chunk(world, chunk_to_load);
     }
-
-    return false;
 }
 
-
 world_draw :: (use world: ^World) {
     for chunks {
+        if it == null do continue;
         chunk_build_mesh(it);
         chunk_draw(it);
     }
index 96041d2c6028f47fb82d248fba42c3fa333e7c81..e3a3e59c796307042f5445321a38e6a357f6f937 100644 (file)
@@ -7,14 +7,20 @@ use package core
 generate_chunk :: (world: ^World, chunk: ^Chunk) {
     for cz: 32 do for cx: 32 {
         t := chunk_coords_to_world(chunk, cx, 0, cz);
-        px := cast(f64) t.x / 16;
-        pz := cast(f64) t.z / 16;
-        h: i32 = ~~(perlin.noise(px, ~~(10 * seed), pz) * 24 + 14);
+        px := cast(f64) t.x / 24;
+        pz := cast(f64) t.z / 24;
+
+        n := perlin.noise(px, ~~(10 * seed), pz);
+        h := cast(i32) (n * 32 + 18);
+        h = math.max(h, 14);
+        if n < -0.9 do h += ~~((n + 0.9) * 4);
 
         h -= chunk.coord.y * Chunk_Size;
         if h >= 0 { chunk_set(chunk, cx, h, cz, block_make(0.2, 1, 0.2, 1)); h -= 1; }
         for cy: 2 .. h+1 do chunk_set(chunk, cx, cy, cz, block_make(0.3, 0.3, 0.1, 1, .{texture_enabled=false}));
         for cy: 0 .. math.min(h, 2)+1 do chunk_set(chunk, cx, cy, cz, block_make(0.2, 0.2, 0.2, 0.5, .{texture_enabled=false}));
     }
+
+    chunk_set(chunk, 0, 0, 0, block_make(1, 0, 1, 1));
 }