Linked repository source
examples/voxel_stream/project/main.gd
This read-only view comes from the file in the Gododin repository. It retains its design, example or evidence context.
Download the original file · Return to the guide
extends Node3D
# Godot owns presentation and input. VoxelWorld owns chunk work, staging,
# adopted mesh RIDs and instance RIDs. One Dictionary surface-add bridges them.
const CHUNK_MATERIAL := preload("res://chunk_material.tres")
const STREAM_EVAL := preload("res://stream_eval.gd")
# Time-spread upload budget: keep staging+committing finished chunks while the
# frame has headroom instead of a fixed chunk count. One pump+commit cycle
# always runs so progress never stalls; the native upload_budget stays as a
# hard per-frame ceiling.
const UPLOAD_BUDGET_USEC := 2000
@onready var world: Node = $World
@onready var cam_rig: Node3D = $CameraRig
@onready var camera: Camera3D = $CameraRig/Camera3D
@onready var stats_label: Label = $UI/Panel/VBox/Stats
@onready var seed_field: LineEdit = $UI/Panel/VBox/SeedRow/Seed
@onready var radius_slider: HSlider = $UI/Panel/VBox/RadiusRow/Radius
@onready var radius_label: Label = $UI/Panel/VBox/RadiusRow/RadiusLabel
@onready var feedback: Label = $UI/Panel/VBox/Feedback
# Keep the Resource alive for as long as any surface refers to its RID.
var _material: Material = CHUNK_MATERIAL
var _last_anchor := Vector3(1e9, 1e9, 1e9)
var _quitting := false
var _stats_commits := 0
var _stats_stamp := 0
var evaluation: RefCounted
func _ready() -> void:
if OS.get_environment("GODODIN_VOXEL_STD_MATERIAL") != "":
var standard := StandardMaterial3D.new()
standard.vertex_color_use_as_albedo = true
standard.roughness = 1.0
_material = standard
if OS.get_environment("GODODIN_VOXEL_NOSHADOW") != "":
$Sun.shadow_enabled = false
if OS.get_environment("GODODIN_VOXEL_NOFOG") != "":
$WorldEnvironment.environment.fog_enabled = false
$UI/Panel/VBox/SeedRow/Generate.pressed.connect(_on_generate)
seed_field.text_submitted.connect(func(_text: String) -> void: _on_generate())
radius_slider.value_changed.connect(_on_radius_changed)
$StatsTimer.timeout.connect(_on_stats_timer)
# EX-VOXEL: the authored world settings Resource seeds the controls, and
# the coarse edit-committed event drives the success feedback.
var settings: Resource = world.get("settings")
if settings != null:
seed_field.text = str(int(settings.seed))
radius_slider.value = clampf(float(int(settings.view_radius)), 1.0, 12.0)
world.connect("edit_committed", _on_edit_committed)
if "--eval" in OS.get_cmdline_user_args() or "--probe" in OS.get_cmdline_user_args():
seed_field.editable = false
radius_slider.editable = false
$UI/Panel/VBox/SeedRow/Generate.disabled = true
evaluation = STREAM_EVAL.new(self)
cam_rig.set_process(false)
cam_rig.set_process_unhandled_input(false)
if not evaluation.start():
return
else:
_on_generate()
_stats_stamp = Time.get_ticks_usec()
func _on_edit_committed(edit_id: int, chunks: int, wait_usec: int) -> void:
# The coarse edit-committed event: geometry already changed as each chunk
# committed; this is the success feedback, never the write notification.
feedback.text = "Edit #%d committed — %d chunks in %d µs" % [edit_id, chunks, wait_usec]
func _on_generate() -> void:
if not seed_field.text.is_valid_int():
feedback.text = "Enter a whole-number seed."
return
if not configure_world(int(seed_field.text), int(radius_slider.value)):
return
feedback.text = "Streaming a new world…"
seed_field.release_focus()
_stats_commits = 0
_stats_stamp = Time.get_ticks_usec()
func configure_world(seed_value: int, radius: int) -> bool:
var code: int = world.call("configure", seed_value, radius)
if code != 0:
fail("configure=%d" % code)
return false
_last_anchor = Vector3(1e9, 1e9, 1e9)
seed_field.text = str(seed_value)
radius_slider.set_value_no_signal(radius)
radius_label.text = "Radius %d" % radius
_stats_commits = 0
_stats_stamp = Time.get_ticks_usec()
return true
func _on_radius_changed(value: float) -> void:
radius_label.text = "Radius %d" % int(value)
feedback.text = "Press Generate to apply the radius."
func fail(reason: String) -> void:
if _quitting:
return
_quitting = true
print("GODODIN_VOXEL_STREAM_FAIL %s" % reason)
world.call("shutdown")
get_tree().quit(1)
func _process(delta: float) -> void:
if _quitting:
return
var entered := Time.get_ticks_usec()
var anchor := cam_rig.global_position
if anchor.distance_squared_to(_last_anchor) > 0.5:
_last_anchor = anchor
var code: int = world.call("set_anchor", anchor.x, anchor.y, anchor.z)
if code < 0:
fail("set_anchor=%d" % code)
return
var began: int = world.call("begin_frame")
if began < 0:
fail("begin_frame=%d" % began)
return
while true:
var pumped: int = world.call("pump")
if pumped < 0:
fail("pump=%d last_error=%d" % [pumped, world.call("get_last_error")])
return
if pumped == 0:
break
if not _consume_staged():
fail("consume")
return
if Time.get_ticks_usec() - entered > UPLOAD_BUDGET_USEC:
break
if evaluation != null:
evaluation.tick(delta, entered, Time.get_ticks_usec() - entered)
func _consume_staged() -> bool:
var vertex: PackedByteArray = world.call("take_vertex_bytes")
var attribute: PackedByteArray = world.call("take_attribute_bytes")
var index: PackedByteArray = world.call("take_index_bytes")
var box_bytes: PackedByteArray = world.call("take_aabb_bytes")
if box_bytes.size() != 24:
return false
var count: int = world.call("front_vertex_count")
var index_count: int = world.call("front_index_count")
if count == 0:
return vertex.is_empty() and attribute.is_empty() and index.is_empty() and world.call("commit_front") == 0
if vertex.size() != count * 16 or attribute.size() != count * 4 or index.size() != index_count * 2:
return false
var box := box_bytes.to_float32_array()
var bounds := AABB(Vector3(box[0], box[1], box[2]), Vector3.ZERO)
bounds.end = Vector3(box[3], box[4], box[5])
var mesh := RenderingServer.mesh_create()
# stage_front adopts the RID immediately; native rollback/commit/shutdown
# owns it from here, including an upload or verification failure.
if world.call("stage_front", mesh.get_id()) != 0:
RenderingServer.free_rid(mesh)
return false
var surface := {
"primitive": RenderingServer.PRIMITIVE_TRIANGLES,
"format": int(world.call("get_surface_format")),
"vertex_data": vertex,
"attribute_data": attribute,
"vertex_count": count,
"aabb": bounds,
"index_data": index,
"index_count": index_count,
"material": _material.get_rid(),
}
RenderingServer.mesh_add_surface(mesh, surface)
if RenderingServer.mesh_get_surface_count(mesh) != 1:
return false
if evaluation != null and not evaluation.check_upload(mesh, surface, int(world.call("front_lod"))):
return false
return world.call("commit_front") == 0
func _unhandled_input(event: InputEvent) -> void:
if evaluation != null:
return
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
if Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
_dig()
func _dig() -> void:
# No physics bodies are needed for the demo: sample the short voxel ray.
# This is input-event work, never a per-frame/per-voxel foreign loop.
var direction := -camera.global_transform.basis.z
for sample_index in range(1, 49):
var position := camera.global_position + direction * (float(sample_index) * 0.25)
var cell := Vector3i(position.floor())
if world.call("get_voxel", cell.x, cell.y, cell.z) > 0:
var edit_id: int = world.call("begin_edit")
if edit_id < 0:
return
var changed := carve_sphere(cell)
feedback.text = "Dug %d voxels — waiting for chunk commits…" % changed
return
feedback.text = "No terrain within 12 blocks."
func carve_sphere(center: Vector3i) -> int:
var changed := 0
for dx in range(-2, 3):
for dy in range(-2, 3):
for dz in range(-2, 3):
if dx * dx + dy * dy + dz * dz > 4:
continue
var at := center + Vector3i(dx, dy, dz)
var code: int = world.call("set_voxel", at.x, at.y, at.z, 0)
if code < 0:
fail("set_voxel=%d" % code)
return -1
changed += code
if changed > 0:
print("GODODIN_VOXEL_STREAM_DIG voxels=%d" % changed)
return changed
func _on_stats_timer() -> void:
if _quitting:
return
var now := Time.get_ticks_usec()
var commits := int(world.call("get_chunks_meshed"))
var rate := float(maxi(commits - _stats_commits, 0)) * 1e6 / float(maxi(now - _stats_stamp, 1))
_stats_commits = commits
_stats_stamp = now
stats_label.text = "%d resident · %d waiting · %d fps\n%.1f uploads/s · %d LOD transitions" % [
world.call("get_chunks_resident"), world.call("get_unsettled_chunks"),
Engine.get_frames_per_second(), rate, world.call("get_lod_remeshes")]
if feedback.text == "Streaming a new world…" and world.call("is_settled"):
feedback.text = "Ready · edits last while chunks remain loaded"
func _exit_tree() -> void:
# Native deinit has no Godot call authority, so free server RIDs here.
var code: int = world.call("shutdown")
if code != 0:
push_error("GODODIN_VOXEL_STREAM_FAIL exit_shutdown=%d" % code)
evaluation = null