feat: 3D blobber dungeon generator (PR 1)
Replaces the 2D-only demo pipeline with a 3D cell-based blobber generator. Per-cell face walls, per-material mesh emission, and a GDExtension binding that returns a Dictionary with ArrayMesh surfaces the demo consumes directly. - src/blobber/: cell3d_t data model, dungeon container, pipeline that wraps the 2D generator per level and materializes into cell3d - src/mesh/: face-quad emitter with per-material groups + .obj dump - src/genesis3d_main.c: new CLI driving the blobber + mesh - godot/: BrogueGen.generate_dungeon(seed, num_levels, depth) binding with dungeon_to_dict packing cells + mesh surfaces - demo/: demo_blobber.tscn + dungeon_builder.gd, func_godot addon for the .map export path, point/entity templates, TrenchBroom docs - Retired: old arcade/FPS demo scenes and their scripts, unused meshlib Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
6ee49c3375
commit
7a6ae79d01
160 changed files with 7209 additions and 2072 deletions
|
|
@ -0,0 +1,333 @@
|
|||
@tool
|
||||
@icon("res://addons/func_godot/icons/icon_godot_ranger.svg")
|
||||
class_name TrenchBroomGameConfig extends Resource
|
||||
## Game configuration definition for TrenchBroom.
|
||||
##
|
||||
## Defines a game for TrenchBroom to express a set of entity definitions and editor behaviors.
|
||||
##
|
||||
## @tutorial(TrenchBroom Manual Game Configuration Information): https://trenchbroom.github.io/manual/latest/#game_configuration
|
||||
|
||||
enum GameConfigVersion {
|
||||
Latest,
|
||||
Version4,
|
||||
Version8,
|
||||
Version9
|
||||
}
|
||||
|
||||
@export_tool_button("Export GameConfig") var _export_file: Callable = export_file
|
||||
|
||||
## Name of the game in TrenchBroom's game list.
|
||||
@export var game_name : String = "FuncGodot"
|
||||
|
||||
## Icon for TrenchBroom's game list.
|
||||
@export var icon : Texture2D = preload("res://addons/func_godot/icon32.png")
|
||||
|
||||
## Available map formats when creating a new map in TrenchBroom. The order of elements in the array is the order TrenchBroom will list the available formats.
|
||||
## The [i]"initialmap"[/i] key value is optional.
|
||||
@export var map_formats: Array[Dictionary] = [
|
||||
{ "format": "Valve", "initialmap": "initial_valve.map" },
|
||||
{ "format": "Standard", "initialmap": "initial_standard.map" },
|
||||
{ "format": "Quake2", "initialmap": "initial_quake2.map" },
|
||||
{ "format": "Quake3" }
|
||||
]
|
||||
|
||||
@export_group("Textures")
|
||||
|
||||
## Path to top level textures folder relative to the game path. Also referred to as materials in the latest versions of TrenchBroom.
|
||||
@export var textures_root_folder: String = "textures"
|
||||
|
||||
## Textures matching these patterns will be hidden from TrenchBroom.
|
||||
@export var texture_exclusion_patterns: Array[String] = ["*_albedo", "*_ao", "*_emission", "*_height", "*_metallic", "*_normal", "*_orm", "*_roughness", "*_sss"]
|
||||
|
||||
## Palette path relative to your Game Path. Only needed for Quake WAD2 files. Half-Life WAD3 files contain the palettes within the texture information.
|
||||
@export var palette_path: String = "textures/palette.lmp"
|
||||
|
||||
@export_group("Entities")
|
||||
|
||||
## [FuncGodotFGDFile] resource to include with this game. If using multiple FGD File resources,
|
||||
## this should be the master FGD File that contains them in [member FuncGodotFGDFile.base_fgd_files].
|
||||
@export var fgd_file : FuncGodotFGDFile = preload("res://addons/func_godot/fgd/func_godot_fgd.tres")
|
||||
|
||||
## Scale expression that modifies the default display scale of entities in TrenchBroom.
|
||||
## See [url="https://trenchbroom.github.io/manual/latest/#game_configuration_files_entities"]TrenchBroom Manual Entity Configuration Information[/url] for more information.
|
||||
@export var entity_scale: String = "32"
|
||||
|
||||
## Toggles whether [FuncGodotFGDModelPointClass] resources will generate models from their [PackedScene] files.
|
||||
@export var generate_model_point_class_models: bool = true
|
||||
|
||||
## Arrays containing the [TrenchbroomTag] resource type.
|
||||
@export_group("Tags")
|
||||
|
||||
## [TrenchbroomTag] resources that apply to brush entities.
|
||||
@export var brush_tags : Array[Resource] = []
|
||||
|
||||
## [TrenchbroomTag] resources that apply to brush faces.
|
||||
@export var brushface_tags : Array[Resource] = [
|
||||
preload("res://addons/func_godot/game_config/trenchbroom/tb_face_tag_clip.tres"),
|
||||
preload("res://addons/func_godot/game_config/trenchbroom/tb_face_tag_skip.tres"),
|
||||
preload("res://addons/func_godot/game_config/trenchbroom/tb_face_tag_origin.tres")
|
||||
]
|
||||
|
||||
@export_group("Face Attributes")
|
||||
|
||||
## Default scale of textures on new brushes and when UV scale is reset.
|
||||
@export var default_uv_scale : Vector2 = Vector2(1, 1)
|
||||
|
||||
@export_group("Compatibility")
|
||||
|
||||
## Game configuration format compatible with the version of TrenchBroom being used.
|
||||
@export var game_config_version: GameConfigVersion = GameConfigVersion.Latest
|
||||
|
||||
# Matches tag key enum to the [String] name used in .cfg
|
||||
static func _get_match_key(tag_match_type: int) -> String:
|
||||
match tag_match_type:
|
||||
TrenchBroomTag.TagMatchType.TEXTURE:
|
||||
return "material"
|
||||
TrenchBroomTag.TagMatchType.CLASSNAME:
|
||||
return "classname"
|
||||
_:
|
||||
push_error("Tag match type %s is not valid" % [tag_match_type])
|
||||
return "ERROR"
|
||||
|
||||
# Generates completed text for a .cfg file.
|
||||
func _build_class_text() -> String:
|
||||
var map_formats_str : String = ""
|
||||
for map_format in map_formats:
|
||||
map_formats_str += "{ \"format\": \"" + map_format.format + "\""
|
||||
if map_format.has("initialmap"):
|
||||
map_formats_str += ", \"initialmap\": \"" + map_format.initialmap + "\""
|
||||
if map_format != map_formats[-1]:
|
||||
map_formats_str += " },\n\t\t"
|
||||
else:
|
||||
map_formats_str += " }"
|
||||
|
||||
var texture_exclusion_patterns_str := ""
|
||||
for tex_pattern in texture_exclusion_patterns:
|
||||
texture_exclusion_patterns_str += "\"" + tex_pattern + "\""
|
||||
if tex_pattern != texture_exclusion_patterns[-1]:
|
||||
texture_exclusion_patterns_str += ", "
|
||||
|
||||
var fgd_filename_str : String = "\"" + fgd_file.fgd_name + ".fgd\""
|
||||
|
||||
var brush_tags_str = _parse_tags(brush_tags)
|
||||
var brushface_tags_str = _parse_tags(brushface_tags)
|
||||
var uv_scale_str = _parse_default_uv_scale(default_uv_scale)
|
||||
|
||||
var config_text : String = ""
|
||||
match game_config_version:
|
||||
GameConfigVersion.Latest, GameConfigVersion.Version8, GameConfigVersion.Version9:
|
||||
config_text = _get_game_config_v9v8_text() % [
|
||||
game_name,
|
||||
map_formats_str,
|
||||
textures_root_folder,
|
||||
texture_exclusion_patterns_str,
|
||||
palette_path,
|
||||
fgd_filename_str,
|
||||
entity_scale,
|
||||
brush_tags_str,
|
||||
brushface_tags_str,
|
||||
uv_scale_str
|
||||
]
|
||||
|
||||
GameConfigVersion.Version4:
|
||||
config_text = _get_game_config_v4_text() % [
|
||||
game_name,
|
||||
map_formats_str,
|
||||
textures_root_folder,
|
||||
texture_exclusion_patterns_str,
|
||||
palette_path,
|
||||
fgd_filename_str,
|
||||
entity_scale,
|
||||
brush_tags_str,
|
||||
brushface_tags_str,
|
||||
uv_scale_str
|
||||
]
|
||||
|
||||
_:
|
||||
push_error("Unsupported Game Config Version!")
|
||||
|
||||
return config_text
|
||||
|
||||
# Converts brush, face, and attribute tags into a .cfg-usable String.
|
||||
func _parse_tags(tags: Array) -> String:
|
||||
var tags_str := ""
|
||||
for brush_tag in tags:
|
||||
if brush_tag.tag_match_type >= TrenchBroomTag.TagMatchType.size():
|
||||
continue
|
||||
tags_str += "{\n"
|
||||
tags_str += "\t\t\t\t\"name\": \"%s\",\n" % brush_tag.tag_name
|
||||
var attribs_str := ""
|
||||
for brush_tag_attrib in brush_tag.tag_attributes:
|
||||
attribs_str += "\"%s\"" % brush_tag_attrib
|
||||
if brush_tag_attrib != brush_tag.tag_attributes[-1]:
|
||||
attribs_str += ", "
|
||||
tags_str += "\t\t\t\t\"attribs\": [ %s ],\n" % attribs_str
|
||||
tags_str += "\t\t\t\t\"match\": \"%s\",\n" % _get_match_key(brush_tag.tag_match_type)
|
||||
tags_str += "\t\t\t\t\"pattern\": \"%s\"" % brush_tag.tag_pattern
|
||||
if brush_tag.texture_name != "":
|
||||
tags_str += ",\n"
|
||||
tags_str += "\t\t\t\t\"material\": \"%s\"" % brush_tag.texture_name
|
||||
tags_str += "\n"
|
||||
tags_str += "\t\t\t}"
|
||||
if brush_tag != tags[-1]:
|
||||
tags_str += ","
|
||||
if game_config_version > GameConfigVersion.Latest and game_config_version < GameConfigVersion.Version9:
|
||||
tags_str = tags_str.replace("material", "texture")
|
||||
return tags_str
|
||||
|
||||
# Converts array of flags to .cfg String.
|
||||
func _parse_flags(flags: Array) -> String:
|
||||
var flags_str := ""
|
||||
for attrib_flag in flags:
|
||||
flags_str += "{\n"
|
||||
flags_str += "\t\t\t\t\"name\": \"%s\",\n" % attrib_flag.attrib_name
|
||||
flags_str += "\t\t\t\t\"description\": \"%s\"\n" % attrib_flag.attrib_description
|
||||
flags_str += "\t\t\t}"
|
||||
if attrib_flag != flags[-1]:
|
||||
flags_str += ","
|
||||
return flags_str
|
||||
|
||||
# Converts default uv scale vector to .cfg String.
|
||||
func _parse_default_uv_scale(texture_scale : Vector2) -> String:
|
||||
var entry_str = "\"scale\": [{x}, {y}]"
|
||||
return entry_str.format({
|
||||
"x": texture_scale.x,
|
||||
"y": texture_scale.y
|
||||
})
|
||||
|
||||
## Exports this game's configuration with an icon, .cfg, and all accompanying FGD files in the [FuncGodotLocalConfig] [b]Trenchbroom Game Config Folder[/b].
|
||||
func export_file() -> void:
|
||||
var config_folder: String = FuncGodotLocalConfig.get_setting(FuncGodotLocalConfig.PROPERTY.TRENCHBROOM_GAME_CONFIG_FOLDER) as String
|
||||
if config_folder.is_empty():
|
||||
printerr("Skipping export: No TrenchBroom Game folder")
|
||||
return
|
||||
|
||||
# Make sure FGD file is set
|
||||
if not fgd_file:
|
||||
printerr("Skipping export: No FGD file")
|
||||
return
|
||||
|
||||
var config_dir := DirAccess.open(config_folder)
|
||||
# Create config folder in case it does not exist
|
||||
if config_dir == null:
|
||||
print("Couldn't open directory, creating...")
|
||||
var err := DirAccess.make_dir_recursive_absolute(config_folder)
|
||||
if err != OK:
|
||||
printerr("Skipping export: Failed to create directory")
|
||||
return
|
||||
|
||||
# Icon
|
||||
var icon_path : String = config_folder + "/icon.png"
|
||||
print("Exporting icon to ", icon_path)
|
||||
var export_icon : Image = icon.get_image()
|
||||
export_icon.resize(32, 32, Image.INTERPOLATE_LANCZOS)
|
||||
export_icon.save_png(icon_path)
|
||||
|
||||
# .cfg
|
||||
var target_file_path: String = config_folder + "/GameConfig.cfg"
|
||||
print("Exporting TrenchBroom Game Config to ", target_file_path)
|
||||
var file = FileAccess.open(target_file_path, FileAccess.WRITE)
|
||||
file.store_string(_build_class_text())
|
||||
file.close()
|
||||
|
||||
# FGD
|
||||
var export_fgd : FuncGodotFGDFile = fgd_file.duplicate()
|
||||
export_fgd.generate_model_point_class_models = generate_model_point_class_models
|
||||
export_fgd.do_export_file(FuncGodotFGDFile.FuncGodotTargetMapEditors.TRENCHBROOM, config_folder)
|
||||
print("TrenchBroom Game Config export complete\n")
|
||||
|
||||
#region GameConfigDeclarations
|
||||
func _get_game_config_v4_text() -> String:
|
||||
return """\
|
||||
{
|
||||
"version": 4,
|
||||
"name": "%s",
|
||||
"icon": "icon.png",
|
||||
"fileformats": [
|
||||
%s
|
||||
],
|
||||
"filesystem": {
|
||||
"searchpath": ".",
|
||||
"packageformat": { "extension": ".zip", "format": "zip" }
|
||||
},
|
||||
"textures": {
|
||||
"package": { "type": "directory", "root": "%s" },
|
||||
"format": { "extensions": ["jpg", "jpeg", "tga", "png", "D", "C"], "format": "image" },
|
||||
"excludes": [ %s ],
|
||||
"palette": "%s",
|
||||
"attribute": ["_tb_textures", "wad"]
|
||||
},
|
||||
"entities": {
|
||||
"definitions": [ %s ],
|
||||
"defaultcolor": "0.6 0.6 0.6 1.0",
|
||||
"modelformats": [ "bsp, mdl, md2" ],
|
||||
"scale": %s
|
||||
},
|
||||
"tags": {
|
||||
"brush": [
|
||||
%s
|
||||
],
|
||||
"brushface": [
|
||||
%s
|
||||
]
|
||||
},
|
||||
"faceattribs": {
|
||||
"defaults": {
|
||||
%s
|
||||
},
|
||||
"contentflags": [],
|
||||
"surfaceflags": []
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
func _get_game_config_v9v8_text() -> String:
|
||||
var config_text: String = """\
|
||||
{
|
||||
"version": 9,
|
||||
"name": "%s",
|
||||
"icon": "icon.png",
|
||||
"fileformats": [
|
||||
%s
|
||||
],
|
||||
"filesystem": {
|
||||
"searchpath": ".",
|
||||
"packageformat": { "extension": ".zip", "format": "zip" }
|
||||
},
|
||||
"materials": {
|
||||
"root": "%s",
|
||||
"extensions": [".bmp", ".exr", ".hdr", ".jpeg", ".jpg", ".png", ".tga", ".webp", ".D", ".C"],
|
||||
"excludes": [ %s ],
|
||||
"palette": "%s",
|
||||
"attribute": "wad"
|
||||
},
|
||||
"entities": {
|
||||
"definitions": [ %s ],
|
||||
"defaultcolor": "0.6 0.6 0.6 1.0",
|
||||
"scale": %s
|
||||
},
|
||||
"tags": {
|
||||
"brush": [
|
||||
%s
|
||||
],
|
||||
"brushface": [
|
||||
%s
|
||||
]
|
||||
},
|
||||
"faceattribs": {
|
||||
"defaults": {
|
||||
%s
|
||||
},
|
||||
"contentflags": [],
|
||||
"surfaceflags": []
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
if game_config_version == GameConfigVersion.Version8:
|
||||
config_text = config_text.replace(": 9,", ": 8,")
|
||||
config_text = config_text.replace("material", "texture")
|
||||
|
||||
return config_text
|
||||
|
||||
#endregion
|
||||
Loading…
Add table
Add a link
Reference in a new issue