Refactor the way Blocks are loaded. Now a node to avoid cyclic references.
parent
d01056015c
commit
f9de1b5fcb
|
@ -0,0 +1,23 @@
|
|||
extends Node
|
||||
|
||||
# Note: can't import `Blocks` here, otherwise it's a cylcic ref...
|
||||
# And I don't want to pollute global space of all the demos with this
|
||||
|
||||
# Info packed into a class,
|
||||
# to not pollute namespace of all the block scripts that could inherit from it
|
||||
class BaseInfo:
|
||||
var id := 0
|
||||
var name := ""
|
||||
var gui_model_path := ""
|
||||
var directory := ""
|
||||
var rotation_type := 0
|
||||
var sprite_texture : Texture
|
||||
var transparent := false
|
||||
var backface_culling := true
|
||||
# TODO Rename `variants`
|
||||
var voxels := []
|
||||
|
||||
|
||||
var base_info := BaseInfo.new()
|
||||
|
||||
|
|
@ -1,5 +1,10 @@
|
|||
extends Resource
|
||||
# Container for all block types.
|
||||
# It is not a resource because it references scripts that can depend on it,
|
||||
# causing cycles. So instead, it's more convenient to make it a node in the tree.
|
||||
# IMPORTANT: Needs to be first in tree. Other nodes may use it in _ready().
|
||||
extends Node
|
||||
|
||||
const Block = preload("./block.gd")
|
||||
const Util = preload("res://common/util.gd")
|
||||
|
||||
const ROTATION_TYPE_NONE = 0
|
||||
|
@ -30,20 +35,6 @@ const ROOT = "res://blocky_game/blocks"
|
|||
|
||||
const AIR_ID = 0
|
||||
|
||||
|
||||
class Block:
|
||||
var id := 0
|
||||
var name := ""
|
||||
var gui_model_path := ""
|
||||
var directory := ""
|
||||
var rotation_type := ROTATION_TYPE_NONE
|
||||
var sprite_texture : Texture
|
||||
var transparent := false
|
||||
var backface_culling := true
|
||||
var voxels := []
|
||||
var behavior = null
|
||||
|
||||
|
||||
class RawMapping:
|
||||
var block_id := 0
|
||||
var variant_index := 0
|
||||
|
@ -165,8 +156,9 @@ func get_model_library() -> VoxelLibrary:
|
|||
|
||||
func get_block_by_name(block_name: String) -> Block:
|
||||
for b in _blocks:
|
||||
if b.name == block_name:
|
||||
if b.base_info.name == block_name:
|
||||
return b
|
||||
assert(false)
|
||||
return null
|
||||
|
||||
|
||||
|
@ -191,8 +183,19 @@ func _create_block(params: Dictionary):
|
|||
"behavior": ""
|
||||
})
|
||||
|
||||
var block = Block.new()
|
||||
block.id = len(_blocks)
|
||||
var block : Block
|
||||
if params.behavior != "":
|
||||
# Block with special behavior
|
||||
var behavior_path := str(ROOT, "/", params.directory, "/", params.behavior)
|
||||
var behavior = load(behavior_path)
|
||||
block = behavior.new()
|
||||
else:
|
||||
# Generic
|
||||
block = Block.new()
|
||||
|
||||
# Fill in base info
|
||||
var base_info = block.base_info
|
||||
base_info.id = len(_blocks)
|
||||
|
||||
for i in len(params.voxels):
|
||||
var vname = params.voxels[i]
|
||||
|
@ -202,28 +205,25 @@ func _create_block(params: Dictionary):
|
|||
assert(id != -1)
|
||||
params.voxels[i] = id
|
||||
var rm = RawMapping.new()
|
||||
rm.block_id = block.id
|
||||
rm.block_id = base_info.id
|
||||
rm.variant_index = i
|
||||
if id >= len(_raw_mappings):
|
||||
_raw_mappings.resize(id + 1)
|
||||
_raw_mappings[id] = rm
|
||||
|
||||
block.name = params.name
|
||||
block.directory = params.directory
|
||||
block.rotation_type = params.rotation_type
|
||||
block.voxels = params.voxels
|
||||
block.transparent = params.transparent
|
||||
block.backface_culling = params.backface_culling
|
||||
if block.directory != "":
|
||||
block.gui_model_path = str(ROOT, "/", params.directory, "/", params.gui_model)
|
||||
base_info.name = params.name
|
||||
base_info.directory = params.directory
|
||||
base_info.rotation_type = params.rotation_type
|
||||
base_info.voxels = params.voxels
|
||||
base_info.transparent = params.transparent
|
||||
base_info.backface_culling = params.backface_culling
|
||||
if base_info.directory != "":
|
||||
base_info.gui_model_path = str(ROOT, "/", params.directory, "/", params.gui_model)
|
||||
var sprite_path = str(ROOT, "/", params.directory, "/", params.name, "_sprite.png")
|
||||
block.sprite_texture = load(sprite_path)
|
||||
|
||||
if params.behavior != "":
|
||||
var behavior_path := str(ROOT, "/", params.directory, "/", params.behavior)
|
||||
call_deferred("_load_behavior", block, behavior_path)
|
||||
base_info.sprite_texture = load(sprite_path)
|
||||
|
||||
_blocks.append(block)
|
||||
add_child(block)
|
||||
|
||||
|
||||
func _notification(what):
|
||||
|
@ -232,15 +232,6 @@ func _notification(what):
|
|||
print("Deleting blocks.gd")
|
||||
|
||||
|
||||
# TODO Find a better design.
|
||||
# Workaround for now... Godot can't finish loading blocks.tres,
|
||||
# because it has to load and reference block behavior scripts, which themselves
|
||||
# are const-referencing blocks.gd...
|
||||
func _load_behavior(block: Block, behavior_path: String):
|
||||
var b = load(behavior_path)
|
||||
block.behavior = b.new(block)
|
||||
|
||||
|
||||
static func _defaults(d, defaults):
|
||||
for k in defaults:
|
||||
if not d.has(k):
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
[gd_resource type="Resource" load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://blocky_game/blocks/blocks.gd" type="Script" id=1]
|
||||
|
||||
[resource]
|
||||
script = ExtResource( 1 )
|
|
@ -1,7 +1,7 @@
|
|||
extends "../block.gd"
|
||||
|
||||
# TODO Check if this import causes a cyclic reference, hopefully not
|
||||
const Blocks = preload("../blocks.tres")
|
||||
const Util = preload("res://common/util.gd")
|
||||
const Blocks = preload("../blocks.gd")
|
||||
|
||||
const _STRAIGHT = 0
|
||||
const _TURN = 2
|
||||
|
@ -63,15 +63,8 @@ const _auto_orient_table = [ # -x | +x | -z | +z
|
|||
]
|
||||
|
||||
|
||||
var _variants : Array
|
||||
var _rail_block_id : int
|
||||
|
||||
|
||||
func _init(b):
|
||||
# TODO Can't store whole block info, it would cause a cyclic reference.
|
||||
# Need to think about a better design eventually.
|
||||
_variants = b.voxels
|
||||
_rail_block_id = b.id
|
||||
func _get_blocks() -> Blocks:
|
||||
return get_parent() as Blocks
|
||||
|
||||
|
||||
func place(voxel_tool: VoxelTool, pos: Vector3, look_dir: Vector3):
|
||||
|
@ -94,7 +87,7 @@ func place(voxel_tool: VoxelTool, pos: Vector3, look_dir: Vector3):
|
|||
|
||||
# Orient and place rail
|
||||
var variant_index := _get_auto_oriented_variant(pos, available_neighbors, look_dir)
|
||||
voxel_tool.set_voxel(pos, _variants[variant_index])
|
||||
voxel_tool.set_voxel(pos, base_info.voxels[variant_index])
|
||||
|
||||
# Orient neighbors
|
||||
for di in available_neighbors:
|
||||
|
@ -109,7 +102,7 @@ func place(voxel_tool: VoxelTool, pos: Vector3, look_dir: Vector3):
|
|||
|
||||
var nn := _find_neighbor_rails(voxel_tool, neighbor.pos, connected_dirs)
|
||||
var neighbor_variant_index := _get_auto_oriented_variant(neighbor.pos, nn, Vector3())
|
||||
voxel_tool.set_voxel(neighbor.pos, _variants[neighbor_variant_index])
|
||||
voxel_tool.set_voxel(neighbor.pos, base_info.voxels[neighbor_variant_index])
|
||||
|
||||
|
||||
static func _get_auto_oriented_variant(
|
||||
|
@ -138,6 +131,7 @@ static func _get_auto_oriented_variant(
|
|||
|
||||
func _find_neighbor_rails(voxel_tool: VoxelTool, pos: Vector3, direction_list: Array) -> Dictionary:
|
||||
var neighbors := {}
|
||||
var blocks := _get_blocks()
|
||||
|
||||
# We only want to keep one rail per direction.
|
||||
# Priority is given to rails at the same level, then upward, then downward.
|
||||
|
@ -150,13 +144,13 @@ func _find_neighbor_rails(voxel_tool: VoxelTool, pos: Vector3, direction_list: A
|
|||
var npos := pos + Blocks.get_y_dir_vec(di)
|
||||
npos.y += dy
|
||||
var nv := voxel_tool.get_voxel(npos)
|
||||
var nrm := Blocks.get_raw_mapping(nv)
|
||||
var nrm := blocks.get_raw_mapping(nv)
|
||||
|
||||
if nrm.block_id == _rail_block_id:
|
||||
if nrm.block_id == base_info.id:
|
||||
var group := _get_group_from_index(nrm.variant_index)
|
||||
# Decode rail
|
||||
neighbors[di] = {
|
||||
#"id": nrm.block_id,
|
||||
"id": nrm.block_id,
|
||||
"group": group,
|
||||
"rotation": nrm.variant_index - group,
|
||||
"pos": npos
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[gd_scene load_steps=15 format=2]
|
||||
[gd_scene load_steps=16 format=2]
|
||||
|
||||
[ext_resource path="res://blocky_game/blocks/voxel_library.tres" type="VoxelLibrary" id=1]
|
||||
[ext_resource path="res://blocky_game/blocks/terrain_material.tres" type="Material" id=2]
|
||||
|
@ -11,6 +11,7 @@
|
|||
[ext_resource path="res://blocky_game/blocks/terrain_material_foliage.tres" type="Material" id=9]
|
||||
[ext_resource path="res://blocky_game/random_ticks.gd" type="Script" id=10]
|
||||
[ext_resource path="res://blocky_game/water.gd" type="Script" id=11]
|
||||
[ext_resource path="res://blocky_game/blocks/blocks.gd" type="Script" id=12]
|
||||
|
||||
[sub_resource type="ProceduralSky" id=1]
|
||||
sky_top_color = Color( 0.268204, 0.522478, 0.847656, 1 )
|
||||
|
@ -47,6 +48,9 @@ directory = "res://blocky_game/save"
|
|||
[node name="Main" type="Node"]
|
||||
script = ExtResource( 5 )
|
||||
|
||||
[node name="Blocks" type="Node" parent="."]
|
||||
script = ExtResource( 12 )
|
||||
|
||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
||||
environment = SubResource( 2 )
|
||||
|
||||
|
@ -55,6 +59,7 @@ stream = SubResource( 3 )
|
|||
voxel_library = ExtResource( 1 )
|
||||
viewer_path = NodePath("../CharacterAvatar")
|
||||
generate_collisions = false
|
||||
run_stream_in_editor = false
|
||||
material/0 = ExtResource( 2 )
|
||||
material/1 = ExtResource( 3 )
|
||||
material/2 = ExtResource( 9 )
|
||||
|
|
|
@ -15,6 +15,10 @@ var _current_block_id := -1
|
|||
var _blocks := Blocks.new()
|
||||
|
||||
|
||||
func _ready():
|
||||
add_child(_blocks)
|
||||
|
||||
|
||||
func _process(_delta):
|
||||
print("Block ", _current_block_id)
|
||||
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
extends CenterContainer
|
||||
|
||||
const Blocks = preload("../../blocks/blocks.tres")
|
||||
|
||||
onready var _selected_frame = $HBoxContainer/HotbarSlot/HotbarSlotSelect
|
||||
onready var _slot_container = $HBoxContainer
|
||||
onready var _block_types = get_node("/root/Main/Blocks")
|
||||
|
||||
var _inventory = [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
var _inventory_index = 0
|
||||
var _inventory := [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
var _inventory_index := 0
|
||||
|
||||
|
||||
func _ready():
|
||||
|
@ -25,8 +24,8 @@ func select_slot(i: int):
|
|||
|
||||
var block_id = _inventory[_inventory_index]
|
||||
if block_id != -1:
|
||||
var block = Blocks.get_block(block_id)
|
||||
print("Inventory select ", block.name)
|
||||
var block = _block_types.get_block(block_id)
|
||||
print("Inventory select ", block.base_info.name)
|
||||
|
||||
_selected_frame.get_parent().remove_child(_selected_frame)
|
||||
var slot = _slot_container.get_child(i)
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
extends Control
|
||||
|
||||
const Blocks = preload("../../blocks/blocks.tres")
|
||||
|
||||
|
||||
onready var _texture_rect = $TextureRect
|
||||
onready var _block_types = get_node("/root/Main/Blocks")
|
||||
|
||||
|
||||
func set_block_id(id: int):
|
||||
if id == -1:
|
||||
_texture_rect.texture = null
|
||||
else:
|
||||
var block = Blocks.get_block(id)
|
||||
_texture_rect.texture = block.sprite_texture
|
||||
var block = _block_types.get_block(id)
|
||||
_texture_rect.texture = block.base_info.sprite_texture
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
extends Node
|
||||
|
||||
const Util = preload("res://common/util.gd")
|
||||
const Blocks = preload("../blocks/blocks.tres")
|
||||
const Blocks = preload("../blocks/blocks.gd")
|
||||
|
||||
const COLLISION_LAYER_AVATAR = 2
|
||||
|
||||
|
@ -23,6 +23,8 @@ export(Material) var cursor_material = null
|
|||
# TODO Eventually invert these dependencies
|
||||
onready var _head : Camera = get_parent().get_node("Camera")
|
||||
onready var _hotbar = get_node("../HotBar")
|
||||
onready var _block_types : Blocks = get_node("/root/Main/Blocks")
|
||||
onready var _water_updater = get_node("../../Water")
|
||||
|
||||
var _terrain = null
|
||||
var _terrain_tool = null
|
||||
|
@ -94,7 +96,7 @@ func _physics_process(delta):
|
|||
print("Can't place here!")
|
||||
|
||||
elif _action_pick:
|
||||
var rm := Blocks.get_raw_mapping(hit_raw_id)
|
||||
var rm := _block_types.get_raw_mapping(hit_raw_id)
|
||||
_hotbar.try_select_slot_by_block_id(rm.block_id)
|
||||
|
||||
_action_place = false
|
||||
|
@ -139,33 +141,32 @@ func _can_place_voxel_at(pos: Vector3):
|
|||
|
||||
|
||||
func _place_single_block(pos: Vector3, block_id: int):
|
||||
var block := Blocks.get_block(block_id)
|
||||
var block := _block_types.get_block(block_id)
|
||||
var voxel_id := 0
|
||||
var look_dir := -_head.get_transform().basis.z
|
||||
|
||||
match block.rotation_type:
|
||||
match block.base_info.rotation_type:
|
||||
Blocks.ROTATION_TYPE_NONE:
|
||||
voxel_id = block.voxels[0]
|
||||
voxel_id = block.base_info.voxels[0]
|
||||
|
||||
Blocks.ROTATION_TYPE_AXIAL:
|
||||
var axis := Util.get_longest_axis(look_dir)
|
||||
voxel_id = block.voxels[axis]
|
||||
voxel_id = block.base_info.voxels[axis]
|
||||
|
||||
Blocks.ROTATION_TYPE_Y:
|
||||
var rot := Blocks.get_y_rotation_from_look_dir(look_dir)
|
||||
voxel_id = block.voxels[rot]
|
||||
voxel_id = block.base_info.voxels[rot]
|
||||
|
||||
Blocks.ROTATION_TYPE_CUSTOM_BEHAVIOR:
|
||||
block.behavior.place(_terrain_tool, pos, look_dir)
|
||||
block.place(_terrain_tool, pos, look_dir)
|
||||
_:
|
||||
# Unknown value
|
||||
assert(false)
|
||||
|
||||
if block.rotation_type != Blocks.ROTATION_TYPE_CUSTOM_BEHAVIOR:
|
||||
if block.base_info.rotation_type != Blocks.ROTATION_TYPE_CUSTOM_BEHAVIOR:
|
||||
_place_single_voxel(pos, voxel_id)
|
||||
|
||||
var updater = get_node("../../Water")
|
||||
updater.schedule(pos)
|
||||
_water_updater.schedule(pos)
|
||||
|
||||
|
||||
func _place_single_voxel(pos: Vector3, type: int):
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
extends Node
|
||||
|
||||
const Blocks = preload("./blocks/blocks.tres")
|
||||
const Blocks = preload("./blocks/blocks.gd")
|
||||
|
||||
const MAX_UPDATES_PER_FRAME = 64
|
||||
const INTERVAL_SECONDS = 0.2
|
||||
|
@ -15,8 +15,9 @@ const _spread_directions = [
|
|||
|
||||
onready var _terrain : VoxelTerrain = get_node("../VoxelTerrain")
|
||||
onready var _terrain_tool := _terrain.get_voxel_tool()
|
||||
onready var _blocks : Blocks = get_node("../Blocks")
|
||||
|
||||
# TODO An efficient Queue data structure would ne NICE
|
||||
# TODO An efficient Queue data structure would be NICE
|
||||
var _update_queue := []
|
||||
var _process_queue := []
|
||||
var _process_index := 0
|
||||
|
@ -29,7 +30,7 @@ var _time_before_next_process := 0.0
|
|||
|
||||
func _ready():
|
||||
_terrain_tool.set_channel(VoxelBuffer.CHANNEL_TYPE)
|
||||
var water = Blocks.get_block_by_name("water")
|
||||
var water = _blocks.get_block_by_name("water").base_info
|
||||
_water_id = water.id
|
||||
_water_full = water.voxels[0]
|
||||
_water_top = water.voxels[1]
|
||||
|
@ -84,7 +85,7 @@ func _swap_queues():
|
|||
|
||||
func _process_cell(pos: Vector3):
|
||||
var v := _terrain_tool.get_voxel(pos)
|
||||
var rm := Blocks.get_raw_mapping(v)
|
||||
var rm := _blocks.get_raw_mapping(v)
|
||||
|
||||
if rm.block_id != _water_id:
|
||||
# Water got removed in the meantime
|
||||
|
@ -107,7 +108,7 @@ func _fill_with_water(pos: Vector3):
|
|||
var below := pos - Vector3(0, 1, 0)
|
||||
var above_v := _terrain_tool.get_voxel(above)
|
||||
var below_v := _terrain_tool.get_voxel(below)
|
||||
var above_rm := Blocks.get_raw_mapping(above_v)
|
||||
var above_rm := _blocks.get_raw_mapping(above_v)
|
||||
# Make sure the top has the surface model
|
||||
if above_rm.block_id == _water_id:
|
||||
_terrain_tool.set_voxel(pos, _water_full)
|
||||
|
|
Loading…
Reference in New Issue