-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Infinite Worlds Multiplayer Seamless Chunk System
Used with BlockyGame to generate infinite 3D three dirt voxel blocks in thickness flat planes that can be used to build on top of including massive multiplayer games: Zylann/voxelgame#101 + Zylann/voxelgame@2147d81
- Loading branch information
1 parent
1fb1bc7
commit 6eeb73e
Showing
2 changed files
with
209 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,203 @@ | ||
#tool | ||
extends VoxelGeneratorScript | ||
|
||
const Structure = preload("./structure.gd") | ||
const TreeGenerator = preload("./tree_generator.gd") | ||
const HeightmapCurve = preload("./heightmap_curve.tres") | ||
|
||
# TODO Don't hardcode, get by name from library somehow | ||
const AIR = 0 | ||
const DIRT = 1 | ||
const GRASS = 2 | ||
const WATER_FULL = 14 | ||
const WATER_TOP = 13 | ||
const LOG = 4 | ||
const LEAVES = 25 | ||
const TALL_GRASS = 8 | ||
const DEAD_SHRUB = 26 | ||
#const STONE = 8 | ||
|
||
const _CHANNEL = VoxelBuffer.CHANNEL_TYPE | ||
|
||
const _moore_dirs = [ | ||
Vector3(-1, 0, -1), | ||
Vector3(0, 0, -1), | ||
Vector3(1, 0, -1), | ||
Vector3(-1, 0, 0), | ||
Vector3(1, 0, 0), | ||
Vector3(-1, 0, 1), | ||
Vector3(0, 0, 1), | ||
Vector3(1, 0, 1) | ||
] | ||
|
||
|
||
var _tree_structures := [] | ||
|
||
var _heightmap_min_y := 1 #int(HeightmapCurve.min_value) | ||
var _heightmap_max_y := 1 #int(HeightmapCurve.max_value) | ||
var _heightmap_range := 0 | ||
var _heightmap_noise := 0 #FastNoiseLite.new() | ||
var _trees_min_y := 0 | ||
var _trees_max_y := 0 | ||
|
||
|
||
func _init(): | ||
# TODO Even this must be based on a seed, but I'm lazy | ||
var tree_generator = TreeGenerator.new() | ||
tree_generator.log_type = LOG | ||
tree_generator.leaves_type = LEAVES | ||
for i in 16: | ||
var s = tree_generator.generate() | ||
_tree_structures.append(s) | ||
|
||
var tallest_tree_height = 0 | ||
for structure in _tree_structures: | ||
var h = int(structure.voxels.get_size().y) | ||
if tallest_tree_height < h: | ||
tallest_tree_height = h | ||
_trees_min_y = _heightmap_min_y | ||
_trees_max_y = _heightmap_max_y + tallest_tree_height | ||
|
||
#_heightmap_noise.seed = 131183 | ||
#_heightmap_noise.frequency = 1.0 / 128.0 | ||
#_heightmap_noise.fractal_octaves = 4 | ||
|
||
# IMPORTANT | ||
# If we don't do this `Curve` could bake itself when interpolated, | ||
# and this causes crashes when used in multiple threads | ||
HeightmapCurve.bake() | ||
|
||
|
||
func _get_used_channels_mask() -> int: | ||
return 1 << _CHANNEL | ||
|
||
|
||
func _generate_block(buffer: VoxelBuffer, origin_in_voxels: Vector3i, lod: int): | ||
# TODO There is an issue doing this, need to investigate why because it should be supported | ||
# Saves from this demo used 8-bit, which is no longer the default | ||
# buffer.set_channel_depth(_CHANNEL, VoxelBuffer.DEPTH_8_BIT) | ||
|
||
# Assuming input is cubic in our use case (it doesn't have to be!) | ||
var block_size := int(buffer.get_size().x) | ||
var oy := origin_in_voxels.y | ||
# TODO This hardcodes a cubic block size of 16, find a non-ugly way... | ||
# Dividing is a false friend because of negative values | ||
var chunk_pos := Vector3( | ||
origin_in_voxels.x >> 4, | ||
origin_in_voxels.y >> 4, | ||
origin_in_voxels.z >> 4) | ||
|
||
_heightmap_range = _heightmap_max_y - _heightmap_min_y | ||
|
||
# Ground | ||
|
||
if origin_in_voxels.y > _heightmap_max_y: | ||
buffer.fill(AIR, _CHANNEL) | ||
|
||
elif origin_in_voxels.y + block_size < _heightmap_min_y: | ||
buffer.fill(DIRT, _CHANNEL) | ||
|
||
else: | ||
var rng := RandomNumberGenerator.new() | ||
rng.seed = _get_chunk_seed_2d(chunk_pos) | ||
|
||
var gx : int | ||
var gz := origin_in_voxels.z | ||
|
||
for z in block_size: | ||
gx = origin_in_voxels.x | ||
|
||
for x in block_size: | ||
var height := 1 | ||
var relative_height := 1 | ||
|
||
# Dirt and grass | ||
if relative_height > block_size: | ||
buffer.fill_area(DIRT, | ||
Vector3(x, 0, z), Vector3(x + 1, block_size, z + 1), _CHANNEL) | ||
elif relative_height > 0: | ||
buffer.fill_area(DIRT, | ||
Vector3(x, 0, z), Vector3(x + 1, relative_height, z + 1), _CHANNEL) | ||
if height >= 0: | ||
buffer.set_voxel(DIRT, x, relative_height +1, z, _CHANNEL) | ||
if relative_height < block_size and rng.randf() > 0.1: | ||
var foliage = DIRT # TALL_GRASS | ||
#if # rng.randf() < 0.1: | ||
# foliage = GRASS # DEAD_SHRUB | ||
buffer.set_voxel(DIRT, x, relative_height, z, _CHANNEL) | ||
|
||
# Water | ||
if height < 0 and oy < 0: | ||
var start_relative_height := 0 | ||
if relative_height > 0: | ||
start_relative_height = relative_height | ||
buffer.fill_area(WATER_FULL, | ||
Vector3(x, start_relative_height, z), | ||
Vector3(x + 1, block_size, z + 1), _CHANNEL) | ||
if oy + block_size == 0: | ||
# Surface block | ||
buffer.set_voxel(WATER_TOP, x, block_size - 1, z, _CHANNEL) | ||
|
||
gx += 1 | ||
|
||
gz += 1 | ||
|
||
# Trees | ||
|
||
# if origin_in_voxels.y <= _trees_max_y and origin_in_voxels.y + block_size >= _trees_min_y: | ||
# var voxel_tool := buffer.get_voxel_tool() | ||
# var structure_instances := [] | ||
# | ||
# _get_tree_instances_in_chunk(chunk_pos, origin_in_voxels, block_size, structure_instances) | ||
# | ||
# # Relative to current block | ||
# var block_aabb := AABB(Vector3(), buffer.get_size() + Vector3i(1, 1, 1)) | ||
|
||
# for dir in _moore_dirs: | ||
# var ncpos : Vector3 = (chunk_pos + dir).round() | ||
# _get_tree_instances_in_chunk(ncpos, origin_in_voxels, block_size, structure_instances) | ||
|
||
# for structure_instance in structure_instances: | ||
# var pos : Vector3 = structure_instance[0] | ||
# var structure : Structure = structure_instance[1] | ||
# var lower_corner_pos := pos - structure.offset | ||
# var aabb := AABB(lower_corner_pos, structure.voxels.get_size() + Vector3i(1, 1, 1)) | ||
|
||
# if aabb.intersects(block_aabb): | ||
# voxel_tool.paste_masked(lower_corner_pos, | ||
# structure.voxels, 1 << VoxelBuffer.CHANNEL_TYPE, | ||
# # Masking | ||
# VoxelBuffer.CHANNEL_TYPE, AIR) | ||
|
||
# buffer.compress_uniform_channels() | ||
|
||
|
||
#func _get_tree_instances_in_chunk( | ||
# cpos: Vector3, offset: Vector3, chunk_size: int, tree_instances: Array): | ||
# | ||
# var rng := RandomNumberGenerator.new() | ||
# rng.seed = _get_chunk_seed_2d(cpos) | ||
|
||
# for i in 4: | ||
# var pos := Vector3(rng.randi() % chunk_size, 0, rng.randi() % chunk_size) | ||
# pos += cpos * chunk_size | ||
# pos.y = 1 | ||
# | ||
# if pos.y > 0: | ||
# pos -= offset | ||
# var si := rng.randi() % len(_tree_structures) | ||
# var structure : Structure = _tree_structures[si] | ||
# tree_instances.append([pos.round(), structure]) | ||
|
||
|
||
#static func get_chunk_seed(cpos: Vector3) -> int: | ||
# return cpos.x ^ (13 * int(cpos.y)) ^ (31 * int(cpos.z)) | ||
|
||
|
||
static func _get_chunk_seed_2d(cpos: Vector3) -> int: | ||
return int(cpos.x) ^ (31 * int(cpos.z)) | ||
|
||
|
||
#func _get_height_at(x: int, z: int) -> int: | ||
# var t = 0.5 + 0.5 * _heightmap_noise.get_noise_2d(x, z) | ||
# return int(HeightmapCurve.sample_baked(t)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
[gd_resource type="VoxelGeneratorScript" load_steps=2 format=3 uid="uid://b7s8gfvrf0gc4"] | ||
|
||
[ext_resource type="Script" path="res://blocky_game/generator/world_generator_test3.gd" id="1"] | ||
|
||
[resource] | ||
script = ExtResource("1") |